LibGfx+icc: Read viewingConditionsType

Not terribly useful in practice either and also mostly for
completionism. But with this, we can dump all types present
in Lightroom Classic-exported jpegs :^)
This commit is contained in:
Nico Weber 2023-02-09 20:18:11 -05:00 committed by Linus Groh
parent 664946c543
commit c61cfdd5ed
Notes: sideshowbarker 2024-07-17 02:56:25 +09:00
4 changed files with 60 additions and 1 deletions

View file

@ -600,6 +600,8 @@ ErrorOr<NonnullRefPtr<TagData>> Profile::read_tag(ReadonlyBytes bytes, u32 offse
return TextDescriptionTagData::from_bytes(tag_bytes, offset_to_beginning_of_tag_data_element, size_of_tag_data_element);
case TextTagData::Type:
return TextTagData::from_bytes(tag_bytes, offset_to_beginning_of_tag_data_element, size_of_tag_data_element);
case ViewingConditionsTagData::Type:
return ViewingConditionsTagData::from_bytes(tag_bytes, offset_to_beginning_of_tag_data_element, size_of_tag_data_element);
case XYZTagData::Type:
return XYZTagData::from_bytes(tag_bytes, offset_to_beginning_of_tag_data_element, size_of_tag_data_element);
default:
@ -1259,7 +1261,8 @@ ErrorOr<void> Profile::check_tag_types()
// ICC v4, 9.2.51 viewingConditionsTag
// "Permitted tag types: viewingConditionsType"
// FIXME
if (!has_type(viewingConditionsTag, { ViewingConditionsTagData::Type }, {}))
return Error::from_string_literal("ICC::Profile: viewingConditionsTag has unexpected type");
// FIXME: Add validation for v2-only tags:
// - ICC v2, 6.4.14 crdInfoTag

View file

@ -934,6 +934,31 @@ ErrorOr<NonnullRefPtr<TextTagData>> TextTagData::from_bytes(ReadonlyBytes bytes,
return adopt_ref(*new TextTagData(offset, size, TRY(String::from_utf8(StringView(text_data, length - 1)))));
}
ErrorOr<NonnullRefPtr<ViewingConditionsTagData>> ViewingConditionsTagData::from_bytes(ReadonlyBytes bytes, u32 offset, u32 size)
{
// ICC v4, 10.30 viewingConditionsType
VERIFY(tag_type(bytes) == Type);
TRY(check_reserved(bytes));
// Table 84 — viewingConditionsType encoding
struct ViewingConditionsHeader {
XYZNumber unnormalized_ciexyz_values_for_illuminant; // "(in which Y is in cd/m2)"
XYZNumber unnormalized_ciexyz_values_for_surround; // "(in which Y is in cd/m2)"
BigEndian<MeasurementTagData::StandardIlluminant> illuminant_type;
};
static_assert(AssertSize<ViewingConditionsHeader, 28>());
if (bytes.size() < 2 * sizeof(u32) + sizeof(ViewingConditionsHeader))
return Error::from_string_literal("ICC::Profile: viewingConditionsType has not enough data");
auto& header = *bit_cast<ViewingConditionsHeader const*>(bytes.data() + 8);
TRY(MeasurementTagData::validate_standard_illuminant(header.illuminant_type));
return adopt_ref(*new ViewingConditionsTagData(offset, size, header.unnormalized_ciexyz_values_for_illuminant,
header.unnormalized_ciexyz_values_for_surround, header.illuminant_type));
}
ErrorOr<NonnullRefPtr<XYZTagData>> XYZTagData::from_bytes(ReadonlyBytes bytes, u32 offset, u32 size)
{
// ICC v4, 10.31 XYZType

View file

@ -679,6 +679,32 @@ private:
String m_text;
};
// ICC v4, 10.30 viewingConditionsType
class ViewingConditionsTagData : public TagData {
public:
static constexpr TagTypeSignature Type { 0x76696577 }; // 'view'
static ErrorOr<NonnullRefPtr<ViewingConditionsTagData>> from_bytes(ReadonlyBytes, u32 offset, u32 size);
ViewingConditionsTagData(u32 offset, u32 size, XYZ const& unnormalized_ciexyz_values_for_illuminant,
XYZ const& unnormalized_ciexyz_values_for_surround, MeasurementTagData::StandardIlluminant illuminant_type)
: TagData(offset, size, Type)
, m_unnormalized_ciexyz_values_for_illuminant(unnormalized_ciexyz_values_for_illuminant)
, m_unnormalized_ciexyz_values_for_surround(unnormalized_ciexyz_values_for_surround)
, m_illuminant_type(illuminant_type)
{
}
XYZ const& unnormalized_ciexyz_values_for_illuminant() const { return m_unnormalized_ciexyz_values_for_illuminant; }
XYZ const& unnormalized_ciexyz_values_for_surround() const { return m_unnormalized_ciexyz_values_for_surround; }
MeasurementTagData::StandardIlluminant illuminant_type() const { return m_illuminant_type; }
private:
XYZ m_unnormalized_ciexyz_values_for_illuminant; // "(in which Y is in cd/m2)"
XYZ m_unnormalized_ciexyz_values_for_surround; // "(in which Y is in cd/m2)"
MeasurementTagData::StandardIlluminant m_illuminant_type;
};
// ICC v4, 10.31 XYZType
class XYZTagData : public TagData {
public:

View file

@ -311,6 +311,11 @@ ErrorOr<int> 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<Gfx::ICC::TextTagData&>(*tag_data).text());
} else if (tag_data->type() == Gfx::ICC::ViewingConditionsTagData::Type) {
auto& viewing_conditions = static_cast<Gfx::ICC::ViewingConditionsTagData&>(*tag_data);
outln(" unnormalized CIEXYZ values for illuminant (in which Y is in cd/m²): {}", viewing_conditions.unnormalized_ciexyz_values_for_illuminant());
outln(" unnormalized CIEXYZ values for surround (in which Y is in cd/m²): {}", viewing_conditions.unnormalized_ciexyz_values_for_surround());
outln(" illuminant type: {}", Gfx::ICC::MeasurementTagData::standard_illuminant_name(viewing_conditions.illuminant_type()));
} else if (tag_data->type() == Gfx::ICC::XYZTagData::Type) {
for (auto& xyz : static_cast<Gfx::ICC::XYZTagData&>(*tag_data).xyzs())
outln(" {}", xyz);