mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-21 23:20:20 +00:00
LibGfx+icc: Read measurementType
Also not terribly useful in practice and mostly for completionism. Lightroom Classic-exported jpegs contain this type in their ICC data.
This commit is contained in:
parent
143f28b735
commit
664946c543
Notes:
sideshowbarker
2024-07-17 00:34:18 +09:00
Author: https://github.com/nico Commit: https://github.com/SerenityOS/serenity/commit/664946c543 Pull-request: https://github.com/SerenityOS/serenity/pull/17402
4 changed files with 199 additions and 1 deletions
|
@ -584,6 +584,8 @@ ErrorOr<NonnullRefPtr<TagData>> Profile::read_tag(ReadonlyBytes bytes, u32 offse
|
|||
return LutAToBTagData::from_bytes(tag_bytes, offset_to_beginning_of_tag_data_element, size_of_tag_data_element);
|
||||
case LutBToATagData::Type:
|
||||
return LutBToATagData::from_bytes(tag_bytes, offset_to_beginning_of_tag_data_element, size_of_tag_data_element);
|
||||
case MeasurementTagData::Type:
|
||||
return MeasurementTagData::from_bytes(tag_bytes, offset_to_beginning_of_tag_data_element, size_of_tag_data_element);
|
||||
case MultiLocalizedUnicodeTagData::Type:
|
||||
return MultiLocalizedUnicodeTagData::from_bytes(tag_bytes, offset_to_beginning_of_tag_data_element, size_of_tag_data_element);
|
||||
case NamedColor2TagData::Type:
|
||||
|
@ -1115,7 +1117,8 @@ ErrorOr<void> Profile::check_tag_types()
|
|||
|
||||
// ICC v4, 9.2.34 measurementTag
|
||||
// "Permitted tag types: measurementType"
|
||||
// FIXME
|
||||
if (!has_type(measurementTag, { MeasurementTagData::Type }, {}))
|
||||
return Error::from_string_literal("ICC::Profile: measurementTag has unexpected type");
|
||||
|
||||
// ICC v4, 9.2.35 metadataTag
|
||||
// "Permitted tag types: dictType"
|
||||
|
|
|
@ -16,6 +16,9 @@ namespace {
|
|||
// ICC V4, 4.6 s15Fixed16Number
|
||||
using s15Fixed16Number = i32;
|
||||
|
||||
// ICC V4, 4.7 u16Fixed16Number
|
||||
using u16Fixed16Number = u32;
|
||||
|
||||
// ICC V4, 4.14 XYZNumber
|
||||
struct XYZNumber {
|
||||
BigEndian<s15Fixed16Number> x;
|
||||
|
@ -432,6 +435,125 @@ ErrorOr<NonnullRefPtr<LutBToATagData>> LutBToATagData::from_bytes(ReadonlyBytes
|
|||
return adopt_ref(*new LutBToATagData(offset, size, header.number_of_input_channels, header.number_of_output_channels, e, move(clut_data)));
|
||||
}
|
||||
|
||||
ErrorOr<NonnullRefPtr<MeasurementTagData>> MeasurementTagData::from_bytes(ReadonlyBytes bytes, u32 offset, u32 size)
|
||||
{
|
||||
// ICC v4, 10.14 measurementType
|
||||
VERIFY(tag_type(bytes) == Type);
|
||||
TRY(check_reserved(bytes));
|
||||
|
||||
// Table 49 — measurementType structure
|
||||
struct MeasurementHeader {
|
||||
BigEndian<StandardObserver> standard_observer;
|
||||
XYZNumber tristimulus_value_for_measurement_backing;
|
||||
BigEndian<MeasurementGeometry> measurement_geometry;
|
||||
BigEndian<u16Fixed16Number> measurement_flare;
|
||||
BigEndian<StandardIlluminant> standard_illuminant;
|
||||
};
|
||||
static_assert(AssertSize<MeasurementHeader, 28>());
|
||||
|
||||
if (bytes.size() < 2 * sizeof(u32) + sizeof(MeasurementHeader))
|
||||
return Error::from_string_literal("ICC::Profile: measurementTag has not enough data");
|
||||
|
||||
auto& header = *bit_cast<MeasurementHeader const*>(bytes.data() + 8);
|
||||
|
||||
TRY(validate_standard_observer(header.standard_observer));
|
||||
TRY(validate_measurement_geometry(header.measurement_geometry));
|
||||
TRY(validate_standard_illuminant(header.standard_illuminant));
|
||||
|
||||
return adopt_ref(*new MeasurementTagData(offset, size, header.standard_observer, header.tristimulus_value_for_measurement_backing,
|
||||
header.measurement_geometry, U16Fixed16::create_raw(header.measurement_flare), header.standard_illuminant));
|
||||
}
|
||||
|
||||
ErrorOr<void> MeasurementTagData::validate_standard_observer(StandardObserver standard_observer)
|
||||
{
|
||||
switch (standard_observer) {
|
||||
case StandardObserver::Unknown:
|
||||
case StandardObserver::CIE_1931_standard_colorimetric_observer:
|
||||
case StandardObserver::CIE_1964_standard_colorimetric_observer:
|
||||
return {};
|
||||
}
|
||||
return Error::from_string_literal("ICC::Profile: unknown standard_observer");
|
||||
}
|
||||
|
||||
StringView MeasurementTagData::standard_observer_name(StandardObserver standard_observer)
|
||||
{
|
||||
switch (standard_observer) {
|
||||
case StandardObserver::Unknown:
|
||||
return "Unknown"sv;
|
||||
case StandardObserver::CIE_1931_standard_colorimetric_observer:
|
||||
return "CIE 1931 standard colorimetric observer"sv;
|
||||
case StandardObserver::CIE_1964_standard_colorimetric_observer:
|
||||
return "CIE 1964 standard colorimetric observer"sv;
|
||||
}
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
ErrorOr<void> MeasurementTagData::validate_measurement_geometry(MeasurementGeometry measurement_geometry)
|
||||
{
|
||||
switch (measurement_geometry) {
|
||||
case MeasurementGeometry::Unknown:
|
||||
case MeasurementGeometry::Degrees_0_45_or_45_0:
|
||||
case MeasurementGeometry::Degrees_0_d_or_d_0:
|
||||
return {};
|
||||
}
|
||||
return Error::from_string_literal("ICC::Profile: unknown measurement_geometry");
|
||||
}
|
||||
|
||||
StringView MeasurementTagData::measurement_geometry_name(MeasurementGeometry measurement_geometry)
|
||||
{
|
||||
switch (measurement_geometry) {
|
||||
case MeasurementGeometry::Unknown:
|
||||
return "Unknown"sv;
|
||||
case MeasurementGeometry::Degrees_0_45_or_45_0:
|
||||
return "0°:45° or 45°:0°"sv;
|
||||
case MeasurementGeometry::Degrees_0_d_or_d_0:
|
||||
return "0°:d or d:0°"sv;
|
||||
}
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
ErrorOr<void> MeasurementTagData::validate_standard_illuminant(StandardIlluminant standard_illuminant)
|
||||
{
|
||||
switch (standard_illuminant) {
|
||||
case StandardIlluminant::Unknown:
|
||||
case StandardIlluminant::D50:
|
||||
case StandardIlluminant::D65:
|
||||
case StandardIlluminant::D93:
|
||||
case StandardIlluminant::F2:
|
||||
case StandardIlluminant::D55:
|
||||
case StandardIlluminant::A:
|
||||
case StandardIlluminant::Equi_Power_E:
|
||||
case StandardIlluminant::F8:
|
||||
return {};
|
||||
}
|
||||
return Error::from_string_literal("ICC::Profile: unknown standard_illuminant");
|
||||
}
|
||||
|
||||
StringView MeasurementTagData::standard_illuminant_name(StandardIlluminant standard_illuminant)
|
||||
{
|
||||
switch (standard_illuminant) {
|
||||
case StandardIlluminant::Unknown:
|
||||
return "Unknown"sv;
|
||||
case StandardIlluminant::D50:
|
||||
return "D50"sv;
|
||||
case StandardIlluminant::D65:
|
||||
return "D65"sv;
|
||||
case StandardIlluminant::D93:
|
||||
return "D93"sv;
|
||||
case StandardIlluminant::F2:
|
||||
return "F2"sv;
|
||||
case StandardIlluminant::D55:
|
||||
return "D55"sv;
|
||||
case StandardIlluminant::A:
|
||||
return "A"sv;
|
||||
case StandardIlluminant::Equi_Power_E:
|
||||
return "Equi-Power (E)"sv;
|
||||
case StandardIlluminant::F8:
|
||||
return "F8"sv;
|
||||
}
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
ErrorOr<NonnullRefPtr<MultiLocalizedUnicodeTagData>> MultiLocalizedUnicodeTagData::from_bytes(ReadonlyBytes bytes, u32 offset, u32 size)
|
||||
{
|
||||
// ICC v4, 10.15 multiLocalizedUnicodeType
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
namespace Gfx::ICC {
|
||||
|
||||
using S15Fixed16 = FixedPoint<16, i32>;
|
||||
using U16Fixed16 = FixedPoint<16, u32>;
|
||||
|
||||
struct XYZ {
|
||||
double x { 0 };
|
||||
|
@ -332,6 +333,71 @@ private:
|
|||
Optional<CLUTData> m_clut;
|
||||
};
|
||||
|
||||
// ICC v4, 10.14 measurementType
|
||||
class MeasurementTagData : public TagData {
|
||||
public:
|
||||
static constexpr TagTypeSignature Type { 0x6D656173 }; // 'meas'
|
||||
|
||||
static ErrorOr<NonnullRefPtr<MeasurementTagData>> from_bytes(ReadonlyBytes, u32 offset, u32 size);
|
||||
|
||||
// Table 50 — Standard observer encodings
|
||||
enum class StandardObserver {
|
||||
Unknown = 0,
|
||||
CIE_1931_standard_colorimetric_observer = 1,
|
||||
CIE_1964_standard_colorimetric_observer = 2,
|
||||
};
|
||||
static ErrorOr<void> validate_standard_observer(StandardObserver);
|
||||
static StringView standard_observer_name(StandardObserver);
|
||||
|
||||
// Table 51 — Measurement geometry encodings
|
||||
enum class MeasurementGeometry {
|
||||
Unknown = 0,
|
||||
Degrees_0_45_or_45_0 = 1,
|
||||
Degrees_0_d_or_d_0 = 2,
|
||||
};
|
||||
static ErrorOr<void> validate_measurement_geometry(MeasurementGeometry);
|
||||
static StringView measurement_geometry_name(MeasurementGeometry);
|
||||
|
||||
// Table 53 — Standard illuminant encodings
|
||||
enum class StandardIlluminant {
|
||||
Unknown = 0,
|
||||
D50 = 1,
|
||||
D65 = 2,
|
||||
D93 = 3,
|
||||
F2 = 4,
|
||||
D55 = 5,
|
||||
A = 6,
|
||||
Equi_Power_E = 7,
|
||||
F8 = 8,
|
||||
};
|
||||
static ErrorOr<void> validate_standard_illuminant(StandardIlluminant);
|
||||
static StringView standard_illuminant_name(StandardIlluminant);
|
||||
|
||||
MeasurementTagData(u32 offset, u32 size, StandardObserver standard_observer, XYZ tristimulus_value_for_measurement_backing,
|
||||
MeasurementGeometry measurement_geometry, U16Fixed16 measurement_flare, StandardIlluminant standard_illuminant)
|
||||
: TagData(offset, size, Type)
|
||||
, m_standard_observer(standard_observer)
|
||||
, m_tristimulus_value_for_measurement_backing(tristimulus_value_for_measurement_backing)
|
||||
, m_measurement_geometry(measurement_geometry)
|
||||
, m_measurement_flare(measurement_flare)
|
||||
, m_standard_illuminant(standard_illuminant)
|
||||
{
|
||||
}
|
||||
|
||||
StandardObserver standard_observer() const { return m_standard_observer; }
|
||||
XYZ const& tristimulus_value_for_measurement_backing() const { return m_tristimulus_value_for_measurement_backing; }
|
||||
MeasurementGeometry measurement_geometry() const { return m_measurement_geometry; }
|
||||
U16Fixed16 measurement_flare() const { return m_measurement_flare; }
|
||||
StandardIlluminant standard_illuminant() const { return m_standard_illuminant; }
|
||||
|
||||
private:
|
||||
StandardObserver m_standard_observer;
|
||||
XYZ m_tristimulus_value_for_measurement_backing;
|
||||
MeasurementGeometry m_measurement_geometry;
|
||||
U16Fixed16 m_measurement_flare;
|
||||
StandardIlluminant m_standard_illuminant;
|
||||
};
|
||||
|
||||
// ICC v4, 10.15 multiLocalizedUnicodeType
|
||||
class MultiLocalizedUnicodeTagData : public TagData {
|
||||
public:
|
||||
|
|
|
@ -212,6 +212,13 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
|||
} else {
|
||||
outln(" color lookup table: (not set)");
|
||||
}
|
||||
} else if (tag_data->type() == Gfx::ICC::MeasurementTagData::Type) {
|
||||
auto& measurement = static_cast<Gfx::ICC::MeasurementTagData&>(*tag_data);
|
||||
outln(" standard observer: {}", Gfx::ICC::MeasurementTagData::standard_observer_name(measurement.standard_observer()));
|
||||
outln(" tristimulus value for measurement backing: {}", measurement.tristimulus_value_for_measurement_backing());
|
||||
outln(" measurement geometry: {}", Gfx::ICC::MeasurementTagData::measurement_geometry_name(measurement.measurement_geometry()));
|
||||
outln(" measurement flare: {} %", measurement.measurement_flare() * 100);
|
||||
outln(" standard illuminant: {}", Gfx::ICC::MeasurementTagData::standard_illuminant_name(measurement.standard_illuminant()));
|
||||
} else if (tag_data->type() == Gfx::ICC::MultiLocalizedUnicodeTagData::Type) {
|
||||
auto& multi_localized_unicode = static_cast<Gfx::ICC::MultiLocalizedUnicodeTagData&>(*tag_data);
|
||||
for (auto& record : multi_localized_unicode.records()) {
|
||||
|
|
Loading…
Reference in a new issue