Extracting Color Space from Decoded Images in libavif
This article explains how to retrieve color space properties, such as
CICP (Color Primaries, Transfer Characteristics, and Matrix
Coefficients) and ICC profiles, from an AVIF image using the
libavif C library. It covers the specific fields within the
avifImage structure populated during decoding and the
helper functions available to interpret this metadata.
In libavif, image decoding is handled by the
avifDecoder object. Once an image is parsed and decoded
successfully using avifDecoderParse() and
avifDecoderNextImage(), the decoded image metadata and
pixel data are stored in an avifImage structure (accessible
via decoder->image).
Because libavif is a C library, color space properties
are exposed directly as public fields within the avifImage
struct, supplemented by utility functions to convert these properties
into human-readable formats.
1. Extracting CICP (Color Parameter) Values
CICP values define the color properties of the image. You can extract
these values directly from the fields of the decoded
avifImage structure:
- Color Primaries:
image->colorPrimaries(of typeavifColorPrimaries) defines the color gamut (e.g., BT.709, BT.2020, or sRGB). - Transfer Characteristics:
image->transferCharacteristics(of typeavifTransferCharacteristics) defines the opto-electronic transfer function (e.g., SRGB, Linear, or PQ). - Matrix Coefficients:
image->matrixCoefficients(of typeavifMatrixCoefficients) defines the matrix used to derive luma and chroma signals from RGB.
To convert these enum values into human-readable string
representations, libavif provides the following helper
functions:
const char * avifColorPrimariesToString(avifColorPrimaries val);
const char * avifTransferCharacteristicsToString(avifTransferCharacteristics val);
const char * avifMatrixCoefficientsToString(avifMatrixCoefficients val);2. Extracting ICC Profiles
If the AVIF image contains an embedded ICC profile, it is stored in
the icc field of the avifImage structure. This
field is of type avifRWData, which holds raw binary
data.
- Data Pointer:
image->icc.data - Data Size:
image->icc.size
If image->icc.size is greater than zero, an ICC
profile is present and can be extracted or copied directly from the
memory buffer.
Example Implementation
The following C code demonstrates how to decode an AVIF file and extract its color space properties using the fields and utility functions described above:
#include "avif/avif.h"
#include <stdio.h>
void print_color_space_properties(const char* filename) {
avifDecoder * decoder = avifDecoderCreate();
// Read and parse the AVIF file
avifResult result = avifDecoderSetIOFile(decoder, filename);
if (result != AVIF_RESULT_OK) {
printf("Failed to open file: %s\n", avifResultToString(result));
avifDecoderDestroy(decoder);
return;
}
result = avifDecoderParse(decoder);
if (result != AVIF_RESULT_OK) {
printf("Failed to parse AVIF: %s\n", avifResultToString(result));
avifDecoderDestroy(decoder);
return;
}
result = avifDecoderNextImage(decoder);
if (result != AVIF_RESULT_OK) {
printf("Failed to decode image: %s\n", avifResultToString(result));
avifDecoderDestroy(decoder);
return;
}
// Access the decoded image container
avifImage * image = decoder->image;
// 1. Extract CICP properties using helper functions
const char* primaries = avifColorPrimariesToString(image->colorPrimaries);
const char* transfer = avifTransferCharacteristicsToString(image->transferCharacteristics);
const char* matrix = avifMatrixCoefficientsToString(image->matrixCoefficients);
printf("Color Primaries: %s (%d)\n", primaries, image->colorPrimaries);
printf("Transfer Characteristics: %s (%d)\n", transfer, image->transferCharacteristics);
printf("Matrix Coefficients: %s (%d)\n", matrix, image->matrixCoefficients);
// 2. Extract ICC Profile
if (image->icc.size > 0) {
printf("ICC Profile found: %zu bytes\n", image->icc.size);
// Process raw ICC bytes at image->icc.data here if needed
} else {
printf("No ICC profile embedded in the image.\n");
}
avifDecoderDestroy(decoder);
}