diff options
author | Nico Weber <thakis@chromium.org> | 2023-02-09 16:14:32 -0500 |
---|---|---|
committer | Linus Groh <mail@linusgroh.de> | 2023-02-10 14:02:19 +0000 |
commit | 664946c543df709ccf375bd5dab63d95a013d70f (patch) | |
tree | 390a2d44b2dcf4c138226ed8fe46f75d0ff07f27 /Userland | |
parent | 143f28b7358583398b7104e1b87734ca0e6c656b (diff) | |
download | serenity-664946c543df709ccf375bd5dab63d95a013d70f.zip |
LibGfx+icc: Read measurementType
Also not terribly useful in practice and mostly for completionism.
Lightroom Classic-exported jpegs contain this type in their ICC data.
Diffstat (limited to 'Userland')
-rw-r--r-- | Userland/Libraries/LibGfx/ICC/Profile.cpp | 5 | ||||
-rw-r--r-- | Userland/Libraries/LibGfx/ICC/TagTypes.cpp | 122 | ||||
-rw-r--r-- | Userland/Libraries/LibGfx/ICC/TagTypes.h | 66 | ||||
-rw-r--r-- | Userland/Utilities/icc.cpp | 7 |
4 files changed, 199 insertions, 1 deletions
diff --git a/Userland/Libraries/LibGfx/ICC/Profile.cpp b/Userland/Libraries/LibGfx/ICC/Profile.cpp index f7d1537db7..75041f8f8d 100644 --- a/Userland/Libraries/LibGfx/ICC/Profile.cpp +++ b/Userland/Libraries/LibGfx/ICC/Profile.cpp @@ -584,6 +584,8 @@ ErrorOr<NonnullRefPtr<TagData>> Profile::read_tag(ReadonlyBytes bytes, u32 offse return LutAToBTagData::from_bytes(tag_bytes, offset_to_beginning_of_tag_data_element, size_of_tag_data_element); case LutBToATagData::Type: return LutBToATagData::from_bytes(tag_bytes, offset_to_beginning_of_tag_data_element, size_of_tag_data_element); + case MeasurementTagData::Type: + return MeasurementTagData::from_bytes(tag_bytes, offset_to_beginning_of_tag_data_element, size_of_tag_data_element); case MultiLocalizedUnicodeTagData::Type: return MultiLocalizedUnicodeTagData::from_bytes(tag_bytes, offset_to_beginning_of_tag_data_element, size_of_tag_data_element); case NamedColor2TagData::Type: @@ -1115,7 +1117,8 @@ ErrorOr<void> Profile::check_tag_types() // ICC v4, 9.2.34 measurementTag // "Permitted tag types: measurementType" - // FIXME + if (!has_type(measurementTag, { MeasurementTagData::Type }, {})) + return Error::from_string_literal("ICC::Profile: measurementTag has unexpected type"); // ICC v4, 9.2.35 metadataTag // "Permitted tag types: dictType" diff --git a/Userland/Libraries/LibGfx/ICC/TagTypes.cpp b/Userland/Libraries/LibGfx/ICC/TagTypes.cpp index 8bbcb4f762..e3466d8fc1 100644 --- a/Userland/Libraries/LibGfx/ICC/TagTypes.cpp +++ b/Userland/Libraries/LibGfx/ICC/TagTypes.cpp @@ -16,6 +16,9 @@ namespace { // ICC V4, 4.6 s15Fixed16Number using s15Fixed16Number = i32; +// ICC V4, 4.7 u16Fixed16Number +using u16Fixed16Number = u32; + // ICC V4, 4.14 XYZNumber struct XYZNumber { BigEndian<s15Fixed16Number> x; @@ -432,6 +435,125 @@ ErrorOr<NonnullRefPtr<LutBToATagData>> LutBToATagData::from_bytes(ReadonlyBytes return adopt_ref(*new LutBToATagData(offset, size, header.number_of_input_channels, header.number_of_output_channels, e, move(clut_data))); } +ErrorOr<NonnullRefPtr<MeasurementTagData>> MeasurementTagData::from_bytes(ReadonlyBytes bytes, u32 offset, u32 size) +{ + // ICC v4, 10.14 measurementType + VERIFY(tag_type(bytes) == Type); + TRY(check_reserved(bytes)); + + // Table 49 — measurementType structure + struct MeasurementHeader { + BigEndian<StandardObserver> standard_observer; + XYZNumber tristimulus_value_for_measurement_backing; + BigEndian<MeasurementGeometry> measurement_geometry; + BigEndian<u16Fixed16Number> measurement_flare; + BigEndian<StandardIlluminant> standard_illuminant; + }; + static_assert(AssertSize<MeasurementHeader, 28>()); + + if (bytes.size() < 2 * sizeof(u32) + sizeof(MeasurementHeader)) + return Error::from_string_literal("ICC::Profile: measurementTag has not enough data"); + + auto& header = *bit_cast<MeasurementHeader const*>(bytes.data() + 8); + + TRY(validate_standard_observer(header.standard_observer)); + TRY(validate_measurement_geometry(header.measurement_geometry)); + TRY(validate_standard_illuminant(header.standard_illuminant)); + + return adopt_ref(*new MeasurementTagData(offset, size, header.standard_observer, header.tristimulus_value_for_measurement_backing, + header.measurement_geometry, U16Fixed16::create_raw(header.measurement_flare), header.standard_illuminant)); +} + +ErrorOr<void> MeasurementTagData::validate_standard_observer(StandardObserver standard_observer) +{ + switch (standard_observer) { + case StandardObserver::Unknown: + case StandardObserver::CIE_1931_standard_colorimetric_observer: + case StandardObserver::CIE_1964_standard_colorimetric_observer: + return {}; + } + return Error::from_string_literal("ICC::Profile: unknown standard_observer"); +} + +StringView MeasurementTagData::standard_observer_name(StandardObserver standard_observer) +{ + switch (standard_observer) { + case StandardObserver::Unknown: + return "Unknown"sv; + case StandardObserver::CIE_1931_standard_colorimetric_observer: + return "CIE 1931 standard colorimetric observer"sv; + case StandardObserver::CIE_1964_standard_colorimetric_observer: + return "CIE 1964 standard colorimetric observer"sv; + } + VERIFY_NOT_REACHED(); +} + +ErrorOr<void> MeasurementTagData::validate_measurement_geometry(MeasurementGeometry measurement_geometry) +{ + switch (measurement_geometry) { + case MeasurementGeometry::Unknown: + case MeasurementGeometry::Degrees_0_45_or_45_0: + case MeasurementGeometry::Degrees_0_d_or_d_0: + return {}; + } + return Error::from_string_literal("ICC::Profile: unknown measurement_geometry"); +} + +StringView MeasurementTagData::measurement_geometry_name(MeasurementGeometry measurement_geometry) +{ + switch (measurement_geometry) { + case MeasurementGeometry::Unknown: + return "Unknown"sv; + case MeasurementGeometry::Degrees_0_45_or_45_0: + return "0°:45° or 45°:0°"sv; + case MeasurementGeometry::Degrees_0_d_or_d_0: + return "0°:d or d:0°"sv; + } + VERIFY_NOT_REACHED(); +} + +ErrorOr<void> MeasurementTagData::validate_standard_illuminant(StandardIlluminant standard_illuminant) +{ + switch (standard_illuminant) { + case StandardIlluminant::Unknown: + case StandardIlluminant::D50: + case StandardIlluminant::D65: + case StandardIlluminant::D93: + case StandardIlluminant::F2: + case StandardIlluminant::D55: + case StandardIlluminant::A: + case StandardIlluminant::Equi_Power_E: + case StandardIlluminant::F8: + return {}; + } + return Error::from_string_literal("ICC::Profile: unknown standard_illuminant"); +} + +StringView MeasurementTagData::standard_illuminant_name(StandardIlluminant standard_illuminant) +{ + switch (standard_illuminant) { + case StandardIlluminant::Unknown: + return "Unknown"sv; + case StandardIlluminant::D50: + return "D50"sv; + case StandardIlluminant::D65: + return "D65"sv; + case StandardIlluminant::D93: + return "D93"sv; + case StandardIlluminant::F2: + return "F2"sv; + case StandardIlluminant::D55: + return "D55"sv; + case StandardIlluminant::A: + return "A"sv; + case StandardIlluminant::Equi_Power_E: + return "Equi-Power (E)"sv; + case StandardIlluminant::F8: + return "F8"sv; + } + VERIFY_NOT_REACHED(); +} + ErrorOr<NonnullRefPtr<MultiLocalizedUnicodeTagData>> MultiLocalizedUnicodeTagData::from_bytes(ReadonlyBytes bytes, u32 offset, u32 size) { // ICC v4, 10.15 multiLocalizedUnicodeType diff --git a/Userland/Libraries/LibGfx/ICC/TagTypes.h b/Userland/Libraries/LibGfx/ICC/TagTypes.h index 7096643fd6..ba2af312fb 100644 --- a/Userland/Libraries/LibGfx/ICC/TagTypes.h +++ b/Userland/Libraries/LibGfx/ICC/TagTypes.h @@ -17,6 +17,7 @@ namespace Gfx::ICC { using S15Fixed16 = FixedPoint<16, i32>; +using U16Fixed16 = FixedPoint<16, u32>; struct XYZ { double x { 0 }; @@ -332,6 +333,71 @@ private: Optional<CLUTData> m_clut; }; +// ICC v4, 10.14 measurementType +class MeasurementTagData : public TagData { +public: + static constexpr TagTypeSignature Type { 0x6D656173 }; // 'meas' + + static ErrorOr<NonnullRefPtr<MeasurementTagData>> from_bytes(ReadonlyBytes, u32 offset, u32 size); + + // Table 50 — Standard observer encodings + enum class StandardObserver { + Unknown = 0, + CIE_1931_standard_colorimetric_observer = 1, + CIE_1964_standard_colorimetric_observer = 2, + }; + static ErrorOr<void> validate_standard_observer(StandardObserver); + static StringView standard_observer_name(StandardObserver); + + // Table 51 — Measurement geometry encodings + enum class MeasurementGeometry { + Unknown = 0, + Degrees_0_45_or_45_0 = 1, + Degrees_0_d_or_d_0 = 2, + }; + static ErrorOr<void> validate_measurement_geometry(MeasurementGeometry); + static StringView measurement_geometry_name(MeasurementGeometry); + + // Table 53 — Standard illuminant encodings + enum class StandardIlluminant { + Unknown = 0, + D50 = 1, + D65 = 2, + D93 = 3, + F2 = 4, + D55 = 5, + A = 6, + Equi_Power_E = 7, + F8 = 8, + }; + static ErrorOr<void> validate_standard_illuminant(StandardIlluminant); + static StringView standard_illuminant_name(StandardIlluminant); + + MeasurementTagData(u32 offset, u32 size, StandardObserver standard_observer, XYZ tristimulus_value_for_measurement_backing, + MeasurementGeometry measurement_geometry, U16Fixed16 measurement_flare, StandardIlluminant standard_illuminant) + : TagData(offset, size, Type) + , m_standard_observer(standard_observer) + , m_tristimulus_value_for_measurement_backing(tristimulus_value_for_measurement_backing) + , m_measurement_geometry(measurement_geometry) + , m_measurement_flare(measurement_flare) + , m_standard_illuminant(standard_illuminant) + { + } + + StandardObserver standard_observer() const { return m_standard_observer; } + XYZ const& tristimulus_value_for_measurement_backing() const { return m_tristimulus_value_for_measurement_backing; } + MeasurementGeometry measurement_geometry() const { return m_measurement_geometry; } + U16Fixed16 measurement_flare() const { return m_measurement_flare; } + StandardIlluminant standard_illuminant() const { return m_standard_illuminant; } + +private: + StandardObserver m_standard_observer; + XYZ m_tristimulus_value_for_measurement_backing; + MeasurementGeometry m_measurement_geometry; + U16Fixed16 m_measurement_flare; + StandardIlluminant m_standard_illuminant; +}; + // ICC v4, 10.15 multiLocalizedUnicodeType class MultiLocalizedUnicodeTagData : public TagData { public: diff --git a/Userland/Utilities/icc.cpp b/Userland/Utilities/icc.cpp index 4b511295f8..e3580b1600 100644 --- a/Userland/Utilities/icc.cpp +++ b/Userland/Utilities/icc.cpp @@ -212,6 +212,13 @@ ErrorOr<int> serenity_main(Main::Arguments arguments) } else { outln(" color lookup table: (not set)"); } + } else if (tag_data->type() == Gfx::ICC::MeasurementTagData::Type) { + auto& measurement = static_cast<Gfx::ICC::MeasurementTagData&>(*tag_data); + outln(" standard observer: {}", Gfx::ICC::MeasurementTagData::standard_observer_name(measurement.standard_observer())); + outln(" tristimulus value for measurement backing: {}", measurement.tristimulus_value_for_measurement_backing()); + outln(" measurement geometry: {}", Gfx::ICC::MeasurementTagData::measurement_geometry_name(measurement.measurement_geometry())); + outln(" measurement flare: {} %", measurement.measurement_flare() * 100); + outln(" standard illuminant: {}", Gfx::ICC::MeasurementTagData::standard_illuminant_name(measurement.standard_illuminant())); } else if (tag_data->type() == Gfx::ICC::MultiLocalizedUnicodeTagData::Type) { auto& multi_localized_unicode = static_cast<Gfx::ICC::MultiLocalizedUnicodeTagData&>(*tag_data); for (auto& record : multi_localized_unicode.records()) { |