From 8bd64f001cde327d5c2b6f3ba90d9c31d29d8934 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Tue, 7 Feb 2023 15:15:55 -0500 Subject: LibGfx+icc: Read signatureType This isn't used by any mandatory tags, and it's not terribly useful. But jpegs exported by Lightroom Classic write the 'tech' tag, and it seems nice to be able to dump its contents. signatureType stores a single u32 which for different tags with this type means different things. In each case, the value is one from a short table of valid values, suggesting this should be a per-tag enum class instead of a per-tag DistinctFourCC, per the comment at the top of DistincFourCC.h. On the other hand, 3 of the 4 tables have an explicit "It is possible that the ICC will define other signature values in the future" note, which suggests the FourCC might actually be the way to go. For now, just punt on that and manually dump the u32 in fourcc style in icc.cpp and don't add any to_string() methods that return a readable string based on the contents of these tables. --- Userland/Libraries/LibGfx/ICC/Profile.cpp | 14 ++++++++++---- Userland/Libraries/LibGfx/ICC/TagTypes.cpp | 14 ++++++++++++++ Userland/Libraries/LibGfx/ICC/TagTypes.h | 19 +++++++++++++++++++ Userland/Utilities/icc.cpp | 10 ++++++++++ 4 files changed, 53 insertions(+), 4 deletions(-) diff --git a/Userland/Libraries/LibGfx/ICC/Profile.cpp b/Userland/Libraries/LibGfx/ICC/Profile.cpp index b3f96177e8..f4d5a8cedc 100644 --- a/Userland/Libraries/LibGfx/ICC/Profile.cpp +++ b/Userland/Libraries/LibGfx/ICC/Profile.cpp @@ -586,6 +586,8 @@ ErrorOr> Profile::read_tag(ReadonlyBytes bytes, u32 offse return ParametricCurveTagData::from_bytes(tag_bytes, offset_to_beginning_of_tag_data_element, size_of_tag_data_element); case S15Fixed16ArrayTagData::Type: return S15Fixed16ArrayTagData::from_bytes(tag_bytes, offset_to_beginning_of_tag_data_element, size_of_tag_data_element); + case SignatureTagData::Type: + return SignatureTagData::from_bytes(tag_bytes, offset_to_beginning_of_tag_data_element, size_of_tag_data_element); case TextDescriptionTagData::Type: return TextDescriptionTagData::from_bytes(tag_bytes, offset_to_beginning_of_tag_data_element, size_of_tag_data_element); case TextTagData::Type: @@ -992,7 +994,8 @@ ErrorOr Profile::check_tag_types() // ICC v4, 9.2.21 colorimetricIntentImageStateTag // "Permitted tag types: signatureType" - // FIXME + if (!has_type(colorimetricIntentImageStateTag, { SignatureTagData::Type }, {})) + return Error::from_string_literal("ICC::Profile: colorimetricIntentImageStateTag has unexpected type"); // ICC v4, 9.2.22 copyrightTag // "Permitted tag types: multiLocalizedUnicodeType" @@ -1154,7 +1157,8 @@ ErrorOr Profile::check_tag_types() // ICC v4, 9.2.39 perceptualRenderingIntentGamutTag // "Permitted tag types: signatureType" - // FIXME + if (!has_type(perceptualRenderingIntentGamutTag, { SignatureTagData::Type }, {})) + return Error::from_string_literal("ICC::Profile: perceptualRenderingIntentGamutTag has unexpected type"); // ICC v4, 9.2.40 preview0Tag // "Permitted tag types: lut8Type or lut16Type or lutAToBType or lutBToAType" @@ -1220,11 +1224,13 @@ ErrorOr Profile::check_tag_types() // ICC v4, 9.2.48 saturationRenderingIntentGamutTag // "Permitted tag types: signatureType" - // FIXME + if (!has_type(saturationRenderingIntentGamutTag, { SignatureTagData::Type }, {})) + return Error::from_string_literal("ICC::Profile: saturationRenderingIntentGamutTag has unexpected type"); // ICC v4, 9.2.49 technologyTag // "Permitted tag types: signatureType" - // FIXME + if (!has_type(technologyTag, { SignatureTagData::Type }, {})) + return Error::from_string_literal("ICC::Profile: technologyTag has unexpected type"); // ICC v4, 9.2.50 viewingCondDescTag // "Permitted tag types: multiLocalizedUnicodeType" diff --git a/Userland/Libraries/LibGfx/ICC/TagTypes.cpp b/Userland/Libraries/LibGfx/ICC/TagTypes.cpp index 7ddf2db61d..d29321a7ea 100644 --- a/Userland/Libraries/LibGfx/ICC/TagTypes.cpp +++ b/Userland/Libraries/LibGfx/ICC/TagTypes.cpp @@ -530,6 +530,20 @@ ErrorOr> TextDescriptionTagData::from_byte return adopt_ref(*new TextDescriptionTagData(offset, size, TRY(String::from_utf8(ascii_description)), unicode_language_code, move(unicode_description), move(macintosh_description))); } +ErrorOr> SignatureTagData::from_bytes(ReadonlyBytes bytes, u32 offset, u32 size) +{ + // ICC v4, 10.23 signatureType + VERIFY(tag_type(bytes) == Type); + TRY(check_reserved(bytes)); + + if (bytes.size() < 3 * sizeof(u32)) + return Error::from_string_literal("ICC::Profile: signatureType has not enough data"); + + u32 signature = *bit_cast const*>(bytes.data() + 8); + + return adopt_ref(*new SignatureTagData(offset, size, signature)); +} + ErrorOr> TextTagData::from_bytes(ReadonlyBytes bytes, u32 offset, u32 size) { // ICC v4, 10.24 textType diff --git a/Userland/Libraries/LibGfx/ICC/TagTypes.h b/Userland/Libraries/LibGfx/ICC/TagTypes.h index 9fd56484c0..9c3b3969a4 100644 --- a/Userland/Libraries/LibGfx/ICC/TagTypes.h +++ b/Userland/Libraries/LibGfx/ICC/TagTypes.h @@ -464,6 +464,25 @@ private: Optional m_macintosh_description; }; +// ICC v4, 10.23 signatureType +class SignatureTagData : public TagData { +public: + static constexpr TagTypeSignature Type { 0x73696720 }; // 'sig ' + + static ErrorOr> from_bytes(ReadonlyBytes, u32 offset, u32 size); + + SignatureTagData(u32 offset, u32 size, u32 signature) + : TagData(offset, size, Type) + , m_signature(signature) + { + } + + u32 signature() const { return m_signature; } + +private: + u32 m_signature; +}; + // ICC v4, 10.24 textType class TextTagData : public TagData { public: diff --git a/Userland/Utilities/icc.cpp b/Userland/Utilities/icc.cpp index 3f3f67107a..e0c43c68b5 100644 --- a/Userland/Utilities/icc.cpp +++ b/Userland/Utilities/icc.cpp @@ -229,6 +229,16 @@ ErrorOr serenity_main(Main::Arguments arguments) i++; } outln(" ]"); + } else if (tag_data->type() == Gfx::ICC::SignatureTagData::Type) { + auto& signature = static_cast(*tag_data); + + // FIXME: For colorimetricIntentImageStateTag, interpret signature according to ICC v4 Table 26 + // FIXME: For perceptualRenderingIntentGamutTag, interpret signature according to ICC v4 Table 27 + // FIXME: For saturationRenderingIntentGamutTag, interpret signature according to ICC v4 Table 28 + // FIXME: For technologyTag, interpret signature according to ICC v4 Table 29 + outln(" signature: '{:c}{:c}{:c}{:c}' / 0x{:08x}", + signature.signature() >> 24, (signature.signature() >> 16) & 0xff, (signature.signature() >> 8) & 0xff, signature.signature() & 0xff, + signature.signature()); } else if (tag_data->type() == Gfx::ICC::TextDescriptionTagData::Type) { auto& text_description = static_cast(*tag_data); outln(" ascii: \"{}\"", text_description.ascii_description()); -- cgit v1.2.3