138 static const int floor_log2_table[] =
140 { 0, 0, 2, 2, 4, 4, 4, 4, 8, 8,
141 8, 8, 8, 8, 8, 8, 16, 16, 16, 16,
142 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
143 16, 16, 32, 32, 32, 32, 32, 32, 32, 32,
144 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
145 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
154 return floor_log2_table[
i];
175 const char *filename,
178 const char *over_filename,
185 const gboolean export_masks)
189 avifPixelFormat format = AVIF_PIXEL_FORMAT_NONE;
190 avifImage *image = NULL;
191 avifRGBImage
rgb = { .format = AVIF_RGB_FORMAT_RGB, };
192 avifEncoder *encoder = NULL;
193 uint8_t *icc_profile_data = NULL;
194 uint32_t icc_profile_len;
199 const size_t height =
d->global.height;
200 const size_t bit_depth =
d->bit_depth > 0 ?
d->bit_depth : 0;
206 switch(
d->compression_type)
209 format = AVIF_PIXEL_FORMAT_YUV444;
214 format = AVIF_PIXEL_FORMAT_YUV444;
216 else if(
d->quality > 80)
218 format = AVIF_PIXEL_FORMAT_YUV422;
222 format = AVIF_PIXEL_FORMAT_YUV420;
229 format = AVIF_PIXEL_FORMAT_YUV400;
237 "Failed to create AVIF image for writing [%s]\n",
244 "Exporting AVIF image [%s] "
245 "[width: %" G_GSIZE_FORMAT
", height: %" G_GSIZE_FORMAT
", bit depth: %" G_GSIZE_FORMAT
", comp: %s, quality: %u]\n",
255 gboolean use_icc =
FALSE;
264 image->colorPrimaries = AVIF_COLOR_PRIMARIES_BT709;
265 image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_SRGB;
266 image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_BT601;
269 image->colorPrimaries = AVIF_COLOR_PRIMARIES_BT709;
270 image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_BT709;
271 image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_BT709;
274 image->colorPrimaries = AVIF_COLOR_PRIMARIES_BT709;
275 image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_LINEAR;
276 image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_BT709;
279 image->colorPrimaries = AVIF_COLOR_PRIMARIES_BT2020;
280 image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_LINEAR;
281 image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_BT2020_NCL;
284 image->colorPrimaries = AVIF_COLOR_PRIMARIES_BT2020;
285 image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_SMPTE2084;
286 image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_BT2020_NCL;
289 image->colorPrimaries = AVIF_COLOR_PRIMARIES_BT2020;
290 image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_HLG;
291 image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_BT2020_NCL;
294 image->colorPrimaries = AVIF_COLOR_PRIMARIES_SMPTE432;
295 image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_SMPTE2084;
296 image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_CHROMA_DERIVED_NCL;
299 image->colorPrimaries = AVIF_COLOR_PRIMARIES_SMPTE432;
300 image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_HLG;
301 image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_CHROMA_DERIVED_NCL;
304 image->colorPrimaries = AVIF_COLOR_PRIMARIES_SMPTE432;
305 image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_SRGB;
306 image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_CHROMA_DERIVED_NCL;
313 if(image->colorPrimaries == AVIF_COLOR_PRIMARIES_UNSPECIFIED)
320 use_icc ?
"icc" :
"nclx");
328 cmsHPROFILE out_profile = cp->
profile;
330 cmsSaveProfileToMem(out_profile, 0, &icc_profile_len);
331 if(icc_profile_len > 0)
333 icc_profile_data = malloc(
sizeof(uint8_t) * icc_profile_len);
339 cmsSaveProfileToMem(out_profile, icc_profile_data, &icc_profile_len);
340 (
void)avifImageSetProfileICC(image, icc_profile_data, icc_profile_len);
359 image->yuvRange = AVIF_RANGE_FULL;
361 avifRGBImageSetDefaults(&
rgb, image);
362 rgb.format = AVIF_RGB_FORMAT_RGB;
364 (
void)avifRGBImageAllocatePixels(&
rgb);
366 const float max_channel_f = (float)((1 <<
bit_depth) - 1);
368 const size_t rowbytes =
rgb.rowBytes;
370 const float *
const restrict in_data = (
const float *)in;
371 uint8_t *
const restrict
out = (uint8_t *)
rgb.pixels;
379 for(
size_t y = 0; y <
height; y++)
383 const float *in_pixel = &in_data[(size_t)4 * ((y *
width) +
x)];
384 uint16_t *out_pixel = (uint16_t *)&
out[(y * rowbytes) + (3 *
sizeof(uint16_t) *
x)];
386 out_pixel[0] = (uint16_t)roundf(CLAMP(in_pixel[0] * max_channel_f, 0, max_channel_f));
387 out_pixel[1] = (uint16_t)roundf(CLAMP(in_pixel[1] * max_channel_f, 0, max_channel_f));
388 out_pixel[2] = (uint16_t)roundf(CLAMP(in_pixel[2] * max_channel_f, 0, max_channel_f));
396 for(
size_t y = 0; y <
height; y++)
400 const float *in_pixel = &in_data[(size_t)4 * ((y *
width) +
x)];
401 uint8_t *out_pixel = (uint8_t *)&
out[(y * rowbytes) + (3 *
sizeof(uint8_t) *
x)];
403 out_pixel[0] = (uint8_t)roundf(CLAMP(in_pixel[0] * max_channel_f, 0, max_channel_f));
404 out_pixel[1] = (uint8_t)roundf(CLAMP(in_pixel[1] * max_channel_f, 0, max_channel_f));
405 out_pixel[2] = (uint8_t)roundf(CLAMP(in_pixel[2] * max_channel_f, 0, max_channel_f));
416 (
void)avifImageRGBToYUV(image, &
rgb);
418 if(exif && exif_len > 0)
419 (
void)avifImageSetMetadataExif(image, exif, exif_len);
424 if(xmp_string && (xmp_len = strlen(xmp_string)) > 0)
426 (
void)avifImageSetMetadataXMP(image, (
const uint8_t *)xmp_string, xmp_len);
430 encoder = avifEncoderCreate();
434 "Failed to create AVIF encoder for image [%s]\n",
440 switch(
d->compression_type)
444 encoder->speed = AVIF_SPEED_SLOWEST + 1;
446 encoder->minQuantizer = AVIF_QUANTIZER_LOSSLESS;
447 encoder->maxQuantizer = AVIF_QUANTIZER_LOSSLESS;
451 encoder->speed = AVIF_SPEED_DEFAULT;
453 encoder->maxQuantizer = 100 -
d->quality;
454 encoder->maxQuantizer = CLAMP(encoder->maxQuantizer, 0, 63);
456 encoder->minQuantizer = 64 -
d->quality;
457 encoder->minQuantizer = CLAMP(encoder->minQuantizer, 0, 63);
480 else if (
width >= 8192) {
487 else if (
height >= 8192) {
498 max_threads = (1 << encoder->tileRowsLog2) * (1 << encoder->tileColsLog2);
507 "[avif quality: %u => maxQuantizer: %u, minQuantizer: %u, "
508 "tileColsLog2: %u, tileRowsLog2: %u, threads: %u]\n",
510 encoder->maxQuantizer,
511 encoder->minQuantizer,
512 encoder->tileColsLog2,
513 encoder->tileRowsLog2,
514 encoder->maxThreads);
516 avifRWData output = AVIF_DATA_EMPTY;
518 result = avifEncoderWrite(encoder, image, &output);
519 if(result != AVIF_RESULT_OK)
522 "Failed to encode AVIF image [%s]: %s\n",
523 filename, avifResultToString(result));
531 "AVIF encoder returned empty data for [%s]\n",
543 f = g_fopen(filename,
"wb");
550 cnt = fwrite(output.data, 1, output.size,
f);
552 if(cnt != output.size)
561 avifRGBImageFreePixels(&
rgb);
562 avifImageDestroy(image);
563 avifEncoderDestroy(encoder);
564 avifRWDataFree(&output);