Add avifalphapremtest
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 765880a..11d1173 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt
@@ -75,6 +75,11 @@ target_include_directories(avifallocationtest PRIVATE ${GTEST_INCLUDE_DIRS}) add_test(NAME avifallocationtest COMMAND avifallocationtest) + add_executable(avifalphapremtest gtest/avifalphapremtest.cc) + target_link_libraries(avifalphapremtest aviftest_helpers ${GTEST_BOTH_LIBRARIES}) + target_include_directories(avifalphapremtest PRIVATE ${GTEST_INCLUDE_DIRS}) + add_test(NAME avifalphapremtest COMMAND avifalphapremtest) + add_executable(avifchangesettingtest gtest/avifchangesettingtest.cc) target_link_libraries(avifchangesettingtest aviftest_helpers ${GTEST_BOTH_LIBRARIES}) target_include_directories(avifchangesettingtest PRIVATE ${GTEST_INCLUDE_DIRS})
diff --git a/tests/gtest/avifalphapremtest.cc b/tests/gtest/avifalphapremtest.cc new file mode 100644 index 0000000..b8c97a3 --- /dev/null +++ b/tests/gtest/avifalphapremtest.cc
@@ -0,0 +1,66 @@ +// Copyright 2022 Google LLC +// SPDX-License-Identifier: BSD-2-Clause + +#include "avif/avif.h" +#include "aviftest_helpers.h" +#include "gtest/gtest.h" + +namespace libavif { +namespace { + +//------------------------------------------------------------------------------ + +TEST(AlphaMultiplyTest, OpaqueIsNoOp) { + for (bool premultiplied_input : {false, true}) { + if (!premultiplied_input) { + // TODO(yguyon): Fix the issue and remove this condition. + // The issue is that avifPrepareReformatState() will result + // in different YUV(A)-to-RGB conversion algorithm choices + // (built-in or libyuv) depending on the presence of an + // alpha channel, no matter if it is opaque or not, because + // it considers that unpremultiplied YUVA samples should be + // premultiplied before discarding alpha and converting to + // RGB. + continue; + } + + // YUVA. + testutil::AvifImagePtr opaque_alpha = testutil::CreateImage( + 1024, 1024, /*depth=*/8, AVIF_PIXEL_FORMAT_YUV444, AVIF_PLANES_ALL); + const uint32_t yuva[] = {255, 255, 255, 255}; + testutil::FillImagePlain(opaque_alpha.get(), yuva); + opaque_alpha->alphaPremultiplied = premultiplied_input; + + // View on YUV (no alpha), to make sure the color values are identical. + testutil::AvifImagePtr no_alpha(avifImageCreateEmpty(), avifImageDestroy); + const avifCropRect rect = {0, 0, opaque_alpha->width, opaque_alpha->height}; + ASSERT_EQ(avifImageSetViewRect(no_alpha.get(), opaque_alpha.get(), &rect), + AVIF_RESULT_OK); + avifImageFreePlanes(no_alpha.get(), AVIF_PLANES_A); + + // Decorrelate YUV and Alpha. + testutil::FillImageGradient(no_alpha.get()); + + // Convert to RGB and discard any Alpha. + testutil::AvifRgbImage opaque_rgb(opaque_alpha.get(), opaque_alpha->depth, + AVIF_RGB_FORMAT_RGB); + ASSERT_EQ(avifImageYUVToRGB(opaque_alpha.get(), &opaque_rgb), + AVIF_RESULT_OK); + testutil::AvifRgbImage no_alpha_rgb(no_alpha.get(), no_alpha->depth, + AVIF_RGB_FORMAT_RGB); + ASSERT_EQ(avifImageYUVToRGB(no_alpha.get(), &no_alpha_rgb), AVIF_RESULT_OK); + + // YUV samples with opaque alpha and with missing alpha should be converted + // to the same RGB values. + EXPECT_TRUE(testutil::AreByteSequencesEqual( + opaque_rgb.pixels, opaque_rgb.height * opaque_rgb.rowBytes, + no_alpha_rgb.pixels, no_alpha_rgb.height * no_alpha_rgb.rowBytes)); + + // TODO(yguyon): Also compare avifImageYUVToRGB() with ignoreAlpha. + } +} + +//------------------------------------------------------------------------------ + +} // namespace +} // namespace libavif