diff --git a/Userland/Libraries/LibGfx/ICC/Profile.cpp b/Userland/Libraries/LibGfx/ICC/Profile.cpp index 75041f8f8d8..7afa21c88ea 100644 --- a/Userland/Libraries/LibGfx/ICC/Profile.cpp +++ b/Userland/Libraries/LibGfx/ICC/Profile.cpp @@ -600,6 +600,8 @@ ErrorOr> Profile::read_tag(ReadonlyBytes bytes, u32 offse return TextDescriptionTagData::from_bytes(tag_bytes, offset_to_beginning_of_tag_data_element, size_of_tag_data_element); case TextTagData::Type: return TextTagData::from_bytes(tag_bytes, offset_to_beginning_of_tag_data_element, size_of_tag_data_element); + case ViewingConditionsTagData::Type: + return ViewingConditionsTagData::from_bytes(tag_bytes, offset_to_beginning_of_tag_data_element, size_of_tag_data_element); case XYZTagData::Type: return XYZTagData::from_bytes(tag_bytes, offset_to_beginning_of_tag_data_element, size_of_tag_data_element); default: @@ -1259,7 +1261,8 @@ ErrorOr Profile::check_tag_types() // ICC v4, 9.2.51 viewingConditionsTag // "Permitted tag types: viewingConditionsType" - // FIXME + if (!has_type(viewingConditionsTag, { ViewingConditionsTagData::Type }, {})) + return Error::from_string_literal("ICC::Profile: viewingConditionsTag has unexpected type"); // FIXME: Add validation for v2-only tags: // - ICC v2, 6.4.14 crdInfoTag diff --git a/Userland/Libraries/LibGfx/ICC/TagTypes.cpp b/Userland/Libraries/LibGfx/ICC/TagTypes.cpp index e3466d8fc1f..bcb6e8b63f3 100644 --- a/Userland/Libraries/LibGfx/ICC/TagTypes.cpp +++ b/Userland/Libraries/LibGfx/ICC/TagTypes.cpp @@ -934,6 +934,31 @@ ErrorOr> TextTagData::from_bytes(ReadonlyBytes bytes, return adopt_ref(*new TextTagData(offset, size, TRY(String::from_utf8(StringView(text_data, length - 1))))); } +ErrorOr> ViewingConditionsTagData::from_bytes(ReadonlyBytes bytes, u32 offset, u32 size) +{ + // ICC v4, 10.30 viewingConditionsType + VERIFY(tag_type(bytes) == Type); + TRY(check_reserved(bytes)); + + // Table 84 — viewingConditionsType encoding + struct ViewingConditionsHeader { + XYZNumber unnormalized_ciexyz_values_for_illuminant; // "(in which Y is in cd/m2)" + XYZNumber unnormalized_ciexyz_values_for_surround; // "(in which Y is in cd/m2)" + BigEndian illuminant_type; + }; + static_assert(AssertSize()); + + if (bytes.size() < 2 * sizeof(u32) + sizeof(ViewingConditionsHeader)) + return Error::from_string_literal("ICC::Profile: viewingConditionsType has not enough data"); + + auto& header = *bit_cast(bytes.data() + 8); + + TRY(MeasurementTagData::validate_standard_illuminant(header.illuminant_type)); + + return adopt_ref(*new ViewingConditionsTagData(offset, size, header.unnormalized_ciexyz_values_for_illuminant, + header.unnormalized_ciexyz_values_for_surround, header.illuminant_type)); +} + ErrorOr> XYZTagData::from_bytes(ReadonlyBytes bytes, u32 offset, u32 size) { // ICC v4, 10.31 XYZType diff --git a/Userland/Libraries/LibGfx/ICC/TagTypes.h b/Userland/Libraries/LibGfx/ICC/TagTypes.h index ba2af312fb7..b8f46aebf1f 100644 --- a/Userland/Libraries/LibGfx/ICC/TagTypes.h +++ b/Userland/Libraries/LibGfx/ICC/TagTypes.h @@ -679,6 +679,32 @@ private: String m_text; }; +// ICC v4, 10.30 viewingConditionsType +class ViewingConditionsTagData : public TagData { +public: + static constexpr TagTypeSignature Type { 0x76696577 }; // 'view' + + static ErrorOr> from_bytes(ReadonlyBytes, u32 offset, u32 size); + + ViewingConditionsTagData(u32 offset, u32 size, XYZ const& unnormalized_ciexyz_values_for_illuminant, + XYZ const& unnormalized_ciexyz_values_for_surround, MeasurementTagData::StandardIlluminant illuminant_type) + : TagData(offset, size, Type) + , m_unnormalized_ciexyz_values_for_illuminant(unnormalized_ciexyz_values_for_illuminant) + , m_unnormalized_ciexyz_values_for_surround(unnormalized_ciexyz_values_for_surround) + , m_illuminant_type(illuminant_type) + { + } + + XYZ const& unnormalized_ciexyz_values_for_illuminant() const { return m_unnormalized_ciexyz_values_for_illuminant; } + XYZ const& unnormalized_ciexyz_values_for_surround() const { return m_unnormalized_ciexyz_values_for_surround; } + MeasurementTagData::StandardIlluminant illuminant_type() const { return m_illuminant_type; } + +private: + XYZ m_unnormalized_ciexyz_values_for_illuminant; // "(in which Y is in cd/m2)" + XYZ m_unnormalized_ciexyz_values_for_surround; // "(in which Y is in cd/m2)" + MeasurementTagData::StandardIlluminant m_illuminant_type; +}; + // ICC v4, 10.31 XYZType class XYZTagData : public TagData { public: diff --git a/Userland/Utilities/icc.cpp b/Userland/Utilities/icc.cpp index e3580b16002..60b33391b9b 100644 --- a/Userland/Utilities/icc.cpp +++ b/Userland/Utilities/icc.cpp @@ -311,6 +311,11 @@ ErrorOr serenity_main(Main::Arguments arguments) out_optional(" macintosh", MUST(text_description.macintosh_description().map([](auto description) { return String::formatted("\"{}\"", description); }))); } else if (tag_data->type() == Gfx::ICC::TextTagData::Type) { outln(" text: \"{}\"", static_cast(*tag_data).text()); + } else if (tag_data->type() == Gfx::ICC::ViewingConditionsTagData::Type) { + auto& viewing_conditions = static_cast(*tag_data); + outln(" unnormalized CIEXYZ values for illuminant (in which Y is in cd/m²): {}", viewing_conditions.unnormalized_ciexyz_values_for_illuminant()); + outln(" unnormalized CIEXYZ values for surround (in which Y is in cd/m²): {}", viewing_conditions.unnormalized_ciexyz_values_for_surround()); + outln(" illuminant type: {}", Gfx::ICC::MeasurementTagData::standard_illuminant_name(viewing_conditions.illuminant_type())); } else if (tag_data->type() == Gfx::ICC::XYZTagData::Type) { for (auto& xyz : static_cast(*tag_data).xyzs()) outln(" {}", xyz);