How to Embed ICC Profile into AVIF with libavif
This article provides a straightforward technical guide on how to
embed a custom ICC (International Color Consortium) color profile into
an AVIF image using the libavif C library. It covers the
essential API calls and provides a concise code example demonstrating
how to read an ICC profile file and attach it to an
avifImage structure before encoding.
Understanding ICC Profiles in libavif
To ensure accurate color reproduction across different displays, AVIF
images can store color management information either as NCLX (color
property coordinates) or as an embedded ICC profile. When you embed a
custom ICC profile, libavif packages the raw profile
payload into the colr box of the AVIF container.
The primary function used to attach an ICC profile in
libavif is:
void avifImageSetProfileICC(avifImage * image, const uint8_t * icc, size_t iccSize);This function copies the provided buffer containing the raw ICC
profile data into the avifImage structure.
Step-by-Step Implementation
To embed a custom ICC profile, you must read the profile data from a
source (such as a .icc or .icm file) and apply
it to your image structure before passing it to the encoder.
1. Read the ICC Profile Data
First, load the raw binary data of your custom ICC profile into a memory buffer.
size_t iccSize = 0;
uint8_t * iccBuffer = NULL;
FILE * iccFile = fopen("custom_profile.icc", "rb");
if (iccFile) {
fseek(iccFile, 0, SEEK_END);
iccSize = ftell(iccFile);
fseek(iccFile, 0, SEEK_SET);
iccBuffer = (uint8_t *)malloc(iccSize);
fread(iccBuffer, 1, iccSize, iccFile);
fclose(iccFile);
}2. Allocate and Configure the AVIF Image
Create your avifImage structure and set its basic
properties (width, height, depth, and pixel format).
avifImage * image = avifImageCreate(width, height, depth, AVIF_PIXEL_FORMAT_YUV444);
// Allocate pixels and populate image->yuvPlanes here...3. Embed the ICC Profile
Call avifImageSetProfileICC to copy the loaded buffer
into the image structure. Once copied, you can safely free your local
buffer.
if (iccBuffer && iccSize > 0) {
avifImageSetProfileICC(image, iccBuffer, iccSize);
free(iccBuffer);
}4. Encode the Image to AVIF
Create the encoder, set your desired quality parameters, and write the final AVIF container. The encoder will automatically detect the presence of the ICC profile and write it to the output file.
avifEncoder * encoder = avifEncoderCreate();
encoder->quality = 80; // Set quality (0-100)
avifRWData avifOutput = AVIF_RAW_DATA_CHARS_ZERO;
avifResult result = avifEncoderWrite(encoder, image, &avifOutput);
if (result == AVIF_RESULT_OK) {
// Save avifOutput.data to a file
FILE * outFile = fopen("output.avif", "wb");
fwrite(avifOutput.data, 1, avifOutput.size, outFile);
fclose(outFile);
}
// Cleanup
avifRWDataFree(&avifOutput);
avifEncoderDestroy(encoder);
avifImageDestroy(image);