diff --git a/Userland/Libraries/LibGfx/ICCProfile.cpp b/Userland/Libraries/LibGfx/ICCProfile.cpp index 3b1e527085..9d807fecd0 100644 --- a/Userland/Libraries/LibGfx/ICCProfile.cpp +++ b/Userland/Libraries/LibGfx/ICCProfile.cpp @@ -198,6 +198,17 @@ ErrorOr parse_creation_date_time(ICCHeader const& header) return parse_date_time_number(header.profile_creation_time); } +ErrorOr parse_device_attributes(ICCHeader const& header) +{ + // ICC v4, 7.2.14 Device attributes field + + // "4 to 31": "Reserved (set to binary zero)" + if (header.device_attributes & 0xffff'fff0) + return Error::from_string_literal("ICC::Profile: Device attributes reserved bits not set to 0"); + + return DeviceAttributes { header.device_attributes }; +} + ErrorOr parse_file_signature(ICCHeader const& header) { // ICC v4, 7.2.9 Profile file signature field @@ -383,6 +394,12 @@ Flags::Flags(u32 bits) { } +DeviceAttributes::DeviceAttributes() = default; +DeviceAttributes::DeviceAttributes(u64 bits) + : m_bits(bits) +{ +} + ErrorOr> Profile::try_load_from_externally_owned_memory(ReadonlyBytes bytes) { auto profile = adopt_ref(*new Profile()); @@ -399,6 +416,7 @@ ErrorOr> Profile::try_load_from_externally_owned_memory(R profile->m_connection_space = TRY(parse_connection_space(header)); profile->m_creation_timestamp = TRY(parse_creation_date_time(header)); profile->m_flags = Flags { header.profile_flags }; + profile->m_device_attributes = TRY(parse_device_attributes(header)); profile->m_rendering_intent = TRY(parse_rendering_intent(header)); profile->m_pcs_illuminant = TRY(parse_pcs_illuminant(header)); profile->m_id = TRY(parse_profile_id(header, bytes)); diff --git a/Userland/Libraries/LibGfx/ICCProfile.h b/Userland/Libraries/LibGfx/ICCProfile.h index 706732a751..ea09084968 100644 --- a/Userland/Libraries/LibGfx/ICCProfile.h +++ b/Userland/Libraries/LibGfx/ICCProfile.h @@ -116,6 +116,61 @@ private: u32 m_bits = 0; }; +// ICC v4, 7.2.14 Device attributes field +class DeviceAttributes { +public: + DeviceAttributes(); + + // "The device attributes field shall contain flags used to identify attributes + // unique to the particular device setup for which the profile is applicable." + DeviceAttributes(u64); + + u64 bits() const { return m_bits; } + + // "The least-significant 32 bits of this 64-bit value are defined by the ICC. " + u32 icc_bits() const { return bits() & 0xffff'ffff; } + + // "Notice that bits 0, 1, 2, and 3 describe the media, not the device." + + // "0": "Reflective (0) or transparency (1)" + enum class MediaReflectivity { + Reflective, + Transparent, + }; + MediaReflectivity media_reflectivity() const { return MediaReflectivity(icc_bits() & 1); } + + // "1": "Glossy (0) or matte (1)" + enum class MediaGlossiness { + Glossy, + Matte, + }; + MediaGlossiness media_glossiness() const { return MediaGlossiness((icc_bits() >> 1) & 1); } + + // "2": "Media polarity, positive (0) or negative (1)" + enum class MediaPolarity { + Positive, + Negative, + }; + MediaPolarity media_polarity() const { return MediaPolarity((icc_bits() >> 2) & 1); } + + // "3": "Colour media (0), black & white media (1)" + enum class MediaColor { + Colored, + BlackAndWhite, + }; + MediaColor media_color() const { return MediaColor((icc_bits() >> 3) & 1); } + + // "4 to 31": Reserved (set to binary zero)" + + // "32 to 63": "Use not defined by ICC (vendor specific" + u32 vendor_bits() const { return bits() >> 32; } + + static constexpr u64 KnownBitsMask = 0xf; + +private: + u64 m_bits = 0; +}; + struct XYZ { double x { 0 }; double y { 0 }; @@ -135,6 +190,7 @@ public: time_t creation_timestamp() const { return m_creation_timestamp; } Flags flags() const { return m_flags; } + DeviceAttributes device_attributes() const { return m_device_attributes; } RenderingIntent rendering_intent() const { return m_rendering_intent; } XYZ const& pcs_illuminant() const { return m_pcs_illuminant; } Optional const& id() const { return m_id; } @@ -148,6 +204,7 @@ private: ColorSpace m_connection_space; time_t m_creation_timestamp; Flags m_flags; + DeviceAttributes m_device_attributes; RenderingIntent m_rendering_intent; XYZ m_pcs_illuminant; Optional m_id; diff --git a/Userland/Utilities/icc.cpp b/Userland/Utilities/icc.cpp index 6c67b7fec1..55180835da 100644 --- a/Userland/Utilities/icc.cpp +++ b/Userland/Utilities/icc.cpp @@ -36,6 +36,17 @@ ErrorOr serenity_main(Main::Arguments arguments) if (auto color_management_module_bits = flags.color_management_module_bits()) outln(" CMM bits: 0x{:04x}", color_management_module_bits); + auto device_attributes = profile->device_attributes(); + outln("device attributes: 0x{:016x}", device_attributes.bits()); + outln(" media is {}, {}, {}, {}", + device_attributes.media_reflectivity() == Gfx::ICC::DeviceAttributes::MediaReflectivity::Reflective ? "reflective" : "transparent", + device_attributes.media_glossiness() == Gfx::ICC::DeviceAttributes::MediaGlossiness::Glossy ? "glossy" : "matte", + device_attributes.media_polarity() == Gfx::ICC::DeviceAttributes::MediaPolarity::Positive ? "of positive polarity" : "of negative polarity", + device_attributes.media_color() == Gfx::ICC::DeviceAttributes::MediaColor::Colored ? "colored" : "black and white"); + VERIFY((flags.icc_bits() & ~Gfx::ICC::DeviceAttributes::KnownBitsMask) == 0); + if (auto vendor_bits = device_attributes.vendor_bits()) + outln(" vendor bits: 0x{:08x}", vendor_bits); + outln("rendering intent: {}", Gfx::ICC::rendering_intent_name(profile->rendering_intent())); outln("pcs illuminant: {}", profile->pcs_illuminant());