Set Color Space and ICC Profile in libavif

This article explains how to configure the color space (CICP) and assign an ICC profile to an image using the libavif library before encoding. You will learn the specific struct members and API functions required to ensure your AVIF images retain accurate color representation across different devices and platforms.

Setting the Color Space (CICP)

In libavif, the color space is defined using CICP (Coding-Independent Code Points) values, which specify the color primaries, transfer characteristics, and matrix coefficients. These properties are set directly on the avifImage structure before passing it to the encoder.

The following members of the avifImage struct are used to define the color space:

Code Example: Configuring CICP

#include "avif/avif.h"

void configure_color_space(avifImage * image) {
    // Set the color space to sRGB (BT.709)
    image->colorPrimaries = AVIF_COLOR_PRIMARIES_BT709;
    image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_SRGB;
    image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_BT709;
    
    // Set the YUV range (typically AVIF_RANGE_LIMITED or AVIF_RANGE_FULL)
    image->yuvRange = AVIF_RANGE_FULL;
}

Setting the ICC Profile

While CICP values are highly efficient, some workflows require an ICC (International Color Consortium) profile for precise color management. libavif allows you to attach raw ICC profile payload data to the avifImage structure.

The primary function used to set the ICC profile is:

avifImageSetProfileICC

void avifImageSetProfileICC(avifImage * image, const uint8_t * icc, size_t iccSize);

Calling this function copies the provided ICC data into the avifImage structure, which the encoder will then embed in the output AVIF container.

Code Example: Attaching an ICC Profile

#include "avif/avif.h"

void attach_icc_profile(avifImage * image, const uint8_t * icc_data, size_t icc_data_size) {
    // Copy the ICC profile data into the avifImage structure
    avifImageSetProfileICC(image, icc_data, icc_data_size);
}

Integration into the Encoding Pipeline

To apply these settings, configure the avifImage properties and call the ICC profile function after allocating the image but before passing it to the encoder.

// 1. Allocate the image
avifImage * image = avifImageCreate(width, height, depth, AVIF_PIXEL_FORMAT_YUV420);

// 2. Set pixel data (omitted for brevity)

// 3. Set Color Space (CICP)
image->colorPrimaries = AVIF_COLOR_PRIMARIES_BT2020;
image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_PQ;
image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_BT2020;

// 4. Set ICC Profile (Optional)
avifImageSetProfileICC(image, raw_icc_buffer, icc_buffer_size);

// 5. Encode the image
avifEncoder * encoder = avifEncoderCreate();
avifRWData raw_avif = AVIF_RAW_DATA_EMPTY;
avifResult result = avifEncoderWrite(encoder, image, &raw_avif);

if (result == AVIF_RESULT_OK) {
    // AVIF data successfully encoded with color metadata
}

// Cleanup
avifEncoderDestroy(encoder);
avifImageDestroy(image);
avifRWDataFree(&raw_avif);