132 static const int floor_log2_table[] =
134 { 0, 0, 2, 2, 4, 4, 4, 4, 8, 8,
135 8, 8, 8, 8, 8, 8, 16, 16, 16, 16,
136 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
137 16, 16, 32, 32, 32, 32, 32, 32, 32, 32,
138 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
139 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
148 return floor_log2_table[
i];
169 const char *filename,
172 const char *over_filename,
179 const gboolean export_masks)
183 avifPixelFormat format = AVIF_PIXEL_FORMAT_NONE;
184 avifImage *image = NULL;
185 avifRGBImage
rgb = { .format = AVIF_RGB_FORMAT_RGB, };
186 avifEncoder *encoder = NULL;
187 uint8_t *icc_profile_data = NULL;
188 uint32_t icc_profile_len;
193 const size_t height =
d->global.height;
194 const size_t bit_depth =
d->bit_depth > 0 ?
d->bit_depth : 0;
200 switch(
d->compression_type)
203 format = AVIF_PIXEL_FORMAT_YUV444;
208 format = AVIF_PIXEL_FORMAT_YUV444;
210 else if(
d->quality > 80)
212 format = AVIF_PIXEL_FORMAT_YUV422;
216 format = AVIF_PIXEL_FORMAT_YUV420;
223 format = AVIF_PIXEL_FORMAT_YUV400;
231 "Failed to create AVIF image for writing [%s]\n",
238 "Exporting AVIF image [%s] "
239 "[width: %" G_GSIZE_FORMAT
", height: %" G_GSIZE_FORMAT
", bit depth: %" G_GSIZE_FORMAT
", comp: %s, quality: %u]\n",
249 gboolean use_icc =
FALSE;
258 image->colorPrimaries = AVIF_COLOR_PRIMARIES_BT709;
259 image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_SRGB;
260 image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_BT601;
263 image->colorPrimaries = AVIF_COLOR_PRIMARIES_BT709;
264 image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_BT709;
265 image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_BT709;
268 image->colorPrimaries = AVIF_COLOR_PRIMARIES_BT709;
269 image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_LINEAR;
270 image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_BT709;
273 image->colorPrimaries = AVIF_COLOR_PRIMARIES_BT2020;
274 image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_LINEAR;
275 image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_BT2020_NCL;
278 image->colorPrimaries = AVIF_COLOR_PRIMARIES_BT2020;
279 image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_SMPTE2084;
280 image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_BT2020_NCL;
283 image->colorPrimaries = AVIF_COLOR_PRIMARIES_BT2020;
284 image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_HLG;
285 image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_BT2020_NCL;
288 image->colorPrimaries = AVIF_COLOR_PRIMARIES_SMPTE432;
289 image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_SMPTE2084;
290 image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_CHROMA_DERIVED_NCL;
293 image->colorPrimaries = AVIF_COLOR_PRIMARIES_SMPTE432;
294 image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_HLG;
295 image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_CHROMA_DERIVED_NCL;
298 image->colorPrimaries = AVIF_COLOR_PRIMARIES_SMPTE432;
299 image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_SRGB;
300 image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_CHROMA_DERIVED_NCL;
307 if(image->colorPrimaries == AVIF_COLOR_PRIMARIES_UNSPECIFIED)
314 use_icc ?
"icc" :
"nclx");
322 cmsHPROFILE out_profile = cp->
profile;
324 cmsSaveProfileToMem(out_profile, 0, &icc_profile_len);
325 if(icc_profile_len > 0)
327 icc_profile_data = malloc(
sizeof(uint8_t) * icc_profile_len);
333 cmsSaveProfileToMem(out_profile, icc_profile_data, &icc_profile_len);
334 (
void)avifImageSetProfileICC(image, icc_profile_data, icc_profile_len);
353 image->yuvRange = AVIF_RANGE_FULL;
355 avifRGBImageSetDefaults(&
rgb, image);
356 rgb.format = AVIF_RGB_FORMAT_RGB;
358 (
void)avifRGBImageAllocatePixels(&
rgb);
360 const float max_channel_f = (float)((1 <<
bit_depth) - 1);
362 const size_t rowbytes =
rgb.rowBytes;
364 const float *
const restrict in_data = (
const float *)in;
365 uint8_t *
const restrict
out = (uint8_t *)
rgb.pixels;
373 for(
size_t y = 0; y <
height; y++)
377 const float *in_pixel = &in_data[(size_t)4 * ((y *
width) +
x)];
378 uint16_t *out_pixel = (uint16_t *)&
out[(y * rowbytes) + (3 *
sizeof(uint16_t) *
x)];
380 out_pixel[0] = (uint16_t)roundf(CLAMP(in_pixel[0] * max_channel_f, 0, max_channel_f));
381 out_pixel[1] = (uint16_t)roundf(CLAMP(in_pixel[1] * max_channel_f, 0, max_channel_f));
382 out_pixel[2] = (uint16_t)roundf(CLAMP(in_pixel[2] * max_channel_f, 0, max_channel_f));
390 for(
size_t y = 0; y <
height; y++)
394 const float *in_pixel = &in_data[(size_t)4 * ((y *
width) +
x)];
395 uint8_t *out_pixel = (uint8_t *)&
out[(y * rowbytes) + (3 *
sizeof(uint8_t) *
x)];
397 out_pixel[0] = (uint8_t)roundf(CLAMP(in_pixel[0] * max_channel_f, 0, max_channel_f));
398 out_pixel[1] = (uint8_t)roundf(CLAMP(in_pixel[1] * max_channel_f, 0, max_channel_f));
399 out_pixel[2] = (uint8_t)roundf(CLAMP(in_pixel[2] * max_channel_f, 0, max_channel_f));
410 (
void)avifImageRGBToYUV(image, &
rgb);
412 if(exif && exif_len > 0)
413 (
void)avifImageSetMetadataExif(image, exif, exif_len);
418 if(xmp_string && (xmp_len = strlen(xmp_string)) > 0)
420 (
void)avifImageSetMetadataXMP(image, (
const uint8_t *)xmp_string, xmp_len);
424 encoder = avifEncoderCreate();
428 "Failed to create AVIF encoder for image [%s]\n",
434 switch(
d->compression_type)
438 encoder->speed = AVIF_SPEED_SLOWEST + 1;
440 encoder->minQuantizer = AVIF_QUANTIZER_LOSSLESS;
441 encoder->maxQuantizer = AVIF_QUANTIZER_LOSSLESS;
445 encoder->speed = AVIF_SPEED_DEFAULT;
447 encoder->maxQuantizer = 100 -
d->quality;
448 encoder->maxQuantizer = CLAMP(encoder->maxQuantizer, 0, 63);
450 encoder->minQuantizer = 64 -
d->quality;
451 encoder->minQuantizer = CLAMP(encoder->minQuantizer, 0, 63);
474 else if (
width >= 8192) {
481 else if (
height >= 8192) {
492 max_threads = (1 << encoder->tileRowsLog2) * (1 << encoder->tileColsLog2);
501 "[avif quality: %u => maxQuantizer: %u, minQuantizer: %u, "
502 "tileColsLog2: %u, tileRowsLog2: %u, threads: %u]\n",
504 encoder->maxQuantizer,
505 encoder->minQuantizer,
506 encoder->tileColsLog2,
507 encoder->tileRowsLog2,
508 encoder->maxThreads);
510 avifRWData output = AVIF_DATA_EMPTY;
512 result = avifEncoderWrite(encoder, image, &output);
513 if(result != AVIF_RESULT_OK)
516 "Failed to encode AVIF image [%s]: %s\n",
517 filename, avifResultToString(result));
525 "AVIF encoder returned empty data for [%s]\n",
537 f = g_fopen(filename,
"wb");
544 cnt = fwrite(output.data, 1, output.size,
f);
546 if(cnt != output.size)
555 avifRGBImageFreePixels(&
rgb);
556 avifImageDestroy(image);
557 avifEncoderDestroy(encoder);
558 avifRWDataFree(&output);