diff options
author | Nico Weber <thakis@chromium.org> | 2023-02-09 12:26:43 -0500 |
---|---|---|
committer | Linus Groh <mail@linusgroh.de> | 2023-02-10 14:23:37 +0000 |
commit | b232281d1510378834c7b971b441480789082727 (patch) | |
tree | 1c09b7f956b31582586e0d6ac891439d10bc9b89 /Userland/Libraries | |
parent | c61cfdd5edc0684e6a667be74004e5407893f337 (diff) | |
download | serenity-b232281d1510378834c7b971b441480789082727.zip |
LibGfx+icc: Read chromaticityTag
This isn't terribly useful. But some profiles, for example the ones at
https://vpifg.com/help/icc-profiles/, do contain this tag and it seems
nice to be able to dump it, just for completeness.
I haven't seen any files that contain a phosphor or colorant type
different from "Unknown", even for the Rec2020 profile on that page.
(It has x,y coordinates that match the values required for Rec2020,
but it doesn't set the phosphor or colorant type to that.)
Diffstat (limited to 'Userland/Libraries')
-rw-r--r-- | Userland/Libraries/LibGfx/ICC/Profile.cpp | 5 | ||||
-rw-r--r-- | Userland/Libraries/LibGfx/ICC/TagTypes.cpp | 66 | ||||
-rw-r--r-- | Userland/Libraries/LibGfx/ICC/TagTypes.h | 40 |
3 files changed, 110 insertions, 1 deletions
diff --git a/Userland/Libraries/LibGfx/ICC/Profile.cpp b/Userland/Libraries/LibGfx/ICC/Profile.cpp index 7afa21c88e..9c797a5a05 100644 --- a/Userland/Libraries/LibGfx/ICC/Profile.cpp +++ b/Userland/Libraries/LibGfx/ICC/Profile.cpp @@ -572,6 +572,8 @@ ErrorOr<NonnullRefPtr<TagData>> Profile::read_tag(ReadonlyBytes bytes, u32 offse auto type = tag_type(tag_bytes); switch (type) { + case ChromaticityTagData::Type: + return ChromaticityTagData::from_bytes(tag_bytes, offset_to_beginning_of_tag_data_element, size_of_tag_data_element); case CicpTagData::Type: return CicpTagData::from_bytes(tag_bytes, offset_to_beginning_of_tag_data_element, size_of_tag_data_element); case CurveTagData::Type: @@ -988,7 +990,8 @@ ErrorOr<void> Profile::check_tag_types() // ICC v4, 9.2.16 chromaticityTag // "Permitted tag types: chromaticityType" - // FIXME + if (!has_type(chromaticityTag, { ChromaticityTagData::Type }, {})) + return Error::from_string_literal("ICC::Profile: ChromaticityTagData has unexpected type"); // ICC v4, 9.2.17 cicpTag // "Permitted tag types: cicpType" diff --git a/Userland/Libraries/LibGfx/ICC/TagTypes.cpp b/Userland/Libraries/LibGfx/ICC/TagTypes.cpp index bcb6e8b63f..94d0ec70d7 100644 --- a/Userland/Libraries/LibGfx/ICC/TagTypes.cpp +++ b/Userland/Libraries/LibGfx/ICC/TagTypes.cpp @@ -83,6 +83,72 @@ TagTypeSignature tag_type(ReadonlyBytes tag_bytes) return *bit_cast<BigEndian<TagTypeSignature> const*>(tag_bytes.data()); } +StringView ChromaticityTagData::phosphor_or_colorant_type_name(PhosphorOrColorantType phosphor_or_colorant_type) +{ + switch (phosphor_or_colorant_type) { + case PhosphorOrColorantType::Unknown: + return "Unknown"sv; + case PhosphorOrColorantType::ITU_R_BT_709_2: + return "ITU-R BT.709-2"sv; + case PhosphorOrColorantType::SMPTE_RP145: + return "SMPTE RP145"sv; + case PhosphorOrColorantType::EBU_Tech_3213_E: + return "EBU Tech. 3213-E"sv; + case PhosphorOrColorantType::P22: + return "P22"sv; + case PhosphorOrColorantType::P3: + return "P3"sv; + case PhosphorOrColorantType::ITU_R_BT_2020: + return "ITU-R BT.2020"sv; + } + VERIFY_NOT_REACHED(); +} + +ErrorOr<NonnullRefPtr<ChromaticityTagData>> ChromaticityTagData::from_bytes(ReadonlyBytes bytes, u32 offset, u32 size) +{ + // ICC v4, 10.2 chromaticityType + VERIFY(tag_type(bytes) == Type); + TRY(check_reserved(bytes)); + + if (bytes.size() < 2 * sizeof(u32) + 2 * sizeof(u16)) + return Error::from_string_literal("ICC::Profile: chromaticityType has not enough data"); + + u16 number_of_device_channels = *bit_cast<BigEndian<u16> const*>(bytes.data() + 8); + PhosphorOrColorantType phosphor_or_colorant_type = *bit_cast<BigEndian<PhosphorOrColorantType> const*>(bytes.data() + 10); + + switch (phosphor_or_colorant_type) { + case PhosphorOrColorantType::Unknown: + case PhosphorOrColorantType::ITU_R_BT_709_2: + case PhosphorOrColorantType::SMPTE_RP145: + case PhosphorOrColorantType::EBU_Tech_3213_E: + case PhosphorOrColorantType::P22: + case PhosphorOrColorantType::P3: + case PhosphorOrColorantType::ITU_R_BT_2020: + break; + default: + return Error::from_string_literal("ICC::Profile: chromaticityType invalid phosphor_or_colorant_type"); + } + + // "If the value is 0001h to 0004h, the number of channels shall be three..." + if (phosphor_or_colorant_type != PhosphorOrColorantType::Unknown && number_of_device_channels != 3) + return Error::from_string_literal("ICC::Profile: chromaticityType unexpected number of channels for phosphor_or_colorant_type"); + + if (bytes.size() < 2 * sizeof(u32) + 2 * sizeof(u16) + number_of_device_channels * 2 * sizeof(u16Fixed16Number)) + return Error::from_string_literal("ICC::Profile: chromaticityType has not enough data for xy coordinates"); + + auto* raw_xy_coordinates = bit_cast<BigEndian<u16Fixed16Number> const*>(bytes.data() + 12); + Vector<xyCoordinate> xy_coordinates; + TRY(xy_coordinates.try_resize(number_of_device_channels)); + for (size_t i = 0; i < number_of_device_channels; ++i) { + xy_coordinates[i].x = U16Fixed16::create_raw(raw_xy_coordinates[2 * i]); + xy_coordinates[i].y = U16Fixed16::create_raw(raw_xy_coordinates[2 * i + 1]); + } + + // FIXME: Once I find files that have phosphor_or_colorant_type != Unknown, check that the values match the values in Table 31. + + return adopt_ref(*new ChromaticityTagData(offset, size, phosphor_or_colorant_type, move(xy_coordinates))); +} + ErrorOr<NonnullRefPtr<CicpTagData>> CicpTagData::from_bytes(ReadonlyBytes bytes, u32 offset, u32 size) { // ICC v4, 10.3 cicpType diff --git a/Userland/Libraries/LibGfx/ICC/TagTypes.h b/Userland/Libraries/LibGfx/ICC/TagTypes.h index b8f46aebf1..75a6e2dd2d 100644 --- a/Userland/Libraries/LibGfx/ICC/TagTypes.h +++ b/Userland/Libraries/LibGfx/ICC/TagTypes.h @@ -59,6 +59,46 @@ public: } }; +// ICC v4, 10.2 chromaticityType +class ChromaticityTagData : public TagData { +public: + static constexpr TagTypeSignature Type { 0x6368726D }; // 'chrm' + + static ErrorOr<NonnullRefPtr<ChromaticityTagData>> from_bytes(ReadonlyBytes, u32 offset, u32 size); + + // ICC v4, Table 31 — Colorant and phosphor encoding + enum class PhosphorOrColorantType : u16 { + Unknown = 0, + ITU_R_BT_709_2 = 1, + SMPTE_RP145 = 2, + EBU_Tech_3213_E = 3, + P22 = 4, + P3 = 5, + ITU_R_BT_2020 = 6, + }; + + static StringView phosphor_or_colorant_type_name(PhosphorOrColorantType); + + struct xyCoordinate { + U16Fixed16 x; + U16Fixed16 y; + }; + + ChromaticityTagData(u32 offset, u32 size, PhosphorOrColorantType phosphor_or_colorant_type, Vector<xyCoordinate> xy_coordinates) + : TagData(offset, size, Type) + , m_phosphor_or_colorant_type(phosphor_or_colorant_type) + , m_xy_coordinates(move(xy_coordinates)) + { + } + + PhosphorOrColorantType phosphor_or_colorant_type() const { return m_phosphor_or_colorant_type; } + Vector<xyCoordinate> xy_coordinates() const { return m_xy_coordinates; } + +private: + PhosphorOrColorantType m_phosphor_or_colorant_type; + Vector<xyCoordinate> m_xy_coordinates; +}; + // ICC v4, 10.3 cicpType // "The cicpType specifies Coding-independent code points for video signal type identification." // See presentations at https://www.color.org/events/HDR_experts.xalter for background. |