diff --git a/Userland/Libraries/LibGfx/ICCProfile.cpp b/Userland/Libraries/LibGfx/ICCProfile.cpp index d42e6f6be4..371283f937 100644 --- a/Userland/Libraries/LibGfx/ICCProfile.cpp +++ b/Userland/Libraries/LibGfx/ICCProfile.cpp @@ -781,6 +781,28 @@ ErrorOr> TextTagData::from_bytes(ReadonlyBytes bytes, return adopt_ref(*new TextTagData(offset, size, TRY(String::from_utf8(StringView(text_data, length - 1))))); } +ErrorOr> XYZTagData::from_bytes(ReadonlyBytes bytes, u32 offset, u32 size) +{ + // ICC v4, 10.31 XYZType + VERIFY(tag_type(bytes) == XYZTagData::Type); + TRY(check_reserved(bytes)); + + // "The XYZType contains an array of three encoded values for PCSXYZ, CIEXYZ, or nCIEXYZ values. The + // number of sets of values is determined from the size of the tag." + size_t byte_size = bytes.size() - 8; + if (byte_size % sizeof(XYZNumber) != 0) + return Error::from_string_literal("ICC::Profile: XYZType wrong size"); + + size_t xyz_count = byte_size / sizeof(XYZNumber); + XYZNumber const* raw_xyzs = bit_cast(bytes.data() + 8); + Vector xyzs; + TRY(xyzs.try_resize(xyz_count)); + for (size_t i = 0; i < xyz_count; ++i) + xyzs[i] = (XYZ)raw_xyzs[i]; + + return adopt_ref(*new XYZTagData(offset, size, move(xyzs))); +} + ErrorOr Profile::read_header(ReadonlyBytes bytes) { if (bytes.size() < sizeof(ICCHeader)) @@ -832,6 +854,8 @@ ErrorOr> Profile::read_tag(ReadonlyBytes bytes, Detail::T return TextDescriptionTagData::from_bytes(tag_bytes, entry.offset_to_beginning_of_tag_data_element, entry.size_of_tag_data_element); case TextTagData::Type: return TextTagData::from_bytes(tag_bytes, entry.offset_to_beginning_of_tag_data_element, entry.size_of_tag_data_element); + case XYZTagData::Type: + return XYZTagData::from_bytes(tag_bytes, entry.offset_to_beginning_of_tag_data_element, entry.size_of_tag_data_element); default: // FIXME: optionally ignore tags of unknown type return adopt_ref(*new UnknownTagData(entry.offset_to_beginning_of_tag_data_element, entry.size_of_tag_data_element, type)); diff --git a/Userland/Libraries/LibGfx/ICCProfile.h b/Userland/Libraries/LibGfx/ICCProfile.h index 7b285b658a..3f3ae202cb 100644 --- a/Userland/Libraries/LibGfx/ICCProfile.h +++ b/Userland/Libraries/LibGfx/ICCProfile.h @@ -335,6 +335,25 @@ private: String m_text; }; +// ICC v4, 10.31 XYZType +class XYZTagData : public TagData { +public: + static constexpr TagTypeSignature Type { 0x58595A20 }; // 'XYZ ' + + static ErrorOr> from_bytes(ReadonlyBytes, u32 offset, u32 size); + + XYZTagData(u32 offset, u32 size, Vector xyzs) + : TagData(offset, size, Type) + , m_xyzs(move(xyzs)) + { + } + + Vector const& xyzs() const { return m_xyzs; } + +private: + Vector m_xyzs; +}; + namespace Detail { struct TagTableEntry; } diff --git a/Userland/Utilities/icc.cpp b/Userland/Utilities/icc.cpp index 0f17ebaea2..7f38fd672c 100644 --- a/Userland/Utilities/icc.cpp +++ b/Userland/Utilities/icc.cpp @@ -110,6 +110,9 @@ 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::XYZTagData::Type) { + for (auto& xyz : static_cast(*tag_data).xyzs()) + outln(" {}", xyz); } });