diff --git a/Userland/Libraries/LibPDF/ColorSpace.cpp b/Userland/Libraries/LibPDF/ColorSpace.cpp index ae464a2c37..a3352db524 100644 --- a/Userland/Libraries/LibPDF/ColorSpace.cpp +++ b/Userland/Libraries/LibPDF/ColorSpace.cpp @@ -506,24 +506,90 @@ Vector ICCBasedColorSpace::default_decode() const } } -PDFErrorOr> LabColorSpace::create(Document*, Vector&& parameters) +PDFErrorOr> LabColorSpace::create(Document* document, Vector&& parameters) { if (parameters.size() != 1) return Error { Error::Type::MalformedPDF, "Lab color space expects one parameter" }; + auto param = parameters[0]; + if (!param.has>() || !param.get>()->is()) + return Error { Error::Type::MalformedPDF, "Lab color space expects a dict parameter" }; + + auto dict = param.get>()->cast(); + if (!dict->contains(CommonNames::WhitePoint)) + return Error { Error::Type::MalformedPDF, "Lab color space expects a Whitepoint key" }; + + auto white_point_array = TRY(dict->get_array(document, CommonNames::WhitePoint)); + if (white_point_array->size() != 3) + return Error { Error::Type::MalformedPDF, "Lab color space expects 3 Whitepoint parameters" }; + auto color_space = adopt_ref(*new LabColorSpace()); - // FIXME: Implement. + + color_space->m_whitepoint[0] = white_point_array->at(0).to_float(); + color_space->m_whitepoint[1] = white_point_array->at(1).to_float(); + color_space->m_whitepoint[2] = white_point_array->at(2).to_float(); + + if (color_space->m_whitepoint[1] != 1.0f) + return Error { Error::Type::MalformedPDF, "Lab color space expects 2nd Whitepoint to be 1.0" }; + + if (dict->contains(CommonNames::BlackPoint)) { + auto black_point_array = TRY(dict->get_array(document, CommonNames::BlackPoint)); + if (black_point_array->size() == 3) { + color_space->m_blackpoint[0] = black_point_array->at(0).to_float(); + color_space->m_blackpoint[1] = black_point_array->at(1).to_float(); + color_space->m_blackpoint[2] = black_point_array->at(2).to_float(); + } + } + + if (dict->contains(CommonNames::Range)) { + auto range_array = TRY(dict->get_array(document, CommonNames::Range)); + if (range_array->size() == 4) { + color_space->m_range[0] = range_array->at(0).to_float(); + color_space->m_range[1] = range_array->at(1).to_float(); + color_space->m_range[2] = range_array->at(2).to_float(); + color_space->m_range[3] = range_array->at(3).to_float(); + } + } + return color_space; } -PDFErrorOr LabColorSpace::color(ReadonlySpan) const +PDFErrorOr LabColorSpace::color(ReadonlySpan arguments) const { - return Error::rendering_unsupported_error("Lab color spaces not yet implemented"); + VERIFY(arguments.size() == 3); + auto L_star = clamp(arguments[0].to_float(), 0.0f, 100.0f); + auto a_star = clamp(arguments[1].to_float(), m_range[0], m_range[1]); + auto b_star = clamp(arguments[2].to_float(), m_range[2], m_range[3]); + + auto L = (L_star + 16) / 116 + a_star / 500; + auto M = (L_star + 16) / 116; + auto N = (L_star + 16) / 116 - b_star / 200; + + auto g = [](float x) { + if (x >= 6.0f / 29.0f) + return powf(x, 3); + return 108.0f / 841.0f * (x - 4.0f / 29.0f); + }; + + auto x = m_whitepoint[0] * g(L); + auto y = m_whitepoint[1] * g(M); + auto z = m_whitepoint[2] * g(N); + + auto flattened_xyz = flatten_and_normalize_whitepoint(m_whitepoint, { x, y, z }); + auto scaled_black_point_xyz = scale_black_point(m_blackpoint, flattened_xyz); + auto d65_normalized = convert_to_d65(scaled_black_point_xyz); + auto srgb = convert_to_srgb(d65_normalized); + + auto red = static_cast(clamp(srgb[0], 0.0f, 1.0f) * 255.0f); + auto green = static_cast(clamp(srgb[1], 0.0f, 1.0f) * 255.0f); + auto blue = static_cast(clamp(srgb[2], 0.0f, 1.0f) * 255.0f); + + return Color(red, green, blue); } Vector LabColorSpace::default_decode() const { - return { 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f }; + return { 0.0f, 100.0f, m_range[0], m_range[1], m_range[2], m_range[3] }; } PDFErrorOr> SeparationColorSpace::create(Document*, Vector&&) diff --git a/Userland/Libraries/LibPDF/ColorSpace.h b/Userland/Libraries/LibPDF/ColorSpace.h index 0e80b5c6ad..d79dfe807c 100644 --- a/Userland/Libraries/LibPDF/ColorSpace.h +++ b/Userland/Libraries/LibPDF/ColorSpace.h @@ -193,6 +193,10 @@ public: private: LabColorSpace() = default; + + Array m_whitepoint { 0, 0, 0 }; + Array m_blackpoint { 0, 0, 0 }; + Array m_range { -100, 100, -100, 100 }; }; class SeparationColorSpace final : public ColorSpace { diff --git a/Userland/Libraries/LibPDF/CommonNames.h b/Userland/Libraries/LibPDF/CommonNames.h index 5daf5b7f81..15148d9b07 100644 --- a/Userland/Libraries/LibPDF/CommonNames.h +++ b/Userland/Libraries/LibPDF/CommonNames.h @@ -134,6 +134,7 @@ X(Producer) \ X(R) \ X(RI) \ + X(Range) \ X(Registry) \ X(Resources) \ X(Root) \