mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-21 23:20:20 +00:00
LibGfx+icc: Read chromaticityTag
This isn't terribly useful. But some profiles, for example the ones at https://vpifg.com/help/icc-profiles/, do contain this tag and it seems nice to be able to dump it, just for completeness. I haven't seen any files that contain a phosphor or colorant type different from "Unknown", even for the Rec2020 profile on that page. (It has x,y coordinates that match the values required for Rec2020, but it doesn't set the phosphor or colorant type to that.)
This commit is contained in:
parent
c61cfdd5ed
commit
b232281d15
Notes:
sideshowbarker
2024-07-17 07:31:31 +09:00
Author: https://github.com/nico Commit: https://github.com/SerenityOS/serenity/commit/b232281d15 Pull-request: https://github.com/SerenityOS/serenity/pull/17396
4 changed files with 116 additions and 2 deletions
|
@ -572,6 +572,8 @@ ErrorOr<NonnullRefPtr<TagData>> Profile::read_tag(ReadonlyBytes bytes, u32 offse
|
|||
|
||||
auto type = tag_type(tag_bytes);
|
||||
switch (type) {
|
||||
case ChromaticityTagData::Type:
|
||||
return ChromaticityTagData::from_bytes(tag_bytes, offset_to_beginning_of_tag_data_element, size_of_tag_data_element);
|
||||
case CicpTagData::Type:
|
||||
return CicpTagData::from_bytes(tag_bytes, offset_to_beginning_of_tag_data_element, size_of_tag_data_element);
|
||||
case CurveTagData::Type:
|
||||
|
@ -988,7 +990,8 @@ ErrorOr<void> Profile::check_tag_types()
|
|||
|
||||
// ICC v4, 9.2.16 chromaticityTag
|
||||
// "Permitted tag types: chromaticityType"
|
||||
// FIXME
|
||||
if (!has_type(chromaticityTag, { ChromaticityTagData::Type }, {}))
|
||||
return Error::from_string_literal("ICC::Profile: ChromaticityTagData has unexpected type");
|
||||
|
||||
// ICC v4, 9.2.17 cicpTag
|
||||
// "Permitted tag types: cicpType"
|
||||
|
|
|
@ -83,6 +83,72 @@ TagTypeSignature tag_type(ReadonlyBytes tag_bytes)
|
|||
return *bit_cast<BigEndian<TagTypeSignature> const*>(tag_bytes.data());
|
||||
}
|
||||
|
||||
StringView ChromaticityTagData::phosphor_or_colorant_type_name(PhosphorOrColorantType phosphor_or_colorant_type)
|
||||
{
|
||||
switch (phosphor_or_colorant_type) {
|
||||
case PhosphorOrColorantType::Unknown:
|
||||
return "Unknown"sv;
|
||||
case PhosphorOrColorantType::ITU_R_BT_709_2:
|
||||
return "ITU-R BT.709-2"sv;
|
||||
case PhosphorOrColorantType::SMPTE_RP145:
|
||||
return "SMPTE RP145"sv;
|
||||
case PhosphorOrColorantType::EBU_Tech_3213_E:
|
||||
return "EBU Tech. 3213-E"sv;
|
||||
case PhosphorOrColorantType::P22:
|
||||
return "P22"sv;
|
||||
case PhosphorOrColorantType::P3:
|
||||
return "P3"sv;
|
||||
case PhosphorOrColorantType::ITU_R_BT_2020:
|
||||
return "ITU-R BT.2020"sv;
|
||||
}
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
ErrorOr<NonnullRefPtr<ChromaticityTagData>> ChromaticityTagData::from_bytes(ReadonlyBytes bytes, u32 offset, u32 size)
|
||||
{
|
||||
// ICC v4, 10.2 chromaticityType
|
||||
VERIFY(tag_type(bytes) == Type);
|
||||
TRY(check_reserved(bytes));
|
||||
|
||||
if (bytes.size() < 2 * sizeof(u32) + 2 * sizeof(u16))
|
||||
return Error::from_string_literal("ICC::Profile: chromaticityType has not enough data");
|
||||
|
||||
u16 number_of_device_channels = *bit_cast<BigEndian<u16> const*>(bytes.data() + 8);
|
||||
PhosphorOrColorantType phosphor_or_colorant_type = *bit_cast<BigEndian<PhosphorOrColorantType> const*>(bytes.data() + 10);
|
||||
|
||||
switch (phosphor_or_colorant_type) {
|
||||
case PhosphorOrColorantType::Unknown:
|
||||
case PhosphorOrColorantType::ITU_R_BT_709_2:
|
||||
case PhosphorOrColorantType::SMPTE_RP145:
|
||||
case PhosphorOrColorantType::EBU_Tech_3213_E:
|
||||
case PhosphorOrColorantType::P22:
|
||||
case PhosphorOrColorantType::P3:
|
||||
case PhosphorOrColorantType::ITU_R_BT_2020:
|
||||
break;
|
||||
default:
|
||||
return Error::from_string_literal("ICC::Profile: chromaticityType invalid phosphor_or_colorant_type");
|
||||
}
|
||||
|
||||
// "If the value is 0001h to 0004h, the number of channels shall be three..."
|
||||
if (phosphor_or_colorant_type != PhosphorOrColorantType::Unknown && number_of_device_channels != 3)
|
||||
return Error::from_string_literal("ICC::Profile: chromaticityType unexpected number of channels for phosphor_or_colorant_type");
|
||||
|
||||
if (bytes.size() < 2 * sizeof(u32) + 2 * sizeof(u16) + number_of_device_channels * 2 * sizeof(u16Fixed16Number))
|
||||
return Error::from_string_literal("ICC::Profile: chromaticityType has not enough data for xy coordinates");
|
||||
|
||||
auto* raw_xy_coordinates = bit_cast<BigEndian<u16Fixed16Number> const*>(bytes.data() + 12);
|
||||
Vector<xyCoordinate> xy_coordinates;
|
||||
TRY(xy_coordinates.try_resize(number_of_device_channels));
|
||||
for (size_t i = 0; i < number_of_device_channels; ++i) {
|
||||
xy_coordinates[i].x = U16Fixed16::create_raw(raw_xy_coordinates[2 * i]);
|
||||
xy_coordinates[i].y = U16Fixed16::create_raw(raw_xy_coordinates[2 * i + 1]);
|
||||
}
|
||||
|
||||
// FIXME: Once I find files that have phosphor_or_colorant_type != Unknown, check that the values match the values in Table 31.
|
||||
|
||||
return adopt_ref(*new ChromaticityTagData(offset, size, phosphor_or_colorant_type, move(xy_coordinates)));
|
||||
}
|
||||
|
||||
ErrorOr<NonnullRefPtr<CicpTagData>> CicpTagData::from_bytes(ReadonlyBytes bytes, u32 offset, u32 size)
|
||||
{
|
||||
// ICC v4, 10.3 cicpType
|
||||
|
|
|
@ -59,6 +59,46 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
// ICC v4, 10.2 chromaticityType
|
||||
class ChromaticityTagData : public TagData {
|
||||
public:
|
||||
static constexpr TagTypeSignature Type { 0x6368726D }; // 'chrm'
|
||||
|
||||
static ErrorOr<NonnullRefPtr<ChromaticityTagData>> from_bytes(ReadonlyBytes, u32 offset, u32 size);
|
||||
|
||||
// ICC v4, Table 31 — Colorant and phosphor encoding
|
||||
enum class PhosphorOrColorantType : u16 {
|
||||
Unknown = 0,
|
||||
ITU_R_BT_709_2 = 1,
|
||||
SMPTE_RP145 = 2,
|
||||
EBU_Tech_3213_E = 3,
|
||||
P22 = 4,
|
||||
P3 = 5,
|
||||
ITU_R_BT_2020 = 6,
|
||||
};
|
||||
|
||||
static StringView phosphor_or_colorant_type_name(PhosphorOrColorantType);
|
||||
|
||||
struct xyCoordinate {
|
||||
U16Fixed16 x;
|
||||
U16Fixed16 y;
|
||||
};
|
||||
|
||||
ChromaticityTagData(u32 offset, u32 size, PhosphorOrColorantType phosphor_or_colorant_type, Vector<xyCoordinate> xy_coordinates)
|
||||
: TagData(offset, size, Type)
|
||||
, m_phosphor_or_colorant_type(phosphor_or_colorant_type)
|
||||
, m_xy_coordinates(move(xy_coordinates))
|
||||
{
|
||||
}
|
||||
|
||||
PhosphorOrColorantType phosphor_or_colorant_type() const { return m_phosphor_or_colorant_type; }
|
||||
Vector<xyCoordinate> xy_coordinates() const { return m_xy_coordinates; }
|
||||
|
||||
private:
|
||||
PhosphorOrColorantType m_phosphor_or_colorant_type;
|
||||
Vector<xyCoordinate> m_xy_coordinates;
|
||||
};
|
||||
|
||||
// ICC v4, 10.3 cicpType
|
||||
// "The cicpType specifies Coding-independent code points for video signal type identification."
|
||||
// See presentations at https://www.color.org/events/HDR_experts.xalter for background.
|
||||
|
|
|
@ -126,7 +126,12 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
|||
}
|
||||
tag_data_to_first_signature.set(tag_data, tag_signature);
|
||||
|
||||
if (tag_data->type() == Gfx::ICC::CicpTagData::Type) {
|
||||
if (tag_data->type() == Gfx::ICC::ChromaticityTagData::Type) {
|
||||
auto& chromaticity = static_cast<Gfx::ICC::ChromaticityTagData&>(*tag_data);
|
||||
outln(" phosphor or colorant type: {}", Gfx::ICC::ChromaticityTagData::phosphor_or_colorant_type_name(chromaticity.phosphor_or_colorant_type()));
|
||||
for (auto const& xy : chromaticity.xy_coordinates())
|
||||
outln(" x, y: {}, {}", xy.x, xy.y);
|
||||
} else if (tag_data->type() == Gfx::ICC::CicpTagData::Type) {
|
||||
auto& cicp = static_cast<Gfx::ICC::CicpTagData&>(*tag_data);
|
||||
outln(" color primaries: {} - {}", cicp.color_primaries(),
|
||||
Video::color_primaries_to_string((Video::ColorPrimaries)cicp.color_primaries()));
|
||||
|
|
Loading…
Reference in a new issue