diff --git a/CHANGELOG.md b/CHANGELOG.md index 261f72cb1a..e6fbec1559 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ The changes are relative to the previous release, unless the baseline is specifi fails to allocate the destination gain map image. * avifenc: reject mismatched --depth for Y4M input * Use libaom AOMD_SET_FRAME_SIZE_LIMIT if available +* Fix bug in transfer function 11 (used for gain map creation/tone mapping) ## [1.4.1] - 2026-03-20 diff --git a/src/colr.c b/src/colr.c index c516a2e27f..1b92dcdbba 100644 --- a/src/colr.c +++ b/src/colr.c @@ -317,7 +317,7 @@ static float avifToGammaLog100Sqrt10(float linear) static float avifToLinearIEC61966(float gamma) { if (gamma < -4.5f * 0.018053968510807f) { - return powf((-gamma + 0.09929682680944f) / -1.09929682680944f, 1.0f / 0.45f); + return -powf((gamma - 0.09929682680944f) / -1.09929682680944f, 1.0f / 0.45f); } else if (gamma < 4.5f * 0.018053968510807f) { return gamma / 4.5f; } else { diff --git a/tests/gtest/avifcolrtest.cc b/tests/gtest/avifcolrtest.cc index 56b3bbcd2c..73bf288a49 100644 --- a/tests/gtest/avifcolrtest.cc +++ b/tests/gtest/avifcolrtest.cc @@ -75,6 +75,29 @@ TEST(TransferCharacteristicsTest, RoundTrip) { } } +TEST(TransferCharacteristicsTest, NegativeRoundTrip) { + // Transfer functions that accept negative values. + const avifTransferCharacteristics tcs[] = { + AVIF_TRANSFER_CHARACTERISTICS_IEC61966, + AVIF_TRANSFER_CHARACTERISTICS_BT1361, + }; + for (const avifTransferCharacteristics tc : tcs) { + SCOPED_TRACE("transfer characteristics: " + std::to_string(tc)); + + const avifTransferFunction to_linear = + avifTransferCharacteristicsGetGammaToLinearFunction(tc); + const avifTransferFunction to_gamma = + avifTransferCharacteristicsGetLinearToGammaFunction(tc); + + const float test_values[] = {-0.1f, -0.05f, -0.2f}; + for (const float v : test_values) { + // Check round trips. + EXPECT_NEAR(to_linear(to_gamma(v)), v, 0.00001f); + EXPECT_NEAR(to_gamma(to_linear(v)), v, 0.00001f); + } + } +} + // Check that the liner->gamma function has the right shape, i.e. it's mostly // above the y=x diagonal. // This detects bugs where the linear->gamma and