diff --git a/Userland/Libraries/LibGfx/ICC/Profile.cpp b/Userland/Libraries/LibGfx/ICC/Profile.cpp index 5fa6b66621..94c337315d 100644 --- a/Userland/Libraries/LibGfx/ICC/Profile.cpp +++ b/Userland/Libraries/LibGfx/ICC/Profile.cpp @@ -1570,10 +1570,8 @@ ErrorOr Profile::from_pcs(FloatVector3 const& pcs, Bytes color) const auto evaluate_curve_inverse = [this](TagSignature curve_tag, float f) { auto const& trc = *m_tag_table.get(curve_tag).value(); VERIFY(trc.type() == CurveTagData::Type || trc.type() == ParametricCurveTagData::Type); - if (trc.type() == CurveTagData::Type) { - TODO(); - return 0.f; - } + if (trc.type() == CurveTagData::Type) + return static_cast(trc).evaluate_inverse(f); return static_cast(trc).evaluate_inverse(f); }; diff --git a/Userland/Libraries/LibGfx/ICC/TagTypes.h b/Userland/Libraries/LibGfx/ICC/TagTypes.h index 8c57f0075a..751207f8cf 100644 --- a/Userland/Libraries/LibGfx/ICC/TagTypes.h +++ b/Userland/Libraries/LibGfx/ICC/TagTypes.h @@ -179,6 +179,41 @@ public: return mix(values()[i] / 65535.f, values()[i + 1] / 65535.f, f); } + // y must be in [0..1]. + float evaluate_inverse(float y) const + { + VERIFY(0.f <= y && y <= 1.f); + + if (values().is_empty()) + return y; + + if (values().size() == 1) + return powf(y, 1.f / (values()[0] / (float)0x100)); + + // FIXME: Verify somewhere that: + // * values() is non-decreasing + // * values()[0] is 0, values()[values().size() - 1] is 65535 + + // FIXME: Use binary search. + size_t n = values().size() - 1; + size_t i = 0; + for (; i < n; ++i) { + if (values()[i] / 65535.f <= y && y <= values()[i + 1] / 65535.f) + break; + } + + float x1 = i / (float)n; + float y1 = values()[i] / 65535.f; + float x2 = (i + 1) / (float)n; + float y2 = values()[i + 1] / 65535.f; + + // Flat line segment? + if (y1 == y2) + return (x1 + x2) / 2; + + return (y - y1) / (y2 - y1) * (x2 - x1) + x1; // Same as `((y - y1) / (y2 - y1) + i) / (float)n` + } + private: Vector m_values; };