Read/write one of each type of colr box, as allowed in HEIF 6.5.5.1 (Amemendment 3)
diff --git a/src/read.c b/src/read.c
index 03ed41c..6fcf7f1 100644
--- a/src/read.c
+++ b/src/read.c
@@ -2650,16 +2650,32 @@
}
}
- const avifProperty * colrProp = avifPropertyArrayFind(colorProperties, "colr");
- if (colrProp) {
- if (colrProp->u.colr.hasICC) {
- avifImageSetProfileICC(decoder->image, colrProp->u.colr.icc, colrProp->u.colr.iccSize);
- } else if (colrProp->u.colr.hasNCLX) {
- data->cicpSet = AVIF_TRUE;
- decoder->image->colorPrimaries = colrProp->u.colr.colorPrimaries;
- decoder->image->transferCharacteristics = colrProp->u.colr.transferCharacteristics;
- decoder->image->matrixCoefficients = colrProp->u.colr.matrixCoefficients;
- decoder->image->yuvRange = colrProp->u.colr.range;
+ // Find and adopt all colr boxes "at most one for a given value of colour type" (HEIF 6.5.5.1, from Amendment 3)
+ // Accept one of each type, and bail out if more than one of a given type is provided.
+ avifBool colrICCSeen = AVIF_FALSE;
+ avifBool colrNCLXSeen = AVIF_FALSE;
+ for (uint32_t propertyIndex = 0; propertyIndex < colorProperties->count; ++propertyIndex) {
+ avifProperty * prop = &colorProperties->prop[propertyIndex];
+
+ if (!memcmp(prop->type, "colr", 4)) {
+ if (prop->u.colr.hasICC) {
+ if (colrICCSeen) {
+ return AVIF_RESULT_BMFF_PARSE_FAILED;
+ }
+ colrICCSeen = AVIF_TRUE;
+ avifImageSetProfileICC(decoder->image, prop->u.colr.icc, prop->u.colr.iccSize);
+ }
+ if (prop->u.colr.hasNCLX) {
+ if (colrNCLXSeen) {
+ return AVIF_RESULT_BMFF_PARSE_FAILED;
+ }
+ colrNCLXSeen = AVIF_TRUE;
+ data->cicpSet = AVIF_TRUE;
+ decoder->image->colorPrimaries = prop->u.colr.colorPrimaries;
+ decoder->image->transferCharacteristics = prop->u.colr.transferCharacteristics;
+ decoder->image->matrixCoefficients = prop->u.colr.matrixCoefficients;
+ decoder->image->yuvRange = prop->u.colr.range;
+ }
}
}
diff --git a/src/write.c b/src/write.c
index 2913403..df04997 100644
--- a/src/write.c
+++ b/src/write.c
@@ -204,18 +204,20 @@
if (ipma && itemPropertyIndex) {
ipmaPush(ipma, ++(*itemPropertyIndex), AVIF_FALSE);
}
- } else {
- avifBoxMarker colr = avifRWStreamWriteBox(s, "colr", AVIF_BOX_SIZE_TBD);
- avifRWStreamWriteChars(s, "nclx", 4); // unsigned int(32) colour_type;
- avifRWStreamWriteU16(s, (uint16_t)imageMetadata->colorPrimaries); // unsigned int(16) colour_primaries;
- avifRWStreamWriteU16(s, (uint16_t)imageMetadata->transferCharacteristics); // unsigned int(16) transfer_characteristics;
- avifRWStreamWriteU16(s, (uint16_t)imageMetadata->matrixCoefficients); // unsigned int(16) matrix_coefficients;
- avifRWStreamWriteU8(s, (imageMetadata->yuvRange == AVIF_RANGE_FULL) ? 0x80 : 0); // unsigned int(1) full_range_flag;
- // unsigned int(7) reserved = 0;
- avifRWStreamFinishBox(s, colr);
- if (ipma && itemPropertyIndex) {
- ipmaPush(ipma, ++(*itemPropertyIndex), AVIF_FALSE);
- }
+ }
+
+ // HEIF 6.5.5.1, from Amendment 3 allows multiple colr boxes: "at most one for a given value of colour type"
+ // Therefore, *always* writing an nclx box, even if an a prof box was already written above.
+ avifBoxMarker colr = avifRWStreamWriteBox(s, "colr", AVIF_BOX_SIZE_TBD);
+ avifRWStreamWriteChars(s, "nclx", 4); // unsigned int(32) colour_type;
+ avifRWStreamWriteU16(s, (uint16_t)imageMetadata->colorPrimaries); // unsigned int(16) colour_primaries;
+ avifRWStreamWriteU16(s, (uint16_t)imageMetadata->transferCharacteristics); // unsigned int(16) transfer_characteristics;
+ avifRWStreamWriteU16(s, (uint16_t)imageMetadata->matrixCoefficients); // unsigned int(16) matrix_coefficients;
+ avifRWStreamWriteU8(s, (imageMetadata->yuvRange == AVIF_RANGE_FULL) ? 0x80 : 0); // unsigned int(1) full_range_flag;
+ // unsigned int(7) reserved = 0;
+ avifRWStreamFinishBox(s, colr);
+ if (ipma && itemPropertyIndex) {
+ ipmaPush(ipma, ++(*itemPropertyIndex), AVIF_FALSE);
}
// Write (Optional) Transformations