diff --git a/Userland/Libraries/LibGfx/ICCProfile.cpp b/Userland/Libraries/LibGfx/ICCProfile.cpp index 70798183a9d..84d11f254e6 100644 --- a/Userland/Libraries/LibGfx/ICCProfile.cpp +++ b/Userland/Libraries/LibGfx/ICCProfile.cpp @@ -550,6 +550,29 @@ static ErrorOr check_reserved(ReadonlyBytes tag_bytes) return {}; } +ErrorOr> CurveTagData::from_bytes(ReadonlyBytes bytes, u32 offset, u32 size) +{ + // ICC v4, 10.6 curveType + VERIFY(tag_type(bytes) == Type); + TRY(check_reserved(bytes)); + + if (bytes.size() < 3 * sizeof(u32)) + return Error::from_string_literal("ICC::Profile: curveType has not enough data for count"); + u32 count = *bit_cast const*>(bytes.data() + 8); + + if (bytes.size() < 3 * sizeof(u32) + count * sizeof(u16)) + return Error::from_string_literal("ICC::Profile: curveType has not enough data for curve points"); + + BigEndian const* raw_values = bit_cast const*>(bytes.data() + 12); + Vector values; + TRY(values.try_resize(count)); + + for (u32 i = 0; i < count; ++i) + values[i] = raw_values[i]; + + return adopt_ref(*new CurveTagData(offset, size, move(values))); +} + ErrorOr> MultiLocalizedUnicodeTagData::from_bytes(ReadonlyBytes bytes, u32 offset, u32 size) { // ICC v4, 10.15 multiLocalizedUnicodeType @@ -870,6 +893,8 @@ ErrorOr> Profile::read_tag(ReadonlyBytes bytes, Detail::T auto type = tag_type(tag_bytes); switch (type) { + case CurveTagData::Type: + return CurveTagData::from_bytes(tag_bytes, entry.offset_to_beginning_of_tag_data_element, entry.size_of_tag_data_element); case MultiLocalizedUnicodeTagData::Type: return MultiLocalizedUnicodeTagData::from_bytes(tag_bytes, entry.offset_to_beginning_of_tag_data_element, entry.size_of_tag_data_element); case S15Fixed16ArrayTagData::Type: diff --git a/Userland/Libraries/LibGfx/ICCProfile.h b/Userland/Libraries/LibGfx/ICCProfile.h index 736b57035f3..6243dab5db0 100644 --- a/Userland/Libraries/LibGfx/ICCProfile.h +++ b/Userland/Libraries/LibGfx/ICCProfile.h @@ -258,6 +258,36 @@ public: } }; +// ICC v4, 10.6 curveType +class CurveTagData : public TagData { +public: + static constexpr TagTypeSignature Type { 0x63757276 }; // 'curv' + + static ErrorOr> from_bytes(ReadonlyBytes, u32 offset, u32 size); + + CurveTagData(u32 offset, u32 size, Vector values) + : TagData(offset, size, Type) + , m_values(move(values)) + { + } + + // "The curveType embodies a one-dimensional function which maps an input value in the domain of the function + // to an output value in the range of the function. The domain and range values are in the range of 0,0 to 1,0. + // - When n is equal to 0, an identity response is assumed. + // - When n is equal to 1, then the curve value shall be interpreted as a gamma value, encoded as a + // u8Fixed8Number. Gamma shall be interpreted as the exponent in the equation y = pow(x,γ) and not as an inverse. + // - When n is greater than 1, the curve values (which embody a sampled one-dimensional function) shall be + // defined as follows: + // - The first entry represents the input value 0,0, the last entry represents the input value 1,0, and intermediate + // entries are uniformly spaced using an increment of 1,0/(n-1). These entries are encoded as uInt16Numbers + // (i.e. the values represented by the entries, which are in the range 0,0 to 1,0 are encoded in the range 0 to + // 65 535). Function values between the entries shall be obtained through linear interpolation." + Vector const& values() const { return m_values; } + +private: + Vector m_values; +}; + // ICC v4, 10.15 multiLocalizedUnicodeType class MultiLocalizedUnicodeTagData : public TagData { public: diff --git a/Userland/Utilities/icc.cpp b/Userland/Utilities/icc.cpp index a92ec51d4ea..a989a275c8e 100644 --- a/Userland/Utilities/icc.cpp +++ b/Userland/Utilities/icc.cpp @@ -94,7 +94,17 @@ ErrorOr serenity_main(Main::Arguments arguments) profile->for_each_tag([](auto tag_signature, auto tag_data) { outln("{}: {}, offset {}, size {}", tag_signature, tag_data->type(), tag_data->offset(), tag_data->size()); - if (tag_data->type() == Gfx::ICC::MultiLocalizedUnicodeTagData::Type) { + if (tag_data->type() == Gfx::ICC::CurveTagData::Type) { + auto& curve = static_cast(*tag_data); + if (curve.values().is_empty()) { + outln(" identity curve"); + } else if (curve.values().size() == 1) { + outln(" gamma: {}", FixedPoint<8, u16>::create_raw(curve.values()[0])); + } else { + // FIXME: Maybe print the actual points if -v is passed? + outln(" curve with {} points", curve.values().size()); + } + } else if (tag_data->type() == Gfx::ICC::MultiLocalizedUnicodeTagData::Type) { auto& multi_localized_unicode = static_cast(*tag_data); for (auto& record : multi_localized_unicode.records()) { outln(" {:c}{:c}/{:c}{:c}: \"{}\"",