29#include <glib/gstdio.h>
42 return fminf(fmaxf(
value, 0.0f), 1.0f);
55 static const uint32_t shifted_exp = 0x7c00u << 13;
58 out.
u = (h & 0x7fffu) << 13;
59 const uint32_t exp = shifted_exp &
out.u;
60 out.u += (127u - 15u) << 23;
62 if(exp == shifted_exp)
63 out.u += (128u - 16u) << 23;
70 out.u |= (h & 0x8000u) << 16;
78 const uint32_t
sign = (in.
u >> 16) & 0x8000u;
79 const uint32_t
exponent = (in.
u >> 23) & 0xffu;
80 uint32_t mantissa = in.
u & 0x007fffffu;
84 if(mantissa)
return (uint16_t)(
sign | 0x7e00u);
85 return (uint16_t)(
sign | 0x7c00u);
88 const int32_t half_exponent = (int32_t)
exponent - 127 + 15;
90 if(half_exponent >= 0x1f)
return (uint16_t)(
sign | 0x7c00u);
91 if(half_exponent <= 0)
93 if(half_exponent < -10)
return (uint16_t)
sign;
95 mantissa |= 0x00800000u;
96 const uint32_t shift = (uint32_t)(1 - half_exponent);
97 uint32_t half_mantissa = mantissa >> (shift + 13);
98 const uint32_t round_bit = 1u << (shift + 12);
100 if((mantissa & round_bit) && ((mantissa & (round_bit - 1u)) || (half_mantissa & 1u)))
103 return (uint16_t)(
sign | half_mantissa);
106 uint32_t half_exp = (uint32_t)half_exponent << 10;
107 uint32_t half_mantissa = mantissa >> 13;
109 if((mantissa & 0x00001000u) && ((mantissa & 0x00001fffu) || (half_mantissa & 1u)))
113 if(half_mantissa == 0x0400u)
117 if(half_exp >= 0x7c00u)
return (uint16_t)(
sign | 0x7c00u);
121 return (uint16_t)(
sign | half_exp | half_mantissa);
128 memset(pixels, 0, pixel_count * 4 *
sizeof(uint16_t));
153 g_strlcpy(tmp,
name,
sizeof(tmp));
155 return tmp[0] !=
'\0';
160 if(
IS_NULL_PTR(path) || path[0] ==
'\0' || !g_file_test(path, G_FILE_TEST_EXISTS))
return 0;
163 if(g_stat(path, &st) != 0)
return 0;
164 return (int64_t)st.st_mtime;
179 format_params->
width = 0;
180 format_params->
height = 0;
181 format_params->
style[0] =
'\0';
186 tiff_params->
bpp = 32;
193 imgid, path, format, format_params,
TRUE,
FALSE,
TRUE,
FALSE,
FALSE, (filter && filter[0]) ? filter : NULL,
194 FALSE,
FALSE,
DT_COLORSPACE_NONE, NULL,
DT_INTENT_PERCEPTUAL, NULL, NULL, 0, 0, NULL, NULL);
196 format->free_params(format, format_params);
203 if(icc_data) *icc_data = NULL;
207 const char *sep0 = strchr(work_profile,
'|');
209 const char *sep1 = strchr(sep0 + 1,
'|');
213 const long type_long = strtol(work_profile, &endptr, 10);
214 if(endptr != sep0)
return FALSE;
217 const char *filename = sep1 + 1;
221 cmsUInt32Number len = 0;
222 cmsSaveProfileToMem(profile->
profile, NULL, &len);
223 if(len == 0)
return FALSE;
225 uint8_t *buf = g_malloc(len);
228 if(!cmsSaveProfileToMem(profile->
profile, buf, &len) || len == 0)
235 *icc_len = (uint32_t)len;
241 const char *work_profile)
243 const uint16_t extrasamples[] = { EXTRASAMPLE_ASSOCALPHA };
245 if(!TIFFSetField(tiff, TIFFTAG_IMAGEWIDTH,
width))
return FALSE;
246 if(!TIFFSetField(tiff, TIFFTAG_IMAGELENGTH,
height))
return FALSE;
247 if(!TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, 16))
return FALSE;
248 if(!TIFFSetField(tiff, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP))
return FALSE;
249 if(!TIFFSetField(tiff, TIFFTAG_SAMPLESPERPIXEL, 4))
return FALSE;
250 if(!TIFFSetField(tiff, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG))
return FALSE;
251 if(!TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB))
return FALSE;
252 if(!TIFFSetField(tiff, TIFFTAG_EXTRASAMPLES, 1, extrasamples))
return FALSE;
254 if(!TIFFSetField(tiff, TIFFTAG_COMPRESSION, COMPRESSION_ADOBE_DEFLATE)
255 && !TIFFSetField(tiff, TIFFTAG_COMPRESSION, COMPRESSION_DEFLATE)
256 && !TIFFSetField(tiff, TIFFTAG_COMPRESSION, COMPRESSION_LZW))
257 TIFFSetField(tiff, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
259 TIFFSetField(tiff, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(tiff, 0));
261 if(!
IS_NULL_PTR(work_profile) && work_profile[0]) TIFFSetField(tiff, TIFFTAG_IMAGEDESCRIPTION, work_profile);
270 uint16_t sampleformat = SAMPLEFORMAT_UINT;
272 TIFFGetField(tiff, TIFFTAG_BITSPERSAMPLE, &
bpp);
273 TIFFGetField(tiff, TIFFTAG_SAMPLESPERPIXEL, &spp);
274 TIFFGetFieldDefaulted(tiff, TIFFTAG_SAMPLEFORMAT, &sampleformat);
276 if(spp != 4)
return FALSE;
278 const tsize_t scanline = TIFFScanlineSize(tiff);
279 tdata_t buffer = _TIFFmalloc((tsize_t)scanline);
282 const int ok = TIFFReadScanline(tiff, buffer,
row, 0);
289 if(
bpp == 16 && sampleformat == SAMPLEFORMAT_IEEEFP)
290 memcpy(
out, buffer, (
size_t)
width * 4 *
sizeof(uint16_t));
304 return TIFFWriteScanline(tiff, (tdata_t)in,
row, 0) != -1;
313 const int dst_x0 =
MAX(0, patch->
x - offset_x);
314 const int dst_x1 =
MIN((
int)
width, patch->
x + patch->
width - offset_x);
315 if(dst_x0 >= dst_x1)
return;
317 const float *patch_row = patch->
pixels + 4 * (size_t)(raw_y - patch->
y) * patch->
width;
319 for(
int dst_x = dst_x0; dst_x < dst_x1; dst_x++)
321 const float *src_pixel = patch_row + 4 * (size_t)(dst_x + offset_x - patch->
x);
333 memset(info, 0,
sizeof(*info));
337 if(!TIFFSetDirectory(tiff, 0))
return;
339 const gboolean has_target_name = (target_name && target_name[0] !=
'\0');
340 const gboolean has_target_order = (target_order >= 0);
341 gboolean exact_found =
FALSE;
342 gboolean named_found =
FALSE;
343 gboolean order_found =
FALSE;
354 char *page_name = NULL;
355 char *page_profile = NULL;
358 TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &
width);
359 TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &
height);
360 TIFFGetField(tiff, TIFFTAG_PAGENAME, &page_name);
361 TIFFGetField(tiff, TIFFTAG_IMAGEDESCRIPTION, &page_profile);
363 const gboolean order_match = (has_target_order && index == target_order);
364 const gboolean name_match = (has_target_name && !g_strcmp0(page_name ? page_name :
"", target_name));
365 const gboolean exact_match = (name_match && order_match);
367 if(exact_match && !exact_found)
374 g_strlcpy(exact.
name, page_name ? page_name :
"",
sizeof(exact.
name));
378 if(name_match && !named_found)
385 g_strlcpy(named.
name, page_name ? page_name :
"",
sizeof(named.
name));
389 if(order_match && !order_found)
393 ordered.
index = index;
396 g_strlcpy(ordered.
name, page_name ? page_name :
"",
sizeof(ordered.
name));
401 }
while(TIFFReadDirectory(tiff));
427 g_strlcpy(info->
name, ordered.
name,
sizeof(info->
name));
432 TIFFSetDirectory(tiff, 0);
436static gboolean
_write_page(TIFF *dst, TIFF *src,
const int src_dir,
const char *
name,
const char *work_profile,
439 uint32_t
width = patch ? (uint32_t)patch->
width : (uint32_t)layer_width;
440 uint32_t
height = patch ? (uint32_t)patch->
height : (uint32_t)layer_height;
441 const char *page_profile = work_profile;
442 uint8_t *icc_profile = NULL;
443 uint32_t icc_profile_len = 0;
447 if(!TIFFSetDirectory(src, (tdir_t)src_dir))
return FALSE;
450 TIFFGetField(src, TIFFTAG_IMAGEWIDTH, &
width);
451 TIFFGetField(src, TIFFTAG_IMAGELENGTH, &
height);
455 char *src_name = NULL;
456 TIFFGetField(src, TIFFTAG_PAGENAME, &src_name);
461 char *src_profile = NULL;
462 TIFFGetField(src, TIFFTAG_IMAGEDESCRIPTION, &src_profile);
463 page_profile = src_profile;
469 TIFFSetField(dst, TIFFTAG_ICCPROFILE, icc_profile_len, icc_profile);
471 uint16_t *src_row = g_malloc_n((gsize)
width * 4,
sizeof(uint16_t));
472 uint16_t *dst_row = g_malloc_n((gsize)
width * 4,
sizeof(uint16_t));
481 const int offset_x = (layer_width - (int)
width) / 2;
482 const int offset_y = (layer_height - (int)
height) / 2;
484 for(uint32_t y = 0; y <
height; y++)
495 memcpy(dst_row, src_row, (
size_t)
width * 4 *
sizeof(uint16_t));
502 const int layer_y = (int)y + offset_y;
518 return TIFFWriteDirectory(dst) != 0;
522static gboolean
_rewrite_sidecar(
const char *path,
const char *target_name,
const int target_order,
524 const int layer_height,
const gboolean delete_target,
const int insert_order,
531 memset(&info, 0,
sizeof(info));
534 if(g_file_test(path, G_FILE_TEST_EXISTS))
536 src = TIFFOpen(path,
"rb");
550 return g_unlink(path) == 0;
553 gchar *tmp_path = g_strdup_printf(
"%s.tmp", path);
554 TIFF *dst = TIFFOpen(tmp_path,
"wb");
562 int written_index = 0;
567 for(
int dir = 0; dir < info.
count && ok; dir++)
569 if(!delete_target && !info.
found && insert_order >= 0 && written_index == insert_order)
571 ok =
_write_page(dst, NULL, -1, target_name, work_profile, patch, layer_width, layer_height);
572 if(ok && final_order) *final_order = written_index;
573 if(ok) written_index++;
576 const gboolean is_target = info.
found && dir == info.
index;
577 if(is_target && delete_target)
continue;
580 const char *page_label = is_target ? target_name : NULL;
582 ok =
_write_page(dst, src, dir, page_label, is_target ? work_profile : NULL, page_patch, layer_width,
584 if(ok && is_target && !delete_target && final_order) *final_order = written_index;
585 if(ok) written_index++;
591 const gboolean append_at_end = (insert_order < 0 || insert_order >= written_index || !src);
594 ok =
_write_page(dst, NULL, -1, target_name, work_profile, patch, layer_width, layer_height);
595 if(ok && !
IS_NULL_PTR(final_order)) *final_order = written_index;
603 ok = (g_rename(tmp_path, path) == 0);
614 if(
IS_NULL_PTR(path) || !candidate || candidate[0] ==
'\0' || !g_file_test(path, G_FILE_TEST_EXISTS))
return FALSE;
616 TIFF *tiff = TIFFOpen(path,
"rb");
619 gboolean exists =
FALSE;
621 if(TIFFSetDirectory(tiff, 0))
625 char *page_name = NULL;
626 TIFFGetField(tiff, TIFFTAG_PAGENAME, &page_name);
627 if(index != ignore_index && !g_strcmp0(page_name ? page_name :
"", candidate))
633 }
while(TIFFReadDirectory(tiff));
642 const size_t name_size)
648 gboolean last_was_space =
FALSE;
650 for(
size_t in = 0; requested[in] !=
'\0' &&
out + 1 < name_size; in++)
652 const unsigned char ch = (
unsigned char)requested[in];
653 if(g_ascii_isspace(
ch))
655 if(
out > 0 && !last_was_space)
658 last_was_space =
TRUE;
664 last_was_space =
FALSE;
669 if(
name[0] ==
'\0' && !
IS_NULL_PTR(fallback_name) && fallback_name[0]) g_strlcpy(
name, fallback_name, name_size);
675 gboolean from_cache =
FALSE;
678 if(path[0] ==
'\0')
return FALSE;
679 g_strlcat(path,
".ansel.tiff", path_size);
687 if(!
IS_NULL_PTR(info)) memset(info, 0,
sizeof(*info));
688 if(
IS_NULL_PTR(path) || !g_file_test(path, G_FILE_TEST_EXISTS))
return FALSE;
690 TIFF *tiff = TIFFOpen(path,
"rb");
694 return info && info->
found;
704 if(!g_file_test(path, G_FILE_TEST_EXISTS))
return TRUE;
706 TIFF *tiff = TIFFOpen(path,
"rb");
717 if(!TIFFSetDirectory(tiff, (tdir_t)info.
index))
723 uint16_t *
row = g_malloc_n((gsize)info.
width * 4,
sizeof(uint16_t));
730 const int offset_x = (layer_width - (int)info.
width) / 2;
731 const int offset_y = (layer_height - (int)info.
height) / 2;
733 for(
int py = 0; py < patch->
height; py++)
735 const int layer_y = patch->
y + py;
736 const int src_y = layer_y - offset_y;
737 if(src_y < 0 || src_y >= (
int)info.
height)
continue;
745 for(
int px = 0; px < patch->
width; px++)
747 const int layer_x = patch->
x + px;
748 const int src_x = layer_x - offset_x;
749 if(src_x < 0 || src_x >= (
int)info.
width)
continue;
750 float *dst = patch->
pixels + 4 * ((size_t)py * patch->
width + px);
763 if(pixels) *pixels = NULL;
768 TIFF *tiff = TIFFOpen(path,
"rb");
771 uint32_t w = 0, h = 0;
772 uint16_t spp = 0,
bpp = 0, sampleformat = SAMPLEFORMAT_UINT;
773 TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &w);
774 TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &h);
775 TIFFGetFieldDefaulted(tiff, TIFFTAG_SAMPLESPERPIXEL, &spp);
776 TIFFGetFieldDefaulted(tiff, TIFFTAG_BITSPERSAMPLE, &
bpp);
777 TIFFGetFieldDefaulted(tiff, TIFFTAG_SAMPLEFORMAT, &sampleformat);
779 if(w == 0 || h == 0 || spp < 1)
785 float *
out = g_malloc_n((
size_t)w * h * 4,
sizeof(
float));
793 const tsize_t scanline = TIFFScanlineSize(tiff);
794 tdata_t
row = _TIFFmalloc((tsize_t)scanline);
803 for(uint32_t y = 0; y < h && ok; y++)
805 if(TIFFReadScanline(tiff,
row, y, 0) == -1)
811 for(uint32_t
x = 0;
x < w;
x++)
813 float r = 0.0f,
g = 0.0f, b = 0.0f, a = 1.0f;
815 if(
bpp == 32 && sampleformat == SAMPLEFORMAT_IEEEFP)
817 const float *src = (
const float *)
row + (
size_t)
x * spp;
828 if(spp >= 4) a = src[3];
830 else if(
bpp == 16 && sampleformat == SAMPLEFORMAT_IEEEFP)
832 const uint16_t *src = (
const uint16_t *)
row + (
size_t)
x * spp;
847 const uint16_t *src = (
const uint16_t *)
row + (
size_t)
x * spp;
850 r = src[0] / 65535.0f;
851 g = src[1] / 65535.0f;
852 b = src[2] / 65535.0f;
856 r =
g = b = src[0] / 65535.0f;
858 if(spp >= 4) a = src[3] / 65535.0f;
862 const uint8_t *src = (
const uint8_t *)
row + (
size_t)
x * spp;
871 r =
g = b = src[0] / 255.0f;
873 if(spp >= 4) a = src[3] / 255.0f;
881 float *dst =
out + 4 * ((size_t)y * w +
x);
906 const int layer_width,
const int layer_height,
const gboolean delete_target,
910 return _rewrite_sidecar(path, target_name, target_order, work_profile, patch, layer_width, layer_height,
911 delete_target, -1, final_order);
917 const int layer_width,
const int layer_height,
int *final_order)
920 const int insert_order = (insert_after_order >= 0) ? (insert_after_order + 1) : -1;
921 return _rewrite_sidecar(path, target_name, -1, work_profile, patch, layer_width, layer_height,
FALSE, insert_order,
927 const char *work_profile,
const int layer_width,
const int layer_height,
930 if(!
IS_NULL_PTR(info)) memset(info, 0,
sizeof(*info));
932 if(!g_file_test(path, G_FILE_TEST_EXISTS))
return FALSE;
938 int final_order = current.
index;
947 info->
index = final_order;
948 g_strlcpy(info->
name, new_name,
sizeof(info->
name));
949 if(!
IS_NULL_PTR(work_profile) && work_profile[0] !=
'\0')
957 const int layer_height)
960 if(!g_file_test(path, G_FILE_TEST_EXISTS))
return FALSE;
971 const size_t name_size)
974 if(
name[0] ==
'\0')
return;
978 g_strlcpy(base,
name,
sizeof(base));
980 for(
int suffix = 2; suffix < 100000; suffix++)
982 g_snprintf(
name, name_size,
"%.*s %d",
MAX((
int)name_size - 12, 1), base, suffix);
994 if(
name[0] ==
'\0')
return;
998 g_strlcpy(base,
name,
sizeof(base));
1000 for(
int suffix = 2; suffix < 100000; suffix++)
1002 g_snprintf(
name, name_size,
"%.*s %d",
MAX((
int)name_size - 12, 1), base, suffix);
1010 if(names) *names = NULL;
1014 TIFF *tiff = TIFFOpen(path,
"rb");
1017 GPtrArray *arr = g_ptr_array_new_with_free_func(g_free);
1018 if(TIFFSetDirectory(tiff, 0))
1022 char *page_name = NULL;
1023 TIFFGetField(tiff, TIFFTAG_PAGENAME, &page_name);
1024 g_ptr_array_add(arr, g_strdup(page_name ? page_name :
""));
1025 }
while(TIFFReadDirectory(tiff));
1029 *count = (int)arr->len;
1032 g_ptr_array_free(arr,
TRUE);
1037 const guint layer_count = arr->len;
1038 char **
out = (
char **)g_ptr_array_free(arr,
FALSE);
1039 out = g_renew(
char *,
out, layer_count + 1);
1040 out[layer_count] = NULL;
1049 const int n = (!
IS_NULL_PTR(count) && *count > 0) ? *count : 0;
1056 for(
int i = 0; (*names)[
i];
i++)
dt_free((*names)[
i]);
1069 result->
imgid = params->imgid;
1072 g_strlcpy(result->
message, _(
"failed to create background layer from input"),
sizeof(result->
message));
1074 gchar *tmp_path = NULL;
1075 const int tmp_fd = g_file_open_tmp(
"ansel-drawlayer-bg-XXXXXX.tiff", &tmp_path, NULL);
1076 if(tmp_fd >= 0) g_close(tmp_fd, NULL);
1078 float *export_pixels = NULL;
1088 if(
IS_NULL_PTR(export_pixels) || export_w <= 0 || export_h <= 0)
break;
1090 bg_patch.
width = params->layer_width;
1091 bg_patch.
height = params->layer_height;
1095 (
size_t)params->layer_width * params->layer_height * 4 *
sizeof(
float),
"drawlayer bg layer");
1099 const int clip_x0 =
MAX(params->dst_x, 0);
1100 const int clip_y0 =
MAX(params->dst_y, 0);
1101 const int clip_x1 =
MIN(params->dst_x + export_w, params->layer_width);
1102 const int clip_y1 =
MIN(params->dst_y + export_h, params->layer_height);
1103 if(clip_x1 <= clip_x0 || clip_y1 <= clip_y0)
break;
1105 const int copy_w = clip_x1 - clip_x0;
1106 const int copy_h = clip_y1 - clip_y0;
1107 const int src_x0 = clip_x0 - params->dst_x;
1108 const int src_y0 = clip_y0 - params->dst_y;
1109 for(
int y = 0; y < copy_h; y++)
1111 const float *src = export_pixels + 4 * ((size_t)(src_y0 + y) * export_w + src_x0);
1112 float *dst = bg_patch.
pixels + 4 * ((size_t)(clip_y0 + y) * params->layer_width + clip_x0);
1113 memcpy(dst, src, (
size_t)copy_w * 4 *
sizeof(
float));
1121 int final_order = -1;
1123 params->work_profile, &bg_patch, params->layer_width, params->layer_height,
1133 g_snprintf(result->
message,
sizeof(result->
message), _(
"created background layer `%s'"), bg_name);
1144 if(params->done_idle)
1145 g_main_context_invoke(NULL, params->done_idle, result);
const dt_colorspaces_color_profile_t * dt_colorspaces_get_profile(dt_colorspaces_color_profile_type_t type, const char *filename, dt_colorspaces_profile_direction_t direction)
dt_colorspaces_color_profile_type_t
@ DT_PROFILE_DIRECTION_ANY
const dt_colormatrix_t dt_aligned_pixel_t out
void dt_image_full_path(const int32_t imgid, char *pathname, size_t pathname_len, gboolean *from_cache, const char *calling_func)
Get the full path of an image out of the database.
static const dt_aligned_pixel_simd_t sign
static const dt_aligned_pixel_simd_t value
#define __OMP_FOR_SIMD__(...)
static const dt_aligned_pixel_simd_t exponent
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
int dt_imageio_export_with_flags(const int32_t imgid, const char *filename, dt_imageio_module_format_t *format, dt_imageio_module_data_t *format_params, const gboolean ignore_exif, const gboolean display_byteorder, const gboolean high_quality, gboolean is_scaling, const gboolean thumbnail_export, const char *filter, const gboolean copy_metadata, const gboolean export_masks, dt_colorspaces_color_profile_type_t icc_type, const gchar *icc_filename, dt_iop_color_intent_t icc_intent, dt_imageio_module_storage_t *storage, dt_imageio_module_data_t *storage_params, int num, int total, dt_export_metadata_t *metadata, dt_atomic_int *shutdown)
dt_imageio_module_format_t * dt_imageio_get_format_by_name(const char *name)
int32_t dt_drawlayer_io_background_layer_job_run(dt_job_t *job)
Worker entrypoint for async "create background from input" sidecar jobs.
gboolean dt_drawlayer_io_layer_name_exists(const char *path, const char *candidate, const int ignore_index)
Test if a layer name already exists in sidecar TIFF.
gboolean dt_drawlayer_io_find_layer(const char *path, const char *target_name, const int target_order, dt_drawlayer_io_layer_info_t *info)
Find target layer metadata in sidecar TIFF.
void dt_drawlayer_io_make_unique_name_plain(const char *path, const char *requested, char *name, const size_t name_size)
Create unique layer name without fallback source.
static gboolean _write_scanline_rgba(TIFF *tiff, const uint32_t row, const uint16_t *in)
Write one half-float RGBA scanline into TIFF page.
static float _clamp01(const float value)
Clamp scalar to [0,1].
gboolean dt_drawlayer_io_insert_layer(const char *path, const char *target_name, const int insert_after_order, const char *work_profile, const dt_drawlayer_io_patch_t *patch, const int layer_width, const int layer_height, int *final_order)
Insert a new layer after given order in sidecar TIFF.
gboolean dt_drawlayer_io_sidecar_path(const int32_t imgid, char *path, const size_t path_size)
Build absolute sidecar path from image id.
void dt_drawlayer_io_make_unique_name(const char *path, const char *requested, const char *fallback_name, char *name, const size_t name_size)
Create unique layer name with fallback if requested name is empty.
static gboolean _rewrite_sidecar(const char *path, const char *target_name, const int target_order, const char *work_profile, const dt_drawlayer_io_patch_t *patch, const int layer_width, const int layer_height, const gboolean delete_target, const int insert_order, int *final_order)
Rewrite sidecar with optional update/insert/delete of one target layer.
static void _sanitize_requested_layer_name(const char *requested, const char *fallback_name, char *name, const size_t name_size)
Normalize/sanitize requested layer name with fallback handling.
static void _load_half_pixel_rgba(const uint16_t *src, float rgba[4])
Load one half-float RGBA texel to float RGBA.
static int64_t _sidecar_timestamp_from_path(const char *path)
static float _half_to_float(const uint16_t h)
Convert IEEE-754 binary16 to float32.
static gboolean _set_directory_tags(TIFF *tiff, const uint32_t width, const uint32_t height, const char *name, const char *work_profile)
Write TIFF directory tags for one RGBA half-float page.
static gboolean _icc_blob_from_profile_key(const char *work_profile, uint8_t **icc_data, uint32_t *icc_len)
Resolve embedded ICC blob from serialized work-profile key.
static void _clear_transparent_half(uint16_t *pixels, const size_t pixel_count)
Clear uint16 RGBA row/buffer to transparent black.
gboolean dt_drawlayer_io_rename_layer(const char *path, const char *current_name, const char *new_name, const char *work_profile, const int layer_width, const int layer_height, dt_drawlayer_io_layer_info_t *info)
Rename one existing layer page while preserving its directory payload.
gboolean dt_drawlayer_io_list_layer_names(const char *path, char ***names, int *count)
List all TIFF layer page names.
gboolean dt_drawlayer_io_load_layer(const char *path, const char *target_name, const int target_order, const int layer_width, const int layer_height, dt_drawlayer_io_patch_t *patch)
Load one sidecar layer patch into float RGBA destination patch.
static void _overlay_patch_row_rgba(uint16_t *dst_row, const uint32_t width, const int offset_x, const int raw_y, const dt_drawlayer_io_patch_t *patch)
Overlay one clipped float patch span into a half-float TIFF row.
gboolean dt_drawlayer_io_delete_layer(const char *path, const char *target_name, const int layer_width, const int layer_height)
Delete one existing layer page from the sidecar TIFF.
gboolean dt_drawlayer_io_load_flat_rgba(const char *path, float **pixels, int *width, int *height)
Load first TIFF page as flat RGBA float image.
static uint16_t _float_to_half(float value)
Convert float32 to IEEE-754 binary16 with rounding.
static void _scan_directories(TIFF *tiff, const char *target_name, const int target_order, dt_drawlayer_io_layer_info_t *info)
Scan TIFF directories and resolve best match for name/order target.
gboolean dt_drawlayer_io_store_layer(const char *path, const char *target_name, const int target_order, const char *work_profile, const dt_drawlayer_io_patch_t *patch, const int layer_width, const int layer_height, const gboolean delete_target, int *final_order)
Store/update/delete one layer entry in sidecar TIFF.
static gboolean _export_pre_module_fullres_to_tiff(const int32_t imgid, const char *filter, const char *path)
static gboolean _layer_name_non_empty(const char *name)
static gboolean _read_scanline_rgba(TIFF *tiff, const uint32_t width, const uint32_t row, uint16_t *out)
Read one TIFF scanline into half-float RGBA buffer.
static gboolean _write_page(TIFF *dst, TIFF *src, const int src_dir, const char *name, const char *work_profile, const dt_drawlayer_io_patch_t *patch, const int layer_width, const int layer_height)
Write one output page, optionally copying from source and patch overlay.
void dt_drawlayer_io_free_layer_names(char ***names, int *count)
Free array returned by dt_drawlayer_io_list_layer_names.
TIFF sidecar I/O API for drawlayer layers.
#define DT_DRAWLAYER_IO_NAME_SIZE
Patch/cache helpers for drawlayer process and preview buffers.
void * dt_control_job_get_params(const _dt_job_t *job)
float *const restrict const size_t const size_t ch
void * dt_drawlayer_cache_alloc_temp_buffer(const size_t bytes, const char *name)
Allocate temporary aligned cache buffer.
void dt_drawlayer_cache_free_temp_buffer(void **buffer, const char *name)
Free temporary aligned cache buffer.
void dt_drawlayer_cache_clear_transparent_float(float *pixels, const size_t pixel_count)
Fill float RGBA buffer with transparent black.
dt_imageio_module_data_t global
Parameters owned by the async "create background from input" job.
Result posted back to the UI after background-layer creation.
int initiator_layer_order
char initiator_layer_name[64]
int64_t sidecar_timestamp
Metadata returned when probing one layer directory in sidecar TIFF.
Float RGBA patch used by drawlayer I/O routines.