blob: 11a9442c0745bf2d34fbf3d8a56f77977ad2d7c8 [file] [log] [blame]
// Copyright 2023 Google LLC
// SPDX-License-Identifier: BSD-2-Clause
#include "avif/avif.h"
#include "aviftest_helpers.h"
#include "gtest/gtest.h"
using ::testing::Combine;
using ::testing::Values;
namespace avif {
namespace {
//------------------------------------------------------------------------------
class AvifMinimizedImageBoxTest
: public testing::TestWithParam<std::tuple<
/*width=*/int, /*height=*/int, /*depth=*/int, avifPixelFormat,
avifPlanesFlags, avifRange, /*create_icc=*/bool, /*create_exif=*/bool,
/*create_xmp=*/bool, /*create_clli=*/bool, avifTransformFlags>> {};
TEST_P(AvifMinimizedImageBoxTest, SimpleOpaque) {
const int width = std::get<0>(GetParam());
const int height = std::get<1>(GetParam());
const int depth = std::get<2>(GetParam());
const avifPixelFormat format = std::get<3>(GetParam());
const avifPlanesFlags planes = std::get<4>(GetParam());
const avifRange range = std::get<5>(GetParam());
const bool create_icc = std::get<6>(GetParam());
const bool create_exif = std::get<7>(GetParam());
const bool create_xmp = std::get<8>(GetParam());
const bool create_clli = std::get<9>(GetParam());
const avifTransformFlags create_transform_flags = std::get<10>(GetParam());
ImagePtr image =
testutil::CreateImage(width, height, depth, format, planes, range);
ASSERT_NE(image, nullptr);
testutil::FillImageGradient(image.get()); // The pixels do not matter.
if (create_icc) {
ASSERT_EQ(avifImageSetProfileICC(image.get(), testutil::kSampleIcc.data(),
testutil::kSampleIcc.size()),
AVIF_RESULT_OK);
}
if (create_exif) {
size_t exif_tiff_header_offset; // Must be 0 for 'mif3' brand.
ASSERT_EQ(avifGetExifTiffHeaderOffset(testutil::kSampleExif.data(),
testutil::kSampleExif.size(),
&exif_tiff_header_offset),
AVIF_RESULT_OK);
ASSERT_EQ(
avifImageSetMetadataExif(
image.get(), testutil::kSampleExif.data() + exif_tiff_header_offset,
testutil::kSampleExif.size() - exif_tiff_header_offset),
AVIF_RESULT_OK);
}
if (create_xmp) {
ASSERT_EQ(avifImageSetMetadataXMP(image.get(), testutil::kSampleXmp.data(),
testutil::kSampleXmp.size()),
AVIF_RESULT_OK);
}
if (create_clli) {
image->clli.maxCLL = 1;
image->clli.maxPALL = 2;
}
image->transformFlags = create_transform_flags;
if (create_transform_flags & AVIF_TRANSFORM_PASP) {
image->pasp.hSpacing = 1;
image->pasp.vSpacing = 2;
}
if (create_transform_flags & AVIF_TRANSFORM_CLAP) {
const avifCropRect rect{image->width / 4, image->height / 4,
std::min(1u, image->width / 2),
std::min(1u, image->height / 2)};
avifDiagnostics diag;
ASSERT_TRUE(avifCleanApertureBoxConvertCropRect(&image->clap, &rect,
image->width, image->height,
image->yuvFormat, &diag));
}
if (create_transform_flags & AVIF_TRANSFORM_IROT) {
image->irot.angle = 2;
}
if (create_transform_flags & AVIF_TRANSFORM_IMIR) {
image->imir.axis = 1;
}
// Encode.
testutil::AvifRwData encoded_mini;
EncoderPtr encoder(avifEncoderCreate());
ASSERT_NE(encoder, nullptr);
encoder->speed = AVIF_SPEED_FASTEST;
encoder->headerFormat = AVIF_HEADER_REDUCED;
ASSERT_EQ(avifEncoderWrite(encoder.get(), image.get(), &encoded_mini),
AVIF_RESULT_OK);
// Decode.
const ImagePtr decoded_mini =
testutil::Decode(encoded_mini.data, encoded_mini.size);
ASSERT_NE(decoded_mini, nullptr);
// Compare.
testutil::AvifRwData encoded_meta =
testutil::Encode(image.get(), encoder->speed);
ASSERT_NE(encoded_meta.data, nullptr);
// At least 200 bytes should be saved.
EXPECT_LT(encoded_mini.size, encoded_meta.size - 200);
const ImagePtr decoded_meta =
testutil::Decode(encoded_meta.data, encoded_meta.size);
ASSERT_NE(decoded_meta, nullptr);
// Only the container changed. The pixels, features and metadata should be
// identical.
EXPECT_TRUE(
testutil::AreImagesEqual(*decoded_meta.get(), *decoded_mini.get()));
}
INSTANTIATE_TEST_SUITE_P(OnePixel, AvifMinimizedImageBoxTest,
Combine(/*width=*/Values(1), /*height=*/Values(1),
/*depth=*/Values(8),
Values(AVIF_PIXEL_FORMAT_YUV444),
Values(AVIF_PLANES_YUV, AVIF_PLANES_ALL),
Values(AVIF_RANGE_LIMITED, AVIF_RANGE_FULL),
/*create_icc=*/Values(false, true),
/*create_exif=*/Values(false, true),
/*create_xmp=*/Values(false, true),
/*create_clli=*/Values(false),
Values(AVIF_TRANSFORM_NONE)));
INSTANTIATE_TEST_SUITE_P(
DepthsSubsamplings, AvifMinimizedImageBoxTest,
Combine(/*width=*/Values(12), /*height=*/Values(34),
/*depth=*/Values(8, 10, 12),
Values(AVIF_PIXEL_FORMAT_YUV444, AVIF_PIXEL_FORMAT_YUV422,
AVIF_PIXEL_FORMAT_YUV420, AVIF_PIXEL_FORMAT_YUV400),
Values(AVIF_PLANES_ALL), Values(AVIF_RANGE_FULL),
/*create_icc=*/Values(false), /*create_exif=*/Values(false),
/*create_xmp=*/Values(false), /*create_clli=*/Values(false),
Values(AVIF_TRANSFORM_NONE)));
INSTANTIATE_TEST_SUITE_P(
Dimensions, AvifMinimizedImageBoxTest,
Combine(/*width=*/Values(127), /*height=*/Values(200), /*depth=*/Values(8),
Values(AVIF_PIXEL_FORMAT_YUV444), Values(AVIF_PLANES_ALL),
Values(AVIF_RANGE_FULL), /*create_icc=*/Values(true),
/*create_exif=*/Values(true), /*create_xmp=*/Values(true),
/*create_clli=*/Values(false), Values(AVIF_TRANSFORM_NONE)));
// Use CLLI and transform properties that are not supported by a plain
// MinimizedImageBox to force the use of an extended_meta field.
INSTANTIATE_TEST_SUITE_P(
ExtendedMetaField, AvifMinimizedImageBoxTest,
Combine(/*width=*/Values(16), /*height=*/Values(24), /*depth=*/Values(8),
Values(AVIF_PIXEL_FORMAT_YUV444), Values(AVIF_PLANES_ALL),
Values(AVIF_RANGE_FULL), /*create_icc=*/Values(true),
/*create_exif=*/Values(true), /*create_xmp=*/Values(true),
/*create_clli=*/Values(true),
Values(AVIF_TRANSFORM_NONE,
AVIF_TRANSFORM_PASP | AVIF_TRANSFORM_CLAP |
AVIF_TRANSFORM_IROT | AVIF_TRANSFORM_IMIR)));
//------------------------------------------------------------------------------
} // namespace
} // namespace avif