31#include <glib/gstdio.h>
44 return fminf(fmaxf(
value, 0.0f), 1.0f);
57 static const uint32_t shifted_exp = 0x7c00u << 13;
60 out.
u = (h & 0x7fffu) << 13;
61 const uint32_t exp = shifted_exp &
out.u;
62 out.u += (127u - 15u) << 23;
64 if(exp == shifted_exp)
65 out.u += (128u - 16u) << 23;
72 out.u |= (h & 0x8000u) << 16;
80 const uint32_t
sign = (in.
u >> 16) & 0x8000u;
81 const uint32_t
exponent = (in.
u >> 23) & 0xffu;
82 uint32_t mantissa = in.
u & 0x007fffffu;
86 if(mantissa)
return (uint16_t)(
sign | 0x7e00u);
87 return (uint16_t)(
sign | 0x7c00u);
90 const int32_t half_exponent = (int32_t)
exponent - 127 + 15;
92 if(half_exponent >= 0x1f)
return (uint16_t)(
sign | 0x7c00u);
93 if(half_exponent <= 0)
95 if(half_exponent < -10)
return (uint16_t)
sign;
97 mantissa |= 0x00800000u;
98 const uint32_t shift = (uint32_t)(1 - half_exponent);
99 uint32_t half_mantissa = mantissa >> (shift + 13);
100 const uint32_t round_bit = 1u << (shift + 12);
102 if((mantissa & round_bit) && ((mantissa & (round_bit - 1u)) || (half_mantissa & 1u)))
105 return (uint16_t)(
sign | half_mantissa);
108 uint32_t half_exp = (uint32_t)half_exponent << 10;
109 uint32_t half_mantissa = mantissa >> 13;
111 if((mantissa & 0x00001000u) && ((mantissa & 0x00001fffu) || (half_mantissa & 1u)))
115 if(half_mantissa == 0x0400u)
119 if(half_exp >= 0x7c00u)
return (uint16_t)(
sign | 0x7c00u);
123 return (uint16_t)(
sign | half_exp | half_mantissa);
130 memset(pixels, 0, pixel_count * 4 *
sizeof(uint16_t));
155 g_strlcpy(tmp,
name,
sizeof(tmp));
157 return tmp[0] !=
'\0';
162 if(
IS_NULL_PTR(path) || path[0] ==
'\0' || !g_file_test(path, G_FILE_TEST_EXISTS))
return 0;
165 if(g_stat(path, &st) != 0)
return 0;
166 return (int64_t)st.st_mtime;
181 format_params->
width = 0;
182 format_params->
height = 0;
183 format_params->
style[0] =
'\0';
188 tiff_params->
bpp = 32;
195 imgid, path, format, format_params,
TRUE,
FALSE,
TRUE,
FALSE,
FALSE, (filter && filter[0]) ? filter : NULL,
196 FALSE,
FALSE,
DT_COLORSPACE_NONE, NULL,
DT_INTENT_PERCEPTUAL, NULL, NULL, 0, 0, NULL, NULL);
198 format->free_params(format, format_params);
205 if(icc_data) *icc_data = NULL;
209 const char *sep0 = strchr(work_profile,
'|');
211 const char *sep1 = strchr(sep0 + 1,
'|');
215 const long type_long = strtol(work_profile, &endptr, 10);
216 if(endptr != sep0)
return FALSE;
219 const char *filename = sep1 + 1;
223 cmsUInt32Number len = 0;
224 cmsSaveProfileToMem(profile->
profile, NULL, &len);
225 if(len == 0)
return FALSE;
227 uint8_t *buf = g_malloc(len);
230 if(!cmsSaveProfileToMem(profile->
profile, buf, &len) || len == 0)
237 *icc_len = (uint32_t)len;
243 const char *work_profile)
245 const uint16_t extrasamples[] = { EXTRASAMPLE_ASSOCALPHA };
247 if(!TIFFSetField(tiff, TIFFTAG_IMAGEWIDTH,
width))
return FALSE;
248 if(!TIFFSetField(tiff, TIFFTAG_IMAGELENGTH,
height))
return FALSE;
249 if(!TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, 16))
return FALSE;
250 if(!TIFFSetField(tiff, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP))
return FALSE;
251 if(!TIFFSetField(tiff, TIFFTAG_SAMPLESPERPIXEL, 4))
return FALSE;
252 if(!TIFFSetField(tiff, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG))
return FALSE;
253 if(!TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB))
return FALSE;
254 if(!TIFFSetField(tiff, TIFFTAG_EXTRASAMPLES, 1, extrasamples))
return FALSE;
256 if(!TIFFSetField(tiff, TIFFTAG_COMPRESSION, COMPRESSION_ADOBE_DEFLATE)
257 && !TIFFSetField(tiff, TIFFTAG_COMPRESSION, COMPRESSION_DEFLATE)
258 && !TIFFSetField(tiff, TIFFTAG_COMPRESSION, COMPRESSION_LZW))
259 TIFFSetField(tiff, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
261 TIFFSetField(tiff, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(tiff, 0));
263 if(!
IS_NULL_PTR(work_profile) && work_profile[0]) TIFFSetField(tiff, TIFFTAG_IMAGEDESCRIPTION, work_profile);
272 uint16_t sampleformat = SAMPLEFORMAT_UINT;
274 TIFFGetField(tiff, TIFFTAG_BITSPERSAMPLE, &
bpp);
275 TIFFGetField(tiff, TIFFTAG_SAMPLESPERPIXEL, &spp);
276 TIFFGetFieldDefaulted(tiff, TIFFTAG_SAMPLEFORMAT, &sampleformat);
278 if(spp != 4)
return FALSE;
280 const tsize_t scanline = TIFFScanlineSize(tiff);
281 tdata_t buffer = _TIFFmalloc((tsize_t)scanline);
284 const int ok = TIFFReadScanline(tiff, buffer,
row, 0);
291 if(
bpp == 16 && sampleformat == SAMPLEFORMAT_IEEEFP)
292 memcpy(
out, buffer, (
size_t)
width * 4 *
sizeof(uint16_t));
306 return TIFFWriteScanline(tiff, (tdata_t)in,
row, 0) != -1;
315 const int dst_x0 =
MAX(0, patch->
x - offset_x);
316 const int dst_x1 =
MIN((
int)
width, patch->
x + patch->
width - offset_x);
317 if(dst_x0 >= dst_x1)
return;
319 const float *patch_row = patch->
pixels + 4 * (size_t)(raw_y - patch->
y) * patch->
width;
321 for(
int dst_x = dst_x0; dst_x < dst_x1; dst_x++)
323 const float *src_pixel = patch_row + 4 * (size_t)(dst_x + offset_x - patch->
x);
335 memset(info, 0,
sizeof(*info));
339 if(!TIFFSetDirectory(tiff, 0))
return;
341 const gboolean has_target_name = (target_name && target_name[0] !=
'\0');
342 const gboolean has_target_order = (target_order >= 0);
343 gboolean exact_found =
FALSE;
344 gboolean named_found =
FALSE;
345 gboolean order_found =
FALSE;
356 char *page_name = NULL;
357 char *page_profile = NULL;
360 TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &
width);
361 TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &
height);
362 TIFFGetField(tiff, TIFFTAG_PAGENAME, &page_name);
363 TIFFGetField(tiff, TIFFTAG_IMAGEDESCRIPTION, &page_profile);
365 const gboolean order_match = (has_target_order && index == target_order);
366 const gboolean name_match = (has_target_name && !g_strcmp0(page_name ? page_name :
"", target_name));
367 const gboolean exact_match = (name_match && order_match);
369 if(exact_match && !exact_found)
376 g_strlcpy(exact.
name, page_name ? page_name :
"",
sizeof(exact.
name));
380 if(name_match && !named_found)
387 g_strlcpy(named.
name, page_name ? page_name :
"",
sizeof(named.
name));
391 if(order_match && !order_found)
395 ordered.
index = index;
398 g_strlcpy(ordered.
name, page_name ? page_name :
"",
sizeof(ordered.
name));
403 }
while(TIFFReadDirectory(tiff));
429 g_strlcpy(info->
name, ordered.
name,
sizeof(info->
name));
434 TIFFSetDirectory(tiff, 0);
438static gboolean
_write_page(TIFF *dst, TIFF *src,
const int src_dir,
const char *
name,
const char *work_profile,
441 uint32_t
width = patch ? (uint32_t)patch->
width : (uint32_t)layer_width;
442 uint32_t
height = patch ? (uint32_t)patch->
height : (uint32_t)layer_height;
443 const char *page_profile = work_profile;
444 uint8_t *icc_profile = NULL;
445 uint32_t icc_profile_len = 0;
449 if(!TIFFSetDirectory(src, (tdir_t)src_dir))
return FALSE;
452 TIFFGetField(src, TIFFTAG_IMAGEWIDTH, &
width);
453 TIFFGetField(src, TIFFTAG_IMAGELENGTH, &
height);
457 char *src_name = NULL;
458 TIFFGetField(src, TIFFTAG_PAGENAME, &src_name);
463 char *src_profile = NULL;
464 TIFFGetField(src, TIFFTAG_IMAGEDESCRIPTION, &src_profile);
465 page_profile = src_profile;
471 TIFFSetField(dst, TIFFTAG_ICCPROFILE, icc_profile_len, icc_profile);
473 uint16_t *src_row = g_malloc_n((gsize)
width * 4,
sizeof(uint16_t));
474 uint16_t *dst_row = g_malloc_n((gsize)
width * 4,
sizeof(uint16_t));
483 const int offset_x = (layer_width - (int)
width) / 2;
484 const int offset_y = (layer_height - (int)
height) / 2;
486 for(uint32_t y = 0; y <
height; y++)
497 memcpy(dst_row, src_row, (
size_t)
width * 4 *
sizeof(uint16_t));
504 const int layer_y = (int)y + offset_y;
520 return TIFFWriteDirectory(dst) != 0;
524static gboolean
_rewrite_sidecar(
const char *path,
const char *target_name,
const int target_order,
526 const int layer_height,
const gboolean delete_target,
const int insert_order,
533 memset(&info, 0,
sizeof(info));
536 if(g_file_test(path, G_FILE_TEST_EXISTS))
538 src = TIFFOpen(path,
"rb");
552 return g_unlink(path) == 0;
555 gchar *tmp_path = g_strdup_printf(
"%s.tmp", path);
556 TIFF *dst = TIFFOpen(tmp_path,
"wb");
564 int written_index = 0;
569 for(
int dir = 0; dir < info.
count && ok; dir++)
571 if(!delete_target && !info.
found && insert_order >= 0 && written_index == insert_order)
573 ok =
_write_page(dst, NULL, -1, target_name, work_profile, patch, layer_width, layer_height);
574 if(ok && final_order) *final_order = written_index;
575 if(ok) written_index++;
578 const gboolean is_target = info.
found && dir == info.
index;
579 if(is_target && delete_target)
continue;
582 const char *page_label = is_target ? target_name : NULL;
584 ok =
_write_page(dst, src, dir, page_label, is_target ? work_profile : NULL, page_patch, layer_width,
586 if(ok && is_target && !delete_target && final_order) *final_order = written_index;
587 if(ok) written_index++;
593 const gboolean append_at_end = (insert_order < 0 || insert_order >= written_index || !src);
596 ok =
_write_page(dst, NULL, -1, target_name, work_profile, patch, layer_width, layer_height);
597 if(ok && !
IS_NULL_PTR(final_order)) *final_order = written_index;
605 ok = (g_rename(tmp_path, path) == 0);
616 if(
IS_NULL_PTR(path) || !candidate || candidate[0] ==
'\0' || !g_file_test(path, G_FILE_TEST_EXISTS))
return FALSE;
618 TIFF *tiff = TIFFOpen(path,
"rb");
621 gboolean exists =
FALSE;
623 if(TIFFSetDirectory(tiff, 0))
627 char *page_name = NULL;
628 TIFFGetField(tiff, TIFFTAG_PAGENAME, &page_name);
629 if(index != ignore_index && !g_strcmp0(page_name ? page_name :
"", candidate))
635 }
while(TIFFReadDirectory(tiff));
644 const size_t name_size)
650 gboolean last_was_space =
FALSE;
652 for(
size_t in = 0; requested[in] !=
'\0' &&
out + 1 < name_size; in++)
654 const unsigned char ch = (
unsigned char)requested[in];
655 if(g_ascii_isspace(
ch))
657 if(
out > 0 && !last_was_space)
660 last_was_space =
TRUE;
666 last_was_space =
FALSE;
671 if(
name[0] ==
'\0' && !
IS_NULL_PTR(fallback_name) && fallback_name[0]) g_strlcpy(
name, fallback_name, name_size);
677 gboolean from_cache =
FALSE;
680 if(path[0] ==
'\0')
return FALSE;
681 g_strlcat(path,
".ansel.tiff", path_size);
689 if(!
IS_NULL_PTR(info)) memset(info, 0,
sizeof(*info));
690 if(
IS_NULL_PTR(path) || !g_file_test(path, G_FILE_TEST_EXISTS))
return FALSE;
692 TIFF *tiff = TIFFOpen(path,
"rb");
696 return info && info->
found;
706 if(!g_file_test(path, G_FILE_TEST_EXISTS))
return TRUE;
708 TIFF *tiff = TIFFOpen(path,
"rb");
719 if(!TIFFSetDirectory(tiff, (tdir_t)info.
index))
725 uint16_t *
row = g_malloc_n((gsize)info.
width * 4,
sizeof(uint16_t));
732 const int offset_x = (layer_width - (int)info.
width) / 2;
733 const int offset_y = (layer_height - (int)info.
height) / 2;
735 for(
int py = 0; py < patch->
height; py++)
737 const int layer_y = patch->
y + py;
738 const int src_y = layer_y - offset_y;
739 if(src_y < 0 || src_y >= (
int)info.
height)
continue;
747 for(
int px = 0; px < patch->
width; px++)
749 const int layer_x = patch->
x + px;
750 const int src_x = layer_x - offset_x;
751 if(src_x < 0 || src_x >= (
int)info.
width)
continue;
752 float *dst = patch->
pixels + 4 * ((size_t)py * patch->
width + px);
765 if(pixels) *pixels = NULL;
770 TIFF *tiff = TIFFOpen(path,
"rb");
773 uint32_t w = 0, h = 0;
774 uint16_t spp = 0,
bpp = 0, sampleformat = SAMPLEFORMAT_UINT;
775 TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &w);
776 TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &h);
777 TIFFGetFieldDefaulted(tiff, TIFFTAG_SAMPLESPERPIXEL, &spp);
778 TIFFGetFieldDefaulted(tiff, TIFFTAG_BITSPERSAMPLE, &
bpp);
779 TIFFGetFieldDefaulted(tiff, TIFFTAG_SAMPLEFORMAT, &sampleformat);
781 if(w == 0 || h == 0 || spp < 1)
787 float *
out = g_malloc_n((
size_t)w * h * 4,
sizeof(
float));
795 const tsize_t scanline = TIFFScanlineSize(tiff);
796 tdata_t
row = _TIFFmalloc((tsize_t)scanline);
805 for(uint32_t y = 0; y < h && ok; y++)
807 if(TIFFReadScanline(tiff,
row, y, 0) == -1)
813 for(uint32_t
x = 0;
x < w;
x++)
815 float r = 0.0f,
g = 0.0f, b = 0.0f, a = 1.0f;
817 if(
bpp == 32 && sampleformat == SAMPLEFORMAT_IEEEFP)
819 const float *src = (
const float *)
row + (
size_t)
x * spp;
830 if(spp >= 4) a = src[3];
832 else if(
bpp == 16 && sampleformat == SAMPLEFORMAT_IEEEFP)
834 const uint16_t *src = (
const uint16_t *)
row + (
size_t)
x * spp;
849 const uint16_t *src = (
const uint16_t *)
row + (
size_t)
x * spp;
852 r = src[0] / 65535.0f;
853 g = src[1] / 65535.0f;
854 b = src[2] / 65535.0f;
858 r =
g = b = src[0] / 65535.0f;
860 if(spp >= 4) a = src[3] / 65535.0f;
864 const uint8_t *src = (
const uint8_t *)
row + (
size_t)
x * spp;
873 r =
g = b = src[0] / 255.0f;
875 if(spp >= 4) a = src[3] / 255.0f;
883 float *dst =
out + 4 * ((size_t)y * w +
x);
908 const int layer_width,
const int layer_height,
const gboolean delete_target,
912 return _rewrite_sidecar(path, target_name, target_order, work_profile, patch, layer_width, layer_height,
913 delete_target, -1, final_order);
919 const int layer_width,
const int layer_height,
int *final_order)
922 const int insert_order = (insert_after_order >= 0) ? (insert_after_order + 1) : -1;
923 return _rewrite_sidecar(path, target_name, -1, work_profile, patch, layer_width, layer_height,
FALSE, insert_order,
929 const char *work_profile,
const int layer_width,
const int layer_height,
932 if(!
IS_NULL_PTR(info)) memset(info, 0,
sizeof(*info));
934 if(!g_file_test(path, G_FILE_TEST_EXISTS))
return FALSE;
940 int final_order = current.
index;
949 info->
index = final_order;
950 g_strlcpy(info->
name, new_name,
sizeof(info->
name));
951 if(!
IS_NULL_PTR(work_profile) && work_profile[0] !=
'\0')
959 const int layer_height)
962 if(!g_file_test(path, G_FILE_TEST_EXISTS))
return FALSE;
973 const size_t name_size)
976 if(
name[0] ==
'\0')
return;
980 g_strlcpy(base,
name,
sizeof(base));
982 for(
int suffix = 2; suffix < 100000; suffix++)
984 g_snprintf(
name, name_size,
"%.*s %d",
MAX((
int)name_size - 12, 1), base, suffix);
996 if(
name[0] ==
'\0')
return;
1000 g_strlcpy(base,
name,
sizeof(base));
1002 for(
int suffix = 2; suffix < 100000; suffix++)
1004 g_snprintf(
name, name_size,
"%.*s %d",
MAX((
int)name_size - 12, 1), base, suffix);
1016 TIFF *tiff = TIFFOpen(path,
"rb");
1019 GPtrArray *arr = g_ptr_array_new_with_free_func(g_free);
1020 if(TIFFSetDirectory(tiff, 0))
1024 char *page_name = NULL;
1025 TIFFGetField(tiff, TIFFTAG_PAGENAME, &page_name);
1026 g_ptr_array_add(arr, g_strdup(page_name ? page_name :
""));
1027 }
while(TIFFReadDirectory(tiff));
1031 *count = (int)arr->len;
1034 g_ptr_array_free(arr,
TRUE);
1039 const guint layer_count = arr->len;
1040 char **
out = (
char **)g_ptr_array_free(arr,
FALSE);
1041 out = g_renew(
char *,
out, layer_count + 1);
1042 out[layer_count] = NULL;
1051 const int n = (!
IS_NULL_PTR(count) && *count > 0) ? *count : 0;
1071 result->
imgid = params->imgid;
1074 g_strlcpy(result->
message, _(
"failed to create background layer from input"),
sizeof(result->
message));
1076 gchar *tmp_path = NULL;
1077 const int tmp_fd = g_file_open_tmp(
"ansel-drawlayer-bg-XXXXXX.tiff", &tmp_path, NULL);
1078 if(tmp_fd >= 0) g_close(tmp_fd, NULL);
1080 float *export_pixels = NULL;
1090 if(
IS_NULL_PTR(export_pixels) || export_w <= 0 || export_h <= 0)
break;
1092 bg_patch.
width = params->layer_width;
1093 bg_patch.
height = params->layer_height;
1097 (
size_t)params->layer_width * params->layer_height * 4 *
sizeof(
float),
"drawlayer bg layer");
1101 const int clip_x0 =
MAX(params->dst_x, 0);
1102 const int clip_y0 =
MAX(params->dst_y, 0);
1103 const int clip_x1 =
MIN(params->dst_x + export_w, params->layer_width);
1104 const int clip_y1 =
MIN(params->dst_y + export_h, params->layer_height);
1105 if(clip_x1 <= clip_x0 || clip_y1 <= clip_y0)
break;
1107 const int copy_w = clip_x1 - clip_x0;
1108 const int copy_h = clip_y1 - clip_y0;
1109 const int src_x0 = clip_x0 - params->dst_x;
1110 const int src_y0 = clip_y0 - params->dst_y;
1111 for(
int y = 0; y < copy_h; y++)
1113 const float *src = export_pixels + 4 * ((size_t)(src_y0 + y) * export_w + src_x0);
1114 float *dst = bg_patch.
pixels + 4 * ((size_t)(clip_y0 + y) * params->layer_width + clip_x0);
1115 memcpy(dst, src, (
size_t)copy_w * 4 *
sizeof(
float));
1123 int final_order = -1;
1125 params->work_profile, &bg_patch, params->layer_width, params->layer_height,
1135 g_snprintf(result->
message,
sizeof(result->
message), _(
"created background layer `%s'"), bg_name);
1146 if(params->done_idle)
1147 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_role_t role)
Resolve a profile identity to its registered entry.
The colour-profile module's API: which profiles exist, and how to apply one.
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.
GHashTable * names
GtkWidget* -> the name the application knows it by.
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)
_lib_location_type_t type
float *const restrict const size_t const size_t ch
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
#define dt_free(ptr)
g_free() ptr and set it to NULL, skipping both if it is already NULL.
#define __OMP_FOR_SIMD__(...)
dt_colorspaces_color_profile_type_t
@ DT_COLORSPACE_NONE
No profile / "take it from the image settings". Never matches a list entry.
@ DT_PROFILE_ROLE_ANY
All four roles, in registration order.
static const dt_aligned_pixel_simd_t sign
static const dt_aligned_pixel_simd_t value
static const dt_aligned_pixel_simd_t exponent
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
One registered profile: its identity, its LCMS handle, and where it sits in each combo box.
cmsHPROFILE profile
the actual profile; NULL for the three category entries
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.