diff --git a/Userland/Libraries/LibPDF/ColorSpace.cpp b/Userland/Libraries/LibPDF/ColorSpace.cpp index 5fbdfddb5d..e93d618c53 100644 --- a/Userland/Libraries/LibPDF/ColorSpace.cpp +++ b/Userland/Libraries/LibPDF/ColorSpace.cpp @@ -4,6 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include #include #include #include @@ -11,6 +12,8 @@ namespace PDF { +RefPtr ICCBasedColorSpace::s_srgb_profile; + #define ENUMERATE(name, ever_needs_parameters) \ ColorSpaceFamily ColorSpaceFamily::name { #name, ever_needs_parameters }; ENUMERATE_COLOR_SPACE_FAMILIES(ENUMERATE); @@ -303,39 +306,66 @@ PDFErrorOr> ICCBasedColorSpace::create(Document* docum if (!param.has>() || !param.get>()->is()) return Error { Error::Type::MalformedPDF, "ICCBased color space expects a stream parameter" }; - auto dict = param.get>()->cast()->dict(); + auto stream = param.get>()->cast(); + auto dict = stream->dict(); - DeprecatedFlyString name; - if (!dict->contains(CommonNames::Alternate)) { - auto number_of_components = dict->get_value(CommonNames::N).to_int(); - if (number_of_components == 1) - name = CommonNames::DeviceGray; - else if (number_of_components == 3) - name = CommonNames::DeviceRGB; - else if (number_of_components == 4) - name = CommonNames::DeviceCMYK; - else - VERIFY_NOT_REACHED(); - return ColorSpace::create(name); + auto maybe_profile = Gfx::ICC::Profile::try_load_from_externally_owned_memory(stream->bytes()); + if (!maybe_profile.is_error()) + return adopt_ref(*new ICCBasedColorSpace(maybe_profile.release_value())); + + if (dict->contains(CommonNames::Alternate)) { + auto alternate_color_space_object = MUST(dict->get_object(document, CommonNames::Alternate)); + if (alternate_color_space_object->is()) + return ColorSpace::create(alternate_color_space_object->cast()->name()); + + return Error { Error::Type::Internal, "Alternate color spaces in array format are not supported" }; } - auto alternate_color_space_object = MUST(dict->get_object(document, CommonNames::Alternate)); - if (alternate_color_space_object->is()) { - return ColorSpace::create(alternate_color_space_object->cast()->name()); - } - - dbgln("Alternate color spaces in array format not supported yet "); - TODO(); + return Error { Error::Type::MalformedPDF, "Failed to load ICC color space with malformed profile and no alternate" }; } -Color ICCBasedColorSpace::color(Vector const&) const +ICCBasedColorSpace::ICCBasedColorSpace(NonnullRefPtr profile) + : m_profile(profile) { - VERIFY_NOT_REACHED(); +} + +Color ICCBasedColorSpace::color(Vector const& arguments) const +{ + if (!s_srgb_profile) + s_srgb_profile = MUST(Gfx::ICC::sRGB()); + + Vector bytes; + for (auto const& arg : arguments) { + VERIFY(arg.has_number()); + bytes.append(static_cast(arg.to_float() * 255.0f)); + } + + auto pcs = MUST(m_profile->to_pcs(bytes)); + Array output; + MUST(s_srgb_profile->from_pcs(pcs, output.span())); + + return Color(output[0], output[1], output[2]); } Vector ICCBasedColorSpace::default_decode() const { - VERIFY_NOT_REACHED(); + auto color_space = m_profile->data_color_space(); + switch (color_space) { + case Gfx::ICC::ColorSpace::Gray: + return { 0.0, 1.0 }; + case Gfx::ICC::ColorSpace::RGB: + return { 0.0, 1.0, 0.0, 1.0, 0.0, 1.0 }; + case Gfx::ICC::ColorSpace::CMYK: + return { 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0 }; + default: + warnln("PDF: Unknown default_decode params for color space {}", Gfx::ICC::data_color_space_name(color_space)); + Vector decoding_ranges; + for (u8 i = 0; i < Gfx::ICC::number_of_components_in_color_space(color_space); i++) { + decoding_ranges.append(0.0); + decoding_ranges.append(1.0); + } + return decoding_ranges; + } } } diff --git a/Userland/Libraries/LibPDF/ColorSpace.h b/Userland/Libraries/LibPDF/ColorSpace.h index 1a24c37b23..bc6839a222 100644 --- a/Userland/Libraries/LibPDF/ColorSpace.h +++ b/Userland/Libraries/LibPDF/ColorSpace.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #define ENUMERATE_COLOR_SPACE_FAMILIES(V) \ @@ -137,7 +138,10 @@ public: ColorSpaceFamily const& family() const override { return ColorSpaceFamily::ICCBased; } private: - ICCBasedColorSpace() = delete; + ICCBasedColorSpace(NonnullRefPtr); + + static RefPtr s_srgb_profile; + NonnullRefPtr m_profile; }; }