associate tmap ICC with tmap item in avifParseMinimizedImageBox (#3401)
diff --git a/src/read.c b/src/read.c
index 51f31e4..6d08c48 100644
--- a/src/read.c
+++ b/src/read.c
@@ -4773,7 +4773,7 @@
tmapColrPropICC->u.colr.iccOffset = rawOffset + avifROStreamOffset(&s);
tmapColrPropICC->u.colr.iccSize = tmapIccDataSize;
AVIF_CHECKERR(avifROStreamSkip(&s, tmapColrPropICC->u.colr.iccSize), AVIF_RESULT_BMFF_PARSE_FAILED);
- AVIF_CHECKERR(avifDecoderItemAddProperty(colorItem, tmapColrPropICC), AVIF_RESULT_OUT_OF_MEMORY);
+ AVIF_CHECKERR(avifDecoderItemAddProperty(tmapItem, tmapColrPropICC), AVIF_RESULT_OUT_OF_MEMORY);
} else {
AVIF_CHECKERR(avifMetaCreateProperty(meta, "skip"), AVIF_RESULT_OUT_OF_MEMORY); // Placeholder.
}
diff --git a/tests/gtest/avifminitest.cc b/tests/gtest/avifminitest.cc
index 6a7c159..1517fa1 100644
--- a/tests/gtest/avifminitest.cc
+++ b/tests/gtest/avifminitest.cc
@@ -196,5 +196,54 @@
//------------------------------------------------------------------------------
+// The ICC profile of the tone mapped ('tmap') image carried by a
+// MinimizedImageBox must be associated with the tone mapped image item, not the
+// primary color item. Here the base image has no ICC while the alternate image
+// does, so after a round trip the profile must surface on the gain map and the
+// base image must stay profile-less.
+TEST(AvifMinimizedImageBoxTest, GainMapAlternateIcc) {
+ ImagePtr image = testutil::CreateImage(/*width=*/8, /*height=*/10,
+ /*depth=*/10, AVIF_PIXEL_FORMAT_YUV420,
+ AVIF_PLANES_YUV, AVIF_RANGE_FULL);
+ ASSERT_NE(image, nullptr);
+ testutil::FillImageGradient(image.get());
+ image->gainMap = avifGainMapCreate();
+ ASSERT_NE(image->gainMap, nullptr);
+ image->gainMap->image =
+ testutil::CreateImage(/*width=*/8, /*height=*/10, /*depth=*/8,
+ AVIF_PIXEL_FORMAT_YUV400, AVIF_PLANES_YUV,
+ AVIF_RANGE_FULL)
+ .release();
+ ASSERT_NE(image->gainMap->image, nullptr);
+ testutil::FillImageGradient(image->gainMap->image);
+ // Only the alternate (tone mapped) image has an ICC profile.
+ ASSERT_EQ(avifRWDataSet(&image->gainMap->altICC, testutil::kSampleIcc.data(),
+ testutil::kSampleIcc.size()),
+ AVIF_RESULT_OK);
+
+ testutil::AvifRwData encoded;
+ EncoderPtr encoder(avifEncoderCreate());
+ ASSERT_NE(encoder, nullptr);
+ encoder->speed = AVIF_SPEED_FASTEST;
+ encoder->headerFormat = AVIF_HEADER_MINI;
+ ASSERT_EQ(avifEncoderWrite(encoder.get(), image.get(), &encoded),
+ AVIF_RESULT_OK);
+
+ ImagePtr decoded(avifImageCreateEmpty());
+ ASSERT_NE(decoded, nullptr);
+ DecoderPtr decoder(avifDecoderCreate());
+ ASSERT_NE(decoder, nullptr);
+ decoder->imageContentToDecode |= AVIF_IMAGE_CONTENT_GAIN_MAP;
+ ASSERT_EQ(avifDecoderReadMemory(decoder.get(), decoded.get(), encoded.data,
+ encoded.size),
+ AVIF_RESULT_OK);
+
+ ASSERT_NE(decoded->gainMap, nullptr);
+ EXPECT_EQ(decoded->gainMap->altICC.size, testutil::kSampleIcc.size());
+ EXPECT_EQ(decoded->icc.size, 0u);
+}
+
+//------------------------------------------------------------------------------
+
} // namespace
} // namespace avif