"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "src/imageio/format/avif.c" between
darktable-3.4.1.1.tar.xz and darktable-3.6.0.tar.xz

About: darktable is an open source photography workflow application and RAW developer. A virtual lighttable and darkroom for photographers.

avif.c  (darktable-3.4.1.1.tar.xz):avif.c  (darktable-3.6.0.tar.xz)
/* /*
* This file is part of darktable, * This file is part of darktable,
* Copyright (C) 2019-2020 darktable developers. * Copyright (C) 2019-2021 darktable developers.
* *
* Copyright (c) 2019 Andreas Schneider * Copyright (c) 2019 Andreas Schneider
* *
* darktable is free software: you can redistribute it and/or modify * darktable is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* darktable is distributed in the hope that it will be useful, * darktable is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
skipping to change at line 41 skipping to change at line 41
#include "common/darktable.h" #include "common/darktable.h"
#include "common/imageio.h" #include "common/imageio.h"
#include "common/imageio_module.h" #include "common/imageio_module.h"
#include "control/conf.h" #include "control/conf.h"
#include "imageio/format/imageio_format_api.h" #include "imageio/format/imageio_format_api.h"
#include <avif/avif.h> #include <avif/avif.h>
#define AVIF_MIN_TILE_SIZE 512 #define AVIF_MIN_TILE_SIZE 512
#define AVIF_MAX_TILE_SIZE 3072 #define AVIF_MAX_TILE_SIZE 3072
#define AVIF_DEFAULT_TILE_SIZE AVIF_MIN_TILE_SIZE * 4 #define AVIF_DEFAULT_TILE_SIZE AVIF_MIN_TILE_SIZE * 2
DT_MODULE(1) DT_MODULE(1)
enum avif_compression_type_e enum avif_compression_type_e
{ {
AVIF_COMP_LOSSLESS = 0, AVIF_COMP_LOSSLESS = 0,
AVIF_COMP_LOSSY = 1, AVIF_COMP_LOSSY = 1,
}; };
enum avif_tiling_e enum avif_tiling_e
skipping to change at line 106 skipping to change at line 106
.name = N_("12 bit"), .name = N_("12 bit"),
.bit_depth = 12 .bit_depth = 12
}, },
{ {
.name = NULL, .name = NULL,
} }
}; };
static const char *avif_get_compression_string(enum avif_compression_type_e comp ) static const char *avif_get_compression_string(enum avif_compression_type_e comp )
{ {
switch (comp) { switch(comp)
case AVIF_COMP_LOSSLESS: {
return "lossless"; case AVIF_COMP_LOSSLESS:
case AVIF_COMP_LOSSY: return "lossless";
return "lossy"; case AVIF_COMP_LOSSY:
return "lossy";
} }
return "unknown"; return "unknown";
} }
/* Lookup table for tiling choices */ /* Lookup table for tiling choices */
static int flp2(int i) static int floor_log2(int i)
{ {
/* 0 1, 2, 3, 4, 5, 6, 7, 8, 9 */ static const int floor_log2_table[] =
static const int flp2_table[] = { 0, 0, 2, 2, 4, 4, 4, 4, 8, 8, /* 0 1, 2, 3, 4, 5, 6, 7, 8, 9 */
8, 8, 8, 8, 8, 8, 16, 16, 16, 16, { 0, 0, 2, 2, 4, 4, 4, 4, 8, 8,
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 8, 8, 8, 8, 8, 8, 16, 16, 16, 16,
16, 16, 32, 32, 32, 32, 32, 32, 32, 32, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 16, 16, 32, 32, 32, 32, 32, 32, 32, 32,
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
32, 32, 32, 32 }; 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
/* 0 1, 2, 3, 4, 5, 6, 7, 8, 9 */ 32, 32, 32, 32 };
/* 0 1, 2, 3, 4, 5, 6, 7, 8, 9 */
if (i >= 64) { if(i >= 64)
{
return 64; return 64;
} }
return flp2_table[i]; return floor_log2_table[i];
} }
void init(dt_imageio_module_format_t *self) void init(dt_imageio_module_format_t *self)
{ {
const char *codecName = avifCodecName(AVIF_CODEC_CHOICE_AUTO,
AVIF_CODEC_FLAG_CAN_ENCODE);
if(codecName == NULL)
{
dt_print(DT_DEBUG_IMAGEIO,
"libavif doesn't offer encoding support!\n");
self->ready = FALSE;
return;
}
#ifdef USE_LUA #ifdef USE_LUA
/* bit depth */ /* bit depth */
dt_lua_register_module_member(darktable.lua_state.state, dt_lua_register_module_member(darktable.lua_state.state,
self, self,
dt_imageio_avif_t, dt_imageio_avif_t,
bit_depth, bit_depth,
int); int);
luaA_enum(darktable.lua_state.state, luaA_enum(darktable.lua_state.state,
enum avif_color_mode_e); enum avif_color_mode_e);
luaA_enum_value(darktable.lua_state.state, luaA_enum_value(darktable.lua_state.state,
skipping to change at line 209 skipping to change at line 222
int imgid, int imgid,
int num, int num,
int total, int total,
struct dt_dev_pixelpipe_t *pipe, struct dt_dev_pixelpipe_t *pipe,
const gboolean export_masks) const gboolean export_masks)
{ {
dt_imageio_avif_t *d = (dt_imageio_avif_t *)data; dt_imageio_avif_t *d = (dt_imageio_avif_t *)data;
avifPixelFormat format = AVIF_PIXEL_FORMAT_NONE; avifPixelFormat format = AVIF_PIXEL_FORMAT_NONE;
avifImage *image = NULL; avifImage *image = NULL;
avifRGBImage rgb = { avifRGBImage rgb = { .format = AVIF_RGB_FORMAT_RGB, };
.format = AVIF_RGB_FORMAT_RGB,
};
avifEncoder *encoder = NULL; avifEncoder *encoder = NULL;
uint8_t *icc_profile_data = NULL; uint8_t *icc_profile_data = NULL;
uint32_t icc_profile_len; uint32_t icc_profile_len;
avifResult result; avifResult result;
int rc; int rc;
const size_t width = d->global.width; const size_t width = d->global.width;
const size_t height = d->global.height; const size_t height = d->global.height;
const size_t bit_depth = d->bit_depth > 0 ? d->bit_depth : 0; const size_t bit_depth = d->bit_depth > 0 ? d->bit_depth : 0;
enum avif_color_mode_e color_mode = d->color_mode; enum avif_color_mode_e color_mode = d->color_mode;
switch (color_mode) switch(color_mode)
{ {
case AVIF_COLOR_MODE_RGB: case AVIF_COLOR_MODE_RGB:
switch (d->compression_type) switch(d->compression_type)
{ {
case AVIF_COMP_LOSSLESS: case AVIF_COMP_LOSSLESS:
format = AVIF_PIXEL_FORMAT_YUV444; format = AVIF_PIXEL_FORMAT_YUV444;
break; break;
case AVIF_COMP_LOSSY: case AVIF_COMP_LOSSY:
if (d->quality > 90) if(d->quality > 90)
{ {
format = AVIF_PIXEL_FORMAT_YUV444; format = AVIF_PIXEL_FORMAT_YUV444;
} }
else if (d->quality > 80) else if(d->quality > 80)
{ {
format = AVIF_PIXEL_FORMAT_YUV422; format = AVIF_PIXEL_FORMAT_YUV422;
} }
else else
{ {
format = AVIF_PIXEL_FORMAT_YUV420; format = AVIF_PIXEL_FORMAT_YUV420;
} }
break; break;
} }
break; break;
case AVIF_COLOR_MODE_GRAYSCALE: case AVIF_COLOR_MODE_GRAYSCALE:
format = AVIF_PIXEL_FORMAT_YUV400; format = AVIF_PIXEL_FORMAT_YUV400;
break; break;
} }
image = avifImageCreate(width, height, bit_depth, format); image = avifImageCreate(width, height, bit_depth, format);
if (image == NULL) { if(image == NULL)
{
dt_print(DT_DEBUG_IMAGEIO, dt_print(DT_DEBUG_IMAGEIO,
"Failed to create AVIF image for writing [%s]\n", "Failed to create AVIF image for writing [%s]\n",
filename); filename);
rc = 1; rc = 1;
goto out; goto out;
} }
dt_print(DT_DEBUG_IMAGEIO, dt_print(DT_DEBUG_IMAGEIO,
"Exporting AVIF image [%s] " "Exporting AVIF image [%s] "
"[width: %zu, height: %zu, bit depth: %zu, comp: %s, quality: %u]\n", "[width: %zu, height: %zu, bit depth: %zu, comp: %s, quality: %u]\n",
filename, filename,
width, width,
height, height,
bit_depth, bit_depth,
avif_get_compression_string(d->compression_type), avif_get_compression_string(d->compression_type),
d->quality); d->quality);
avifRGBImageSetDefaults(&rgb, image); if(imgid > 0)
rgb.format = AVIF_RGB_FORMAT_RGB; {
avifRGBImageAllocatePixels(&rgb);
const float max_channel_f = (float)((1 << bit_depth) - 1);
const size_t rowbytes = rgb.rowBytes;
const float *const restrict in_data = (const float *)in;
uint8_t *const restrict out = (uint8_t *)rgb.pixels;
switch(bit_depth) {
case 12:
case 10: {
#ifdef _OPENMP
#pragma omp parallel for simd default(none) \
dt_omp_firstprivate(in_data, width, height, out, rowbytes, max_channel_f) \
schedule(simd:static) \
collapse(2)
#endif
for (size_t y = 0; y < height; y++)
{
for (size_t x = 0; x < width; x++)
{
const float *in_pixel = &in_data[(size_t)4 * ((y * width) + x)];
uint16_t *out_pixel = (uint16_t *)&out[(y * rowbytes) + (3 * sizeof(ui
nt16_t) * x)];
out_pixel[0] = (uint16_t)CLAMP(in_pixel[0] * max_channel_f, 0, max_cha
nnel_f);
out_pixel[1] = (uint16_t)CLAMP(in_pixel[1] * max_channel_f, 0, max_cha
nnel_f);
out_pixel[2] = (uint16_t)CLAMP(in_pixel[2] * max_channel_f, 0, max_cha
nnel_f);
}
}
break;
}
case 8: {
#ifdef _OPENMP
#pragma omp parallel for simd default(none) \
dt_omp_firstprivate(in_data, width, height, out, rowbytes, max_channel_f) \
schedule(simd:static) \
collapse(2)
#endif
for (size_t y = 0; y < height; y++)
{
for (size_t x = 0; x < width; x++)
{
const float *in_pixel = &in_data[(size_t)4 * ((y * width) + x)];
uint8_t *out_pixel = (uint8_t *)&out[(y * rowbytes) + (3 * sizeof(uint
8_t) * x)];
out_pixel[0] = (uint8_t)CLAMP(in_pixel[0] * max_channel_f, 0, max_chan
nel_f);
out_pixel[1] = (uint8_t)CLAMP(in_pixel[1] * max_channel_f, 0, max_chan
nel_f);
out_pixel[2] = (uint8_t)CLAMP(in_pixel[2] * max_channel_f, 0, max_chan
nel_f);
}
}
break;
}
default:
dt_control_log(_("invalid AVIF bit depth!"));
rc = 1;
goto out;
}
avifImageRGBToYUV(image, &rgb);
if (imgid > 0) {
gboolean use_icc = FALSE; gboolean use_icc = FALSE;
#if AVIF_VERSION >= 800 /*
image->colorPrimaries = AVIF_COLOR_PRIMARIES_UNKNOWN; * Set these in advance so any upcoming RGB -> YUV use the proper
image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_UNKNOWN; * coefficients.
image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_UNSPECIFIED; */
switch(over_type)
switch (over_type) { {
case DT_COLORSPACE_SRGB: case DT_COLORSPACE_SRGB:
image->colorPrimaries = AVIF_COLOR_PRIMARIES_BT709; image->colorPrimaries = AVIF_COLOR_PRIMARIES_BT709;
image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_SRGB; image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_SRGB;
image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_BT709; image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_BT709;
break; break;
case DT_COLORSPACE_REC709: case DT_COLORSPACE_REC709:
image->colorPrimaries = AVIF_COLOR_PRIMARIES_BT709; image->colorPrimaries = AVIF_COLOR_PRIMARIES_BT709;
image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_BT470M; image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_BT709;
image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_BT709; image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_BT709;
break; break;
case DT_COLORSPACE_LIN_REC709: case DT_COLORSPACE_LIN_REC709:
image->colorPrimaries = AVIF_COLOR_PRIMARIES_BT709; image->colorPrimaries = AVIF_COLOR_PRIMARIES_BT709;
image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_LINEAR; image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_LINEAR;
image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_BT709; image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_BT709;
break; break;
case DT_COLORSPACE_LIN_REC2020: case DT_COLORSPACE_LIN_REC2020:
image->colorPrimaries = AVIF_COLOR_PRIMARIES_BT2020; image->colorPrimaries = AVIF_COLOR_PRIMARIES_BT2020;
image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_LINEAR; image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_LINEAR;
skipping to change at line 389 skipping to change at line 338
break; break;
case DT_COLORSPACE_HLG_P3: case DT_COLORSPACE_HLG_P3:
image->colorPrimaries = AVIF_COLOR_PRIMARIES_SMPTE432; image->colorPrimaries = AVIF_COLOR_PRIMARIES_SMPTE432;
image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_HLG; image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_HLG;
image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_CHROMA_DERIVED_NC L; image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_CHROMA_DERIVED_NC L;
break; break;
default: default:
break; break;
} }
if (image->colorPrimaries == AVIF_COLOR_PRIMARIES_UNKNOWN) { // no change from default, unspecified CICP (2/2/2)
if(image->colorPrimaries == AVIF_COLOR_PRIMARIES_UNSPECIFIED)
{
use_icc = TRUE; use_icc = TRUE;
} }
#else /* AVIF_VERSION 700 */
avifNclxColorProfile nclx = {
.colourPrimaries = AVIF_NCLX_COLOUR_PRIMARIES_UNKNOWN,
};
switch (over_type) {
case DT_COLORSPACE_SRGB:
nclx = (avifNclxColorProfile) {
.colourPrimaries = AVIF_NCLX_COLOUR_PRIMARIES_BT709,
.transferCharacteristics = AVIF_NCLX_TRANSFER_CHARACTERISTICS_SRGB,
.matrixCoefficients = AVIF_NCLX_MATRIX_COEFFICIENTS_BT709,
#if AVIF_VERSION > 700
.range = AVIF_RANGE_FULL,
#else
.fullRangeFlag = AVIF_NCLX_FULL_RANGE,
#endif
};
break;
case DT_COLORSPACE_REC709:
nclx = (avifNclxColorProfile) {
.colourPrimaries = AVIF_NCLX_COLOUR_PRIMARIES_BT709,
.transferCharacteristics = AVIF_NCLX_TRANSFER_CHARACTERISTICS_BT470M,
.matrixCoefficients = AVIF_NCLX_MATRIX_COEFFICIENTS_BT709,
#if AVIF_VERSION > 700
.range = AVIF_RANGE_FULL,
#else
.fullRangeFlag = AVIF_NCLX_FULL_RANGE,
#endif
};
break;
case DT_COLORSPACE_LIN_REC709:
nclx = (avifNclxColorProfile) {
.colourPrimaries = AVIF_NCLX_COLOUR_PRIMARIES_BT709,
.transferCharacteristics = AVIF_NCLX_TRANSFER_CHARACTERISTICS_LINEAR,
.matrixCoefficients = AVIF_NCLX_MATRIX_COEFFICIENTS_BT709,
#if AVIF_VERSION > 700
.range = AVIF_RANGE_FULL,
#else
.fullRangeFlag = AVIF_NCLX_FULL_RANGE,
#endif
};
break;
case DT_COLORSPACE_LIN_REC2020:
nclx = (avifNclxColorProfile) {
.colourPrimaries = AVIF_NCLX_COLOUR_PRIMARIES_BT2020,
.transferCharacteristics = AVIF_NCLX_TRANSFER_CHARACTERISTICS_LINEAR,
.matrixCoefficients = AVIF_NCLX_MATRIX_COEFFICIENTS_BT2020_NCL,
#if AVIF_VERSION > 700
.range = AVIF_RANGE_FULL,
#else
.fullRangeFlag = AVIF_NCLX_FULL_RANGE,
#endif
};
break;
case DT_COLORSPACE_PQ_REC2020:
nclx = (avifNclxColorProfile) {
.colourPrimaries = AVIF_NCLX_COLOUR_PRIMARIES_BT2020,
.transferCharacteristics = AVIF_NCLX_TRANSFER_CHARACTERISTICS_SMPTE208
4,
.matrixCoefficients = AVIF_NCLX_MATRIX_COEFFICIENTS_BT2020_NCL,
#if AVIF_VERSION > 700
.range = AVIF_RANGE_FULL,
#else
.fullRangeFlag = AVIF_NCLX_FULL_RANGE,
#endif
};
break;
case DT_COLORSPACE_HLG_REC2020:
nclx = (avifNclxColorProfile) {
.colourPrimaries = AVIF_NCLX_COLOUR_PRIMARIES_BT2020,
.transferCharacteristics = AVIF_NCLX_TRANSFER_CHARACTERISTICS_HLG,
.matrixCoefficients = AVIF_NCLX_MATRIX_COEFFICIENTS_BT2020_NCL,
#if AVIF_VERSION > 700
.range = AVIF_RANGE_FULL,
#else
.fullRangeFlag = AVIF_NCLX_FULL_RANGE,
#endif
};
break;
case DT_COLORSPACE_PQ_P3:
nclx = (avifNclxColorProfile) {
.colourPrimaries = AVIF_NCLX_COLOUR_PRIMARIES_SMPTE432,
.transferCharacteristics = AVIF_NCLX_TRANSFER_CHARACTERISTICS_SMPTE208
4,
.matrixCoefficients = AVIF_NCLX_MATRIX_COEFFICIENTS_CHROMA_DERIVED_NCL
,
#if AVIF_VERSION > 700
.range = AVIF_RANGE_FULL,
#else
.fullRangeFlag = AVIF_NCLX_FULL_RANGE,
#endif
};
break;
case DT_COLORSPACE_HLG_P3:
nclx = (avifNclxColorProfile) {
.colourPrimaries = AVIF_NCLX_COLOUR_PRIMARIES_SMPTE432,
.transferCharacteristics = AVIF_NCLX_TRANSFER_CHARACTERISTICS_HLG,
.matrixCoefficients = AVIF_NCLX_MATRIX_COEFFICIENTS_CHROMA_DERIVED_NCL
,
#if AVIF_VERSION > 700
.range = AVIF_RANGE_FULL,
#else
.fullRangeFlag = AVIF_NCLX_FULL_RANGE,
#endif
};
break;
default:
break;
}
if (nclx.colourPrimaries != AVIF_NCLX_COLOUR_PRIMARIES_UNKNOWN) {
avifImageSetProfileNCLX(image, &nclx);
use_icc = TRUE;
}
#endif
dt_print(DT_DEBUG_IMAGEIO, "[avif colorprofile profile: %s - %s]\n", dt_print(DT_DEBUG_IMAGEIO, "[avif colorprofile profile: %s - %s]\n",
dt_colorspaces_get_name(over_type, filename), dt_colorspaces_get_name(over_type, filename),
use_icc ? "icc" : "nclx"); use_icc ? "icc" : "nclx");
if (use_icc) { if(use_icc)
{
const dt_colorspaces_color_profile_t *cp = const dt_colorspaces_color_profile_t *cp =
dt_colorspaces_get_output_profile(imgid, dt_colorspaces_get_output_profile(imgid,
over_type, over_type,
over_filename); over_filename);
cmsHPROFILE out_profile = cp->profile; cmsHPROFILE out_profile = cp->profile;
cmsSaveProfileToMem(out_profile, 0, &icc_profile_len); cmsSaveProfileToMem(out_profile, 0, &icc_profile_len);
if (icc_profile_len > 0) { if(icc_profile_len > 0)
icc_profile_data = malloc(icc_profile_len * sizeof(uint8_t)); {
if (icc_profile_data == NULL) { icc_profile_data = malloc(sizeof(uint8_t) * icc_profile_len);
if(icc_profile_data == NULL)
{
rc = 1; rc = 1;
goto out; goto out;
} }
cmsSaveProfileToMem(out_profile, icc_profile_data, &icc_profile_len); cmsSaveProfileToMem(out_profile, icc_profile_data, &icc_profile_len);
avifImageSetProfileICC(image, avifImageSetProfileICC(image,
icc_profile_data, icc_profile_data,
icc_profile_len); icc_profile_len);
} }
} }
} }
/*
* Set the YUV range before conversion.
*
* Limited range (aka "studio range", "studio swing", etc) is simply when you
* cut off the ends of the actual range you have to avoid the actual minimum
* and maximum of the signal. For example, instead of having full range 8bpc
* ([0-255]) in each channel, you'd only use [16-235]. Anything 16 or below
* is treated as a 0.0 signal, and anything 235 or higher is treated as a 1.0
* signal.
*
* The *reason* this exists, is largely vestigial from the analog era.
*
* For picture we always want the full range.
*/
image->yuvRange = AVIF_RANGE_FULL;
avifRGBImageSetDefaults(&rgb, image);
rgb.format = AVIF_RGB_FORMAT_RGB;
avifRGBImageAllocatePixels(&rgb);
const float max_channel_f = (float)((1 << bit_depth) - 1);
const size_t rowbytes = rgb.rowBytes;
const float *const restrict in_data = (const float *)in;
uint8_t *const restrict out = (uint8_t *)rgb.pixels;
switch(bit_depth)
{
case 12:
case 10:
{
#ifdef _OPENMP
#pragma omp parallel for simd default(none) \
dt_omp_firstprivate(in_data, width, height, out, rowbytes, max_channel_f) \
schedule(simd:static) \
collapse(2)
#endif
for(size_t y = 0; y < height; y++)
{
for(size_t x = 0; x < width; x++)
{
const float *in_pixel = &in_data[(size_t)4 * ((y * width) + x)];
uint16_t *out_pixel = (uint16_t *)&out[(y * rowbytes) + (3 * sizeof(ui
nt16_t) * x)];
out_pixel[0] = (uint16_t)roundf(CLAMP(in_pixel[0] * max_channel_f, 0,
max_channel_f));
out_pixel[1] = (uint16_t)roundf(CLAMP(in_pixel[1] * max_channel_f, 0,
max_channel_f));
out_pixel[2] = (uint16_t)roundf(CLAMP(in_pixel[2] * max_channel_f, 0,
max_channel_f));
}
}
break;
}
case 8:
{
#ifdef _OPENMP
#pragma omp parallel for simd default(none) \
dt_omp_firstprivate(in_data, width, height, out, rowbytes, max_channel_f) \
schedule(simd:static) \
collapse(2)
#endif
for(size_t y = 0; y < height; y++)
{
for(size_t x = 0; x < width; x++)
{
const float *in_pixel = &in_data[(size_t)4 * ((y * width) + x)];
uint8_t *out_pixel = (uint8_t *)&out[(y * rowbytes) + (3 * sizeof(uint
8_t) * x)];
out_pixel[0] = (uint8_t)roundf(CLAMP(in_pixel[0] * max_channel_f, 0, m
ax_channel_f));
out_pixel[1] = (uint8_t)roundf(CLAMP(in_pixel[1] * max_channel_f, 0, m
ax_channel_f));
out_pixel[2] = (uint8_t)roundf(CLAMP(in_pixel[2] * max_channel_f, 0, m
ax_channel_f));
}
}
break;
}
default:
dt_control_log(_("invalid AVIF bit depth!"));
rc = 1;
goto out;
}
avifImageRGBToYUV(image, &rgb);
avifImageSetMetadataExif(image, exif, exif_len); avifImageSetMetadataExif(image, exif, exif_len);
encoder = avifEncoderCreate(); encoder = avifEncoderCreate();
if (encoder == NULL) { if(encoder == NULL)
{
dt_print(DT_DEBUG_IMAGEIO, dt_print(DT_DEBUG_IMAGEIO,
"Failed to create AVIF encoder for image [%s]\n", "Failed to create AVIF encoder for image [%s]\n",
filename); filename);
rc = 1; rc = 1;
goto out; goto out;
} }
switch (d->compression_type) { switch(d->compression_type)
case AVIF_COMP_LOSSLESS: {
/* It isn't recommend to use the extremities */ case AVIF_COMP_LOSSLESS:
encoder->speed = AVIF_SPEED_SLOWEST + 1; /* It isn't recommend to use the extremities */
encoder->speed = AVIF_SPEED_SLOWEST + 1;
encoder->minQuantizer = AVIF_QUANTIZER_LOSSLESS;
encoder->maxQuantizer = AVIF_QUANTIZER_LOSSLESS;
break; encoder->minQuantizer = AVIF_QUANTIZER_LOSSLESS;
case AVIF_COMP_LOSSY: encoder->maxQuantizer = AVIF_QUANTIZER_LOSSLESS;
encoder->speed = AVIF_SPEED_DEFAULT;
encoder->maxQuantizer = 100 - d->quality; break;
encoder->maxQuantizer = CLAMP(encoder->maxQuantizer, 0, 63); case AVIF_COMP_LOSSY:
encoder->speed = AVIF_SPEED_DEFAULT;
encoder->minQuantizer = 64 - d->quality; encoder->maxQuantizer = 100 - d->quality;
encoder->minQuantizer = CLAMP(encoder->minQuantizer, 0, 63); encoder->maxQuantizer = CLAMP(encoder->maxQuantizer, 0, 63);
break; encoder->minQuantizer = 64 - d->quality;
encoder->minQuantizer = CLAMP(encoder->minQuantizer, 0, 63);
break;
} }
encoder->maxThreads = dt_get_num_threads();
/* /*
* Tiling reduces the image quality but it has a negligible impact on * Tiling reduces the image quality but it has a negligible impact on
* still images. * still images.
* *
* The minmum suggested size for a tile is 512x512. * The minimum size for a tile is 512x512. We use a default tile size of
* 1024x1024.
*/ */
switch (d->tiling) { switch(d->tiling)
case AVIF_TILING_ON: { {
size_t width_tile_size = AVIF_DEFAULT_TILE_SIZE; case AVIF_TILING_ON:
size_t height_tile_size = AVIF_DEFAULT_TILE_SIZE; {
size_t width_tile_size = AVIF_DEFAULT_TILE_SIZE;
size_t height_tile_size = AVIF_DEFAULT_TILE_SIZE;
size_t max_threads;
if (width >= 4096) { if(width >= 6144)
{
width_tile_size = AVIF_MIN_TILE_SIZE * 4;
}
else if (width >= 8192) {
width_tile_size = AVIF_MAX_TILE_SIZE; width_tile_size = AVIF_MAX_TILE_SIZE;
} }
if (height >= 4096) { if(height >= 6144)
{
height_tile_size = AVIF_MIN_TILE_SIZE * 4;
}
else if (height >= 8192) {
height_tile_size = AVIF_MAX_TILE_SIZE; height_tile_size = AVIF_MAX_TILE_SIZE;
} }
encoder->tileColsLog2 = flp2(width / width_tile_size); encoder->tileColsLog2 = floor_log2(width / width_tile_size) / 2;
encoder->tileRowsLog2 = flp2(height / height_tile_size); encoder->tileRowsLog2 = floor_log2(height / height_tile_size) / 2;
}
case AVIF_TILING_OFF: /*
break; * This should be set to the final number of tiles, based on
* encoder->tileColsLog2 and encoder->tileRowsLog2.
*/
max_threads = (1 << encoder->tileRowsLog2) * (1 << encoder->tileColsLog2);
encoder->maxThreads = MIN(max_threads, dt_get_num_threads());
}
case AVIF_TILING_OFF:
break;
} }
dt_print(DT_DEBUG_IMAGEIO, dt_print(DT_DEBUG_IMAGEIO,
"[avif quality: %u => maxQuantizer: %u, minQuantizer: %u, " "[avif quality: %u => maxQuantizer: %u, minQuantizer: %u, "
"tileColsLog2: %u, tileRowsLog2: %u, threads: %u]\n", "tileColsLog2: %u, tileRowsLog2: %u, threads: %u]\n",
d->quality, d->quality,
encoder->maxQuantizer, encoder->maxQuantizer,
encoder->minQuantizer, encoder->minQuantizer,
encoder->tileColsLog2, encoder->tileColsLog2,
encoder->tileRowsLog2, encoder->tileRowsLog2,
encoder->maxThreads); encoder->maxThreads);
avifRWData output = AVIF_DATA_EMPTY; avifRWData output = AVIF_DATA_EMPTY;
result = avifEncoderWrite(encoder, image, &output); result = avifEncoderWrite(encoder, image, &output);
if (result != AVIF_RESULT_OK) { if(result != AVIF_RESULT_OK)
{
dt_print(DT_DEBUG_IMAGEIO, dt_print(DT_DEBUG_IMAGEIO,
"Failed to encode AVIF image [%s]: %s\n", "Failed to encode AVIF image [%s]: %s\n",
filename, avifResultToString(result)); filename, avifResultToString(result));
rc = 1; rc = 1;
goto out; goto out;
} }
if (output.size == 0 || output.data == NULL) { if(output.size == 0 || output.data == NULL)
{
dt_print(DT_DEBUG_IMAGEIO, dt_print(DT_DEBUG_IMAGEIO,
"AVIF encoder returned empty data for [%s]\n", "AVIF encoder returned empty data for [%s]\n",
filename); filename);
rc = 1; rc = 1;
goto out; goto out;
} }
/* /*
* Write image to disk * Write image to disk
*/ */
FILE *f = NULL; FILE *f = NULL;
size_t cnt = 0; size_t cnt = 0;
f = g_fopen(filename, "wb"); f = g_fopen(filename, "wb");
if (f == NULL) { if(f == NULL)
{
rc = 1; rc = 1;
goto out; goto out;
} }
cnt = fwrite(output.data, 1, output.size, f); cnt = fwrite(output.data, 1, output.size, f);
fclose(f); fclose(f);
if (cnt != output.size) { if(cnt != output.size)
{
g_unlink(filename); g_unlink(filename);
rc = 1; rc = 1;
goto out; goto out;
} }
rc = 0; /* success */ rc = 0; /* success */
out: out:
avifRGBImageFreePixels(&rgb); avifRGBImageFreePixels(&rgb);
avifImageDestroy(image); avifImageDestroy(image);
avifEncoderDestroy(encoder); avifEncoderDestroy(encoder);
skipping to change at line 657 skipping to change at line 607
size_t params_size(dt_imageio_module_format_t *self) size_t params_size(dt_imageio_module_format_t *self)
{ {
return sizeof(dt_imageio_avif_t); return sizeof(dt_imageio_avif_t);
} }
void *get_params(dt_imageio_module_format_t *self) void *get_params(dt_imageio_module_format_t *self)
{ {
dt_imageio_avif_t *d = (dt_imageio_avif_t *)calloc(1, sizeof(dt_imageio_avif_t )); dt_imageio_avif_t *d = (dt_imageio_avif_t *)calloc(1, sizeof(dt_imageio_avif_t ));
if (d == NULL) { if(d == NULL)
{
return NULL; return NULL;
} }
d->bit_depth = dt_conf_get_int("plugins/imageio/format/avif/bit_depth"); gchar * bpp = dt_conf_get_string("plugins/imageio/format/avif/bpp");
if (d->bit_depth == 0 || d->bit_depth > 12) { d->bit_depth = atoi(bpp);
g_free(bpp);
if(d->bit_depth < 8 || d->bit_depth > 12)
{
d->bit_depth = 8; d->bit_depth = 8;
} }
d->color_mode = dt_conf_get_int("plugins/imageio/format/avif/color_mode"); d->color_mode = dt_conf_get_int("plugins/imageio/format/avif/color_mode");
d->compression_type = dt_conf_get_int("plugins/imageio/format/avif/compression _type"); d->compression_type = dt_conf_get_int("plugins/imageio/format/avif/compression _type");
switch (d->compression_type) { switch(d->compression_type)
case AVIF_COMP_LOSSLESS: {
d->quality = 100; case AVIF_COMP_LOSSLESS:
break; d->quality = 100;
case AVIF_COMP_LOSSY: break;
d->quality = dt_conf_get_int("plugins/imageio/format/avif/quality"); case AVIF_COMP_LOSSY:
if (d->quality > 100) { d->quality = dt_conf_get_int("plugins/imageio/format/avif/quality");
if(d->quality > 100)
{
d->quality = 100; d->quality = 100;
} }
break; break;
} }
d->tiling = dt_conf_get_int("plugins/imageio/format/avif/tiling"); d->tiling = !dt_conf_get_bool("plugins/imageio/format/avif/tiling");
return d; return d;
} }
int set_params(dt_imageio_module_format_t *self, int set_params(dt_imageio_module_format_t *self,
const void *params, const void *params,
const int size) const int size)
{ {
if (size != self->params_size(self)) { if(size != self->params_size(self))
return 1; return 1;
}
const dt_imageio_avif_t *d = (dt_imageio_avif_t *)params; const dt_imageio_avif_t *d = (dt_imageio_avif_t *)params;
dt_imageio_avif_gui_t *g = (dt_imageio_avif_gui_t *)self->gui_data; dt_imageio_avif_gui_t *g = (dt_imageio_avif_gui_t *)self->gui_data;
dt_bauhaus_combobox_set(g->bit_depth, d->bit_depth); dt_bauhaus_combobox_set(g->bit_depth, d->bit_depth);
dt_bauhaus_combobox_set(g->color_mode, d->color_mode); dt_bauhaus_combobox_set(g->color_mode, d->color_mode);
dt_bauhaus_combobox_set(g->tiling, d->tiling); dt_bauhaus_combobox_set(g->tiling, d->tiling);
dt_bauhaus_combobox_set(g->compression_type, d->compression_type); dt_bauhaus_combobox_set(g->compression_type, d->compression_type);
dt_bauhaus_slider_set(g->quality, d->quality); dt_bauhaus_slider_set(g->quality, d->quality);
return 0; return 0;
skipping to change at line 745 skipping to change at line 700
int flags(struct dt_imageio_module_data_t *data) int flags(struct dt_imageio_module_data_t *data)
{ {
return FORMAT_FLAGS_SUPPORT_XMP; return FORMAT_FLAGS_SUPPORT_XMP;
} }
static void bit_depth_changed(GtkWidget *widget, gpointer user_data) static void bit_depth_changed(GtkWidget *widget, gpointer user_data)
{ {
const uint32_t idx = dt_bauhaus_combobox_get(widget); const uint32_t idx = dt_bauhaus_combobox_get(widget);
dt_conf_set_int("plugins/imageio/format/avif/bit_depth", avif_bit_depth[idx].b it_depth); dt_conf_set_int("plugins/imageio/format/avif/bpp", avif_bit_depth[idx].bit_dep th);
} }
static void color_mode_changed(GtkWidget *widget, gpointer user_data) static void color_mode_changed(GtkWidget *widget, gpointer user_data)
{ {
const enum avif_color_mode_e color_mode = dt_bauhaus_combobox_get(widget); const enum avif_color_mode_e color_mode = dt_bauhaus_combobox_get(widget);
dt_conf_set_int("plugins/imageio/format/avif/color_mode", color_mode); dt_conf_set_int("plugins/imageio/format/avif/color_mode", color_mode);
} }
static void tiling_changed(GtkWidget *widget, gpointer user_data) static void tiling_changed(GtkWidget *widget, gpointer user_data)
{ {
const enum avif_tiling_e tiling = dt_bauhaus_combobox_get(widget); const enum avif_tiling_e tiling = dt_bauhaus_combobox_get(widget);
dt_conf_set_int("plugins/imageio/format/avif/tiling", tiling); dt_conf_set_bool("plugins/imageio/format/avif/tiling", !tiling);
} }
static void compression_type_changed(GtkWidget *widget, gpointer user_data) static void compression_type_changed(GtkWidget *widget, gpointer user_data)
{ {
const enum avif_compression_type_e compression_type = dt_bauhaus_combobox_get( widget); const enum avif_compression_type_e compression_type = dt_bauhaus_combobox_get( widget);
dt_imageio_module_format_t *module = (dt_imageio_module_format_t *)user_data; dt_imageio_module_format_t *module = (dt_imageio_module_format_t *)user_data;
dt_imageio_avif_gui_t *gui = (dt_imageio_avif_gui_t *)module->gui_data; dt_imageio_avif_gui_t *gui = (dt_imageio_avif_gui_t *)module->gui_data;
dt_conf_set_int("plugins/imageio/format/avif/compression_type", compression_ty pe); dt_conf_set_int("plugins/imageio/format/avif/compression_type", compression_ty pe);
switch (compression_type) { switch(compression_type)
case AVIF_COMP_LOSSLESS: {
gtk_widget_set_sensitive(gui->quality, FALSE); case AVIF_COMP_LOSSLESS:
break; gtk_widget_set_sensitive(gui->quality, FALSE);
case AVIF_COMP_LOSSY: break;
gtk_widget_set_sensitive(gui->quality, TRUE); case AVIF_COMP_LOSSY:
break; gtk_widget_set_sensitive(gui->quality, TRUE);
break;
} }
} }
static void quality_changed(GtkWidget *slider, gpointer user_data) static void quality_changed(GtkWidget *slider, gpointer user_data)
{ {
const uint32_t quality = (int)dt_bauhaus_slider_get(slider); const uint32_t quality = (int)dt_bauhaus_slider_get(slider);
dt_conf_set_int("plugins/imageio/format/avif/quality", quality); dt_conf_set_int("plugins/imageio/format/avif/quality", quality);
} }
void gui_init(dt_imageio_module_format_t *self) void gui_init(dt_imageio_module_format_t *self)
{ {
dt_imageio_avif_gui_t *gui = dt_imageio_avif_gui_t *gui =
(dt_imageio_avif_gui_t *)malloc(sizeof(dt_imageio_avif_gui_t)); (dt_imageio_avif_gui_t *)malloc(sizeof(dt_imageio_avif_gui_t));
const uint32_t bit_depth = dt_conf_get_int("plugins/imageio/format/avif/bit_de pth"); const uint32_t bit_depth = dt_conf_get_int("plugins/imageio/format/avif/bit_de pth");
const enum avif_color_mode_e color_mode = dt_conf_get_int("plugins/imageio/for mat/avif/color_mode"); const enum avif_color_mode_e color_mode = dt_conf_get_int("plugins/imageio/for mat/avif/color_mode");
const enum avif_tiling_e tiling = dt_conf_get_int("plugins/imageio/format/avif /tiling"); const enum avif_tiling_e tiling = !dt_conf_get_bool("plugins/imageio/format/av if/tiling");
const enum avif_compression_type_e compression_type = dt_conf_get_int("plugins /imageio/format/avif/compression_type"); const enum avif_compression_type_e compression_type = dt_conf_get_int("plugins /imageio/format/avif/compression_type");
const uint32_t quality = dt_conf_get_int("plugins/imageio/format/avif/quality" ); const uint32_t quality = dt_conf_get_int("plugins/imageio/format/avif/quality" );
self->gui_data = (void *)gui; self->gui_data = (void *)gui;
self->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); self->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
/* /*
* Bit depth combo box * Bit depth combo box
*/ */
gui->bit_depth = dt_bauhaus_combobox_new(NULL); gui->bit_depth = dt_bauhaus_combobox_new(NULL);
dt_bauhaus_widget_set_label(gui->bit_depth, NULL, N_("bit depth")); dt_bauhaus_widget_set_label(gui->bit_depth, NULL, N_("bit depth"));
size_t idx = 0; size_t idx = 0;
for (size_t i = 0; avif_bit_depth[i].name != NULL; i++) { for(size_t i = 0; avif_bit_depth[i].name != NULL; i++)
{
dt_bauhaus_combobox_add(gui->bit_depth, _(avif_bit_depth[i].name)); dt_bauhaus_combobox_add(gui->bit_depth, _(avif_bit_depth[i].name));
if (avif_bit_depth[i].bit_depth == bit_depth) { if(avif_bit_depth[i].bit_depth == bit_depth)
{
idx = i; idx = i;
} }
} }
dt_bauhaus_combobox_set(gui->bit_depth, idx); dt_bauhaus_combobox_set(gui->bit_depth, idx);
gtk_widget_set_tooltip_text(gui->bit_depth, gtk_widget_set_tooltip_text(gui->bit_depth,
_("color information stored in an image, higher is better")); _("color information stored in an image, higher is better"));
gtk_box_pack_start(GTK_BOX(self->widget), gui->bit_depth, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(self->widget), gui->bit_depth, TRUE, TRUE, 0);
skipping to change at line 892 skipping to change at line 850
gtk_box_pack_start(GTK_BOX(self->widget), gtk_box_pack_start(GTK_BOX(self->widget),
gui->compression_type, gui->compression_type,
TRUE, TRUE,
TRUE, TRUE,
0); 0);
/* /*
* Quality combo box * Quality combo box
*/ */
gui->quality = dt_bauhaus_slider_new_with_range(NULL, gui->quality = dt_bauhaus_slider_new_with_range(NULL,
5, /* min */ dt_confgen_get_int("plugins/im
100, /* max */ ageio/format/avif/quality", DT_MIN), /* min */
dt_confgen_get_int("plugins/im
ageio/format/avif/quality", DT_MAX), /* max */
1, /* step */ 1, /* step */
92, /* default */ dt_confgen_get_int("plugins/im ageio/format/avif/quality", DT_DEFAULT), /* default */
0); /* digits */ 0); /* digits */
dt_bauhaus_widget_set_label(gui->quality, NULL, N_("quality")); dt_bauhaus_widget_set_label(gui->quality, NULL, N_("quality"));
dt_bauhaus_slider_set_default(gui->quality, 95); dt_bauhaus_slider_set_default(gui->quality, dt_confgen_get_int("plugins/imagei o/format/avif/quality", DT_DEFAULT));
dt_bauhaus_slider_set_format(gui->quality, "%.2f%%"); dt_bauhaus_slider_set_format(gui->quality, "%.2f%%");
gtk_widget_set_tooltip_text(gui->quality, gtk_widget_set_tooltip_text(gui->quality,
_("the quality of an image, less quality means fewer details.\n" _("the quality of an image, less quality means fewer details.\n"
"\n" "\n"
"the following applies only to lossy setting\n" "the following applies only to lossy setting\n"
"\n" "\n"
"pixelformat based on quality:\n" "pixelformat based on quality:\n"
"\n" "\n"
" 91% - 100% -> YUV444\n" " 91% - 100% -> YUV444\n"
" 81% - 90% -> YUV422\n" " 81% - 90% -> YUV422\n"
" 5% - 80% -> YUV420\n")); " 5% - 80% -> YUV420\n"));
if (quality > 0 && quality <= 100) { if(quality > 0 && quality <= 100)
{
dt_bauhaus_slider_set(gui->quality, quality); dt_bauhaus_slider_set(gui->quality, quality);
} }
gtk_box_pack_start(GTK_BOX(self->widget), gui->quality, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(self->widget), gui->quality, TRUE, TRUE, 0);
switch (compression_type) { switch(compression_type)
case AVIF_COMP_LOSSLESS: {
gtk_widget_set_sensitive(gui->quality, FALSE); case AVIF_COMP_LOSSLESS:
break; gtk_widget_set_sensitive(gui->quality, FALSE);
case AVIF_COMP_LOSSY: break;
break; case AVIF_COMP_LOSSY:
break;
} }
g_signal_connect(G_OBJECT(gui->bit_depth), g_signal_connect(G_OBJECT(gui->bit_depth),
"value-changed", "value-changed",
G_CALLBACK(bit_depth_changed), G_CALLBACK(bit_depth_changed),
NULL); NULL);
g_signal_connect(G_OBJECT(gui->color_mode), g_signal_connect(G_OBJECT(gui->color_mode),
"value-changed", "value-changed",
G_CALLBACK(color_mode_changed), G_CALLBACK(color_mode_changed),
(gpointer)self); (gpointer)self);
skipping to change at line 956 skipping to change at line 916
void gui_cleanup(dt_imageio_module_format_t *self) void gui_cleanup(dt_imageio_module_format_t *self)
{ {
free(self->gui_data); free(self->gui_data);
} }
void gui_reset(dt_imageio_module_format_t *self) void gui_reset(dt_imageio_module_format_t *self)
{ {
dt_imageio_avif_gui_t *gui = (dt_imageio_avif_gui_t *)self->gui_data; dt_imageio_avif_gui_t *gui = (dt_imageio_avif_gui_t *)self->gui_data;
const enum avif_color_mode_e color_mode = dt_confgen_get_int("plugins/imageio/
format/avif/color_mode", DT_DEFAULT);
const enum avif_tiling_e tiling = !dt_confgen_get_bool("plugins/imageio/format
/avif/tiling", DT_DEFAULT);
const enum avif_compression_type_e compression_type = dt_confgen_get_int("plug
ins/imageio/format/avif/compression_type", DT_DEFAULT);
const uint32_t quality = dt_confgen_get_int("plugins/imageio/format/avif/quali
ty", DT_DEFAULT);
dt_bauhaus_combobox_set(gui->bit_depth, 0); //8bpp
dt_bauhaus_combobox_set(gui->color_mode, color_mode);
dt_bauhaus_combobox_set(gui->tiling, tiling);
dt_bauhaus_combobox_set(gui->compression_type, compression_type);
dt_bauhaus_slider_set(gui->quality, quality);
compression_type_changed(GTK_WIDGET(gui->compression_type), self); compression_type_changed(GTK_WIDGET(gui->compression_type), self);
quality_changed(GTK_WIDGET(gui->quality), self); quality_changed(GTK_WIDGET(gui->quality), self);
bit_depth_changed(GTK_WIDGET(gui->bit_depth), self); bit_depth_changed(GTK_WIDGET(gui->bit_depth), self);
} }
 End of changes. 58 change blocks. 
301 lines changed or deleted 274 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)