⚝
One Hat Cyber Team
⚝
Your IP:
216.73.216.23
Server IP:
178.33.27.10
Server:
Linux cpanel.dev-unit.com 3.10.0-1160.108.1.el7.x86_64 #1 SMP Thu Jan 25 16:17:31 UTC 2024 x86_64
Server Software:
Apache/2.4.57 (Unix) OpenSSL/1.0.2k-fips
PHP Version:
8.2.11
Buat File
|
Buat Folder
Eksekusi
Dir :
~
/
usr
/
local
/
src
/
libavif-0.11.1
/
tests
/
gtest
/
View File Name :
avifmetadatatest.cc
// Copyright 2022 Google LLC. All rights reserved. // SPDX-License-Identifier: BSD-2-Clause #include <array> #include <tuple> #include "avif/avif.h" #include "aviftest_helpers.h" #include "gtest/gtest.h" using ::testing::Bool; using ::testing::Combine; using ::testing::Values; namespace libavif { namespace { //------------------------------------------------------------------------------ // Used to pass the data folder path to the GoogleTest suites. const char* data_path = nullptr; // ICC color profiles are not checked by libavif so the content does not matter. // This is a truncated widespread ICC color profile. const std::array<uint8_t, 24> kSampleIcc = { 0x00, 0x00, 0x02, 0x0c, 0x6c, 0x63, 0x6d, 0x73, 0x02, 0x10, 0x00, 0x00, 0x6d, 0x6e, 0x74, 0x72, 0x52, 0x47, 0x42, 0x20, 0x58, 0x59, 0x5a, 0x20}; // Exif bytes are partially checked by libavif. This is a truncated widespread // Exif metadata chunk. const std::array<uint8_t, 24> kSampleExif = { 0xff, 0x1, 0x45, 0x78, 0x69, 0x76, 0x32, 0xff, 0xe1, 0x12, 0x5a, 0x45, 0x78, 0x69, 0x66, 0x0, 0x0, 0x49, 0x49, 0x2a, 0x0, 0x8, 0x0, 0x0}; // XMP bytes are not checked by libavif so the content does not matter. // This is a truncated widespread XMP metadata chunk. const std::array<uint8_t, 24> kSampleXmp = { 0x3c, 0x3f, 0x78, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x20, 0x62, 0x65, 0x67, 0x69, 0x6e, 0x3d, 0x22, 0xef, 0xbb, 0xbf, 0x22, 0x20, 0x69, 0x64}; //------------------------------------------------------------------------------ // AVIF encode/decode metadata tests class AvifMetadataTest : public testing::TestWithParam< std::tuple</*use_icc=*/bool, /*use_exif=*/bool, /*use_xmp=*/bool>> {}; // Encodes, decodes then verifies that the output metadata matches the input // metadata defined by the parameters. TEST_P(AvifMetadataTest, EncodeDecode) { const bool use_icc = std::get<0>(GetParam()); const bool use_exif = std::get<1>(GetParam()); const bool use_xmp = std::get<2>(GetParam()); testutil::AvifImagePtr image = testutil::CreateImage(/*width=*/12, /*height=*/34, /*depth=*/10, AVIF_PIXEL_FORMAT_YUV444, AVIF_PLANES_ALL); ASSERT_NE(image, nullptr); testutil::FillImageGradient(image.get()); // The pixels do not matter. if (use_icc) { avifImageSetProfileICC(image.get(), kSampleIcc.data(), kSampleIcc.size()); } if (use_exif) { const avifTransformFlags old_transform_flags = image->transformFlags; const uint8_t old_irot_angle = image->irot.angle; const uint8_t old_imir_mode = image->imir.mode; avifImageSetMetadataExif(image.get(), kSampleExif.data(), kSampleExif.size()); // kSampleExif is not a valid Exif payload, just some part of it. These // fields should not be modified. EXPECT_EQ(image->transformFlags, old_transform_flags); EXPECT_EQ(image->irot.angle, old_irot_angle); EXPECT_EQ(image->imir.mode, old_imir_mode); } if (use_xmp) { avifImageSetMetadataXMP(image.get(), kSampleXmp.data(), kSampleXmp.size()); } // Encode. testutil::AvifEncoderPtr encoder(avifEncoderCreate(), avifEncoderDestroy); ASSERT_NE(encoder, nullptr); encoder->speed = AVIF_SPEED_FASTEST; testutil::AvifRwData encoded_avif; ASSERT_EQ(avifEncoderWrite(encoder.get(), image.get(), &encoded_avif), AVIF_RESULT_OK); // Decode. testutil::AvifImagePtr decoded(avifImageCreateEmpty(), avifImageDestroy); ASSERT_NE(decoded, nullptr); testutil::AvifDecoderPtr decoder(avifDecoderCreate(), avifDecoderDestroy); ASSERT_NE(decoder, nullptr); ASSERT_EQ(avifDecoderReadMemory(decoder.get(), decoded.get(), encoded_avif.data, encoded_avif.size), AVIF_RESULT_OK); // Compare input and output metadata. EXPECT_TRUE(testutil::AreByteSequencesEqual( decoded->icc.data, decoded->icc.size, kSampleIcc.data(), use_icc ? kSampleIcc.size() : 0u)); EXPECT_TRUE(testutil::AreByteSequencesEqual( decoded->exif.data, decoded->exif.size, kSampleExif.data(), use_exif ? kSampleExif.size() : 0u)); EXPECT_TRUE(testutil::AreByteSequencesEqual( decoded->xmp.data, decoded->xmp.size, kSampleXmp.data(), use_xmp ? kSampleXmp.size() : 0u)); } INSTANTIATE_TEST_SUITE_P(All, AvifMetadataTest, Combine(/*use_icc=*/Bool(), /*use_exif=*/Bool(), /*use_xmp=*/Bool())); //------------------------------------------------------------------------------ // Jpeg and PNG metadata tests class MetadataTest : public testing::TestWithParam< std::tuple</*file_name=*/const char*, /*use_icc=*/bool, /*use_exif=*/bool, /*use_xmp=*/bool, /*expect_icc=*/bool, /*expect_exif=*/bool, /*expect_xmp=*/bool>> {}; // zTXt "Raw profile type exif" at the beginning of a PNG file. TEST_P(MetadataTest, Read) { const char* file_name = std::get<0>(GetParam()); const bool use_icc = std::get<1>(GetParam()); const bool use_exif = std::get<2>(GetParam()); const bool use_xmp = std::get<3>(GetParam()); const bool expect_icc = std::get<4>(GetParam()); const bool expect_exif = std::get<5>(GetParam()); const bool expect_xmp = std::get<6>(GetParam()); const testutil::AvifImagePtr image = testutil::ReadImage( data_path, file_name, AVIF_PIXEL_FORMAT_NONE, 0, AVIF_CHROMA_DOWNSAMPLING_AUTOMATIC, !use_icc, !use_exif, !use_xmp); ASSERT_NE(image, nullptr); EXPECT_NE(image->width * image->height, 0u); if (expect_icc) { EXPECT_NE(image->icc.size, 0u); EXPECT_NE(image->icc.data, nullptr); } else { EXPECT_EQ(image->icc.size, 0u); EXPECT_EQ(image->icc.data, nullptr); } if (expect_exif) { EXPECT_NE(image->exif.size, 0u); EXPECT_NE(image->exif.data, nullptr); } else { EXPECT_EQ(image->exif.size, 0u); EXPECT_EQ(image->exif.data, nullptr); } if (expect_xmp) { EXPECT_NE(image->xmp.size, 0u); EXPECT_NE(image->xmp.data, nullptr); } else { EXPECT_EQ(image->xmp.size, 0u); EXPECT_EQ(image->xmp.data, nullptr); } } INSTANTIATE_TEST_SUITE_P( PngNone, MetadataTest, Combine(Values("paris_icc_exif_xmp.png"), // iCCP zTXt zTXt IDAT /*use_icc=*/Values(false), /*use_exif=*/Values(false), /*use_xmp=*/Values(false), /*expected_icc=*/Values(false), /*expected_exif=*/Values(false), /*expected_xmp=*/Values(false))); INSTANTIATE_TEST_SUITE_P( PngAll, MetadataTest, Combine(Values("paris_icc_exif_xmp.png"), // iCCP zTXt zTXt IDAT /*use_icc=*/Values(true), /*use_exif=*/Values(true), /*use_xmp=*/Values(true), /*expected_icc=*/Values(true), /*expected_exif=*/Values(true), /*expected_xmp=*/Values(true))); INSTANTIATE_TEST_SUITE_P( PngExifAtEnd, MetadataTest, Combine(Values("paris_icc_exif_xmp_at_end.png"), // iCCP IDAT eXIf tEXt /*use_icc=*/Values(true), /*use_exif=*/Values(true), /*use_xmp=*/Values(true), /*expected_icc=*/Values(true), /*expected_exif=*/Values(true), /*expected_xmp=*/Values(true))); INSTANTIATE_TEST_SUITE_P( Jpeg, MetadataTest, Combine(Values("paris_exif_xmp_icc.jpg"), // APP1-Exif, APP1-XMP, APP2-ICC /*use_icc=*/Values(true), /*use_exif=*/Values(true), /*use_xmp=*/Values(true), /*expected_icc=*/Values(true), /*expected_exif=*/Values(true), /*expected_xmp=*/Values(true))); // Verify all parsers lead exactly to the same metadata bytes. TEST(MetadataTest, Compare) { const testutil::AvifImagePtr ref = testutil::ReadImage(data_path, "paris_icc_exif_xmp.png"); ASSERT_NE(ref, nullptr); EXPECT_GT(ref->exif.size, 0u); EXPECT_GT(ref->xmp.size, 0u); EXPECT_GT(ref->icc.size, 0u); for (const char* file_name : {"paris_exif_xmp_icc.jpg", "paris_icc_exif_xmp_at_end.png"}) { const testutil::AvifImagePtr image = testutil::ReadImage(data_path, file_name); ASSERT_NE(image, nullptr); EXPECT_TRUE(testutil::AreByteSequencesEqual(image->exif, ref->exif)); EXPECT_TRUE(testutil::AreByteSequencesEqual(image->xmp, ref->xmp)); EXPECT_TRUE(testutil::AreByteSequencesEqual(image->icc, ref->icc)); } } // A test for https://github.com/AOMediaCodec/libavif/issues/1086 to prevent // regression. TEST(MetadataTest, DecoderParseICC) { std::string file_path = std::string(data_path) + "paris_icc_exif_xmp.avif"; avifDecoder* decoder = avifDecoderCreate(); EXPECT_EQ(avifDecoderSetIOFile(decoder, file_path.c_str()), AVIF_RESULT_OK); EXPECT_EQ(avifDecoderParse(decoder), AVIF_RESULT_OK); // Check the first four bytes of the ICC profile. ASSERT_GE(decoder->image->icc.size, 4u); EXPECT_EQ(decoder->image->icc.data[0], 0); EXPECT_EQ(decoder->image->icc.data[1], 0); EXPECT_EQ(decoder->image->icc.data[2], 2); EXPECT_EQ(decoder->image->icc.data[3], 84); avifDecoderDestroy(decoder); } //------------------------------------------------------------------------------ TEST(MetadataTest, ExifButDefaultIrotImir) { const testutil::AvifImagePtr image = testutil::ReadImage(data_path, "paris_exif_xmp_icc.jpg"); ASSERT_NE(image, nullptr); // The Exif metadata contains orientation information: 1. // It is converted to no irot/imir. EXPECT_GT(image->exif.size, 0u); EXPECT_EQ(image->transformFlags & (AVIF_TRANSFORM_IROT | AVIF_TRANSFORM_IMIR), avifTransformFlags{AVIF_TRANSFORM_NONE}); const testutil::AvifRwData encoded = testutil::Encode(image.get(), AVIF_SPEED_FASTEST); const testutil::AvifImagePtr decoded = testutil::Decode(encoded.data, encoded.size); ASSERT_NE(decoded, nullptr); // No irot/imir after decoding because 1 maps to default no irot/imir. EXPECT_TRUE(testutil::AreByteSequencesEqual(image->exif, decoded->exif)); EXPECT_EQ( decoded->transformFlags & (AVIF_TRANSFORM_IROT | AVIF_TRANSFORM_IMIR), avifTransformFlags{AVIF_TRANSFORM_NONE}); } TEST(MetadataTest, ExifOrientation) { const testutil::AvifImagePtr image = testutil::ReadImage(data_path, "paris_exif_orientation_5.jpg"); ASSERT_NE(image, nullptr); // The Exif metadata contains orientation information: 5. EXPECT_GT(image->exif.size, 0u); EXPECT_EQ(image->transformFlags & (AVIF_TRANSFORM_IROT | AVIF_TRANSFORM_IMIR), avifTransformFlags{AVIF_TRANSFORM_IROT | AVIF_TRANSFORM_IMIR}); EXPECT_EQ(image->irot.angle, 1u); EXPECT_EQ(image->imir.mode, 0u); const testutil::AvifRwData encoded = testutil::Encode(image.get(), AVIF_SPEED_FASTEST); const testutil::AvifImagePtr decoded = testutil::Decode(encoded.data, encoded.size); ASSERT_NE(decoded, nullptr); // irot/imir are expected. EXPECT_TRUE(testutil::AreByteSequencesEqual(image->exif, decoded->exif)); EXPECT_EQ( decoded->transformFlags & (AVIF_TRANSFORM_IROT | AVIF_TRANSFORM_IMIR), avifTransformFlags{AVIF_TRANSFORM_IROT | AVIF_TRANSFORM_IMIR}); EXPECT_EQ(decoded->irot.angle, 1u); EXPECT_EQ(decoded->imir.mode, 0u); } TEST(MetadataTest, ExifOrientationAndForcedImir) { const testutil::AvifImagePtr image = testutil::ReadImage(data_path, "paris_exif_orientation_5.jpg"); ASSERT_NE(image, nullptr); // The Exif metadata contains orientation information: 5. // Force irot/imir to values that have a different meaning than 5. // This is not recommended but for testing only. EXPECT_GT(image->exif.size, 0u); image->transformFlags = AVIF_TRANSFORM_IMIR; image->imir.mode = 1; const testutil::AvifRwData encoded = testutil::Encode(image.get(), AVIF_SPEED_FASTEST); const testutil::AvifImagePtr decoded = testutil::Decode(encoded.data, encoded.size); ASSERT_NE(decoded, nullptr); // Exif orientation is still there but irot/imir do not match it. EXPECT_TRUE(testutil::AreByteSequencesEqual(image->exif, decoded->exif)); EXPECT_EQ(decoded->transformFlags, avifTransformFlags{AVIF_TRANSFORM_IMIR}); EXPECT_EQ(decoded->irot.angle, 0u); EXPECT_EQ(decoded->imir.mode, image->imir.mode); } TEST(MetadataTest, ExifIfdOffsetLoopingTo8) { const testutil::AvifImagePtr image(avifImageCreateEmpty(), avifImageDestroy); ASSERT_NE(image, nullptr); const uint8_t kBadExifPayload[128] = { 'M', 'M', 0, 42, // TIFF header 0, 0, 0, 8, // Offset to 0th IFD 0, 1, // fieldCount 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // tag, type, count, valueOffset 0, 0, 0, 8 // Invalid IFD offset, infinitely looping back to 0th IFD. }; // avifImageSetMetadataExif() calls // avifImageExtractExifOrientationToIrotImir() internally. // The avifImageExtractExifOrientationToIrotImir() call should not enter an // infinite loop. // // TODO(wtc): When we change avifImageSetMetadataExif() to return avifResult, // assert that the avifImageSetMetadataExif() call returns AVIF_RESULT_OK // because avifImageExtractExifOrientationToIrotImir() does not verify the // whole payload, only the parts necessary to extract Exif orientation. avifImageSetMetadataExif( image.get(), kBadExifPayload, sizeof(kBadExifPayload) / sizeof(kBadExifPayload[0])); } //------------------------------------------------------------------------------ TEST(MetadataTest, ExtendedXMP) { const testutil::AvifImagePtr image = testutil::ReadImage(data_path, "dog_exif_extended_xmp_icc.jpg"); ASSERT_NE(image, nullptr); ASSERT_NE(image->xmp.size, 0u); } TEST(MetadataTest, MultipleExtendedXMPAndAlternativeGUIDTag) { const testutil::AvifImagePtr image = testutil::ReadImage(data_path, "paris_extended_xmp.jpg"); ASSERT_NE(image, nullptr); ASSERT_GT(image->xmp.size, size_t{65536 * 2}); } //------------------------------------------------------------------------------ } // namespace } // namespace libavif 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; } libavif::data_path = argv[1]; return RUN_ALL_TESTS(); }