Add ICC profile plumbing (via the colr box). This still needs YUV coeff harvesting to be correct
diff --git a/src/avif.c b/src/avif.c
index 96bcf71..60dab89 100644
--- a/src/avif.c
+++ b/src/avif.c
@@ -58,6 +58,17 @@
     avifFree(image);
 }
 
+void avifImageSetProfileICC(avifImage * image, uint8_t * icc, size_t iccSize)
+{
+    if (iccSize) {
+        image->profileFormat = AVIF_PROFILE_FORMAT_ICC;
+        avifRawDataSet(&image->icc, icc, iccSize);
+    } else {
+        image->profileFormat = AVIF_PROFILE_FORMAT_NONE;
+        avifRawDataFree(&image->icc);
+    }
+}
+
 void avifImageAllocatePlanes(avifImage * image, uint32_t planes)
 {
     int channelSize = avifImageUsesU16(image) ? 2 : 1;
diff --git a/src/read.c b/src/read.c
index bea1bf0..ca95083 100644
--- a/src/read.c
+++ b/src/read.c
@@ -37,16 +37,25 @@
     char auxType[AUXTYPE_SIZE];
 } avifAuxiliaryType;
 
+typedef struct avifColourInformationBox
+{
+    avifProfileFormat format;
+    uint8_t * icc;
+    size_t iccSize;
+} avifColourInformationBox;
+
 typedef struct avifItem
 {
     int id;
     uint8_t type[4];
     uint32_t offset;
     uint32_t size;
-    avifBool ispe_seen;
+    avifBool ispePresent;
     avifImageSpatialExtents ispe;
-    avifBool auxC_seen;
+    avifBool auxCPresent;
     avifAuxiliaryType auxC;
+    avifBool colrPresent;
+    avifColourInformationBox colr;
     int thumbnailForID; // if non-zero, this item is a thumbnail for Item #{thumbnailForID}
     int auxForID;       // if non-zero, this item is an auxC plane for Item #{auxForID}
 } avifItem;
@@ -56,6 +65,7 @@
     uint8_t type[4];
     avifImageSpatialExtents ispe;
     avifAuxiliaryType auxC;
+    avifColourInformationBox colr;
 } avifProperty;
 
 typedef struct avifFileType
@@ -184,6 +194,21 @@
     return AVIF_TRUE;
 }
 
+static avifBool avifParseColourInformationBox(avifData * data, uint8_t * raw, size_t rawLen, int propertyIndex)
+{
+    BEGIN_STREAM(s, raw, rawLen);
+    uint8_t colourType[4]; // unsigned int(32) colour_type;
+    CHECK(avifStreamRead(&s, colourType, 4));
+    if (!memcmp(colourType, "rICC", 4) || !memcmp(colourType, "prof", 4)) {
+        data->properties[propertyIndex].colr.format = AVIF_PROFILE_FORMAT_ICC;
+        data->properties[propertyIndex].colr.icc = avifStreamCurrent(&s);
+        data->properties[propertyIndex].colr.iccSize = avifStreamRemainingBytes(&s);
+    } else {
+        data->properties[propertyIndex].colr.format = AVIF_PROFILE_FORMAT_NONE;
+    }
+    return AVIF_TRUE;
+}
+
 static avifBool avifParseItemPropertyContainerBox(avifData * data, uint8_t * raw, size_t rawLen)
 {
     BEGIN_STREAM(s, raw, rawLen);
@@ -207,6 +232,9 @@
         if (!memcmp(header.type, "auxC", 4)) {
             CHECK(avifParseAuxiliaryTypeProperty(data, avifStreamCurrent(&s), header.size, propertyIndex));
         }
+        if (!memcmp(header.type, "colr", 4)) {
+            CHECK(avifParseColourInformationBox(data, avifStreamCurrent(&s), header.size, propertyIndex));
+        }
 
         CHECK(avifStreamSkip(&s, header.size));
     }
@@ -267,11 +295,14 @@
             // Associate property with item
             avifProperty * prop = &data->properties[propertyIndex];
             if (!memcmp(prop->type, "ispe", 4)) {
-                data->items[itemIndex].ispe_seen = AVIF_TRUE;
+                data->items[itemIndex].ispePresent = AVIF_TRUE;
                 memcpy(&data->items[itemIndex].ispe, &prop->ispe, sizeof(avifImageSpatialExtents));
             } else if (!memcmp(prop->type, "auxC", 4)) {
-                data->items[itemIndex].auxC_seen = AVIF_TRUE;
+                data->items[itemIndex].auxCPresent = AVIF_TRUE;
                 memcpy(&data->items[itemIndex].auxC, &prop->auxC, sizeof(avifAuxiliaryType));
+            } else if (!memcmp(prop->type, "colr", 4)) {
+                data->items[itemIndex].colrPresent = AVIF_TRUE;
+                memcpy(&data->items[itemIndex].colr, &prop->colr, sizeof(avifColourInformationBox));
             }
         }
     }
@@ -638,8 +669,8 @@
     }
 
     if (
-        (colorOBUItem && aomColorImage && colorOBUItem->ispe_seen && ((colorOBUItem->ispe.width != aomColorImage->d_w) || (colorOBUItem->ispe.height != aomColorImage->d_h))) ||
-        (alphaOBUItem && aomAlphaImage && alphaOBUItem->ispe_seen && ((alphaOBUItem->ispe.width != aomAlphaImage->d_w) || (alphaOBUItem->ispe.height != aomAlphaImage->d_h)))
+        (colorOBUItem && aomColorImage && colorOBUItem->ispePresent && ((colorOBUItem->ispe.width != aomColorImage->d_w) || (colorOBUItem->ispe.height != aomColorImage->d_h))) ||
+        (alphaOBUItem && aomAlphaImage && alphaOBUItem->ispePresent && ((alphaOBUItem->ispe.width != aomAlphaImage->d_w) || (alphaOBUItem->ispe.height != aomAlphaImage->d_h)))
         )
     {
         aom_codec_destroy(&colorDecoder);
@@ -649,6 +680,10 @@
         return AVIF_RESULT_ISPE_SIZE_MISMATCH;
     }
 
+    if (colorOBUItem->colrPresent && (colorOBUItem->colr.format == AVIF_PROFILE_FORMAT_ICC)) {
+        avifImageSetProfileICC(image, colorOBUItem->colr.icc, colorOBUItem->colr.iccSize);
+    }
+
     avifPixelFormat yuvFormat = AVIF_PIXEL_FORMAT_NONE;
     switch (aomColorImage->fmt) {
         case AOM_IMG_FMT_I420:
diff --git a/src/write.c b/src/write.c
index 675b6f4..e741a6b 100644
--- a/src/write.c
+++ b/src/write.c
@@ -205,6 +205,15 @@
             ipmaPush(&ipmaColor, ipcoIndex); // ipma is 1-indexed, doing this afterwards is correct
             ipmaPush(&ipmaAlpha, ipcoIndex); // Alpha shares the ispe prop
 
+            if ((image->profileFormat == AVIF_PROFILE_FORMAT_ICC) && image->icc.data && (image->icc.data > 0)) {
+                avifBoxMarker colr = avifStreamWriteBox(&s, "colr", -1, 0);
+                avifStreamWrite(&s, "prof", 4); // unsigned int(32) colour_type;
+                avifStreamWrite(&s, image->icc.data, image->icc.size);
+                avifStreamFinishBox(&s, colr);
+                ++ipcoIndex;
+                ipmaPush(&ipmaColor, ipcoIndex);
+            }
+
             avifBoxMarker pixiC = avifStreamWriteBox(&s, "pixi", 0, 0);
             avifStreamWriteU8(&s, 3);            // unsigned int (8) num_channels;
             avifStreamWriteU8(&s, image->depth); // unsigned int (8) bits_per_channel;