From f702ad9c4cee58e8e438e3d22ff202a80ac8b3ff Mon Sep 17 00:00:00 2001 From: Xaver Hugl Date: Thu, 17 Oct 2024 13:06:38 +0200 Subject: [PATCH] core/colorspace: ensure that we don't create elevated blacks with black point compensation There are cases where the minimum luminance can be lower than the transfer function's minimum; in those cases, the transfer function's minimum would get mapped to a value greater than black in the target transfer function. To avoid that, this just takes the max. of the metadata and transfer function minimum BUG: 494854 (cherry picked from commit cef6656ff57e19e7eb551f81ee5b03028a7f38a9) --- autotests/test_colorspaces.cpp | 2 +- src/core/colorspace.cpp | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/autotests/test_colorspaces.cpp b/autotests/test_colorspaces.cpp index cc7333bc9d..b8f26664c2 100644 --- a/autotests/test_colorspaces.cpp +++ b/autotests/test_colorspaces.cpp @@ -225,7 +225,7 @@ void TestColorspaces::testOpenglShader_data() QTest::addColumn("maxError"); // the allowed error here needs to be this high because of llvmpipe. With real GPU drivers it's lower - QTest::addRow("Perceptual") << RenderingIntent::Perceptual << 6.5; + QTest::addRow("Perceptual") << RenderingIntent::Perceptual << 7.0; QTest::addRow("RelativeColorimetric") << RenderingIntent::RelativeColorimetric << 1.5; QTest::addRow("AbsoluteColorimetric") << RenderingIntent::AbsoluteColorimetric << 1.5; QTest::addRow("RelativeColorimetricWithBPC") << RenderingIntent::RelativeColorimetricWithBPC << 1.5; diff --git a/src/core/colorspace.cpp b/src/core/colorspace.cpp index 43c4495481..b583b68857 100644 --- a/src/core/colorspace.cpp +++ b/src/core/colorspace.cpp @@ -461,11 +461,14 @@ QMatrix4x4 ColorDescription::toOther(const ColorDescription &other, RenderingInt // add black point compensation: black and reference white from the source color space // should both be mapped to black and reference white in the destination color space + const double effectiveMin = std::max(minLuminance(), m_transferFunction.minLuminance); + const double otherEffectiveMin = std::max(other.minLuminance(), other.m_transferFunction.minLuminance); + // before color conversions, map [src min, src ref] to [0, 1] luminanceBefore.scale(1.0 / (reference - minLuminance())); - luminanceBefore.translate(-minLuminance(), -minLuminance(), -minLuminance()); + luminanceBefore.translate(-effectiveMin, -effectiveMin, -effectiveMin); // afterwards, map [0, 1] again to [dst min, dst ref] - luminanceAfter.translate(other.minLuminance(), other.minLuminance(), other.minLuminance()); + luminanceAfter.translate(otherEffectiveMin, otherEffectiveMin, otherEffectiveMin); luminanceAfter.scale(other.referenceLuminance() - other.minLuminance()); } else { // map only the reference luminance