Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
colorin.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2009-2014, 2016 johannes hanika.
4 Copyright (C) 2010 Alexandre Prokoudine.
5 Copyright (C) 2010 Bruce Guenter.
6 Copyright (C) 2010-2011 Henrik Andersson.
7 Copyright (C) 2010 Milan Knížek.
8 Copyright (C) 2010, 2012-2014 Pascal de Bruijn.
9 Copyright (C) 2010 Richard Hughes.
10 Copyright (C) 2010 Stuart Henderson.
11 Copyright (C) 2011 Antony Dovgal.
12 Copyright (C) 2011 Robert Bieber.
13 Copyright (C) 2011 Rostyslav Pidgornyi.
14 Copyright (C) 2011-2017, 2019 Tobias Ellinghaus.
15 Copyright (C) 2011-2012, 2014, 2016-2017 Ulrich Pegelow.
16 Copyright (C) 2012, 2020 Aldric Renaudin.
17 Copyright (C) 2012 Christian Tellefsen.
18 Copyright (C) 2012 Jérémy Rosen.
19 Copyright (C) 2012 Richard Wonka.
20 Copyright (C) 2013, 2018-2022 Pascal Obry.
21 Copyright (C) 2013 Thomas Pryds.
22 Copyright (C) 2014 Edouard Gomez.
23 Copyright (C) 2014-2016 Pedro Côrte-Real.
24 Copyright (C) 2014-2017 Roman Lebedev.
25 Copyright (C) 2017, 2019 Heiko Bauke.
26 Copyright (C) 2018, 2020, 2023-2026 Aurélien PIERRE.
27 Copyright (C) 2018-2019 Edgardo Hoszowski.
28 Copyright (C) 2018 Kelvie Wong.
29 Copyright (C) 2018 Maurizio Paglia.
30 Copyright (C) 2018 rawfiner.
31 Copyright (C) 2019, 2021 Andreas Schneider.
32 Copyright (C) 2019-2020, 2022 Hanno Schwalm.
33 Copyright (C) 2019 jakubfi.
34 Copyright (C) 2019 Miroslav Silovic.
35 Copyright (C) 2020 Chris Elston.
36 Copyright (C) 2020 Diederik Ter Rahe.
37 Copyright (C) 2020 Hubert Kowalski.
38 Copyright (C) 2020-2021 Ralf Brown.
39 Copyright (C) 2021 Dan Torop.
40 Copyright (C) 2021 Daniel Vogelbacher.
41 Copyright (C) 2021 Miloš Komarčević.
42 Copyright (C) 2021 Sakari Kapanen.
43 Copyright (C) 2022 Martin Bařinka.
44 Copyright (C) 2022 Philipp Lutz.
45 Copyright (C) 2023 Ricky Moon.
46
47 darktable is free software: you can redistribute it and/or modify
48 it under the terms of the GNU General Public License as published by
49 the Free Software Foundation, either version 3 of the License, or
50 (at your option) any later version.
51
52 darktable is distributed in the hope that it will be useful,
53 but WITHOUT ANY WARRANTY; without even the implied warranty of
54 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
55 GNU General Public License for more details.
56
57 You should have received a copy of the GNU General Public License
58 along with darktable. If not, see <http://www.gnu.org/licenses/>.
59*/
60#ifdef HAVE_CONFIG_H
61#include "common/darktable.h"
62#include "config.h"
63#endif
64#include "bauhaus/bauhaus.h"
65#include "common/imagebuf.h"
66#include "common/iop_profile.h"
68#include "common/colorspaces.h"
71#include "common/image_cache.h"
72#include "common/opencl.h"
73#include "control/control.h"
74#include "develop/develop.h"
75#include "gui/gtk.h"
76
77#ifdef HAVE_OPENJPEG
78#include "common/imageio_j2k.h"
79#endif
80#include "common/imageio_jpeg.h"
81#include "common/imageio_png.h"
82#include "common/imageio_tiff.h"
83#ifdef HAVE_LIBAVIF
84#include "common/imageio_avif.h"
85#endif
86#ifdef HAVE_LIBHEIF
87#include "common/imageio_heif.h"
88#endif
90#include "develop/imageop_gui.h"
91#include "iop/iop_api.h"
92
93#include <assert.h>
94#include <math.h>
95#include <stdlib.h>
96#include <string.h>
97#include <strings.h>
98
99#include <lcms2.h>
100
101// max iccprofile file name length
102// must be in synch with dt_colorspaces_color_profile_t
103#define DT_IOP_COLOR_ICC_LEN 512
104
105#define LUT_SAMPLES 0x10000
106
108
109static void update_profile_list(dt_iop_module_t *self);
110
112{
113 DT_NORMALIZE_OFF, //$DESCRIPTION: "off"
114 DT_NORMALIZE_SRGB, //$DESCRIPTION: "sRGB"
115 DT_NORMALIZE_ADOBE_RGB, //$DESCRIPTION: "Adobe RGB (compatible)"
116 DT_NORMALIZE_LINEAR_REC709_RGB, //$DESCRIPTION: "linear Rec709 RGB"
117 DT_NORMALIZE_LINEAR_REC2020_RGB //$DESCRIPTION: "linear Rec2020 RGB"
119
121{
122 dt_colorspaces_color_profile_type_t type; // $DEFAULT: DT_COLORSPACE_ENHANCED_MATRIX
124 dt_iop_color_intent_t intent; // $DEFAULT: DT_INTENT_PERCEPTUAL
125 dt_iop_color_normalize_t normalize; // $DEFAULT: DT_NORMALIZE_OFF $DESCRIPTION: "gamut clipping"
127 // working color profile
128 dt_colorspaces_color_profile_type_t type_work; // $DEFAULT: DT_COLORSPACE_LIN_REC2020
131
138
144
165
166
167const char *name()
168{
169 return _("input color profile");
170}
171
172const char **description(struct dt_iop_module_t *self)
173{
174 return dt_iop_set_description(self, _("convert any RGB input to pipeline reference RGB\n"
175 "using color profiles to remap RGB values"),
176 _("mandatory"),
177 _("linear or non-linear, RGB, scene-referred"),
178 _("defined by profile"),
179 _("linear, RGB, scene-referred"));
180}
181
183{
184 return IOP_GROUP_TECHNICAL;
185}
186
191
193{
194 return IOP_CS_RGB;
195}
196
202
205{
206 /* The sealed pipeline asks for the buffer contract before commit_params() has refreshed
207 * `piece->data`. Read the module params snapshot instead of the previous image runtime data,
208 * otherwise colorin can publish a stale Lab/RGB contract. */
209 dsc->channels = 4;
210 dsc->datatype = TYPE_FLOAT;
211 dsc->cst = _colorin_format_cst(self);
212}
213
216{
217 dsc->channels = 4;
218 dsc->datatype = TYPE_FLOAT;
219 dsc->cst = _colorin_format_cst(self);
220}
221
222static void _resolve_work_profile(dt_colorspaces_color_profile_type_t *work_type, char *work_filename)
223{
224 for(GList *l = darktable.color_profiles->profiles; l; l = g_list_next(l))
225 {
227 if(prof->work_pos > -1 && *work_type == prof->type
228 && (prof->type != DT_COLORSPACE_FILE || dt_colorspaces_is_profile_equal(prof->filename, work_filename)))
229 return;
230 }
231
233 "[colorin] profile `%s' not suitable for work profile. it has been replaced by linear Rec2020 RGB!\n",
234 dt_colorspaces_get_name(*work_type, work_filename));
235 *work_type = DT_COLORSPACE_LIN_REC2020;
236 work_filename[0] = '\0';
237}
238
239int legacy_params(dt_iop_module_t *self, const void *const old_params, const int old_version,
240 void *new_params, const int new_version)
241{
242#define DT_IOP_COLOR_ICC_LEN_V5 100
243
244 if(old_version == 1 && new_version == 7)
245 {
246 typedef struct dt_iop_colorin_params_v1_t
247 {
251
254 memset(new, 0, sizeof(*new));
255
256 if(!strcmp(old->iccprofile, "eprofile"))
257 new->type = DT_COLORSPACE_EMBEDDED_ICC;
258 else if(!strcmp(old->iccprofile, "ematrix"))
260 else if(!strcmp(old->iccprofile, "cmatrix"))
262 else if(!strcmp(old->iccprofile, "darktable"))
264 else if(!strcmp(old->iccprofile, "vendor"))
265 new->type = DT_COLORSPACE_VENDOR_MATRIX;
266 else if(!strcmp(old->iccprofile, "alternate"))
268 else if(!strcmp(old->iccprofile, "sRGB"))
269 new->type = DT_COLORSPACE_SRGB;
270 else if(!strcmp(old->iccprofile, "adobergb"))
271 new->type = DT_COLORSPACE_ADOBERGB;
272 else if(!strcmp(old->iccprofile, "linear_rec709_rgb") || !strcmp(old->iccprofile, "linear_rgb"))
273 new->type = DT_COLORSPACE_LIN_REC709;
274 else if(!strcmp(old->iccprofile, "linear_rec2020_rgb"))
275 new->type = DT_COLORSPACE_LIN_REC2020;
276 else if(!strcmp(old->iccprofile, "infrared"))
277 new->type = DT_COLORSPACE_INFRARED;
278 else if(!strcmp(old->iccprofile, "XYZ"))
279 new->type = DT_COLORSPACE_XYZ;
280 else if(!strcmp(old->iccprofile, "Lab"))
281 new->type = DT_COLORSPACE_LAB;
282 else
283 {
284 new->type = DT_COLORSPACE_FILE;
285 g_strlcpy(new->filename, old->iccprofile, sizeof(new->filename));
286 }
287
288 new->intent = old->intent;
289 new->normalize = 0;
290 new->blue_mapping = 1;
291 new->type_work = DT_COLORSPACE_LIN_REC709;
292 new->filename_work[0] = '\0';
293 return 0;
294 }
295 if(old_version == 2 && new_version == 7)
296 {
297 typedef struct dt_iop_colorin_params_v2_t
298 {
299 char iccprofile[DT_IOP_COLOR_ICC_LEN_V5];
301 int normalize;
302 } dt_iop_colorin_params_v2_t;
303
304 const dt_iop_colorin_params_v2_t *old = (dt_iop_colorin_params_v2_t *)old_params;
306 memset(new, 0, sizeof(*new));
307
308 if(!strcmp(old->iccprofile, "eprofile"))
309 new->type = DT_COLORSPACE_EMBEDDED_ICC;
310 else if(!strcmp(old->iccprofile, "ematrix"))
312 else if(!strcmp(old->iccprofile, "cmatrix"))
314 else if(!strcmp(old->iccprofile, "darktable"))
316 else if(!strcmp(old->iccprofile, "vendor"))
317 new->type = DT_COLORSPACE_VENDOR_MATRIX;
318 else if(!strcmp(old->iccprofile, "alternate"))
320 else if(!strcmp(old->iccprofile, "sRGB"))
321 new->type = DT_COLORSPACE_SRGB;
322 else if(!strcmp(old->iccprofile, "adobergb"))
323 new->type = DT_COLORSPACE_ADOBERGB;
324 else if(!strcmp(old->iccprofile, "linear_rec709_rgb") || !strcmp(old->iccprofile, "linear_rgb"))
325 new->type = DT_COLORSPACE_LIN_REC709;
326 else if(!strcmp(old->iccprofile, "linear_rec2020_rgb"))
327 new->type = DT_COLORSPACE_LIN_REC2020;
328 else if(!strcmp(old->iccprofile, "infrared"))
329 new->type = DT_COLORSPACE_INFRARED;
330 else if(!strcmp(old->iccprofile, "XYZ"))
331 new->type = DT_COLORSPACE_XYZ;
332 else if(!strcmp(old->iccprofile, "Lab"))
333 new->type = DT_COLORSPACE_LAB;
334 else
335 {
336 new->type = DT_COLORSPACE_FILE;
337 g_strlcpy(new->filename, old->iccprofile, sizeof(new->filename));
338 }
339
340 new->intent = old->intent;
341 new->normalize = old->normalize;
342 new->blue_mapping = 1;
343 new->type_work = DT_COLORSPACE_LIN_REC709;
344 new->filename_work[0] = '\0';
345 return 0;
346 }
347 if(old_version == 3 && new_version == 7)
348 {
349 typedef struct dt_iop_colorin_params_v3_t
350 {
351 char iccprofile[DT_IOP_COLOR_ICC_LEN_V5];
353 int normalize;
354 int blue_mapping;
355 } dt_iop_colorin_params_v3_t;
356
357 const dt_iop_colorin_params_v3_t *old = (dt_iop_colorin_params_v3_t *)old_params;
359 memset(new, 0, sizeof(*new));
360
361 if(!strcmp(old->iccprofile, "eprofile"))
362 new->type = DT_COLORSPACE_EMBEDDED_ICC;
363 else if(!strcmp(old->iccprofile, "ematrix"))
365 else if(!strcmp(old->iccprofile, "cmatrix"))
367 else if(!strcmp(old->iccprofile, "darktable"))
369 else if(!strcmp(old->iccprofile, "vendor"))
370 new->type = DT_COLORSPACE_VENDOR_MATRIX;
371 else if(!strcmp(old->iccprofile, "alternate"))
373 else if(!strcmp(old->iccprofile, "sRGB"))
374 new->type = DT_COLORSPACE_SRGB;
375 else if(!strcmp(old->iccprofile, "adobergb"))
376 new->type = DT_COLORSPACE_ADOBERGB;
377 else if(!strcmp(old->iccprofile, "linear_rec709_rgb") || !strcmp(old->iccprofile, "linear_rgb"))
378 new->type = DT_COLORSPACE_LIN_REC709;
379 else if(!strcmp(old->iccprofile, "linear_rec2020_rgb"))
380 new->type = DT_COLORSPACE_LIN_REC2020;
381 else if(!strcmp(old->iccprofile, "infrared"))
382 new->type = DT_COLORSPACE_INFRARED;
383 else if(!strcmp(old->iccprofile, "XYZ"))
384 new->type = DT_COLORSPACE_XYZ;
385 else if(!strcmp(old->iccprofile, "Lab"))
386 new->type = DT_COLORSPACE_LAB;
387 else
388 {
389 new->type = DT_COLORSPACE_FILE;
390 g_strlcpy(new->filename, old->iccprofile, sizeof(new->filename));
391 }
392
393 new->intent = old->intent;
394 new->normalize = old->normalize;
395 new->blue_mapping = old->blue_mapping;
396 new->type_work = DT_COLORSPACE_LIN_REC709;
397 new->filename_work[0] = '\0';
398
399 return 0;
400 }
401 if(old_version == 4 && new_version == 7)
402 {
403 typedef struct dt_iop_colorin_params_v4_t
404 {
406 char filename[DT_IOP_COLOR_ICC_LEN_V5];
408 int normalize;
409 int blue_mapping;
410 } dt_iop_colorin_params_v4_t;
411
412 const dt_iop_colorin_params_v4_t *old = (dt_iop_colorin_params_v4_t *)old_params;
414 memset(new, 0, sizeof(*new));
415
416 new->type = old->type;
417 g_strlcpy(new->filename, old->filename, sizeof(new->filename));
418 new->intent = old->intent;
419 new->normalize = old->normalize;
420 new->blue_mapping = old->blue_mapping;
421 new->type_work = DT_COLORSPACE_LIN_REC709;
422 new->filename_work[0] = '\0';
423
424 return 0;
425 }
426 if(old_version == 5 && new_version == 7)
427 {
428 typedef struct dt_iop_colorin_params_v5_t
429 {
431 char filename[DT_IOP_COLOR_ICC_LEN_V5];
433 int normalize;
434 int blue_mapping;
435 // working color profile
437 char filename_work[DT_IOP_COLOR_ICC_LEN_V5];
438 } dt_iop_colorin_params_v5_t;
439
440 const dt_iop_colorin_params_v5_t *old = (dt_iop_colorin_params_v5_t *)old_params;
442 memset(new, 0, sizeof(*new));
443
444 new->type = old->type;
445 g_strlcpy(new->filename, old->filename, sizeof(new->filename));
446 new->intent = old->intent;
447 new->normalize = old->normalize;
448 new->blue_mapping = old->blue_mapping;
449 new->type_work = old->type_work;
450 g_strlcpy(new->filename_work, old->filename_work, sizeof(new->filename_work));
451 _resolve_work_profile(&new->type_work, new->filename_work);
452
453 return 0;
454 }
455 if(old_version == 6 && new_version == 7)
456 {
457 // The structure is equal to to v7 (current) but a new version is introduced to convert invalid
458 // working profile choice to the default, linear Rec2020.
459 typedef struct dt_iop_colorin_params_v6_t
460 {
462 char filename[DT_IOP_COLOR_ICC_LEN];
465 int blue_mapping;
466 // working color profile
468 char filename_work[DT_IOP_COLOR_ICC_LEN];
469 } dt_iop_colorin_params_v6_t;
470
471 const dt_iop_colorin_params_v6_t *old = (dt_iop_colorin_params_v6_t *)old_params;
473 memcpy(new, old, sizeof(*new));
474 _resolve_work_profile(&new->type_work, new->filename_work);
475
476 return 0;
477 }
478 return 1;
479#undef DT_IOP_COLOR_ICC_LEN_V5
480}
481
483{
484 const int program = 2; // basic.cl, from programs.conf
487 module->data = gd;
488 gd->kernel_colorin_unbound = dt_opencl_create_kernel(program, "colorin_unbound");
489 gd->kernel_colorin_clipping = dt_opencl_create_kernel(program, "colorin_clipping");
490}
491
499
500#if 0
501static void intent_changed (GtkWidget *widget, gpointer user_data)
502{
503 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
504 if(darktable.gui->reset) return;
508}
509#endif
510
511static void profile_changed(GtkWidget *widget, gpointer user_data)
512{
513 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
514 if(darktable.gui->reset) return;
518 int pos = dt_bauhaus_combobox_get(widget);
519 GList *prof;
520 if(pos < g->n_image_profiles)
521 prof = g->image_profiles;
522 else
523 {
525 pos -= g->n_image_profiles;
526 }
527 for(; prof; prof = g_list_next(prof))
528 {
530 if(pp->in_pos == pos)
531 {
532 p->type = pp->type;
533 memcpy(p->filename, pp->filename, sizeof(p->filename));
535
537 return;
538 }
539 }
540 // should really never happen.
541 dt_print(DT_DEBUG_COLORPROFILE, "[colorin] color profile %s seems to have disappeared!\n",
542 dt_colorspaces_get_name(p->type, p->filename));
543}
544
545static void workicc_changed(GtkWidget *widget, gpointer user_data)
546{
547 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
549 if(darktable.gui->reset) return;
550
552
554 char filename_work[DT_IOP_COLOR_ICC_LEN];
555
556 int pos = dt_bauhaus_combobox_get(widget);
557 for(const GList *prof = darktable.color_profiles->profiles; prof; prof = g_list_next(prof))
558 {
560 if(pp->work_pos == pos)
561 {
562 type_work = pp->type;
563 g_strlcpy(filename_work, pp->filename, sizeof(filename_work));
564 break;
565 }
566 }
567
568 if(type_work != DT_COLORSPACE_NONE)
569 {
570 p->type_work = type_work;
571 g_strlcpy(p->filename_work, filename_work, sizeof(p->filename_work));
572
573 const dt_iop_order_iccprofile_info_t *const work_profile = dt_ioppr_add_profile_info_to_list(self->dev, p->type_work, p->filename_work, DT_INTENT_PERCEPTUAL);
574 if(IS_NULL_PTR(work_profile) || isnan(work_profile->matrix_in[0][0]) || isnan(work_profile->matrix_out[0][0]))
575 {
577 "[colorin] can't extract matrix from colorspace `%s', it will be replaced by Rec2020 RGB!\n",
578 p->filename_work);
579 dt_control_log(_("can't extract matrix from colorspace `%s', it will be replaced by Rec2020 RGB!"), p->filename_work);
580
581 }
583
585
587 }
588 else
589 {
590 // should really never happen.
591 dt_print(DT_DEBUG_COLORPROFILE, "[colorin] color profile %s seems to have disappeared!\n",
592 dt_colorspaces_get_name(p->type_work, p->filename_work));
593 }
594}
595
596
597#ifdef HAVE_OPENCL
598int process_cl(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, cl_mem dev_in, cl_mem dev_out)
599{
600 const dt_iop_roi_t *const roi_in = &piece->roi_in;
603 cl_mem dev_m = NULL, dev_l = NULL, dev_r = NULL, dev_g = NULL, dev_b = NULL, dev_coeffs = NULL;
604
605 int kernel;
606 float cmat[12], lmat[12];
607
608 if(d->nrgb)
609 {
611 pack_3xSSE_to_3x4(d->nmatrix, cmat);
612 pack_3xSSE_to_3x4(d->lmatrix, lmat);
613 }
614 else
615 {
617 pack_3xSSE_to_3x4(d->cmatrix, cmat);
618 pack_3xSSE_to_3x4(d->lmatrix, lmat);
619 }
620
621 cl_int err = -999;
622 const int blue_mapping = d->blue_mapping && dt_image_is_matrix_correction_supported(&pipe->dev->image_storage);
623 const int devid = pipe->devid;
624 const int width = roi_in->width;
625 const int height = roi_in->height;
626
627 if(d->type == DT_COLORSPACE_LAB)
628 {
629 size_t origin[] = { 0, 0, 0 };
630 size_t region[] = { roi_in->width, roi_in->height, 1 };
631 err = dt_opencl_enqueue_copy_image(devid, dev_in, dev_out, origin, origin, region);
632 if(err != CL_SUCCESS) goto error;
633 return TRUE;
634 }
635
636 size_t sizes[] = { ROUNDUPDWD(width, devid), ROUNDUPDHT(height, devid), 1 };
637 dev_m = dt_opencl_copy_host_to_device_constant(devid, sizeof(float) * 12, cmat);
638 if(IS_NULL_PTR(dev_m)) goto error;
639 dev_l = dt_opencl_copy_host_to_device_constant(devid, sizeof(float) * 12, lmat);
640 if(IS_NULL_PTR(dev_l)) goto error;
641 dev_r = dt_opencl_copy_host_to_device(devid, d->lut[0], 256, 256, sizeof(float));
642 if(IS_NULL_PTR(dev_r)) goto error;
643 dev_g = dt_opencl_copy_host_to_device(devid, d->lut[1], 256, 256, sizeof(float));
644 if(IS_NULL_PTR(dev_g)) goto error;
645 dev_b = dt_opencl_copy_host_to_device(devid, d->lut[2], 256, 256, sizeof(float));
646 if(IS_NULL_PTR(dev_b)) goto error;
647 dev_coeffs
648 = dt_opencl_copy_host_to_device_constant(devid, sizeof(float) * 3 * 3, (float *)d->unbounded_coeffs);
649 if(IS_NULL_PTR(dev_coeffs)) goto error;
650 dt_opencl_set_kernel_arg(devid, kernel, 0, sizeof(cl_mem), (void *)&dev_in);
651 dt_opencl_set_kernel_arg(devid, kernel, 1, sizeof(cl_mem), (void *)&dev_out);
652 dt_opencl_set_kernel_arg(devid, kernel, 2, sizeof(int), (void *)&width);
653 dt_opencl_set_kernel_arg(devid, kernel, 3, sizeof(int), (void *)&height);
654 dt_opencl_set_kernel_arg(devid, kernel, 4, sizeof(cl_mem), (void *)&dev_m);
655 dt_opencl_set_kernel_arg(devid, kernel, 5, sizeof(cl_mem), (void *)&dev_l);
656 dt_opencl_set_kernel_arg(devid, kernel, 6, sizeof(cl_mem), (void *)&dev_r);
657 dt_opencl_set_kernel_arg(devid, kernel, 7, sizeof(cl_mem), (void *)&dev_g);
658 dt_opencl_set_kernel_arg(devid, kernel, 8, sizeof(cl_mem), (void *)&dev_b);
659 dt_opencl_set_kernel_arg(devid, kernel, 9, sizeof(cl_int), (void *)&blue_mapping);
660 dt_opencl_set_kernel_arg(devid, kernel, 10, sizeof(cl_mem), (void *)&dev_coeffs);
661 err = dt_opencl_enqueue_kernel_2d(devid, kernel, sizes);
662 if(err != CL_SUCCESS) goto error;
669
670 return TRUE;
671
672error:
679 dt_print(DT_DEBUG_OPENCL, "[opencl_colorin] couldn't enqueue kernel! %d\n", err);
680 return FALSE;
681}
682#endif
683
684static inline void apply_blue_mapping(const float *const in, float *const out)
685{
686 out[0] = in[0];
687 out[1] = in[1];
688 out[2] = in[2];
689
690 const float YY = out[0] + out[1] + out[2];
691 if(YY > 0.0f)
692 {
693 const float zz = out[2] / YY;
694 const float bound_z = 0.5f, bound_Y = 0.5f;
695 const float amount = 0.11f;
696 if(zz > bound_z)
697 {
698 const float t = (zz - bound_z) / (1.0f - bound_z) * fminf(1.0, YY / bound_Y);
699 out[1] += t * amount;
700 out[2] -= t * amount;
701 }
702 }
703}
704
705static inline __attribute__((always_inline)) dt_aligned_pixel_simd_t _colorin_clamp_rgb01_vec4(
706 dt_aligned_pixel_simd_t in)
707{
708 in[0] = CLAMP(in[0], 0.0f, 1.0f);
709 in[1] = CLAMP(in[1], 0.0f, 1.0f);
710 in[2] = CLAMP(in[2], 0.0f, 1.0f);
711 in[3] = 0.0f;
712 return in;
713}
714
716static void process_cmatrix_bm(struct dt_iop_module_t *self, const dt_dev_pixelpipe_iop_t *piece,
717 const void *const ivoid, void *const ovoid, const dt_iop_roi_t *const roi_in,
718 const dt_iop_roi_t *const roi_out)
719{
720 const dt_iop_colorin_data_t *const d = (dt_iop_colorin_data_t *)piece->data;
721 const int ch = 4;
722 const int clipping = (!IS_NULL_PTR(d->nrgb));
723
724 dt_colormatrix_t cmatrix;
725 transpose_3xSSE(d->cmatrix, cmatrix);
726 dt_colormatrix_t nmatrix;
727 transpose_3xSSE(d->nmatrix, nmatrix);
728 dt_colormatrix_t lmatrix;
729 transpose_3xSSE(d->lmatrix, lmatrix);
730 const dt_aligned_pixel_simd_t cm0 = dt_colormatrix_row_to_simd(cmatrix, 0);
731 const dt_aligned_pixel_simd_t cm1 = dt_colormatrix_row_to_simd(cmatrix, 1);
732 const dt_aligned_pixel_simd_t cm2 = dt_colormatrix_row_to_simd(cmatrix, 2);
733 const dt_aligned_pixel_simd_t nm0 = dt_colormatrix_row_to_simd(nmatrix, 0);
734 const dt_aligned_pixel_simd_t nm1 = dt_colormatrix_row_to_simd(nmatrix, 1);
735 const dt_aligned_pixel_simd_t nm2 = dt_colormatrix_row_to_simd(nmatrix, 2);
736 const dt_aligned_pixel_simd_t lm0 = dt_colormatrix_row_to_simd(lmatrix, 0);
737 const dt_aligned_pixel_simd_t lm1 = dt_colormatrix_row_to_simd(lmatrix, 1);
738 const dt_aligned_pixel_simd_t lm2 = dt_colormatrix_row_to_simd(lmatrix, 2);
739
740 // fprintf(stderr, "Using cmatrix codepath\n");
741 // only color matrix. use our optimized fast path!
743 for(int j = 0; j < roi_out->height; j++)
744 {
745 const float *in = (const float *)ivoid + (size_t)ch * j * roi_out->width;
746 float *out = (float *)ovoid + (size_t)ch * j * roi_out->width;
748
749 for(int i = 0; i < roi_out->width; i++)
750 {
751 const float *const in_pixel = in + (size_t)ch * i;
752 float *const out_pixel = out + (size_t)ch * i;
753 // memcpy(cam, buf_in, sizeof(float)*3);
754 // avoid calling this for linear profiles (marked with negative entries), assures unbounded
755 // color management without extrapolation.
756 for(int c = 0; c < 3; c++)
757 cam[c] = (d->lut[c][0] >= 0.0f) ? dt_ioppr_eval_trc(in_pixel[c], d->lut[c], d->unbounded_coeffs[c], LUT_SAMPLES)
758 : in_pixel[c];
759 cam[3] = 0.0f;
760
761 apply_blue_mapping(cam, cam);
762 const dt_aligned_pixel_simd_t cam_v = dt_load_simd_aligned(cam);
763
764 if(!clipping)
765 {
766 dt_store_simd_nontemporal(out_pixel, dt_mat3x4_mul_vec4(cam_v, cm0, cm1, cm2));
767 }
768 else
769 {
770 const dt_aligned_pixel_simd_t nRGB = dt_mat3x4_mul_vec4(cam_v, nm0, nm1, nm2);
771 const dt_aligned_pixel_simd_t cRGB = _colorin_clamp_rgb01_vec4(nRGB);
772 dt_store_simd_nontemporal(out_pixel, dt_mat3x4_mul_vec4(cRGB, lm0, lm1, lm2));
773 }
774 }
775 }
776 dt_omploop_sfence(); // ensure that nontemporal writes complete before we attempt to read output
777}
778
781 const void *const ivoid, void *const ovoid,
782 const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out)
783{
784 const dt_iop_colorin_data_t *const d = (dt_iop_colorin_data_t *)piece->data;
785 const size_t npixels = (size_t)roi_out->width * roi_out->height;
786
787 const float *const restrict in = DT_IS_ALIGNED(ivoid);
788 float *const restrict out = DT_IS_ALIGNED(ovoid);
789
790 dt_colormatrix_t cmatrix;
791 transpose_3xSSE(d->cmatrix, cmatrix);
792 const dt_aligned_pixel_simd_t cm0 = dt_colormatrix_row_to_simd(cmatrix, 0);
793 const dt_aligned_pixel_simd_t cm1 = dt_colormatrix_row_to_simd(cmatrix, 1);
794 const dt_aligned_pixel_simd_t cm2 = dt_colormatrix_row_to_simd(cmatrix, 2);
795
796// fprintf(stderr, "Using cmatrix codepath\n");
797// only color matrix. use our optimized fast path!
798 __OMP_PARALLEL_FOR_SIMD__(aligned(in, out:64))
799 for(size_t k = 0; k < npixels; k++)
800 {
801 const size_t idx = 4 * k;
802 const dt_aligned_pixel_simd_t vin = dt_load_simd_aligned(in + idx);
803 dt_store_simd_nontemporal(out + idx, dt_mat3x4_mul_vec4(vin, cm0, cm1, cm2));
804 }
805 dt_omploop_sfence(); // ensure that nontemporal writes complete before we attempt to read output
806}
807
810 const void *const ivoid, void *const ovoid,
811 const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out)
812{
813 const dt_iop_colorin_data_t *const d = (dt_iop_colorin_data_t *)piece->data;
814 const size_t npixels = (size_t)roi_out->width * roi_out->height;
815 const float *const restrict in = DT_IS_ALIGNED(ivoid);
816 float *const restrict out = DT_IS_ALIGNED(ovoid);
817
818 dt_colormatrix_t nmatrix;
819 dt_colormatrix_t lmatrix;
820 transpose_3xSSE(d->nmatrix, nmatrix);
821 transpose_3xSSE(d->lmatrix, lmatrix);
822 const dt_aligned_pixel_simd_t nm0 = dt_colormatrix_row_to_simd(nmatrix, 0);
823 const dt_aligned_pixel_simd_t nm1 = dt_colormatrix_row_to_simd(nmatrix, 1);
824 const dt_aligned_pixel_simd_t nm2 = dt_colormatrix_row_to_simd(nmatrix, 2);
825 const dt_aligned_pixel_simd_t lm0 = dt_colormatrix_row_to_simd(lmatrix, 0);
826 const dt_aligned_pixel_simd_t lm1 = dt_colormatrix_row_to_simd(lmatrix, 1);
827 const dt_aligned_pixel_simd_t lm2 = dt_colormatrix_row_to_simd(lmatrix, 2);
828
829// fprintf(stderr, "Using cmatrix codepath\n");
830// only color matrix. use our optimized fast path!
831 __OMP_PARALLEL_FOR_SIMD__(aligned(in, out:64))
832 for(size_t k = 0; k < npixels; k++)
833 {
834 const size_t idx = 4 * k;
835 const dt_aligned_pixel_simd_t vin = dt_load_simd_aligned(in + idx);
836 const dt_aligned_pixel_simd_t nRGB = dt_mat3x4_mul_vec4(vin, nm0, nm1, nm2);
837 const dt_aligned_pixel_simd_t cRGB = _colorin_clamp_rgb01_vec4(nRGB);
838 dt_store_simd_nontemporal(out + idx, dt_mat3x4_mul_vec4(cRGB, lm0, lm1, lm2));
839 }
840 dt_omploop_sfence(); // ensure that nontemporal writes complete before we attempt to read output
841}
842
843static inline __attribute__((always_inline)) void process_cmatrix_fastpath(struct dt_iop_module_t *self, const dt_dev_pixelpipe_iop_t *piece,
844 const void *const ivoid, void *const ovoid, const dt_iop_roi_t *const roi_in,
845 const dt_iop_roi_t *const roi_out)
846{
847 const dt_iop_colorin_data_t *const d = (dt_iop_colorin_data_t *)piece->data;
848 const int clipping = (!IS_NULL_PTR(d->nrgb));
849
850 if(!clipping)
851 {
852 process_cmatrix_fastpath_simple(self, piece, ivoid, ovoid, roi_in, roi_out);
853 }
854 else
855 {
856 process_cmatrix_fastpath_clipping(self, piece, ivoid, ovoid, roi_in, roi_out);
857 }
858}
859
861static void process_cmatrix_proper(struct dt_iop_module_t *self, const dt_dev_pixelpipe_iop_t *piece,
862 const void *const ivoid, void *const ovoid, const dt_iop_roi_t *const roi_in,
863 const dt_iop_roi_t *const roi_out)
864{
865 const dt_iop_colorin_data_t *const d = (dt_iop_colorin_data_t *)piece->data;
866 const int clipping = (!IS_NULL_PTR(d->nrgb));
867 const size_t npixels = (size_t)roi_out->width * roi_out->height;
868
869 dt_colormatrix_t cmatrix;
870 transpose_3xSSE(d->cmatrix, cmatrix);
871 dt_colormatrix_t nmatrix;
872 transpose_3xSSE(d->nmatrix, nmatrix);
873 dt_colormatrix_t lmatrix;
874 transpose_3xSSE(d->lmatrix, lmatrix);
875 const dt_aligned_pixel_simd_t cm0 = dt_colormatrix_row_to_simd(cmatrix, 0);
876 const dt_aligned_pixel_simd_t cm1 = dt_colormatrix_row_to_simd(cmatrix, 1);
877 const dt_aligned_pixel_simd_t cm2 = dt_colormatrix_row_to_simd(cmatrix, 2);
878 const dt_aligned_pixel_simd_t nm0 = dt_colormatrix_row_to_simd(nmatrix, 0);
879 const dt_aligned_pixel_simd_t nm1 = dt_colormatrix_row_to_simd(nmatrix, 1);
880 const dt_aligned_pixel_simd_t nm2 = dt_colormatrix_row_to_simd(nmatrix, 2);
881 const dt_aligned_pixel_simd_t lm0 = dt_colormatrix_row_to_simd(lmatrix, 0);
882 const dt_aligned_pixel_simd_t lm1 = dt_colormatrix_row_to_simd(lmatrix, 1);
883 const dt_aligned_pixel_simd_t lm2 = dt_colormatrix_row_to_simd(lmatrix, 2);
884
885// fprintf(stderr, "Using cmatrix codepath\n");
886// only color matrix. use our optimized fast path!
888 for(size_t k = 0; k < npixels; k++)
889 {
890 const float *in = (const float *)ivoid + 4 * k;
891 float *out = (float *)ovoid + 4 * k;
893
894 // memcpy(cam, buf_in, sizeof(float)*3);
895 // avoid calling this for linear profiles (marked with negative entries), assures unbounded
896 // color management without extrapolation.
897 for(int c = 0; c < 3; c++)
898 cam[c] = (d->lut[c][0] >= 0.0f) ? dt_ioppr_eval_trc(in[c], d->lut[c], d->unbounded_coeffs[c], LUT_SAMPLES)
899 : in[c];
900 cam[3] = 0.0f;
901 const dt_aligned_pixel_simd_t cam_v = dt_load_simd_aligned(cam);
902
903 if(!clipping)
904 {
905 dt_store_simd_nontemporal(out, dt_mat3x4_mul_vec4(cam_v, cm0, cm1, cm2));
906 }
907 else
908 {
909 const dt_aligned_pixel_simd_t nRGB = dt_mat3x4_mul_vec4(cam_v, nm0, nm1, nm2);
910 const dt_aligned_pixel_simd_t cRGB = _colorin_clamp_rgb01_vec4(nRGB);
911 dt_store_simd_nontemporal(out, dt_mat3x4_mul_vec4(cRGB, lm0, lm1, lm2));
912 }
913 }
914 dt_omploop_sfence(); // ensure that nontemporal writes complete before we attempt to read output
915}
916
917static inline __attribute__((always_inline)) void process_cmatrix(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe,
918 const dt_dev_pixelpipe_iop_t *piece, const void *const ivoid, void *const ovoid,
919 const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out)
920{
921 const dt_iop_colorin_data_t *const d = (dt_iop_colorin_data_t *)piece->data;
922 const int blue_mapping = d->blue_mapping && dt_image_is_matrix_correction_supported(&pipe->dev->image_storage);
923
924 if(!blue_mapping && d->nonlinearlut == 0)
925 {
926 process_cmatrix_fastpath(self, piece, ivoid, ovoid, roi_in, roi_out);
927 }
928 else if(blue_mapping)
929 {
930 process_cmatrix_bm(self, piece, ivoid, ovoid, roi_in, roi_out);
931 }
932 else
933 {
934 process_cmatrix_proper(self, piece, ivoid, ovoid, roi_in, roi_out);
935 }
936}
937
939static void process_lcms2_bm(struct dt_iop_module_t *self, const dt_dev_pixelpipe_iop_t *piece, const void *const ivoid,
940 void *const ovoid, const dt_iop_roi_t *const roi_in,
941 const dt_iop_roi_t *const roi_out)
942{
943 const dt_iop_colorin_data_t *const d = (dt_iop_colorin_data_t *)piece->data;
944 /* LCMS is handled through local aliases so the OpenMP region shares explicit
945 * transform state rather than dereferencing `d->xform_*` inside the loop. */
946 const cmsHTRANSFORM xform_cam_lab = d->xform_cam_Lab;
947 const cmsHTRANSFORM xform_cam_nrgb = d->xform_cam_nrgb;
948 const cmsHTRANSFORM xform_nrgb_lab = d->xform_nrgb_Lab;
949 const gboolean use_nrgb = (!IS_NULL_PTR(d->nrgb));
950 const int ch = 4;
951// use general lcms2 fallback
953 for(int k = 0; k < roi_out->height; k++)
954 {
955 const float *in = (const float *)ivoid + (size_t)ch * k * roi_out->width;
956 float *out = (float *)ovoid + (size_t)ch * k * roi_out->width;
957
958 float *camptr = (float *)out;
959 for(int j = 0; j < roi_out->width; j++)
960 {
961 float *const pixel = camptr + 4 * j;
962 apply_blue_mapping(in + 4 * j, pixel);
963 pixel[3] = 0.0f;
964 }
965
966 // convert from input profile to pipeline work RGB.
967 if(!use_nrgb)
968 {
969 dt_colorspaces_transform_rgba_float_row(xform_cam_lab, out, out, roi_out->width);
970 }
971 else
972 {
973 dt_colorspaces_transform_rgba_float_row(xform_cam_nrgb, out, out, roi_out->width);
974
975 float *rgbptr = (float *)out;
976 __OMP_SIMD__(aligned(rgbptr:64))
977 for(int j = 0; j < roi_out->width; j++)
978 {
979 float *const pixel = rgbptr + 4 * j;
980 for(int c = 0; c < 3; c++) pixel[c] = CLAMP(pixel[c], 0.0f, 1.0f);
981 pixel[3] = 0.0f;
982 }
983
984 dt_colorspaces_transform_rgba_float_row(xform_nrgb_lab, out, out, roi_out->width);
985 }
986 }
987}
988
990static void process_lcms2_proper(struct dt_iop_module_t *self, const dt_dev_pixelpipe_iop_t *piece,
991 const void *const ivoid, void *const ovoid, const dt_iop_roi_t *const roi_in,
992 const dt_iop_roi_t *const roi_out)
993{
994 const dt_iop_colorin_data_t *const d = (dt_iop_colorin_data_t *)piece->data;
995 /* LCMS is handled through local aliases so the OpenMP region shares explicit
996 * transform state rather than dereferencing `d->xform_*` inside the loop. */
997 const cmsHTRANSFORM xform_cam_lab = d->xform_cam_Lab;
998 const cmsHTRANSFORM xform_cam_nrgb = d->xform_cam_nrgb;
999 const cmsHTRANSFORM xform_nrgb_lab = d->xform_nrgb_Lab;
1000 const gboolean use_nrgb = (!IS_NULL_PTR(d->nrgb));
1001 const int ch = 4;
1002
1003// use general lcms2 fallback
1005 for(int k = 0; k < roi_out->height; k++)
1006 {
1007 const float *in = (const float *)ivoid + (size_t)ch * k * roi_out->width;
1008 float *out = (float *)ovoid + (size_t)ch * k * roi_out->width;
1009
1010 // convert from input profile to pipeline work RGB.
1011 if(!use_nrgb)
1012 {
1013 dt_colorspaces_transform_rgba_float_row(xform_cam_lab, in, out, roi_out->width);
1014 }
1015 else
1016 {
1017 dt_colorspaces_transform_rgba_float_row(xform_cam_nrgb, in, out, roi_out->width);
1018
1019 float *rgbptr = (float *)out;
1020 __OMP_SIMD__(aligned(rgbptr:64))
1021 for(int j = 0; j < roi_out->width; j++)
1022 {
1023 float *const pixel = rgbptr + 4 * j;
1024 for(int c = 0; c < 3; c++) pixel[c] = CLAMP(pixel[c], 0.0f, 1.0f);
1025 }
1026
1027 dt_colorspaces_transform_rgba_float_row(xform_nrgb_lab, out, out, roi_out->width);
1028 }
1029 }
1030}
1031
1032static inline __attribute__((always_inline)) void process_lcms2(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe,
1033 const dt_dev_pixelpipe_iop_t *piece, const void *const ivoid, void *const ovoid,
1034 const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out)
1035{
1036 const dt_iop_colorin_data_t *const d = (dt_iop_colorin_data_t *)piece->data;
1037 const int blue_mapping = d->blue_mapping && dt_image_is_matrix_correction_supported(&pipe->dev->image_storage);
1038
1039 // use general lcms2 fallback
1040 if(blue_mapping)
1041 {
1042 process_lcms2_bm(self, piece, ivoid, ovoid, roi_in, roi_out);
1043 }
1044 else
1045 {
1046 process_lcms2_proper(self, piece, ivoid, ovoid, roi_in, roi_out);
1047 }
1048}
1049
1050int process(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const void *const ivoid,
1051 void *const ovoid)
1052{
1053 const dt_iop_roi_t *const roi_in = &piece->roi_in;
1054 const dt_iop_roi_t *const roi_out = &piece->roi_out;
1055 const dt_iop_colorin_data_t *const d = (dt_iop_colorin_data_t *)piece->data;
1056
1057 if(d->type == DT_COLORSPACE_LAB)
1058 {
1059 dt_iop_image_copy_by_size(ovoid, ivoid, roi_out->width, roi_out->height, 4);
1060 }
1061 else if(!isnan(d->cmatrix[0][0]))
1062 {
1063 process_cmatrix(self, pipe, piece, ivoid, ovoid, roi_in, roi_out);
1064 }
1065 else
1066 {
1067 process_lcms2(self, pipe, piece, ivoid, ovoid, roi_in, roi_out);
1068 }
1069
1070 if(pipe->mask_display & DT_DEV_PIXELPIPE_DISPLAY_MASK) dt_iop_alpha_copy(ivoid, ovoid, roi_out->width, roi_out->height);
1071 return 0;
1072}
1073
1075{
1076 if(d->xform_cam_Lab)
1077 {
1078 cmsDeleteTransform(d->xform_cam_Lab);
1079 d->xform_cam_Lab = NULL;
1080 }
1081 if(d->xform_cam_nrgb)
1082 {
1083 cmsDeleteTransform(d->xform_cam_nrgb);
1084 d->xform_cam_nrgb = NULL;
1085 }
1086 if(d->xform_nrgb_Lab)
1087 {
1088 cmsDeleteTransform(d->xform_nrgb_Lab);
1089 d->xform_nrgb_Lab = NULL;
1090 }
1091}
1092
1094{
1095 d->cmatrix[0][0] = d->nmatrix[0][0] = d->lmatrix[0][0] = NAN;
1096 d->lut[0][0] = -1.0f;
1097 d->lut[1][0] = -1.0f;
1098 d->lut[2][0] = -1.0f;
1099 d->nonlinearlut = 0;
1100 piece->process_cl_ready = 1;
1101}
1102
1124
1126 dt_dev_pixelpipe_t *pipe,
1128{
1130 const dt_colorspaces_color_profile_type_t requested_type = type;
1131
1133 {
1136 else d->clear_input = 1;
1137 }
1139 {
1142 else d->clear_input = 1;
1143 }
1145 {
1148 else d->clear_input = 1;
1149 }
1150
1154 {
1155 gboolean new_profile = FALSE;
1156 cmsHPROFILE profile = NULL;
1157 type = dt_colorspaces_get_input_profile_from_image(pipe->dev->image_storage.id, type, &profile, &new_profile);
1158 if(!IS_NULL_PTR(profile))
1159 {
1160 d->input = profile;
1161 d->clear_input = new_profile;
1162 }
1163 }
1164
1165 if(requested_type == DT_COLORSPACE_STANDARD_MATRIX
1168 {
1169 dt_print(DT_DEBUG_COLORPROFILE, "[colorin] `%s' color matrix not found!\n", pipe->dev->image_storage.camera_makermodel);
1170 dt_control_log(_("`%s' color matrix not found!"), pipe->dev->image_storage.camera_makermodel);
1171 }
1172
1173 if(IS_NULL_PTR(d->input))
1174 {
1176 if(!IS_NULL_PTR(profile)) d->input = profile->profile;
1177 }
1178
1179 if(IS_NULL_PTR(d->input) && type != DT_COLORSPACE_SRGB)
1180 {
1181 // use linear_rec709_rgb as fallback for missing non-sRGB profiles:
1183 d->clear_input = 0;
1184 }
1185
1186 // final resort: sRGB
1187 if(IS_NULL_PTR(d->input))
1188 {
1190 d->clear_input = 0;
1191 }
1192
1193 return type;
1194}
1195
1199{
1200 d->type = type;
1202 g_strlcpy(d->filename, p->filename, sizeof(d->filename));
1203 else
1204 d->filename[0] = '\0';
1205}
1206
1208{
1211
1212 d->type_work = p->type_work;
1213 g_strlcpy(d->filename_work, p->filename_work, sizeof(d->filename_work));
1214
1215 // only clean up when it's a type that we created here
1216 if(d->input && d->clear_input) dt_colorspaces_cleanup_profile(d->input);
1217 d->input = NULL;
1218 d->clear_input = 0;
1219 d->nrgb = NULL;
1220
1221 d->blue_mapping = p->blue_mapping;
1224 _reset_processing_state(d, piece);
1225
1226 // commit and resolve working profile first, it is the target output profile of this module
1227 dt_iop_order_iccprofile_info_t *work_profile_info
1228 = dt_ioppr_set_pipe_work_profile_info(self->dev, pipe, d->type_work, d->filename_work, DT_INTENT_PERCEPTUAL);
1229 if(work_profile_info)
1230 {
1231 d->type_work = work_profile_info->type;
1232 g_strlcpy(d->filename_work, work_profile_info->filename, sizeof(d->filename_work));
1233 }
1234
1235 const dt_colorspaces_color_profile_t *work_profile
1236 = dt_colorspaces_get_profile(d->type_work, d->filename_work, DT_PROFILE_DIRECTION_ANY);
1237 const cmsHPROFILE work = work_profile ? work_profile->profile : NULL;
1238 const gboolean can_use_work_matrix = (work_profile_info
1239 && !work_profile_info->nonlinearlut
1240 && !isnan(work_profile_info->matrix_out[0][0]));
1241
1243 if(type == DT_COLORSPACE_LAB)
1244 {
1246 piece->enabled = 0;
1247 return;
1248 }
1249 piece->enabled = 1;
1250
1251 const dt_colorspaces_color_profile_type_t requested_input_type = p->type;
1252 type = _resolve_input_profile(p, pipe, d);
1253 dt_iop_fmt_log(self, "commit: class=%s matrix_supported=%d requested_input=%d resolved_input=%d blue_mapping=%d",
1256 requested_input_type, type, d->blue_mapping);
1257
1258 // should never happen, but catch that case to avoid a crash
1259 if(IS_NULL_PTR(d->input))
1260 {
1261 dt_print(DT_DEBUG_COLORPROFILE, "[colorin] input profile could not be generated!\n");
1262 dt_control_log(_("input profile could not be generated!"));
1263 piece->enabled = 0;
1264 return;
1265 }
1266
1268
1269 cmsColorSpaceSignature input_color_space = cmsGetColorSpace(d->input);
1270 cmsUInt32Number input_format;
1271 switch(input_color_space)
1272 {
1273 case cmsSigRgbData:
1274 input_format = TYPE_RGBA_FLT;
1275 break;
1276 case cmsSigXYZData:
1277 // FIXME: even though this is allowed/works, dt_ioppr_generate_profile_info still complains about these profiles
1279 break;
1280 default:
1281 // fprintf("%.*s", 4, input_color_space) doesn't work, it prints the string backwards :(
1282 dt_print(DT_DEBUG_COLORPROFILE, "[colorin] input profile color space `%c%c%c%c' not supported\n",
1283 (char)(input_color_space>>24),
1284 (char)(input_color_space>>16),
1285 (char)(input_color_space>>8),
1286 (char)(input_color_space));
1287 input_format = TYPE_RGBA_FLT; // this will fail later, triggering the linear rec709 fallback
1288 }
1289
1290 gboolean use_matrix = FALSE;
1291 dt_colormatrix_t input_matrix;
1292
1293 // prepare transformation matrix or lcms2 transforms as fallback
1294 if(d->nrgb)
1295 {
1296 // user wants us to clip to a given RGB profile before converting to work RGB
1297 if(!dt_colorspaces_get_matrix_from_input_profile(d->input, input_matrix, d->lut[0], d->lut[1], d->lut[2],
1299 && can_use_work_matrix)
1300 {
1301 float lutr[1], lutg[1], lutb[1];
1302 dt_colormatrix_t omat;
1303 dt_colormatrix_t nrgb_in;
1304 if(!dt_colorspaces_get_matrix_from_output_profile(d->nrgb, omat, lutr, lutg, lutb, 1)
1305 && !dt_colorspaces_get_matrix_from_input_profile(d->nrgb, nrgb_in, lutr, lutg, lutb, 1))
1306 {
1307 dt_colormatrix_mul(d->cmatrix, work_profile_info->matrix_out, input_matrix);
1308 dt_colormatrix_mul(d->nmatrix, omat, input_matrix);
1309 dt_colormatrix_mul(d->lmatrix, work_profile_info->matrix_out, nrgb_in);
1310 use_matrix = TRUE;
1311 }
1312 }
1313
1314 if(!use_matrix)
1315 {
1316 piece->process_cl_ready = 0;
1317 d->cmatrix[0][0] = NAN;
1318 d->xform_cam_Lab = work ? cmsCreateTransform(d->input, input_format, work, TYPE_RGBA_FLT, p->intent, 0) : NULL;
1319 d->xform_cam_nrgb = cmsCreateTransform(d->input, input_format, d->nrgb, TYPE_RGBA_FLT, p->intent, 0);
1320 d->xform_nrgb_Lab = work ? cmsCreateTransform(d->nrgb, TYPE_RGBA_FLT, work, TYPE_RGBA_FLT, p->intent, 0) : NULL;
1321 }
1322 }
1323 else
1324 {
1325 // default mode: unbound processing directly to work RGB
1326 if(!dt_colorspaces_get_matrix_from_input_profile(d->input, input_matrix, d->lut[0], d->lut[1], d->lut[2],
1328 && can_use_work_matrix)
1329 {
1330 dt_colormatrix_mul(d->cmatrix, work_profile_info->matrix_out, input_matrix);
1331 use_matrix = TRUE;
1332 }
1333
1334 if(!use_matrix)
1335 {
1336 piece->process_cl_ready = 0;
1337 d->cmatrix[0][0] = NAN;
1338 d->xform_cam_Lab = work ? cmsCreateTransform(d->input, input_format, work, TYPE_RGBA_FLT, p->intent, 0) : NULL;
1339 }
1340 }
1341
1342 // we might have failed generating the clipping transformations, check that:
1343 if(d->nrgb && ((IS_NULL_PTR(d->xform_cam_nrgb) && isnan(d->nmatrix[0][0])) || (IS_NULL_PTR(d->xform_nrgb_Lab) && isnan(d->lmatrix[0][0]))))
1344 {
1345 if(d->xform_cam_nrgb)
1346 {
1347 cmsDeleteTransform(d->xform_cam_nrgb);
1348 d->xform_cam_nrgb = NULL;
1349 }
1350 if(d->xform_nrgb_Lab)
1351 {
1352 cmsDeleteTransform(d->xform_nrgb_Lab);
1353 d->xform_nrgb_Lab = NULL;
1354 }
1355 d->nrgb = NULL;
1356 }
1357
1358 // user selected a non-supported input profile, check that:
1359 if(IS_NULL_PTR(d->xform_cam_Lab) && isnan(d->cmatrix[0][0]))
1360 {
1361 if(p->type == DT_COLORSPACE_FILE)
1363 "[colorin] unsupported input profile `%s' has been replaced by linear Rec709 RGB!\n",
1364 p->filename);
1365 else
1366 dt_print(DT_DEBUG_COLORPROFILE, "[colorin] unsupported input profile has been replaced by linear Rec709 RGB!\n");
1367 dt_control_log(_("unsupported input profile has been replaced by linear Rec709 RGB!"));
1368 if(d->input && d->clear_input) dt_colorspaces_cleanup_profile(d->input);
1369 d->nrgb = NULL;
1371 d->clear_input = 0;
1372 use_matrix = FALSE;
1373 if(!dt_colorspaces_get_matrix_from_input_profile(d->input, input_matrix, d->lut[0], d->lut[1], d->lut[2],
1375 && can_use_work_matrix)
1376 {
1377 dt_colormatrix_mul(d->cmatrix, work_profile_info->matrix_out, input_matrix);
1378 use_matrix = TRUE;
1379 }
1380
1381 if(!use_matrix)
1382 {
1383 piece->process_cl_ready = 0;
1384 d->cmatrix[0][0] = NAN;
1385 d->xform_cam_Lab = work ? cmsCreateTransform(d->input, TYPE_RGBA_FLT, work, TYPE_RGBA_FLT, p->intent, 0) : NULL;
1386 }
1387 }
1388
1389 d->nonlinearlut = 0;
1390
1391 // now try to initialize unbounded mode:
1392 // we do a extrapolation for input values above 1.0f.
1393 // unfortunately we can only do this if we got the computation
1394 // in our hands, i.e. for the fast builtin-dt-matrix-profile path.
1395 for(int k = 0; k < 3; k++)
1396 {
1397 // omit luts marked as linear (negative as marker)
1398 if(d->lut[k][0] >= 0.0f)
1399 {
1400 d->nonlinearlut++;
1401
1402 const float x[4] = { 0.7f, 0.8f, 0.9f, 1.0f };
1403 const float y[4] = { extrapolate_lut(d->lut[k], x[0], LUT_SAMPLES),
1404 extrapolate_lut(d->lut[k], x[1], LUT_SAMPLES),
1405 extrapolate_lut(d->lut[k], x[2], LUT_SAMPLES),
1406 extrapolate_lut(d->lut[k], x[3], LUT_SAMPLES) };
1407 dt_iop_estimate_exp(x, y, 4, d->unbounded_coeffs[k]);
1408 }
1409 else
1410 d->unbounded_coeffs[k][0] = -1.0f;
1411 }
1412
1413 // commit input profile metadata to pipeline with the original input RGB -> XYZ matrix
1414 dt_colormatrix_t input_matrix_for_pipe = { { NAN } };
1415 if(d->input)
1416 dt_colorspaces_get_matrix_from_input_profile(d->input, input_matrix_for_pipe, NULL, NULL, NULL, 0);
1417
1418 dt_ioppr_set_pipe_input_profile_info(self->dev, pipe, d->type, d->filename, p->intent,
1419 input_matrix_for_pipe);
1420}
1421
1423{
1424 piece->data = dt_calloc_align(sizeof(dt_iop_colorin_data_t));
1425 piece->data_size = sizeof(dt_iop_colorin_data_t);
1426}
1427
1429{
1431 if(d->input && d->clear_input) dt_colorspaces_cleanup_profile(d->input);
1432 if(d->xform_cam_Lab)
1433 {
1434 cmsDeleteTransform(d->xform_cam_Lab);
1435 d->xform_cam_Lab = NULL;
1436 }
1437 if(d->xform_cam_nrgb)
1438 {
1439 cmsDeleteTransform(d->xform_cam_nrgb);
1440 d->xform_cam_nrgb = NULL;
1441 }
1442 if(d->xform_nrgb_Lab)
1443 {
1444 cmsDeleteTransform(d->xform_nrgb_Lab);
1445 d->xform_nrgb_Lab = NULL;
1446 }
1447
1448 dt_free_align(piece->data);
1449 piece->data = NULL;
1450}
1451
1452void gui_update(struct dt_iop_module_t *self)
1453{
1456
1457 dt_bauhaus_combobox_set(g->clipping_combobox, p->normalize);
1458
1459 // working profile
1460 int idx = -1;
1461 for(const GList *prof = darktable.color_profiles->profiles; prof; prof = g_list_next(prof))
1462 {
1464 if(pp->work_pos > -1
1465 && pp->type == p->type_work
1466 && (pp->type != DT_COLORSPACE_FILE || dt_colorspaces_is_profile_equal(pp->filename, p->filename_work)))
1467 {
1468 idx = pp->work_pos;
1469 break;
1470 }
1471 }
1472
1473 if(idx < 0)
1474 {
1475 idx = 0;
1476 dt_print(DT_DEBUG_COLORPROFILE, "[colorin] could not find requested working profile `%s'!\n",
1477 dt_colorspaces_get_name(p->type_work, p->filename_work));
1478 }
1479 dt_bauhaus_combobox_set(g->work_combobox, idx);
1480
1481 for(const GList *prof = g->image_profiles; prof; prof = g_list_next(prof))
1482 {
1484 if(pp->type == p->type
1485 && (pp->type != DT_COLORSPACE_FILE || dt_colorspaces_is_profile_equal(pp->filename, p->filename)))
1486 {
1487 dt_bauhaus_combobox_set(g->profile_combobox, pp->in_pos);
1488 return;
1489 }
1490 }
1491
1492 for(const GList *prof = darktable.color_profiles->profiles; prof; prof = g_list_next(prof))
1493 {
1495 if(pp->in_pos > -1
1496 && pp->type == p->type
1497 && (pp->type != DT_COLORSPACE_FILE || dt_colorspaces_is_profile_equal(pp->filename, p->filename)))
1498 {
1499 dt_bauhaus_combobox_set(g->profile_combobox, pp->in_pos + g->n_image_profiles);
1500 return;
1501 }
1502 }
1503
1504 // Error happened, otherwise we would have returned earlier
1505 dt_bauhaus_combobox_set(g->profile_combobox, 0);
1506
1507 const gboolean matrix_supported = dt_image_is_matrix_correction_supported(&self->dev->image_storage);
1509 && !(dt_colorspaces_is_raw_matrix_profile_type(p->type) && !matrix_supported))
1510 {
1511 dt_print(DT_DEBUG_COLORPROFILE, "[colorin] could not find requested profile `%s'!\n",
1512 dt_colorspaces_get_name(p->type, p->filename));
1513
1514 dt_control_log(_("The color profile `%s' referenced as input profile has not been found."), dt_colorspaces_get_name(p->type, p->filename));
1515 }
1516}
1517
1518// FIXME: update the gui when we add/remove the eprofile or ematrix
1520{
1521 module->default_enabled = 1;
1522 module->hide_enable_button = 1;
1523
1524 dt_iop_colorin_params_t *d = module->default_params;
1525 gboolean new_profile;
1526 d->type = dt_image_find_best_color_profile(module->dev->image_storage.id, NULL, &new_profile);
1527 dt_iop_fmt_log(module, "reload_defaults: class=%s matrix_supported=%d -> default_input_profile=%d new_profile=%d",
1529 dt_image_is_matrix_correction_supported(&module->dev->image_storage), d->type, new_profile);
1530 update_profile_list(module);
1531}
1532
1534{
1536
1537 if(IS_NULL_PTR(g)) return;
1538
1539 // clear and refill the image profile list
1540 g_list_free_full(g->image_profiles, dt_free_gpointer);
1541 g->image_profiles = NULL;
1542 g->n_image_profiles = 0;
1543
1544 int pos = -1;
1545 // some file formats like jpeg can have an embedded color profile
1546 // currently we only support jpeg, j2k, tiff and png
1548 if(cimg->profile)
1549 {
1552 g_strlcpy(prof->name, dt_colorspaces_get_name(DT_COLORSPACE_EMBEDDED_ICC, ""), sizeof(prof->name));
1554 g->image_profiles = g_list_append(g->image_profiles, prof);
1555 prof->in_pos = ++pos;
1556 }
1558 // use the matrix embedded in some DNGs and EXRs
1559 if(!isnan(self->dev->image_storage.d65_color_matrix[0]))
1560 {
1563 g_strlcpy(prof->name, dt_colorspaces_get_name(DT_COLORSPACE_EMBEDDED_MATRIX, ""), sizeof(prof->name));
1565 g->image_profiles = g_list_append(g->image_profiles, prof);
1566 prof->in_pos = ++pos;
1567 }
1568
1570 && !(self->dev->image_storage.flags & DT_IMAGE_4BAYER))
1571 {
1574 g_strlcpy(prof->name, dt_colorspaces_get_name(DT_COLORSPACE_STANDARD_MATRIX, ""), sizeof(prof->name));
1576 g->image_profiles = g_list_append(g->image_profiles, prof);
1577 prof->in_pos = ++pos;
1578 }
1579
1580 // darktable built-in, if applicable
1581 for(int k = 0; k < dt_profiled_colormatrix_cnt; k++)
1582 {
1584 {
1587 g_strlcpy(prof->name, dt_colorspaces_get_name(DT_COLORSPACE_ENHANCED_MATRIX, ""), sizeof(prof->name));
1589 g->image_profiles = g_list_append(g->image_profiles, prof);
1590 prof->in_pos = ++pos;
1591 break;
1592 }
1593 }
1594
1595 // darktable vendor matrix, if applicable
1596 for(int k = 0; k < dt_vendor_colormatrix_cnt; k++)
1597 {
1599 {
1602 g_strlcpy(prof->name, dt_colorspaces_get_name(DT_COLORSPACE_VENDOR_MATRIX, ""), sizeof(prof->name));
1604 g->image_profiles = g_list_append(g->image_profiles, prof);
1605 prof->in_pos = ++pos;
1606 break;
1607 }
1608 }
1609
1610 // darktable alternate matrix, if applicable
1611 for(int k = 0; k < dt_alternate_colormatrix_cnt; k++)
1612 {
1614 {
1617 g_strlcpy(prof->name, dt_colorspaces_get_name(DT_COLORSPACE_ALTERNATE_MATRIX, ""), sizeof(prof->name));
1619 g->image_profiles = g_list_append(g->image_profiles, prof);
1620 prof->in_pos = ++pos;
1621 break;
1622 }
1623 }
1624
1625 g->n_image_profiles = pos + 1;
1626
1627 // update the gui
1628 dt_bauhaus_combobox_clear(g->profile_combobox);
1629
1630 for(GList *l = g->image_profiles; l; l = g_list_next(l))
1631 {
1633 dt_bauhaus_combobox_add(g->profile_combobox, prof->name);
1634 }
1635 gboolean input_system_profile_separator_added = FALSE;
1636 gboolean input_file_profile_separator_added = FALSE;
1637 for(GList *l = darktable.color_profiles->profiles; l; l = g_list_next(l))
1638 {
1640 if(prof->in_pos > -1)
1641 {
1642 if(g->n_image_profiles > 0 && !input_system_profile_separator_added)
1643 {
1644 dt_bauhaus_combobox_add_separator(g->profile_combobox);
1645 input_system_profile_separator_added = TRUE;
1646 }
1647 if(prof->type == DT_COLORSPACE_FILE && !input_file_profile_separator_added)
1648 {
1649 dt_bauhaus_combobox_add_separator(g->profile_combobox);
1650 input_file_profile_separator_added = TRUE;
1651 }
1652 if(prof->type == DT_COLORSPACE_FILE)
1653 dt_bauhaus_combobox_add_with_tooltip(g->profile_combobox, prof->name, prof->filename);
1654 else
1655 dt_bauhaus_combobox_add(g->profile_combobox, prof->name);
1656 }
1657 }
1658
1659 // working profile
1660 dt_bauhaus_combobox_clear(g->work_combobox);
1661
1662 gboolean work_file_profile_separator_added = FALSE;
1663 for(GList *l = darktable.color_profiles->profiles; l; l = g_list_next(l))
1664 {
1666 if(prof->work_pos > -1)
1667 {
1668 if(prof->type == DT_COLORSPACE_FILE && !work_file_profile_separator_added)
1669 {
1670 dt_bauhaus_combobox_add_separator(g->work_combobox);
1671 work_file_profile_separator_added = TRUE;
1672 }
1673 if(prof->type == DT_COLORSPACE_FILE)
1674 dt_bauhaus_combobox_add_with_tooltip(g->work_combobox, prof->name, prof->filename);
1675 else
1676 dt_bauhaus_combobox_add(g->work_combobox, prof->name);
1677 }
1678 }
1679}
1680
1681void gui_init(struct dt_iop_module_t *self)
1682{
1683 // pthread_mutex_lock(&darktable.plugin_threadsafe);
1685
1686 g->image_profiles = NULL;
1687
1688 char datadir[PATH_MAX] = { 0 };
1689 char confdir[PATH_MAX] = { 0 };
1690 dt_loc_get_datadir(datadir, sizeof(datadir));
1691 dt_loc_get_user_config_dir(confdir, sizeof(confdir));
1692
1693 self->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING);
1694
1695 g->profile_combobox = dt_bauhaus_combobox_new(darktable.bauhaus, DT_GUI_MODULE(self));
1696 dt_bauhaus_widget_set_label(g->profile_combobox, N_("input profile"));
1697 gtk_box_pack_start(GTK_BOX(self->widget), g->profile_combobox, TRUE, TRUE, 0);
1698
1699 g->work_combobox = dt_bauhaus_combobox_new(darktable.bauhaus, DT_GUI_MODULE(self));
1700 dt_bauhaus_widget_set_label(g->work_combobox, N_("working profile"));
1701 gtk_box_pack_start(GTK_BOX(self->widget), g->work_combobox, TRUE, TRUE, 0);
1702
1703 dt_bauhaus_combobox_set(g->profile_combobox, 0);
1704 {
1705 char *system_profile_dir = g_build_filename(datadir, "color", "in", NULL);
1706 char *user_profile_dir = g_build_filename(confdir, "color", "in", NULL);
1707 char *tooltip = g_strdup_printf(_("ICC profiles in %s or %s"), user_profile_dir, system_profile_dir);
1708 gtk_widget_set_tooltip_text(g->profile_combobox, tooltip);
1709 dt_free(system_profile_dir);
1710 dt_free(user_profile_dir);
1712 }
1713
1714 dt_bauhaus_combobox_set(g->work_combobox, 0);
1715 {
1716 char *system_profile_dir = g_build_filename(datadir, "color", "out", NULL);
1717 char *user_profile_dir = g_build_filename(confdir, "color", "out", NULL);
1718 char *tooltip = g_strdup_printf(_("ICC profiles in %s or %s"), user_profile_dir, system_profile_dir);
1719 gtk_widget_set_tooltip_text(g->work_combobox, tooltip);
1720 dt_free(system_profile_dir);
1721 dt_free(user_profile_dir);
1723 }
1724
1725 g_signal_connect(G_OBJECT(g->profile_combobox), "value-changed", G_CALLBACK(profile_changed), (gpointer)self);
1726 g_signal_connect(G_OBJECT(g->work_combobox), "value-changed", G_CALLBACK(workicc_changed), (gpointer)self);
1727
1728 g->clipping_combobox = dt_bauhaus_combobox_from_params(self, "normalize");
1729 gtk_widget_set_tooltip_text(g->clipping_combobox, _("confine Lab values to gamut of RGB color space"));
1730}
1731
1733{
1735 while(g->image_profiles)
1736 {
1737 dt_free(g->image_profiles->data);
1738 g->image_profiles = g_list_delete_link(g->image_profiles, g->image_profiles);
1739 }
1740
1742}
1743
1744// clang-format off
1745// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
1746// vim: shiftwidth=2 expandtab tabstop=2 cindent
1747// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
1748// clang-format on
static void error(char *msg)
Definition ashift_lsd.c:202
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
void dt_bauhaus_combobox_clear(GtkWidget *widget)
Definition bauhaus.c:2189
int dt_bauhaus_combobox_get(GtkWidget *widget)
Definition bauhaus.c:2347
void dt_bauhaus_combobox_add_separator(GtkWidget *widget)
Definition bauhaus.c:2050
void dt_bauhaus_combobox_set(GtkWidget *widget, const int pos)
Definition bauhaus.c:2301
void dt_bauhaus_widget_set_label(GtkWidget *widget, const char *label)
Definition bauhaus.c:1653
GtkWidget * dt_bauhaus_combobox_new(dt_bauhaus_t *bh, dt_gui_module_t *self)
Definition bauhaus.c:1842
void dt_bauhaus_combobox_add(GtkWidget *widget, const char *text)
Definition bauhaus.c:2016
void dt_bauhaus_combobox_add_with_tooltip(GtkWidget *widget, const char *text, const char *tooltip)
Definition bauhaus.c:2021
int width
Definition bilateral.h:1
int height
Definition bilateral.h:1
static __DT_CLONE_TARGETS__ void normalize(float *const buffer, const size_t width, const size_t height, const float norm)
Definition blurs.c:347
static const dt_aligned_pixel_simd_t const dt_adaptation_t const float p
dt_iop_colorspace_type_t
@ IOP_CS_RGB
@ IOP_CS_LAB
void commit_params(struct dt_iop_module_t *self, dt_iop_params_t *p1, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition colorin.c:1207
static __DT_CLONE_TARGETS__ void process_cmatrix_fastpath_clipping(struct dt_iop_module_t *self, const dt_dev_pixelpipe_iop_t *piece, const void *const ivoid, void *const ovoid, const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out)
Definition colorin.c:809
const char ** description(struct dt_iop_module_t *self)
Definition colorin.c:172
int default_group()
Definition colorin.c:182
static __DT_CLONE_TARGETS__ void process_cmatrix_proper(struct dt_iop_module_t *self, const dt_dev_pixelpipe_iop_t *piece, const void *const ivoid, void *const ovoid, const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out)
Definition colorin.c:861
void reload_defaults(dt_iop_module_t *module)
Definition colorin.c:1519
static dt_colorspaces_color_profile_type_t _resolve_input_profile(const dt_iop_colorin_params_t *p, dt_dev_pixelpipe_t *pipe, dt_iop_colorin_data_t *d)
Definition colorin.c:1125
static void profile_changed(GtkWidget *widget, gpointer user_data)
Definition colorin.c:511
static void apply_blue_mapping(const float *const in, float *const out)
Definition colorin.c:684
void init_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition colorin.c:1422
dt_iop_color_normalize_t
Definition colorin.c:112
@ DT_NORMALIZE_SRGB
Definition colorin.c:114
@ DT_NORMALIZE_ADOBE_RGB
Definition colorin.c:115
@ DT_NORMALIZE_LINEAR_REC2020_RGB
Definition colorin.c:117
@ DT_NORMALIZE_OFF
Definition colorin.c:113
@ DT_NORMALIZE_LINEAR_REC709_RGB
Definition colorin.c:116
const char * name()
Definition colorin.c:167
void output_format(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece, dt_iop_buffer_dsc_t *dsc)
Definition colorin.c:214
#define DT_IOP_COLOR_ICC_LEN
Definition colorin.c:103
void gui_update(struct dt_iop_module_t *self)
Definition colorin.c:1452
void gui_init(struct dt_iop_module_t *self)
Definition colorin.c:1681
static void _reset_input_transforms(dt_iop_colorin_data_t *d)
Definition colorin.c:1074
static dt_iop_colorspace_type_t _colorin_format_cst(dt_iop_module_t *self)
Definition colorin.c:197
#define DT_IOP_COLOR_ICC_LEN_V5
void cleanup_global(dt_iop_module_so_t *module)
Definition colorin.c:492
static void update_profile_list(dt_iop_module_t *self)
Definition colorin.c:1533
int default_colorspace(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
Definition colorin.c:192
void input_format(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece, dt_iop_buffer_dsc_t *dsc)
Definition colorin.c:203
int flags()
Definition colorin.c:187
static __DT_CLONE_TARGETS__ void process_lcms2_proper(struct dt_iop_module_t *self, const dt_dev_pixelpipe_iop_t *piece, const void *const ivoid, void *const ovoid, const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out)
Definition colorin.c:990
void gui_cleanup(struct dt_iop_module_t *self)
Definition colorin.c:1732
static void _resolve_work_profile(dt_colorspaces_color_profile_type_t *work_type, char *work_filename)
Definition colorin.c:222
int process(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const void *const ivoid, void *const ovoid)
Definition colorin.c:1050
void cleanup_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition colorin.c:1428
static __DT_CLONE_TARGETS__ void process_cmatrix_fastpath_simple(struct dt_iop_module_t *self, const dt_dev_pixelpipe_iop_t *piece, const void *const ivoid, void *const ovoid, const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out)
Definition colorin.c:780
static void _select_normalization_profile(const dt_iop_colorin_params_t *p, dt_iop_colorin_data_t *d)
Definition colorin.c:1103
static __DT_CLONE_TARGETS__ void process_cmatrix_bm(struct dt_iop_module_t *self, const dt_dev_pixelpipe_iop_t *piece, const void *const ivoid, void *const ovoid, const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out)
Definition colorin.c:716
static __DT_CLONE_TARGETS__ void process_lcms2_bm(struct dt_iop_module_t *self, const dt_dev_pixelpipe_iop_t *piece, const void *const ivoid, void *const ovoid, const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out)
Definition colorin.c:939
void init_global(dt_iop_module_so_t *module)
Definition colorin.c:482
static void workicc_changed(GtkWidget *widget, gpointer user_data)
Definition colorin.c:545
static void _set_input_profile_metadata(dt_iop_colorin_data_t *d, const dt_iop_colorin_params_t *p, const dt_colorspaces_color_profile_type_t type)
Definition colorin.c:1196
int process_cl(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, cl_mem dev_in, cl_mem dev_out)
Definition colorin.c:598
static void _reset_processing_state(dt_iop_colorin_data_t *d, dt_dev_pixelpipe_iop_t *piece)
Definition colorin.c:1093
int legacy_params(dt_iop_module_t *self, const void *const old_params, const int old_version, void *new_params, const int new_version)
Definition colorin.c:239
#define LUT_SAMPLES
Definition colorin.c:105
static dt_profiled_colormatrix_t dt_profiled_colormatrices[]
static dt_profiled_colormatrix_t dt_vendor_colormatrices[]
static dt_profiled_colormatrix_t dt_alternate_colormatrices[]
static const int dt_vendor_colormatrix_cnt
static const int dt_alternate_colormatrix_cnt
static const int dt_profiled_colormatrix_cnt
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_colorspaces_get_input_profile_from_image(int32_t imgid, dt_colorspaces_color_profile_type_t requested, cmsHPROFILE *output, gboolean *new_profile)
Resolve an embedded/matrix input profile for a given image, honoring the requested type when possible...
int dt_colorspaces_get_matrix_from_output_profile(cmsHPROFILE prof, dt_colormatrix_t matrix, float *lutr, float *lutg, float *lutb, const int lutsize)
cmsHPROFILE dt_colorspaces_create_vendor_profile(const char *makermodel)
int dt_colorspaces_get_matrix_from_input_profile(cmsHPROFILE prof, dt_colormatrix_t matrix, float *lutr, float *lutg, float *lutb, const int lutsize)
cmsHPROFILE dt_colorspaces_create_darktable_profile(const char *makermodel)
void dt_colorspaces_cleanup_profile(cmsHPROFILE p)
dt_colorspaces_color_profile_type_t dt_image_find_best_color_profile(int32_t imgid, cmsHPROFILE *output, gboolean *new_profile)
Best effort to find a suitable (input) color profile for a given image, using embedded ICC or EXIF wh...
const char * dt_colorspaces_get_name(dt_colorspaces_color_profile_type_t type, const char *filename)
cmsHPROFILE dt_colorspaces_create_alternate_profile(const char *makermodel)
gboolean dt_colorspaces_is_profile_equal(const char *fullname, const char *filename)
void dt_colorspaces_transform_rgba_float_row(const cmsHTRANSFORM transform, const float *in, float *out, const int width)
dt_iop_color_intent_t
Definition colorspaces.h:63
@ DT_INTENT_PERCEPTUAL
Definition colorspaces.h:64
#define TYPE_XYZA_FLT
Definition colorspaces.h:53
#define DT_IOP_COLOR_ICC_LEN
Definition colorspaces.h:57
dt_colorspaces_color_profile_type_t
Definition colorspaces.h:81
@ DT_COLORSPACE_ADOBERGB
Definition colorspaces.h:85
@ DT_COLORSPACE_EMBEDDED_MATRIX
Definition colorspaces.h:93
@ DT_COLORSPACE_EMBEDDED_ICC
Definition colorspaces.h:92
@ DT_COLORSPACE_FILE
Definition colorspaces.h:83
@ DT_COLORSPACE_SRGB
Definition colorspaces.h:84
@ DT_COLORSPACE_INFRARED
Definition colorspaces.h:90
@ DT_COLORSPACE_LAB
Definition colorspaces.h:89
@ DT_COLORSPACE_NONE
Definition colorspaces.h:82
@ DT_COLORSPACE_ENHANCED_MATRIX
Definition colorspaces.h:95
@ DT_COLORSPACE_LIN_REC2020
Definition colorspaces.h:87
@ DT_COLORSPACE_STANDARD_MATRIX
Definition colorspaces.h:94
@ DT_COLORSPACE_XYZ
Definition colorspaces.h:88
@ DT_COLORSPACE_VENDOR_MATRIX
Definition colorspaces.h:96
@ DT_COLORSPACE_LIN_REC709
Definition colorspaces.h:86
@ DT_COLORSPACE_ALTERNATE_MATRIX
Definition colorspaces.h:97
@ DT_COLORSPACES_PROFILE_TYPE_INPUT
Definition colorspaces.h:73
@ DT_COLORSPACES_PROFILE_TYPE_WORK
Definition colorspaces.h:74
@ DT_PROFILE_DIRECTION_IN
@ DT_PROFILE_DIRECTION_ANY
static gboolean dt_colorspaces_is_raw_matrix_profile_type(const dt_colorspaces_color_profile_type_t type)
const dt_colormatrix_t dt_aligned_pixel_t out
gboolean dt_image_is_matrix_correction_supported(const dt_image_t *img)
dt_image_pipe_class_t dt_image_pipe_class(const dt_image_t *img)
const char * dt_image_pipe_class_name(const dt_image_pipe_class_t klass)
int type
void dt_control_log(const char *msg,...)
Definition control.c:761
darktable_t darktable
Definition darktable.c:181
void dt_print(dt_debug_thread_t thread, const char *msg,...)
Definition darktable.c:1542
#define dt_free_align(ptr)
Definition darktable.h:481
static void * dt_calloc_align(size_t size)
Definition darktable.h:488
#define __OMP_SIMD__(...)
Definition darktable.h:262
@ DT_DEBUG_OPENCL
Definition darktable.h:722
@ DT_DEBUG_COLORPROFILE
Definition darktable.h:744
#define DT_IS_ALIGNED(x)
Definition darktable.h:371
static void dt_free_gpointer(gpointer ptr)
Definition darktable.h:463
float dt_aligned_pixel_simd_t __attribute__((vector_size(16), aligned(16)))
Enable aggressive floating-point arithmetic optimizations, in denormals handling. Set through user pr...
Definition darktable.h:524
#define dt_free(ptr)
Definition darktable.h:456
#define DT_MODULE_INTROSPECTION(MODVER, PARAMSTYPE)
Definition darktable.h:151
#define __DT_CLONE_TARGETS__
Definition darktable.h:367
#define __OMP_PARALLEL_FOR__(...)
Definition darktable.h:258
#define __OMP_PARALLEL_FOR_SIMD__(...)
Definition darktable.h:259
#define PATH_MAX
Definition darktable.h:1062
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
Definition darktable.h:281
#define dt_dev_add_history_item(dev, module, enable, redraw)
void dt_iop_params_t
Definition dev_history.h:41
#define dt_dev_pixelpipe_rebuild_all(dev)
@ DT_DEV_PIXELPIPE_DISPLAY_MASK
Definition develop.h:118
void dt_loc_get_datadir(char *datadir, size_t bufsize)
void dt_loc_get_user_config_dir(char *configdir, size_t bufsize)
@ TYPE_FLOAT
Definition format.h:46
#define DT_GUI_BOX_SPACING
Definition gtk.h:109
#define DT_GUI_MODULE(x)
const char * tooltip
Definition image.h:251
@ DT_IMAGE_4BAYER
Definition image.h:127
void dt_image_cache_read_release(dt_image_cache_t *cache, const dt_image_t *img)
dt_image_t * dt_image_cache_get(dt_image_cache_t *cache, const int32_t imgid, char mode)
static void dt_iop_image_copy_by_size(float *const __restrict__ out, const float *const __restrict__ in, const size_t width, const size_t height, const size_t ch)
Definition imagebuf.h:87
void dt_iop_request_focus(dt_iop_module_t *module)
Definition imageop.c:2169
const char ** dt_iop_set_description(dt_iop_module_t *module, const char *main_text, const char *purpose, const char *input, const char *process, const char *output)
Definition imageop.c:3141
#define dt_omploop_sfence()
Definition imageop.h:702
#define IOP_GUI_FREE
Definition imageop.h:602
#define dt_iop_fmt_log(module, fmt,...)
Debug helper to trace a module's input-format-driven decisions on the -d pipe channel (DT_DEBUG_PIPE)...
Definition imageop.h:453
@ IOP_FLAGS_ALLOW_TILING
Definition imageop.h:169
@ IOP_FLAGS_UNSAFE_COPY
Definition imageop.h:177
@ IOP_FLAGS_ONE_INSTANCE
Definition imageop.h:172
@ IOP_GROUP_TECHNICAL
Definition imageop.h:143
#define IOP_GUI_ALLOC(module)
Definition imageop.h:599
GtkWidget * dt_bauhaus_combobox_from_params(dt_iop_module_t *self, const char *param)
void *const ovoid
static void dt_iop_estimate_exp(const float *const x, const float *const y, const int num, float *coeff)
static float kernel(const float *x, const float *y)
dt_iop_order_iccprofile_info_t * dt_ioppr_add_profile_info_to_list(struct dt_develop_t *dev, const dt_colorspaces_color_profile_type_t profile_type, const char *profile_filename, const int intent)
dt_iop_order_iccprofile_info_t * dt_ioppr_set_pipe_work_profile_info(struct dt_develop_t *dev, struct dt_dev_pixelpipe_t *pipe, const dt_colorspaces_color_profile_type_t type, const char *filename, const int intent)
dt_iop_order_iccprofile_info_t * dt_ioppr_set_pipe_input_profile_info(struct dt_develop_t *dev, struct dt_dev_pixelpipe_t *pipe, const dt_colorspaces_color_profile_type_t type, const char *filename, const int intent, const dt_colormatrix_t matrix_in)
static const float x
const int t
float *const restrict const size_t k
float *const restrict const size_t const size_t ch
float DT_ALIGNED_ARRAY dt_colormatrix_t[4][4]
Definition matrices.h:33
static void transpose_3xSSE(const dt_colormatrix_t input, dt_colormatrix_t output)
Definition matrices.h:68
static void pack_3xSSE_to_3x4(const dt_colormatrix_t input, float output[12])
Definition matrices.h:149
static void dt_colormatrix_mul(dt_colormatrix_t dst, const dt_colormatrix_t m1, const dt_colormatrix_t m2)
Definition matrices.h:166
float dt_aligned_pixel_t[4]
int dt_opencl_enqueue_kernel_2d(const int dev, const int kernel, const size_t *sizes)
Definition opencl.c:2136
int dt_opencl_create_kernel(const int prog, const char *name)
Definition opencl.c:2030
void * dt_opencl_copy_host_to_device_constant(const int devid, const size_t size, void *host)
Definition opencl.c:2332
int dt_opencl_enqueue_copy_image(const int devid, cl_mem src, cl_mem dst, size_t *orig_src, size_t *orig_dst, size_t *region)
Definition opencl.c:2261
void dt_opencl_free_kernel(const int kernel)
Definition opencl.c:2073
int dt_opencl_set_kernel_arg(const int dev, const int kernel, const int num, const size_t size, const void *arg)
Definition opencl.c:2127
void * dt_opencl_copy_host_to_device(const int devid, void *host, const int width, const int height, const int bpp)
Definition opencl.c:2347
void dt_opencl_release_mem_object(cl_mem mem)
Definition opencl.c:2383
#define ROUNDUPDHT(a, b)
Definition opencl.h:82
#define ROUNDUPDWD(a, b)
Definition opencl.h:81
#define DT_DEBUG_CONTROL_SIGNAL_RAISE(ctlsig, signal,...)
Definition signal.h:347
@ DT_SIGNAL_CONTROL_PROFILE_USER_CHANGED
This signal is raised when a profile is changed by the user 1 uint32_t : the profile type that has ch...
Definition signal.h:242
struct _GtkWidget GtkWidget
Definition splash.h:29
struct dt_gui_gtk_t * gui
Definition darktable.h:775
struct dt_colorspaces_t * color_profiles
Definition darktable.h:788
struct dt_control_signal_t * signals
Definition darktable.h:774
struct dt_bauhaus_t * bauhaus
Definition darktable.h:778
struct dt_image_cache_t * image_cache
Definition darktable.h:777
struct dt_develop_t * develop
Definition darktable.h:770
dt_colorspaces_color_profile_type_t type
struct dt_iop_module_t *void * data
dt_dev_pixelpipe_type_t type
struct dt_develop_t * dev
dt_image_t image_storage
Definition develop.h:259
int32_t reset
Definition gtk.h:172
char camera_makermodel[128]
Definition image.h:300
int32_t flags
Definition image.h:319
float d65_color_matrix[9]
Definition image.h:339
uint8_t * profile
Definition image.h:340
int32_t id
Definition image.h:319
unsigned int channels
Definition format.h:54
dt_iop_buffer_type_t datatype
Definition format.h:56
cmsHTRANSFORM * xform_cam_nrgb
Definition colorin.c:151
cmsHPROFILE nrgb
Definition colorin.c:149
cmsHTRANSFORM * xform_nrgb_Lab
Definition colorin.c:152
cmsHPROFILE input
Definition colorin.c:148
dt_colormatrix_t lmatrix
Definition colorin.c:156
dt_colorspaces_color_profile_type_t type
Definition colorin.c:160
char filename_work[512]
Definition colorin.c:163
cmsHTRANSFORM * xform_cam_Lab
Definition colorin.c:150
dt_colormatrix_t cmatrix
Definition colorin.c:154
dt_colormatrix_t nmatrix
Definition colorin.c:155
dt_colorspaces_color_profile_type_t type_work
Definition colorin.c:161
float lut[3][0x10000]
Definition colorin.c:153
float unbounded_coeffs[3][3]
Definition colorin.c:157
GtkWidget * clipping_combobox
Definition colorin.c:134
GtkWidget * profile_combobox
Definition colorin.c:134
GtkWidget * work_combobox
Definition colorin.c:134
dt_colorspaces_color_profile_type_t type
Definition colorin.c:122
dt_iop_color_intent_t intent
Definition colorin.c:124
dt_colorspaces_color_profile_type_t type_work
Definition colorin.c:128
char filename_work[512]
Definition colorin.c:129
dt_iop_color_normalize_t normalize
Definition colorin.c:125
dt_iop_color_intent_t intent
Definition lightroom.c:221
dt_iop_global_data_t * data
Definition imageop.h:233
GtkWidget * widget
Definition imageop.h:337
struct dt_develop_t * dev
Definition imageop.h:296
dt_iop_gui_data_t * gui_data
Definition imageop.h:311
dt_iop_global_data_t * global_data
Definition imageop.h:314
dt_iop_params_t * params
Definition imageop.h:307
dt_colorspaces_color_profile_type_t type
Definition iop_profile.h:53
char filename[DT_IOP_COLOR_ICC_LEN]
Definition iop_profile.h:54
Region of interest passed through the pixelpipe.
Definition imageop.h:72