| // Copyright 2023 Google LLC | |
| // SPDX-License-Identifier: BSD-2-Clause | |
| #include <cstdint> | |
| #include <limits> | |
| #include "avif/avif.h" | |
| #include "aviftest_helpers.h" | |
| #include "gtest/gtest.h" | |
| using testing::Combine; | |
| using testing::Values; | |
| namespace avif { | |
| namespace { | |
| // Used to pass the data folder path to the GoogleTest suites. | |
| const char* data_path = nullptr; | |
| constexpr bool kIgnoreMetadata = true; | |
| //------------------------------------------------------------------------------ | |
| class ScaleTest | |
| : public testing::TestWithParam< | |
| std::tuple</*bit_depth=*/int, /*yuv_format=*/avifPixelFormat, | |
| /*create_alpha=*/bool>> {}; | |
| TEST_P(ScaleTest, Roundtrip) { | |
| const int bit_depth = std::get<0>(GetParam()); | |
| const avifPixelFormat yuv_format = std::get<1>(GetParam()); | |
| const bool create_alpha = std::get<2>(GetParam()); | |
| const ImagePtr image = | |
| testutil::ReadImage(data_path, "paris_exif_xmp_icc.jpg", yuv_format, | |
| bit_depth, AVIF_CHROMA_DOWNSAMPLING_BEST_QUALITY, | |
| kIgnoreMetadata, kIgnoreMetadata, kIgnoreMetadata); | |
| ASSERT_NE(image, nullptr); | |
| if (create_alpha && !image->alphaPlane) { | |
| // Simulate alpha plane with a view on luma. | |
| image->alphaPlane = image->yuvPlanes[AVIF_CHAN_Y]; | |
| image->alphaRowBytes = image->yuvRowBytes[AVIF_CHAN_Y]; | |
| image->imageOwnsAlphaPlane = false; | |
| } | |
| ImagePtr scaled_image(avifImageCreateEmpty()); | |
| ASSERT_NE(scaled_image, nullptr); | |
| ASSERT_EQ(avifImageCopy(scaled_image.get(), image.get(), AVIF_PLANES_ALL), | |
| AVIF_RESULT_OK); | |
| const uint32_t scaled_width = static_cast<uint32_t>(image->width * 0.9); | |
| const uint32_t scaled_height = static_cast<uint32_t>(image->height * 2.14); | |
| avifDiagnostics diag; | |
| ASSERT_EQ( | |
| avifImageScale(scaled_image.get(), scaled_width, scaled_height, &diag), | |
| AVIF_RESULT_OK) | |
| << diag.error; | |
| EXPECT_EQ(scaled_image->width, scaled_width); | |
| EXPECT_EQ(scaled_image->height, scaled_height); | |
| ASSERT_EQ( | |
| avifImageScale(scaled_image.get(), image->width, image->height, &diag), | |
| AVIF_RESULT_OK) | |
| << diag.error; | |
| EXPECT_EQ(scaled_image->width, image->width); | |
| EXPECT_EQ(scaled_image->height, image->height); | |
| const double psnr = testutil::GetPsnr(*image, *scaled_image); | |
| EXPECT_GT(psnr, 30.0); | |
| EXPECT_LT(psnr, 45.0); | |
| } | |
| INSTANTIATE_TEST_SUITE_P( | |
| Some, ScaleTest, | |
| Combine(/*bit_depth=*/Values(8, 10, 12), | |
| Values(AVIF_PIXEL_FORMAT_YUV444, AVIF_PIXEL_FORMAT_YUV422, | |
| AVIF_PIXEL_FORMAT_YUV420, AVIF_PIXEL_FORMAT_YUV400), | |
| /*create_alpha=*/Values(true, false))); | |
| TEST(ScaleTest, LargerThanDefaultLimits) { | |
| const ImagePtr image = testutil::ReadImage( | |
| data_path, "paris_exif_xmp_icc.jpg", AVIF_PIXEL_FORMAT_YUV420, 8, | |
| AVIF_CHROMA_DOWNSAMPLING_BEST_QUALITY, kIgnoreMetadata, kIgnoreMetadata, | |
| kIgnoreMetadata); | |
| ASSERT_NE(image, nullptr); | |
| avifDiagnostics diag; | |
| // dstWidth*dstHeight is larger than AVIF_DEFAULT_IMAGE_SIZE_LIMIT. | |
| EXPECT_NE(avifImageScale(image.get(), 20000, 20000, &diag), AVIF_RESULT_OK); | |
| // dstWidth is larger than AVIF_DEFAULT_IMAGE_DIMENSION_LIMIT. | |
| EXPECT_NE(avifImageScale(image.get(), 40000, 2, &diag), AVIF_RESULT_OK); | |
| // dstHeight is larger than AVIF_DEFAULT_IMAGE_DIMENSION_LIMIT. | |
| EXPECT_NE(avifImageScale(image.get(), 2, 40000, &diag), AVIF_RESULT_OK); | |
| } | |
| //------------------------------------------------------------------------------ | |
| } // namespace | |
| } // namespace avif | |
| int main(int argc, char** argv) { | |
| ::testing::InitGoogleTest(&argc, argv); | |
| if (argc != 2) { | |
| std::cerr << "There must be exactly one argument containing the path to " | |
| "the test data folder" | |
| << std::endl; | |
| return 1; | |
| } | |
| avif::data_path = argv[1]; | |
| return RUN_ALL_TESTS(); | |
| } |