diff --git a/lib/src/gainmapmath.cpp b/lib/src/gainmapmath.cpp index 9cbe80d1..61ff14b2 100644 --- a/lib/src/gainmapmath.cpp +++ b/lib/src/gainmapmath.cpp @@ -132,7 +132,13 @@ float srgbInvOetfLUT(float e_gamma) { } Color srgbInvOetfLUT(Color e_gamma) { - return {{{srgbInvOetfLUT(e_gamma.r), srgbInvOetfLUT(e_gamma.g), srgbInvOetfLUT(e_gamma.b)}}}; + static LookUpTable kSrgbLut(kSrgbInvOETFNumEntries, static_cast(srgbInvOetfLUT)); + const std::vector& lut = kSrgbLut.getTable(); + const auto index = [](float value) { + int32_t lut_index = static_cast(value * (kSrgbInvOETFNumEntries - 1) + 0.5); + return CLIP3(lut_index, 0, kSrgbInvOETFNumEntries - 1); + }; + return {{{lut[index(e_gamma.r)], lut[index(e_gamma.g)], lut[index(e_gamma.b)]}}}; } // See IEC 61966-2-1/Amd 1:2003, Equations F.10 and F.11. diff --git a/tests/gainmapmath_test.cpp b/tests/gainmapmath_test.cpp index bab77782..6999c91d 100644 --- a/tests/gainmapmath_test.cpp +++ b/tests/gainmapmath_test.cpp @@ -11,6 +11,8 @@ #include #include +#include +#include #include #include "ultrahdr/gainmapmath.h" @@ -1383,6 +1385,46 @@ TEST_F(GainMapMathTest, srgbInvOetfLUT) { } } +TEST_F(GainMapMathTest, SrgbInvOetfLutRgbPreservesScalarIndexing) { + constexpr int32_t kLast = kSrgbInvOETFNumEntries - 1; + const auto expected = [=](float value) { + int32_t index = static_cast(value * kLast + 0.5); + index = CLIP3(index, 0, kLast); + return srgbInvOetf(static_cast(index) / static_cast(kLast)); + }; + const std::array, 6> permutations = {{ + {{0, 1, 2}}, {{0, 2, 1}}, {{1, 0, 2}}, + {{1, 2, 0}}, {{2, 0, 1}}, {{2, 1, 0}}, + }}; + const auto check = [&](float value) { + const std::array source = {value, 0.123f, 0.876f}; + for (const auto& permutation : permutations) { + const std::array input = { + source[permutation[0]], source[permutation[1]], source[permutation[2]]}; + const Color actual = srgbInvOetfLUT({{{input[0], input[1], input[2]}}}); + const std::array output = {actual.r, actual.g, actual.b}; + for (size_t channel = 0; channel < output.size(); ++channel) { + const float scalar = srgbInvOetfLUT(input[channel]); + EXPECT_EQ(output[channel], scalar); + EXPECT_EQ(scalar, expected(input[channel])); + } + } + }; + + for (int32_t index = 0; index <= kLast; ++index) { + check(static_cast(index) / static_cast(kLast)); + } + for (int32_t index = 0; index < kLast; ++index) { + const float boundary = static_cast((static_cast(index) + 0.5) / kLast); + check(std::nextafter(boundary, -1.0f)); + check(boundary); + check(std::nextafter(boundary, 2.0f)); + } + for (const float value : {-1000.0f, -1.0f, -0.0f, 0.0f, 1.0f, 2.0f, 1000.0f}) { + check(value); + } +} + TEST_F(GainMapMathTest, applyGainLUT) { for (float boost = 1.5; boost <= 12; boost++) { uhdr_gainmap_metadata_ext_t metadata(kJpegrVersion);