51#define LAB_CONVERSION_PROFILE DT_COLORSPACE_LIN_REC2020
81 static const fp32_t magic = { 113 << 23 };
82 static const uint32_t shifted_exp = 0x7c00 << 13;
85 o.
u = (h & 0x7fff) << 13;
86 uint32_t exp = shifted_exp & o.
u;
87 o.
u += (127 - 15) << 23;
90 if (exp == shifted_exp)
91 o.
u += (128 - 16) << 23;
98 o.
u |= (h & 0x8000) << 16;
106 uint8_t *in = ((uint8_t *)
t->buf);
107 float *
out = ((
float *)
t->mipbuf) + (size_t)4 *
row *
t->width;
110 if(TIFFReadScanline(
t->tiff, in,
row, 0) == -1)
return -1;
112 for(uint32_t
i = 0;
i <
t->width;
i++, in +=
t->spp,
out += 4)
115 out[0] = ((float)in[0]) * (1.0f / 255.0f);
123 out[1] = ((float)in[1]) * (1.0f / 255.0f);
124 out[2] = ((float)in[2]) * (1.0f / 255.0f);
138 uint16_t *in = ((uint16_t *)
t->buf);
139 float *
out = ((
float *)
t->mipbuf) + (size_t)4 *
row *
t->width;
142 if(TIFFReadScanline(
t->tiff, in,
row, 0) == -1)
return -1;
144 for(uint32_t
i = 0;
i <
t->width;
i++, in +=
t->spp,
out += 4)
146 out[0] = ((float)in[0]) * (1.0f / 65535.0f);
154 out[1] = ((float)in[1]) * (1.0f / 65535.0f);
155 out[2] = ((float)in[2]) * (1.0f / 65535.0f);
169 uint16_t *in = ((uint16_t *)
t->buf);
170 float *
out = ((
float *)
t->mipbuf) + (size_t)4 *
row *
t->width;
173 if(TIFFReadScanline(
t->tiff, in,
row, 0) == -1)
return -1;
175 for(uint32_t
i = 0;
i <
t->width;
i++, in +=
t->spp,
out += 4)
200 float *in = ((
float *)
t->buf);
201 float *
out = ((
float *)
t->mipbuf) + (size_t)4 *
row *
t->width;
204 if(TIFFReadScanline(
t->tiff, in,
row, 0) == -1)
return -1;
206 for(uint32_t
i = 0;
i <
t->width;
i++, in +=
t->spp,
out += 4)
231 const cmsHTRANSFORM xform = cmsCreateTransform(
Lab, TYPE_LabA_FLT, output_profile, TYPE_RGBA_FLT, INTENT_PERCEPTUAL, 0);
235 uint8_t *in = ((uint8_t *)
t->buf);
236 float *output = ((
float *)
t->mipbuf) + (size_t)4 *
row *
t->width;
240 if(TIFFReadScanline(
t->tiff, in,
row, 0) == -1)
goto failed;
242 for(uint32_t
i = 0;
i <
t->width;
i++, in +=
t->spp,
out += 4)
244 out[0] = ((float)in[0]) * (100.0f/255.0f);
252 if(photometric == PHOTOMETRIC_CIELAB)
254 out[1] = ((float)((int8_t)in[1]));
255 out[2] = ((float)((int8_t)in[2]));
259 out[1] = ((float)(in[1])) - 128.0f;
260 out[2] = ((float)(in[2])) - 128.0f;
267 cmsDoTransform(xform, output, output,
t->width);
270 cmsDeleteTransform(xform);
275 cmsDeleteTransform(xform);
284 const cmsHTRANSFORM xform = cmsCreateTransform(
Lab, TYPE_LabA_FLT, output_profile, TYPE_RGBA_FLT, INTENT_PERCEPTUAL, 0);
285 const float range = (photometric == PHOTOMETRIC_CIELAB) ? 65535.0f : 65280.0f;
289 uint16_t *in = ((uint16_t *)
t->buf);
290 float *output = ((
float *)
t->mipbuf) + (size_t)4 *
row *
t->width;
294 if(TIFFReadScanline(
t->tiff, in,
row, 0) == -1)
goto failed;
296 for(uint32_t
i = 0;
i <
t->width;
i++, in +=
t->spp,
out += 4)
298 out[0] = ((float)in[0]) * (100.0f/range);
306 if(photometric == PHOTOMETRIC_CIELAB)
308 out[1] = ((float)((int16_t)in[1])) / 256.0f;
309 out[2] = ((float)((int16_t)in[2])) / 256.0f;
313 out[1] = (((float)(in[1])) - 32768.0f) / 256.0f;
314 out[2] = (((float)(in[2])) - 32768.0f) / 256.0f;
321 cmsDoTransform(xform, output, output,
t->width);
324 cmsDeleteTransform(xform);
329 cmsDeleteTransform(xform);
336 fprintf(stderr,
"[tiff_open] %s: %s: ",
type, module);
337 vfprintf(stderr, fmt, ap);
338 fprintf(stderr,
"\n");
361 const char *ext = filename + strlen(filename);
362 while(*ext !=
'.' && ext > filename) ext--;
363 if(strncmp(ext,
".tif", 4) && strncmp(ext,
".TIF", 4) && strncmp(ext,
".tiff", 5)
364 && strncmp(ext,
".TIFF", 5))
370 uint16_t photometric;
376 wchar_t *wfilename = g_utf8_to_utf16(filename, -1, NULL, NULL, NULL);
377 t.tiff = TIFFOpenW(wfilename,
"rb");
380 t.tiff = TIFFOpen(filename,
"rb");
385 TIFFGetField(
t.tiff, TIFFTAG_IMAGEWIDTH, &
t.width);
386 TIFFGetField(
t.tiff, TIFFTAG_IMAGELENGTH, &
t.height);
387 TIFFGetField(
t.tiff, TIFFTAG_BITSPERSAMPLE, &
t.bpp);
388 TIFFGetField(
t.tiff, TIFFTAG_SAMPLESPERPIXEL, &
t.spp);
389 TIFFGetFieldDefaulted(
t.tiff, TIFFTAG_SAMPLEFORMAT, &
t.sampleformat);
390 TIFFGetField(
t.tiff, TIFFTAG_PLANARCONFIG, &config);
391 TIFFGetField(
t.tiff, TIFFTAG_PHOTOMETRIC, &photometric);
392 TIFFGetField(
t.tiff, TIFFTAG_INKSET, &inkset);
394 if(inkset == INKSET_CMYK || inkset == INKSET_MULTIINK)
396 fprintf(stderr,
"[tiff_open] error: CMYK (or multiink) TIFFs are not supported.\n");
403 t.scanlinesize = TIFFScanlineSize(
t.tiff);
408 if(
t.bpp != 8 &&
t.bpp != 16 &&
t.bpp != 32)
415 if(
t.spp != 1 &&
t.spp != 3 &&
t.spp != 4)
422 if(
t.spp > 1 && config != PLANARCONFIG_CONTIG)
424 fprintf(stderr,
"[tiff_open] error: PlanarConfiguration other than chunky is not supported.\n");
430 t.image->width =
t.width;
431 t.image->height =
t.height;
433 t.image->dsc.channels = 4;
435 t.image->dsc.bpp = 4 *
sizeof(float);
437 t.image->dsc.filters = 0u;
440 if(
t.sampleformat == SAMPLEFORMAT_IEEEFP)
443 t.image->flags &= ~DT_IMAGE_LDR;
450 t.image->flags &= ~DT_IMAGE_HDR;
453 if(photometric == PHOTOMETRIC_CIELAB || photometric == PHOTOMETRIC_ICCLAB)
456 t.image->flags &= ~DT_IMAGE_RAW;
457 t.image->flags &= ~DT_IMAGE_S_RAW;
469 fprintf(stderr,
"[tiff_open] error: could not alloc full buffer for image `%s'\n",
t.image->filename);
474 if((
t.buf = _TIFFmalloc(
t.scanlinesize)) == NULL)
482 if((photometric == PHOTOMETRIC_CIELAB || photometric == PHOTOMETRIC_ICCLAB) &&
t.bpp == 8 &&
t.sampleformat == SAMPLEFORMAT_UINT)
487 else if((photometric == PHOTOMETRIC_CIELAB || photometric == PHOTOMETRIC_ICCLAB) &&
t.bpp == 16 &&
t.sampleformat == SAMPLEFORMAT_UINT)
492 else if(
t.bpp == 8 &&
t.sampleformat == SAMPLEFORMAT_UINT)
494 else if(
t.bpp == 16 &&
t.sampleformat == SAMPLEFORMAT_UINT)
496 else if(
t.bpp == 16 &&
t.sampleformat == SAMPLEFORMAT_IEEEFP)
498 else if(
t.bpp == 32 &&
t.sampleformat == SAMPLEFORMAT_IEEEFP)
502 fprintf(stderr,
"[tiff_open] error: not a supported tiff image format.\n");
520 uint32_t profile_len = 0;
521 uint8_t *profile = NULL;
522 uint16_t photometric;
524 if(!(filename && *filename &&
out))
return 0;
527 wchar_t *wfilename = g_utf8_to_utf16(filename, -1, NULL, NULL, NULL);
528 tiff = TIFFOpenW(wfilename,
"rb");
531 tiff = TIFFOpen(filename,
"rb");
536 TIFFGetField(tiff, TIFFTAG_PHOTOMETRIC, &photometric);
538 if(photometric == PHOTOMETRIC_CIELAB || photometric == PHOTOMETRIC_ICCLAB)
542 cmsSaveProfileToMem(profile, 0, &profile_len);
545 *
out = (uint8_t *)g_malloc(profile_len);
546 cmsSaveProfileToMem(profile, *
out, &profile_len);
549 else if(TIFFGetField(tiff, TIFFTAG_ICCPROFILE, &profile_len, &profile))
553 *
out = (uint8_t *)g_malloc(profile_len);
554 memcpy(*
out, profile, profile_len);
593 if(size <= 0 || blob->pos >= (toff_t)blob->
size)
return 0;
594 const tmsize_t available = (tmsize_t)((toff_t)blob->
size - blob->
pos);
595 const tmsize_t
n = (
size < available) ?
size : available;
596 memcpy(buffer, blob->
data + (
size_t)blob->
pos, (
size_t)
n);
597 blob->
pos += (toff_t)
n;
608static toff_t
_blob_seek(thandle_t handle, toff_t offset,
int whence)
614 case SEEK_SET: base = 0;
break;
615 case SEEK_CUR: base = blob->
pos;
break;
616 case SEEK_END: base = (toff_t)blob->
size;
break;
617 default:
return (toff_t)-1;
619 const toff_t target = base + offset;
620 if(target < base)
return (toff_t)-1;
662 _tiff_blob_t handle = { .
data = blob, .size = (tmsize_t)bufsize, .pos = 0 };
668 uint32_t w = 0, h = 0;
669 if(!TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &w) || !TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &h)
683 char why[1024] = { 0 };
684 if(!TIFFRGBAImageOK(tiff, why))
691 if(TIFFGetField(tiff, TIFFTAG_BITSPERSAMPLE, &bps) && bps != 8)
700 const size_t npixels = (size_t)w * (
size_t)h;
707 if(!TIFFReadRGBAImageOriented(tiff, w, h, (uint32_t *)pixels, ORIENTATION_TOPLEFT, 0))
718 for(
size_t i = 0;
i < npixels;
i++)
720 uint8_t *
const dest = pixels + 4 *
i;
722 memcpy(&px, dest,
sizeof(px));
723 dest[0] = (uint8_t)TIFFGetR(px);
724 dest[1] = (uint8_t)TIFFGetG(px);
725 dest[2] = (uint8_t)TIFFGetB(px);
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
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.
static dt_aligned_pixel_t Lab
const dt_colormatrix_t dt_aligned_pixel_t out
int dt_exif_read(dt_image_t *img, const char *path)
What a photograph says about itself: the EXIF, IPTC and XMP tags a camera and a cataloguer write,...
@ DT_IMAGEIO_FILE_CORRUPTED
static tmsize_t _blob_write(thandle_t handle, void *buffer, tmsize_t size)
static int _blob_map(thandle_t handle, void **base, toff_t *size)
static void _error_handler(const char *module, const char *fmt, va_list ap)
static int _read_chunky_8(tiff_t *t)
static void _warning_handler(const char *module, const char *fmt, va_list ap)
#define LAB_CONVERSION_PROFILE
static toff_t _blob_size(thandle_t handle)
static int _read_chunky_16(tiff_t *t)
static toff_t _blob_seek(thandle_t handle, toff_t offset, int whence)
static void _blob_unmap(thandle_t handle, void *base, toff_t size)
static int _read_chunky_h(tiff_t *t)
int dt_imageio_tiff_read_profile(const char *filename, uint8_t **out)
static void _warning_error_handler(const char *type, const char *module, const char *fmt, va_list ap)
static int _read_chunky_8_Lab(tiff_t *t, uint16_t photometric)
static int _blob_close(thandle_t handle)
static int _read_chunky_f(tiff_t *t)
static tmsize_t _blob_read(thandle_t handle, void *buffer, tmsize_t size)
dt_imageio_retval_t dt_imageio_open_tiff(dt_image_t *img, const char *filename, dt_mipmap_buffer_t *mbuf)
gboolean dt_imageio_tiff_decode_blob(const uint8_t *const blob, const size_t bufsize, uint8_t **out, int32_t *width, int32_t *height)
Decode a TIFF held in memory into 8-bit RGBx, for the previews raw files embed.
static int _read_chunky_16_Lab(tiff_t *t, uint16_t photometric)
static float _half_to_float(uint16_t h)
_lib_location_type_t type
int32_t dt_get_debug_flags(void)
void dt_print(dt_debug_thread_t thread, const char *msg,...) __attribute__((format(printf
Print to stdout when thread is enabled, prefixed with seconds since startup.
#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.
void * dt_mipmap_cache_alloc(dt_mipmap_buffer_t *buf, const dt_image_t *img)
#define dt_pixelpipe_cache_alloc_align_cache(size, id)
#define dt_pixelpipe_cache_free_align(mem)
@ DT_PROFILE_ROLE_OUTPUT
Listed in the output/export-profile combo (colorout, export).
@ DT_PROFILE_ROLE_MONITOR
Eligible for the monitor-profile menu.
@ DT_PROFILE_ROLE_ANY
All four roles, in registration order.
unsigned __int64 uint64_t
cmsHPROFILE profile
the actual profile; NULL for the three category entries