summaryrefslogtreecommitdiff
path: root/Userland
diff options
context:
space:
mode:
authorNico Weber <thakis@chromium.org>2023-02-09 16:14:32 -0500
committerLinus Groh <mail@linusgroh.de>2023-02-10 14:02:19 +0000
commit664946c543df709ccf375bd5dab63d95a013d70f (patch)
tree390a2d44b2dcf4c138226ed8fe46f75d0ff07f27 /Userland
parent143f28b7358583398b7104e1b87734ca0e6c656b (diff)
downloadserenity-664946c543df709ccf375bd5dab63d95a013d70f.zip
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.
Diffstat (limited to 'Userland')
-rw-r--r--Userland/Libraries/LibGfx/ICC/Profile.cpp5
-rw-r--r--Userland/Libraries/LibGfx/ICC/TagTypes.cpp122
-rw-r--r--Userland/Libraries/LibGfx/ICC/TagTypes.h66
-rw-r--r--Userland/Utilities/icc.cpp7
4 files changed, 199 insertions, 1 deletions
diff --git a/Userland/Libraries/LibGfx/ICC/Profile.cpp b/Userland/Libraries/LibGfx/ICC/Profile.cpp
index f7d1537db7..75041f8f8d 100644
--- a/Userland/Libraries/LibGfx/ICC/Profile.cpp
+++ b/Userland/Libraries/LibGfx/ICC/Profile.cpp
@@ -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"
diff --git a/Userland/Libraries/LibGfx/ICC/TagTypes.cpp b/Userland/Libraries/LibGfx/ICC/TagTypes.cpp
index 8bbcb4f762..e3466d8fc1 100644
--- a/Userland/Libraries/LibGfx/ICC/TagTypes.cpp
+++ b/Userland/Libraries/LibGfx/ICC/TagTypes.cpp
@@ -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
diff --git a/Userland/Libraries/LibGfx/ICC/TagTypes.h b/Userland/Libraries/LibGfx/ICC/TagTypes.h
index 7096643fd6..ba2af312fb 100644
--- a/Userland/Libraries/LibGfx/ICC/TagTypes.h
+++ b/Userland/Libraries/LibGfx/ICC/TagTypes.h
@@ -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:
diff --git a/Userland/Utilities/icc.cpp b/Userland/Utilities/icc.cpp
index 4b511295f8..e3580b1600 100644
--- a/Userland/Utilities/icc.cpp
+++ b/Userland/Utilities/icc.cpp
@@ -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()) {