Add support for png iCCP chunk (#2952) Handled using the API if available (libpng version >= 1.6.45), or with an unknown chunk callback otherwise. Simplify the image reading code by removing the allowChangingCicp parameter. This is handled at the call site in avifenc.c instead.
diff --git a/apps/avifenc.c b/apps/avifenc.c index 35cc471..c68eea2 100644 --- a/apps/avifenc.c +++ b/apps/avifenc.c
@@ -607,6 +607,8 @@ } } + const avifColorPrimaries colorPrimariesBefore = dstImage->colorPrimaries; + const avifTransferCharacteristics transferCharacteristicsBefore = dstImage->transferCharacteristics; if (avifReadImage(currentFile->filename, inputFormat, input->requestedFormat, @@ -615,7 +617,6 @@ ignoreColorProfile, ignoreExif, ignoreXMP, - allowChangingCicp, ignoreGainMap, UINT32_MAX, dstImage, @@ -631,6 +632,11 @@ } return AVIF_FALSE; } + if (!allowChangingCicp) { + // Restore the previous primaries/transfer in case avifReadImage changed them. + dstImage->colorPrimaries = colorPrimariesBefore; + dstImage->transferCharacteristics = transferCharacteristicsBefore; + } if (!input->frameIter) { ++input->fileIndex;
diff --git a/apps/avifgainmaputil/convert_command.cc b/apps/avifgainmaputil/convert_command.cc index 706dbb4..b67f512 100644 --- a/apps/avifgainmaputil/convert_command.cc +++ b/apps/avifgainmaputil/convert_command.cc
@@ -59,7 +59,6 @@ arg_image_read_.ignore_profile, /*ignoreExif=*/false, /*ignoreXMP=*/false, - /*allowChangingCicp=*/true, /*ignoreGainMap=*/false, AVIF_DEFAULT_IMAGE_SIZE_LIMIT, image.get(), /*outDepth=*/nullptr, /*sourceTiming=*/nullptr,
diff --git a/apps/avifgainmaputil/imageio.cc b/apps/avifgainmaputil/imageio.cc index 6a7a8cc..4da4742 100644 --- a/apps/avifgainmaputil/imageio.cc +++ b/apps/avifgainmaputil/imageio.cc
@@ -121,8 +121,8 @@ requested_format, static_cast<int>(requested_depth), AVIF_CHROMA_DOWNSAMPLING_AUTOMATIC, ignore_profile, /*ignoreExif=*/false, /*ignoreXMP=*/false, - /*allowChangingCicp=*/true, /*ignoreGainMap=*/true, - AVIF_DEFAULT_IMAGE_SIZE_LIMIT, image, /*outDepth=*/nullptr, + /*ignoreGainMap=*/true, AVIF_DEFAULT_IMAGE_SIZE_LIMIT, image, + /*outDepth=*/nullptr, /*sourceTiming=*/nullptr, /*frameIter=*/nullptr); if (file_format == AVIF_APP_FILE_FORMAT_UNKNOWN) { std::cout << "Failed to decode image: " << input_filename;
diff --git a/apps/shared/avifpng.c b/apps/shared/avifpng.c index 08e18c5..a0e8a12 100644 --- a/apps/shared/avifpng.c +++ b/apps/shared/avifpng.c
@@ -210,6 +210,28 @@ return AVIF_TRUE; } +typedef struct avifUnknownCicpChunkData +{ + avifImage * avif; + avifBool cicpChunkRead; +} avifUnknownCicpChunkData; + +// Callback for unknown chunks. Used to detect/handle chunks that we are missing support for. +static int avifPNGReadUnknownChunk(png_structp png_ptr, png_unknown_chunkp chunk) +{ + avifUnknownCicpChunkData * data = (avifUnknownCicpChunkData *)png_get_user_chunk_ptr(png_ptr); + avifImage * avif = data->avif; + if (!memcmp(chunk->name, "cICP\0", 5)) { + if (chunk->size > 2) { + data->cicpChunkRead = AVIF_TRUE; + avif->colorPrimaries = chunk->data[0]; + avif->transferCharacteristics = chunk->data[1]; + // The matrix coefficient and full range flag are ignored. + } + } + return 1; +} + // Note on setjmp() and volatile variables: // // K & R, The C Programming Language 2nd Ed, p. 254 says: @@ -233,7 +255,6 @@ avifBool ignoreColorProfile, avifBool ignoreExif, avifBool ignoreXMP, - avifBool allowChangingCicp, uint32_t imageSizeLimit, uint32_t * outPNGDepth) { @@ -272,6 +293,9 @@ goto cleanup; } + avifUnknownCicpChunkData unknownChunkData = { avif, AVIF_FALSE }; + png_set_read_user_chunk_fn(png, &unknownChunkData, &avifPNGReadUnknownChunk); + png_init_io(png, f); png_set_sig_bytes(png, 8); png_read_info(png, info); @@ -351,13 +375,28 @@ unsigned char * iccpData = NULL; png_uint_32 iccpDataLen = 0; int srgbIntent; - - // PNG specification 1.2 Section 4.2.2: - // The sRGB and iCCP chunks should not both appear. - // - // When the sRGB / iCCP chunk is present, applications that recognize it and are capable of color management - // must ignore the gAMA and cHRM chunks and use the sRGB / iCCP chunk instead. - if (png_get_iCCP(png, info, &iccpProfileName, &iccpCompression, &iccpData, &iccpDataLen) == PNG_INFO_iCCP) { + // PNG specification Third Edition Section 4.3 lists color space information chunk types by priority: + // Chunk Type Priority + // cICP 1 + // iCCP 2 + // sRGB 3 + // cHRM and gAMA 4 + // If a single image contains more than one of these chunk types, the chunk with the lowest + // Priority number should take precedence and any higher-numbered chunk types should be ignored. +#if defined(PNG_cICP_SUPPORTED) + png_byte cicpColorPrimaries; + png_byte cicpTransferFunction; + png_byte cicpMatrixCoefficients; + png_byte cicpVideoFullRangeFlag; + if (png_get_cICP(png, info, &cicpColorPrimaries, &cicpTransferFunction, &cicpMatrixCoefficients, &cicpVideoFullRangeFlag)) { + avif->colorPrimaries = cicpColorPrimaries; + avif->transferCharacteristics = cicpTransferFunction; + // The matrix coefficient and full range flag are ignored: they are about YUV encoding and the PNG values are irrelevant. + } else +#endif + if (unknownChunkData.cicpChunkRead) { + // Already handled in avifPNGReadUnknownChunk() + } else if (png_get_iCCP(png, info, &iccpProfileName, &iccpCompression, &iccpData, &iccpDataLen) == PNG_INFO_iCCP) { if (!rawColorTypeIsGray && avif->yuvFormat == AVIF_PIXEL_FORMAT_YUV400) { fprintf(stderr, "The image contains a color ICC profile which is incompatible with the requested output " @@ -374,78 +413,75 @@ fprintf(stderr, "Setting ICC profile failed: out of memory.\n"); goto cleanup; } - } else if (allowChangingCicp) { - if (png_get_sRGB(png, info, &srgbIntent) == PNG_INFO_sRGB) { - // srgbIntent ignored - avif->colorPrimaries = AVIF_COLOR_PRIMARIES_SRGB; - avif->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_SRGB; + } else if (png_get_sRGB(png, info, &srgbIntent) == PNG_INFO_sRGB) { + // srgbIntent ignored + avif->colorPrimaries = AVIF_COLOR_PRIMARIES_SRGB; + avif->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_SRGB; + } else { + avifBool needToGenerateICC = AVIF_FALSE; + double gamma; + double wX, wY, rX, rY, gX, gY, bX, bY; + float primaries[8]; + if (png_get_gAMA(png, info, &gamma) == PNG_INFO_gAMA) { + gamma = 1.0 / gamma; + avif->transferCharacteristics = avifTransferCharacteristicsFindByGamma((float)gamma); + if (avif->transferCharacteristics == AVIF_TRANSFER_CHARACTERISTICS_UNKNOWN) { + needToGenerateICC = AVIF_TRUE; + } } else { - avifBool needToGenerateICC = AVIF_FALSE; - double gamma; - double wX, wY, rX, rY, gX, gY, bX, bY; - float primaries[8]; - if (png_get_gAMA(png, info, &gamma) == PNG_INFO_gAMA) { - gamma = 1.0 / gamma; - avif->transferCharacteristics = avifTransferCharacteristicsFindByGamma((float)gamma); - if (avif->transferCharacteristics == AVIF_TRANSFER_CHARACTERISTICS_UNKNOWN) { - needToGenerateICC = AVIF_TRUE; - } + // No gamma information in file. Assume the default value. + // PNG specification 1.2 Section 10.5: + // Assume a CRT exponent of 2.2 unless detailed calibration measurements + // of this particular CRT are available. + gamma = 2.2; + } + + if (png_get_cHRM(png, info, &wX, &wY, &rX, &rY, &gX, &gY, &bX, &bY) == PNG_INFO_cHRM) { + primaries[0] = (float)rX; + primaries[1] = (float)rY; + primaries[2] = (float)gX; + primaries[3] = (float)gY; + primaries[4] = (float)bX; + primaries[5] = (float)bY; + primaries[6] = (float)wX; + primaries[7] = (float)wY; + avif->colorPrimaries = avifColorPrimariesFind(primaries, NULL); + if (avif->colorPrimaries == AVIF_COLOR_PRIMARIES_UNKNOWN) { + needToGenerateICC = AVIF_TRUE; + } + } else { + // No chromaticity information in file. Assume the default value. + // PNG specification 1.2 Section 10.6: + // Decoders may wish to do this for PNG files with no cHRM chunk. + // In that case, a reasonable default would be the CCIR 709 primaries [ITU-R-BT709]. + avifColorPrimariesGetValues(AVIF_COLOR_PRIMARIES_BT709, primaries); + } + + if (needToGenerateICC) { + avif->colorPrimaries = AVIF_COLOR_PRIMARIES_UNSPECIFIED; + avif->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_UNSPECIFIED; + fprintf(stderr, + "INFO: legacy PNG color space information found in file %s not matching any CICP value. libavif is generating an ICC profile for it." + " Use --ignore-profile to ignore color space information instead (may affect the colors of the encoded AVIF image).\n", + inputFilename); + + avifBool generateICCResult = AVIF_FALSE; + if (avif->yuvFormat == AVIF_PIXEL_FORMAT_YUV400) { + generateICCResult = avifGenerateGrayICC(&avif->icc, (float)gamma, &primaries[6]); } else { - // No gamma information in file. Assume the default value. - // PNG specification 1.2 Section 10.5: - // Assume a CRT exponent of 2.2 unless detailed calibration measurements - // of this particular CRT are available. - gamma = 2.2; + generateICCResult = avifGenerateRGBICC(&avif->icc, (float)gamma, primaries); } - if (png_get_cHRM(png, info, &wX, &wY, &rX, &rY, &gX, &gY, &bX, &bY) == PNG_INFO_cHRM) { - primaries[0] = (float)rX; - primaries[1] = (float)rY; - primaries[2] = (float)gX; - primaries[3] = (float)gY; - primaries[4] = (float)bX; - primaries[5] = (float)bY; - primaries[6] = (float)wX; - primaries[7] = (float)wY; - avif->colorPrimaries = avifColorPrimariesFind(primaries, NULL); - if (avif->colorPrimaries == AVIF_COLOR_PRIMARIES_UNKNOWN) { - needToGenerateICC = AVIF_TRUE; - } - } else { - // No chromaticity information in file. Assume the default value. - // PNG specification 1.2 Section 10.6: - // Decoders may wish to do this for PNG files with no cHRM chunk. - // In that case, a reasonable default would be the CCIR 709 primaries [ITU-R-BT709]. - avifColorPrimariesGetValues(AVIF_COLOR_PRIMARIES_BT709, primaries); - } - - if (needToGenerateICC) { - avif->colorPrimaries = AVIF_COLOR_PRIMARIES_UNSPECIFIED; - avif->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_UNSPECIFIED; + if (!generateICCResult) { fprintf(stderr, - "INFO: legacy PNG color space information found in file %s not matching any CICP value. libavif is generating an ICC profile for it." - " Use --ignore-profile to ignore color space information instead (may affect the colors of the encoded AVIF image).\n", + "WARNING: libavif could not generate an ICC profile for file %s. " + "It may be caused by invalid values in the color space information. " + "The encoded AVIF image's colors may be affected.\n", inputFilename); - - avifBool generateICCResult = AVIF_FALSE; - if (avif->yuvFormat == AVIF_PIXEL_FORMAT_YUV400) { - generateICCResult = avifGenerateGrayICC(&avif->icc, (float)gamma, &primaries[6]); - } else { - generateICCResult = avifGenerateRGBICC(&avif->icc, (float)gamma, primaries); - } - - if (!generateICCResult) { - fprintf(stderr, - "WARNING: libavif could not generate an ICC profile for file %s. " - "It may be caused by invalid values in the color space information. " - "The encoded AVIF image's colors may be affected.\n", - inputFilename); - } } } } // Note: There is no support for the rare "Raw profile type icc" or "Raw profile type icm" text chunks. - // TODO(yguyon): Also check if there is a cICp chunk (https://github.com/AOMediaCodec/libavif/pull/1065#discussion_r958534232) } const int numChannels = png_get_channels(png, info); @@ -528,7 +564,6 @@ avifBool ignoreColorProfile, avifBool ignoreExif, avifBool ignoreXMP, - avifBool allowChangingCicp, uint32_t imageSizeLimit, uint32_t * outPNGDepth) { @@ -553,7 +588,6 @@ ignoreColorProfile, ignoreExif, ignoreXMP, - allowChangingCicp, imageSizeLimit, outPNGDepth);
diff --git a/apps/shared/avifpng.h b/apps/shared/avifpng.h index 16d5a2f..5292a27 100644 --- a/apps/shared/avifpng.h +++ b/apps/shared/avifpng.h
@@ -19,7 +19,6 @@ avifBool ignoreColorProfile, avifBool ignoreExif, avifBool ignoreXMP, - avifBool allowChangingCicp, uint32_t imageSizeLimit, uint32_t * outPNGDepth); avifBool avifPNGWrite(const char * outputFilename,
diff --git a/apps/shared/avifutil.c b/apps/shared/avifutil.c index ad5ad2c..111435f 100644 --- a/apps/shared/avifutil.c +++ b/apps/shared/avifutil.c
@@ -315,7 +315,6 @@ avifBool ignoreColorProfile, avifBool ignoreExif, avifBool ignoreXMP, - avifBool allowChangingCicp, avifBool ignoreGainMap, uint32_t imageSizeLimit, avifImage * image, @@ -343,17 +342,7 @@ *outDepth = 8; } } else if (inputFormat == AVIF_APP_FILE_FORMAT_PNG) { - if (!avifPNGRead(filename, - image, - requestedFormat, - requestedDepth, - chromaDownsampling, - ignoreColorProfile, - ignoreExif, - ignoreXMP, - allowChangingCicp, - imageSizeLimit, - outDepth)) { + if (!avifPNGRead(filename, image, requestedFormat, requestedDepth, chromaDownsampling, ignoreColorProfile, ignoreExif, ignoreXMP, imageSizeLimit, outDepth)) { return AVIF_APP_FILE_FORMAT_UNKNOWN; } } else if (inputFormat == AVIF_APP_FILE_FORMAT_UNKNOWN) {
diff --git a/apps/shared/avifutil.h b/apps/shared/avifutil.h index b61c283..1c664e6 100644 --- a/apps/shared/avifutil.h +++ b/apps/shared/avifutil.h
@@ -73,6 +73,8 @@ // 'ignoreGainMap' is only relevant for jpeg files that have a gain map // and only if AVIF_ENABLE_JPEG_GAIN_MAP_CONVERSION is ON // (requires libxml2). Otherwise it has no effect. +// May set the image's colorPrimaries, transferCharacteristics and ICC fields +// based on color information found in the image (unless ignoreColorProfile is true). avifAppFileFormat avifReadImage(const char * filename, avifAppFileFormat inputFormat, avifPixelFormat requestedFormat, @@ -81,7 +83,6 @@ avifBool ignoreColorProfile, avifBool ignoreExif, avifBool ignoreXMP, - avifBool allowChangingCicp, avifBool ignoreGainMap, uint32_t imageSizeLimit, avifImage * image,
diff --git a/doc/avifenc.1.md b/doc/avifenc.1.md index 3899cd9..4d733e0 100644 --- a/doc/avifenc.1.md +++ b/doc/avifenc.1.md
@@ -120,7 +120,7 @@ : Provide an XMP metadata payload to be associated with the primary item (implies \--ignore-xmp). **\--icc** _FILENAME_ -: Provide an ICC profile payload to be associated with the primary item (implies \--ignore-icc). +: Provide an ICC profile payload to be associated with the primary item (implies \--ignore-profile). **\--timescale**, **\--fps** _V_ : Timescale for image sequences. If all frames are 1 timescale in length, this is equivalent to frames per second. (Default: 30)
diff --git a/tests/data/README.md b/tests/data/README.md index a17f24e..48c62ce 100644 --- a/tests/data/README.md +++ b/tests/data/README.md
@@ -133,6 +133,15 @@ It is [kodim03_yuv420_8bpc.avif](io/kodim03_yuv420_8bpc.avif) converted to grayscale and tagged as Gamma 1.6 gAMA PNG chunk. +#### File [kodim03_grayscale_cicp.png](kodim03_grayscale_cicp.png) + + + +License: released by the Eastman Kodak Company for unrestricted usage + +It is [kodim03_yuv420_8bpc.avif](io/kodim03_yuv420_8bpc.avif) converted to +grayscale and tagged with a cICP chunk. + #### File [kodim03_grayscale_gamma1.6-reference.png](kodim03_grayscale_gamma1.6-reference.png) 
diff --git a/tests/data/kodim03_grayscale_cicp.png b/tests/data/kodim03_grayscale_cicp.png new file mode 100644 index 0000000..433c286 --- /dev/null +++ b/tests/data/kodim03_grayscale_cicp.png Binary files differ
diff --git a/tests/data/kodim03_grayscale_gamma1.6.png b/tests/data/kodim03_grayscale_gamma1.6.png index 433c286..0b9ea27 100644 --- a/tests/data/kodim03_grayscale_gamma1.6.png +++ b/tests/data/kodim03_grayscale_gamma1.6.png Binary files differ
diff --git a/tests/gtest/are_images_equal.cc b/tests/gtest/are_images_equal.cc index 64b7c17..11231a9 100644 --- a/tests/gtest/are_images_equal.cc +++ b/tests/gtest/are_images_equal.cc
@@ -37,7 +37,7 @@ AVIF_CHROMA_DOWNSAMPLING_AUTOMATIC, /*ignoreColorProfile==*/AVIF_FALSE, /*ignoreExif=*/AVIF_FALSE, - /*ignoreXMP=*/AVIF_FALSE, /*allowChangingCicp=*/AVIF_TRUE, + /*ignoreXMP=*/AVIF_FALSE, // TODO(maryla): also compare gain maps. /*ignoreGainMap=*/AVIF_TRUE, /*imageSizeLimit=*/std::numeric_limits<uint32_t>::max(),
diff --git a/tests/gtest/avif_fuzztest_read_image.cc b/tests/gtest/avif_fuzztest_read_image.cc index 0a20be8..f04cd18 100644 --- a/tests/gtest/avif_fuzztest_read_image.cc +++ b/tests/gtest/avif_fuzztest_read_image.cc
@@ -46,7 +46,7 @@ avifPixelFormat requested_format, int requested_depth, avifChromaDownsampling chroma_downsampling, bool ignore_color_profile, bool ignore_exif, bool ignore_xmp, - bool allow_changing_cicp, bool ignore_gain_map, + bool ignore_gain_map, avifMatrixCoefficients matrix_coefficients) { ASSERT_FALSE(GetSeedDataDirs().empty()); // Make sure seeds are available. @@ -80,8 +80,8 @@ const avifAppFileFormat file_format = avifReadImage( file_path.c_str(), AVIF_APP_FILE_FORMAT_UNKNOWN /* guess format */, requested_format, requested_depth, chroma_downsampling, - ignore_color_profile, ignore_exif, ignore_xmp, allow_changing_cicp, - ignore_gain_map, imageSizeLimit, avif_image.get(), &out_depth, &timing, + ignore_color_profile, ignore_exif, ignore_xmp, ignore_gain_map, + imageSizeLimit, avif_image.get(), &out_depth, &timing, /*frameIter=*/nullptr); if (file_format != AVIF_APP_FILE_FORMAT_UNKNOWN) { @@ -122,7 +122,6 @@ /*ignore_color_profile=*/Arbitrary<bool>(), /*ignore_exif=*/Arbitrary<bool>(), /*ignore_xmp=*/Arbitrary<bool>(), - /*allow_changing_cicp=*/Arbitrary<bool>(), /*ignore_gain_map=*/Arbitrary<bool>(), ElementOf({AVIF_MATRIX_COEFFICIENTS_IDENTITY, AVIF_MATRIX_COEFFICIENTS_BT709,
diff --git a/tests/gtest/avifjpeggainmaptest.cc b/tests/gtest/avifjpeggainmaptest.cc index a86e0f5..456dd5f 100644 --- a/tests/gtest/avifjpeggainmaptest.cc +++ b/tests/gtest/avifjpeggainmaptest.cc
@@ -77,7 +77,7 @@ testutil::ReadImage(data_path, filename, AVIF_PIXEL_FORMAT_YUV444, 8, AVIF_CHROMA_DOWNSAMPLING_AUTOMATIC, /*ignore_icc=*/false, /*ignore_exif=*/false, - /*ignore_xmp=*/true, /*allow_changing_cicp=*/true, + /*ignore_xmp=*/true, /*ignore_gain_map=*/false); ASSERT_NE(image, nullptr); ASSERT_NE(image->gainMap, nullptr); @@ -104,7 +104,7 @@ data_path, "paris_exif_xmp_gainmap_littleendian.jpg", AVIF_PIXEL_FORMAT_YUV444, 8, AVIF_CHROMA_DOWNSAMPLING_AUTOMATIC, /*ignore_icc=*/false, /*ignore_exif=*/false, - /*ignore_xmp=*/false, /*allow_changing_cicp=*/true, + /*ignore_xmp=*/false, /*ignore_gain_map=*/true); ASSERT_NE(image, nullptr); ASSERT_EQ(image->gainMap, nullptr);
diff --git a/tests/gtest/aviflosslesstest.cc b/tests/gtest/aviflosslesstest.cc index 9832ed0..c74788d 100644 --- a/tests/gtest/aviflosslesstest.cc +++ b/tests/gtest/aviflosslesstest.cc
@@ -28,8 +28,8 @@ /*requestedDepth=*/0, /*chromaDownsampling=*/AVIF_CHROMA_DOWNSAMPLING_AUTOMATIC, /*ignoreColorProfile=*/false, /*ignoreExif=*/false, /*ignoreXMP=*/false, - /*allowChangingCicp=*/true, /*ignoreGainMap=*/true, - AVIF_DEFAULT_IMAGE_SIZE_LIMIT, image.get(), /*outDepth=*/nullptr, + /*ignoreGainMap=*/true, AVIF_DEFAULT_IMAGE_SIZE_LIMIT, image.get(), + /*outDepth=*/nullptr, /*sourceTiming=*/nullptr, /*frameIter=*/nullptr); ASSERT_EQ(file_format, AVIF_APP_FILE_FORMAT_UNKNOWN); } @@ -51,7 +51,7 @@ /*requestedFormat=*/pixel_format, /*requestedDepth=*/0, /*chromaDownsampling=*/AVIF_CHROMA_DOWNSAMPLING_AUTOMATIC, /*ignoreColorProfile=*/ignore_icc, /*ignoreExif=*/false, - /*ignoreXMP=*/false, /*allowChangingCicp=*/true, /*ignoreGainMap=*/true, + /*ignoreXMP=*/false, /*ignoreGainMap=*/true, AVIF_DEFAULT_IMAGE_SIZE_LIMIT, image.get(), /*outDepth=*/nullptr, /*sourceTiming=*/nullptr, /*frameIter=*/nullptr); if (matrix_coefficients == AVIF_MATRIX_COEFFICIENTS_IDENTITY && @@ -72,17 +72,17 @@ ImagePtr image(avifImageCreateEmpty()); ASSERT_NE(image, nullptr); image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_UNSPECIFIED; - ASSERT_NE(AVIF_APP_FILE_FORMAT_UNKNOWN, - avifReadImage( - path.c_str(), AVIF_APP_FILE_FORMAT_UNKNOWN /* guess format */, - AVIF_PIXEL_FORMAT_NONE, /*requestedDepth=*/0, - /*chromaDownsampling=*/AVIF_CHROMA_DOWNSAMPLING_AUTOMATIC, - /*ignoreColorProfile=*/true, /*ignoreExif=*/true, - /*ignoreXMP=*/true, - /*allowChangingCicp=*/true, /*ignoreGainMap=*/true, - AVIF_DEFAULT_IMAGE_SIZE_LIMIT, image.get(), - /*outDepth=*/nullptr, /*sourceTiming=*/nullptr, - /*frameIter=*/nullptr)); + ASSERT_NE( + AVIF_APP_FILE_FORMAT_UNKNOWN, + avifReadImage( + path.c_str(), AVIF_APP_FILE_FORMAT_UNKNOWN /* guess format */, + AVIF_PIXEL_FORMAT_NONE, /*requestedDepth=*/0, + /*chromaDownsampling=*/AVIF_CHROMA_DOWNSAMPLING_AUTOMATIC, + /*ignoreColorProfile=*/true, /*ignoreExif=*/true, + /*ignoreXMP=*/true, + /*ignoreGainMap=*/true, AVIF_DEFAULT_IMAGE_SIZE_LIMIT, image.get(), + /*outDepth=*/nullptr, /*sourceTiming=*/nullptr, + /*frameIter=*/nullptr)); is_gray = image->yuvFormat == AVIF_PIXEL_FORMAT_YUV400; }
diff --git a/tests/gtest/avifpng16bittest.cc b/tests/gtest/avifpng16bittest.cc index ebb8cf3..5472033 100644 --- a/tests/gtest/avifpng16bittest.cc +++ b/tests/gtest/avifpng16bittest.cc
@@ -38,8 +38,8 @@ AVIF_CHROMA_DOWNSAMPLING_AUTOMATIC, /*ignoreColorProfile=*/true, /*ignoreExif=*/true, /*ignoreXMP=*/true, - /*allowChangingCicp=*/true, /*ignoreGainMap=*/true, - AVIF_DEFAULT_IMAGE_SIZE_LIMIT, image.get(), &output_depth, + /*ignoreGainMap=*/true, AVIF_DEFAULT_IMAGE_SIZE_LIMIT, + image.get(), &output_depth, /*sourceTiming=*/nullptr, /*frameIter=*/nullptr) == AVIF_APP_FILE_FORMAT_UNKNOWN) { return nullptr;
diff --git a/tests/gtest/avifreadimagetest.cc b/tests/gtest/avifreadimagetest.cc index 15708c8..c1423fe 100644 --- a/tests/gtest/avifreadimagetest.cc +++ b/tests/gtest/avifreadimagetest.cc
@@ -114,26 +114,6 @@ EXPECT_EQ(image->icc.size, 0u); } -// Verify that color info does not get overwritten if allow_changing_cicp is -// false. -TEST(PngTest, ColorGamma22ForbitChangingCicp) { - const ImagePtr image = testutil::ReadImage( - data_path, "ffffcc-gamma2.2.png", - /*requested_format=*/AVIF_PIXEL_FORMAT_NONE, - /*requested_depth=*/0, AVIF_CHROMA_DOWNSAMPLING_AUTOMATIC, - /*ignore_icc=*/false, /*ignore_exif*/ false, - /*ignore_xmp=*/false, /*allow_changing_cicp=*/false); - ASSERT_NE(image, nullptr); - - // Color info should still be unspecified even if file gamma is 2.2 - EXPECT_EQ(image->colorPrimaries, AVIF_COLOR_PRIMARIES_UNSPECIFIED); - EXPECT_EQ(image->transferCharacteristics, - AVIF_TRANSFER_CHARACTERISTICS_UNSPECIFIED); - - // should not generate ICC profile - EXPECT_EQ(image->icc.size, 0u); -} - // Verify we can read a color PNG file tagged as gamma 1.6 through gAMA chunk, // and generate a color profile for it. TEST(PngTest, ColorGamma16) { @@ -301,7 +281,7 @@ /*requestedDepth=*/0, /*chromaDownsampling=*/AVIF_CHROMA_DOWNSAMPLING_AUTOMATIC, /*ignoreColorProfile=*/ignore_icc, /*ignoreExif=*/false, - /*ignoreXMP=*/false, /*allowChangingCicp=*/true, + /*ignoreXMP=*/false, /*ignoreGainMap=*/true, AVIF_DEFAULT_IMAGE_SIZE_LIMIT, image.get(), /*outDepth=*/nullptr, /*sourceTiming=*/nullptr, /*frameIter=*/nullptr); @@ -470,7 +450,7 @@ filepath.c_str(), AVIF_APP_FILE_FORMAT_UNKNOWN /* guess format */, AVIF_PIXEL_FORMAT_NONE, /*requestedDepth=*/0, AVIF_CHROMA_DOWNSAMPLING_AUTOMATIC, /*ignoreColorProfile=*/true, - /*ignoreExif=*/true, /*ignoreXMP=*/true, /*allowChangingCicp=*/true, + /*ignoreExif=*/true, /*ignoreXMP=*/true, /*ignoreGainMap=*/true, image_size_limit, image.get(), /*outDepth=*/nullptr, /*sourceTiming=*/nullptr, /*frameIter=*/nullptr);
diff --git a/tests/gtest/aviftest_helpers.cc b/tests/gtest/aviftest_helpers.cc index 34357bf..4fd63f3 100644 --- a/tests/gtest/aviftest_helpers.cc +++ b/tests/gtest/aviftest_helpers.cc
@@ -594,15 +594,14 @@ avifPixelFormat requested_format, int requested_depth, avifChromaDownsampling chroma_downsampling, avifBool ignore_icc, avifBool ignore_exif, - avifBool ignore_xmp, avifBool allow_changing_cicp, - avifBool ignore_gain_map) { + avifBool ignore_xmp, avifBool ignore_gain_map) { ImagePtr image(avifImageCreateEmpty()); if (!image || avifReadImage((std::string(folder_path) + file_name).c_str(), AVIF_APP_FILE_FORMAT_UNKNOWN /* guess format */, requested_format, requested_depth, chroma_downsampling, - ignore_icc, ignore_exif, ignore_xmp, allow_changing_cicp, - ignore_gain_map, AVIF_DEFAULT_IMAGE_SIZE_LIMIT, image.get(), + ignore_icc, ignore_exif, ignore_xmp, ignore_gain_map, + AVIF_DEFAULT_IMAGE_SIZE_LIMIT, image.get(), /*outDepth=*/nullptr, /*sourceTiming=*/nullptr, /*frameIter=*/nullptr) == AVIF_APP_FILE_FORMAT_UNKNOWN) { return nullptr;
diff --git a/tests/gtest/aviftest_helpers.h b/tests/gtest/aviftest_helpers.h index 1caf4da..866dd56 100644 --- a/tests/gtest/aviftest_helpers.h +++ b/tests/gtest/aviftest_helpers.h
@@ -171,7 +171,6 @@ AVIF_CHROMA_DOWNSAMPLING_AUTOMATIC, avifBool ignore_icc = false, avifBool ignore_exif = false, avifBool ignore_xmp = false, - avifBool allow_changing_cicp = true, avifBool ignore_gain_map = false); // Convenient wrapper around avifPNGWrite() for debugging purposes. // Do not remove.
diff --git a/tests/test_cmd_icc_profile.sh b/tests/test_cmd_icc_profile.sh index cb2f254..ad8d1a2 100755 --- a/tests/test_cmd_icc_profile.sh +++ b/tests/test_cmd_icc_profile.sh
@@ -22,6 +22,7 @@ INPUT_COLOR_PNG="${TESTDATA_DIR}/ArcTriomphe-cHRM-red-green-swap.png" REFERENCE_COLOR_PNG="${TESTDATA_DIR}/ArcTriomphe-cHRM-red-green-swap-reference.png" INPUT_GRAY_PNG="${TESTDATA_DIR}/kodim03_grayscale_gamma1.6.png" +INPUT_CICP_PNG="${TESTDATA_DIR}/kodim03_grayscale_cicp.png" REFERENCE_GRAY_PNG="${TESTDATA_DIR}/kodim03_grayscale_gamma1.6-reference.png" SRGB_ICC="${TESTDATA_DIR}/sRGB2014.icc" INPUT_ICC_PNG="${TESTDATA_DIR}/paris_icc_exif_xmp.png" @@ -46,6 +47,12 @@ "${AVIFDEC}" "${ENCODED_FILE}" "${DECODED_FILE}" | grep "Transfer Char.* 12$" "${AVIFDEC}" "${ENCODED_FILE}" "${DECODED_FILE}" | grep "Matrix Coeffs.* 8$" + # Check the cICP chunk gets read + "${AVIFENC}" -s 8 "${INPUT_CICP_PNG}" -o "${ENCODED_FILE}" + "${AVIFDEC}" "${ENCODED_FILE}" "${DECODED_FILE}" | grep "Color Primaries.* 1$" + "${AVIFDEC}" "${ENCODED_FILE}" "${DECODED_FILE}" | grep "Transfer Char.* 4$" + "${AVIFDEC}" "${ENCODED_FILE}" "${DECODED_FILE}" | grep "Matrix Coeffs.* 6$" + # RGB ICC cannot be kept when asking for gray. "${AVIFENC}" -s 10 "${INPUT_ICC_JPG}" --yuv 400 -o "${ENCODED_FILE}" && exit 1 "${AVIFENC}" -s 10 "${INPUT_ICC_PNG}" --yuv 400 -o "${ENCODED_FILE}" && exit 1