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 "system/macros.h"
63#include "common/logging.h"
64#include "system/mem_alloc.h"
65#include "system/simd.h"
66#include "system/openmp.h"
68#include "config.h"
69#endif
70#include "widgets/bauhaus.h"
71#include "common/paths.h" // DT_PATH_MAX
72#include "common/imagebuf.h"
73#include "develop/iop_profile.h"
79#include "caches/image_cache.h"
80#include "common/opencl.h"
82#include "develop/develop.h"
83
84#ifdef HAVE_OPENJPEG
85#endif
86#ifdef HAVE_LIBAVIF
87#endif
88#ifdef HAVE_LIBHEIF
89#endif
91#include "develop/imageop_gui.h"
92#include "iop/iop_api.h"
93
94#include <assert.h>
95#include <math.h>
96#include <stdlib.h>
97#include <string.h>
98#include <strings.h>
99
101#include "control/signal.h"
102
103// max iccprofile file name length
104// must be in synch with dt_colorspaces_color_profile_t
105#define DT_IOP_COLOR_ICC_LEN 512
106
107
109
110static void update_profile_list(dt_iop_module_t *self);
111
113{
114 DT_NORMALIZE_OFF, //$DESCRIPTION: "off"
115 DT_NORMALIZE_SRGB, //$DESCRIPTION: "sRGB"
116 DT_NORMALIZE_ADOBE_RGB, //$DESCRIPTION: "Adobe RGB (compatible)"
117 DT_NORMALIZE_LINEAR_REC709_RGB, //$DESCRIPTION: "linear Rec709 RGB"
118 DT_NORMALIZE_LINEAR_REC2020_RGB //$DESCRIPTION: "linear Rec2020 RGB"
120
122{
123 dt_colorspaces_color_profile_type_t type; // $DEFAULT: DT_COLORSPACE_ENHANCED_MATRIX
125 dt_iop_color_intent_t intent; // $DEFAULT: DT_INTENT_PERCEPTUAL
126 dt_iop_color_normalize_t normalize; // $DEFAULT: DT_NORMALIZE_OFF $DESCRIPTION: "gamut clipping"
128 // working color profile
129 dt_colorspaces_color_profile_type_t type_work; // $DEFAULT: DT_COLORSPACE_LIN_REC2020
132
139
145
147{
148 /* This module converts the image's INPUT profile to the pipeline's WORKING profile.
149 * Both are RGB. The `_Lab` names these fields used to carry were left over from when the
150 * pipe was Lab: nothing here has produced Lab since, except in the one case where the
151 * user picks DT_COLORSPACE_LAB as the input profile itself, which _colorin_format_cst()
152 * reports through output_format().
153 *
154 * The optional gamut-clipping detour -- "gamut clipping" set to anything but
155 * DT_NORMALIZE_OFF, which is not the default -- goes input -> clip primaries, clamps to
156 * [0,1] there, then clip -> work. That is a shape colorprofiles/conversion.c expresses, so
157 * it is one endpoint on the request rather than a second set of fields here. */
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 if(dt_colorspaces_profile_exists(DT_PROFILE_ROLE_WORKING, *work_type, work_filename)) return;
225
227 "[colorin] profile `%s' not suitable for work profile. it has been replaced by linear Rec2020 RGB!\n",
228 dt_colorspaces_get_name(*work_type, work_filename));
229 *work_type = DT_COLORSPACE_LIN_REC2020;
230 work_filename[0] = '\0';
231}
232
233int legacy_params(dt_iop_module_t *self, const void *const old_params, const int old_version,
234 void *new_params, const int new_version)
235{
236#define DT_IOP_COLOR_ICC_LEN_V5 100
237
238 if(old_version == 1 && new_version == 7)
239 {
240 typedef struct dt_iop_colorin_params_v1_t
241 {
245
248 memset(new, 0, sizeof(*new));
249
250 if(!strcmp(old->iccprofile, "eprofile"))
251 new->type = DT_COLORSPACE_EMBEDDED_ICC;
252 else if(!strcmp(old->iccprofile, "ematrix"))
254 else if(!strcmp(old->iccprofile, "matrix_in_to_work"))
256 else if(!strcmp(old->iccprofile, "darktable"))
258 else if(!strcmp(old->iccprofile, "vendor"))
259 new->type = DT_COLORSPACE_VENDOR_MATRIX;
260 else if(!strcmp(old->iccprofile, "alternate"))
262 else if(!strcmp(old->iccprofile, "sRGB"))
263 new->type = DT_COLORSPACE_SRGB;
264 else if(!strcmp(old->iccprofile, "adobergb"))
265 new->type = DT_COLORSPACE_ADOBERGB;
266 else if(!strcmp(old->iccprofile, "linear_rec709_rgb") || !strcmp(old->iccprofile, "linear_rgb"))
267 new->type = DT_COLORSPACE_LIN_REC709;
268 else if(!strcmp(old->iccprofile, "linear_rec2020_rgb"))
269 new->type = DT_COLORSPACE_LIN_REC2020;
270 else if(!strcmp(old->iccprofile, "infrared"))
271 new->type = DT_COLORSPACE_INFRARED;
272 else if(!strcmp(old->iccprofile, "XYZ"))
273 new->type = DT_COLORSPACE_XYZ;
274 else if(!strcmp(old->iccprofile, "Lab"))
275 new->type = DT_COLORSPACE_LAB;
276 else
277 {
278 new->type = DT_COLORSPACE_FILE;
279 g_strlcpy(new->filename, old->iccprofile, sizeof(new->filename));
280 }
281
282 new->intent = old->intent;
283 new->normalize = 0;
284 new->blue_mapping = 1;
285 new->type_work = DT_COLORSPACE_LIN_REC709;
286 new->filename_work[0] = '\0';
287 return 0;
288 }
289 if(old_version == 2 && new_version == 7)
290 {
291 typedef struct dt_iop_colorin_params_v2_t
292 {
293 char iccprofile[DT_IOP_COLOR_ICC_LEN_V5];
295 int normalize;
296 } dt_iop_colorin_params_v2_t;
297
298 const dt_iop_colorin_params_v2_t *old = (dt_iop_colorin_params_v2_t *)old_params;
300 memset(new, 0, sizeof(*new));
301
302 if(!strcmp(old->iccprofile, "eprofile"))
303 new->type = DT_COLORSPACE_EMBEDDED_ICC;
304 else if(!strcmp(old->iccprofile, "ematrix"))
306 else if(!strcmp(old->iccprofile, "matrix_in_to_work"))
308 else if(!strcmp(old->iccprofile, "darktable"))
310 else if(!strcmp(old->iccprofile, "vendor"))
311 new->type = DT_COLORSPACE_VENDOR_MATRIX;
312 else if(!strcmp(old->iccprofile, "alternate"))
314 else if(!strcmp(old->iccprofile, "sRGB"))
315 new->type = DT_COLORSPACE_SRGB;
316 else if(!strcmp(old->iccprofile, "adobergb"))
317 new->type = DT_COLORSPACE_ADOBERGB;
318 else if(!strcmp(old->iccprofile, "linear_rec709_rgb") || !strcmp(old->iccprofile, "linear_rgb"))
319 new->type = DT_COLORSPACE_LIN_REC709;
320 else if(!strcmp(old->iccprofile, "linear_rec2020_rgb"))
321 new->type = DT_COLORSPACE_LIN_REC2020;
322 else if(!strcmp(old->iccprofile, "infrared"))
323 new->type = DT_COLORSPACE_INFRARED;
324 else if(!strcmp(old->iccprofile, "XYZ"))
325 new->type = DT_COLORSPACE_XYZ;
326 else if(!strcmp(old->iccprofile, "Lab"))
327 new->type = DT_COLORSPACE_LAB;
328 else
329 {
330 new->type = DT_COLORSPACE_FILE;
331 g_strlcpy(new->filename, old->iccprofile, sizeof(new->filename));
332 }
333
334 new->intent = old->intent;
335 new->normalize = old->normalize;
336 new->blue_mapping = 1;
337 new->type_work = DT_COLORSPACE_LIN_REC709;
338 new->filename_work[0] = '\0';
339 return 0;
340 }
341 if(old_version == 3 && new_version == 7)
342 {
343 typedef struct dt_iop_colorin_params_v3_t
344 {
345 char iccprofile[DT_IOP_COLOR_ICC_LEN_V5];
347 int normalize;
348 int blue_mapping;
349 } dt_iop_colorin_params_v3_t;
350
351 const dt_iop_colorin_params_v3_t *old = (dt_iop_colorin_params_v3_t *)old_params;
353 memset(new, 0, sizeof(*new));
354
355 if(!strcmp(old->iccprofile, "eprofile"))
356 new->type = DT_COLORSPACE_EMBEDDED_ICC;
357 else if(!strcmp(old->iccprofile, "ematrix"))
359 else if(!strcmp(old->iccprofile, "matrix_in_to_work"))
361 else if(!strcmp(old->iccprofile, "darktable"))
363 else if(!strcmp(old->iccprofile, "vendor"))
364 new->type = DT_COLORSPACE_VENDOR_MATRIX;
365 else if(!strcmp(old->iccprofile, "alternate"))
367 else if(!strcmp(old->iccprofile, "sRGB"))
368 new->type = DT_COLORSPACE_SRGB;
369 else if(!strcmp(old->iccprofile, "adobergb"))
370 new->type = DT_COLORSPACE_ADOBERGB;
371 else if(!strcmp(old->iccprofile, "linear_rec709_rgb") || !strcmp(old->iccprofile, "linear_rgb"))
372 new->type = DT_COLORSPACE_LIN_REC709;
373 else if(!strcmp(old->iccprofile, "linear_rec2020_rgb"))
374 new->type = DT_COLORSPACE_LIN_REC2020;
375 else if(!strcmp(old->iccprofile, "infrared"))
376 new->type = DT_COLORSPACE_INFRARED;
377 else if(!strcmp(old->iccprofile, "XYZ"))
378 new->type = DT_COLORSPACE_XYZ;
379 else if(!strcmp(old->iccprofile, "Lab"))
380 new->type = DT_COLORSPACE_LAB;
381 else
382 {
383 new->type = DT_COLORSPACE_FILE;
384 g_strlcpy(new->filename, old->iccprofile, sizeof(new->filename));
385 }
386
387 new->intent = old->intent;
388 new->normalize = old->normalize;
389 new->blue_mapping = old->blue_mapping;
390 new->type_work = DT_COLORSPACE_LIN_REC709;
391 new->filename_work[0] = '\0';
392
393 return 0;
394 }
395 if(old_version == 4 && new_version == 7)
396 {
397 typedef struct dt_iop_colorin_params_v4_t
398 {
400 char filename[DT_IOP_COLOR_ICC_LEN_V5];
402 int normalize;
403 int blue_mapping;
404 } dt_iop_colorin_params_v4_t;
405
406 const dt_iop_colorin_params_v4_t *old = (dt_iop_colorin_params_v4_t *)old_params;
408 memset(new, 0, sizeof(*new));
409
410 new->type = old->type;
411 g_strlcpy(new->filename, old->filename, sizeof(new->filename));
412 new->intent = old->intent;
413 new->normalize = old->normalize;
414 new->blue_mapping = old->blue_mapping;
415 new->type_work = DT_COLORSPACE_LIN_REC709;
416 new->filename_work[0] = '\0';
417
418 return 0;
419 }
420 if(old_version == 5 && new_version == 7)
421 {
422 typedef struct dt_iop_colorin_params_v5_t
423 {
425 char filename[DT_IOP_COLOR_ICC_LEN_V5];
427 int normalize;
428 int blue_mapping;
429 // working color profile
431 char filename_work[DT_IOP_COLOR_ICC_LEN_V5];
432 } dt_iop_colorin_params_v5_t;
433
434 const dt_iop_colorin_params_v5_t *old = (dt_iop_colorin_params_v5_t *)old_params;
436 memset(new, 0, sizeof(*new));
437
438 new->type = old->type;
439 g_strlcpy(new->filename, old->filename, sizeof(new->filename));
440 new->intent = old->intent;
441 new->normalize = old->normalize;
442 new->blue_mapping = old->blue_mapping;
443 new->type_work = old->type_work;
444 g_strlcpy(new->filename_work, old->filename_work, sizeof(new->filename_work));
445 _resolve_work_profile(&new->type_work, new->filename_work);
446
447 return 0;
448 }
449 if(old_version == 6 && new_version == 7)
450 {
451 // The structure is equal to to v7 (current) but a new version is introduced to convert invalid
452 // working profile choice to the default, linear Rec2020.
453 typedef struct dt_iop_colorin_params_v6_t
454 {
456 char filename[DT_IOP_COLOR_ICC_LEN];
459 int blue_mapping;
460 // working color profile
462 char filename_work[DT_IOP_COLOR_ICC_LEN];
463 } dt_iop_colorin_params_v6_t;
464
465 const dt_iop_colorin_params_v6_t *old = (dt_iop_colorin_params_v6_t *)old_params;
467 memcpy(new, old, sizeof(*new));
468 _resolve_work_profile(&new->type_work, new->filename_work);
469
470 return 0;
471 }
472 return 1;
473#undef DT_IOP_COLOR_ICC_LEN_V5
474}
475
477{
478 const int program = 2; // basic.cl, from programs.conf
481 module->data = gd;
482 gd->kernel_colorin_unbound = dt_opencl_create_kernel(program, "colorin_unbound");
483 gd->kernel_colorin_clipping = dt_opencl_create_kernel(program, "colorin_clipping");
484}
485
493
494#if 0
495static void intent_changed (GtkWidget *widget, gpointer user_data)
496{
497 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
498 if(dt_gui_widgets_suppressed()) return;
501 dt_dev_add_history_item(self->dev, self, TRUE, TRUE);
502}
503#endif
504
505static void profile_changed(GtkWidget *widget, gpointer user_data)
506{
507 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
508 if(dt_gui_widgets_suppressed()) return;
512 int pos = dt_bauhaus_combobox_get(widget);
513
514 /* The combo lists this image's own derived profiles first (g->image_profiles, which
515 * belongs to this module and is NOT the module-wide list), then the registered input
516 * profiles. */
517 if(pos < g->n_image_profiles)
518 {
519 /* The combo lists these first and in order, so the row IS the list position. */
520 const dt_colorprofile_desc_t *pp = (const dt_colorprofile_desc_t *)g_list_nth_data(g->image_profiles, pos);
521 if(!IS_NULL_PTR(pp))
522 {
523 p->type = pp->type;
524 memcpy(p->filename, pp->filename, sizeof(p->filename));
525 dt_dev_add_history_item(self->dev, self, TRUE, TRUE);
526
528 return;
529 }
530 }
531 else
532 {
534 if(dt_colorspaces_profile_at(DT_PROFILE_ROLE_INPUT, pos - g->n_image_profiles, &desc))
535 {
536 p->type = desc.type;
537 memcpy(p->filename, desc.filename, sizeof(p->filename));
538 dt_dev_add_history_item(self->dev, self, TRUE, TRUE);
539
541 return;
542 }
543 }
544 // should really never happen.
545 dt_print(DT_DEBUG_COLORPROFILE, "[colorin] color profile %s seems to have disappeared!\n",
546 dt_colorspaces_get_name(p->type, p->filename));
547}
548
549static void workicc_changed(GtkWidget *widget, gpointer user_data)
550{
551 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
553 if(dt_gui_widgets_suppressed()) return;
554
556
558 char filename_work[DT_IOP_COLOR_ICC_LEN];
559
560 const int pos = dt_bauhaus_combobox_get(widget);
561 dt_colorprofile_desc_t work_desc;
563 {
564 type_work = work_desc.type;
565 g_strlcpy(filename_work, work_desc.filename, sizeof(filename_work));
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_colorspaces_add_profile(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 }
582 dt_dev_add_history_item(self->dev, self, TRUE, TRUE);
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 /* The kernel needs the numbers the conversion reduced to. It cannot call back into
606 * colorprofiles, so this is the one place the module reads them -- to upload them, not to
607 * run the conversion here. */
608 dt_colormatrix_t first_leg, second_leg = { { 0.0f } };
609 if(!dt_colorspaces_conversion_matrix(d->conversion, first_leg)) return FALSE;
610 const gboolean clipping = dt_colorspaces_conversion_has_clipping(d->conversion);
611 if(clipping) dt_colorspaces_conversion_clip_matrix(d->conversion, second_leg);
612
613 const int kernel = clipping ? gd->kernel_colorin_clipping : gd->kernel_colorin_unbound;
614 float cmat[12], lmat[12];
615 pack_3xSSE_to_3x4(first_leg, cmat);
616 pack_3xSSE_to_3x4(second_leg, lmat);
617
618 cl_int err = -999;
619 const int blue_mapping = d->blue_mapping && dt_image_is_matrix_correction_supported(&pipe->dev->image_storage);
620 const int devid = pipe->devid;
621 const int width = roi_in->width;
622 const int height = roi_in->height;
623
624 if(d->type == DT_COLORSPACE_LAB)
625 {
626 size_t origin[] = { 0, 0, 0 };
627 size_t region[] = { roi_in->width, roi_in->height, 1 };
628 err = dt_opencl_enqueue_copy_image(devid, dev_in, dev_out, origin, origin, region);
629 if(err != CL_SUCCESS) goto error;
630 return TRUE;
631 }
632
633 size_t sizes[] = { ROUNDUPDWD(width, devid), ROUNDUPDHT(height, devid), 1 };
634 dev_m = dt_opencl_copy_host_to_device_constant(devid, sizeof(float) * 12, cmat);
635 if(IS_NULL_PTR(dev_m)) goto error;
636 dev_l = dt_opencl_copy_host_to_device_constant(devid, sizeof(float) * 12, lmat);
637 if(IS_NULL_PTR(dev_l)) goto error;
638 const float *const curve_r = dt_colorspaces_conversion_source_curve(d->conversion, 0);
639 const float *const curve_g = dt_colorspaces_conversion_source_curve(d->conversion, 1);
640 const float *const curve_b = dt_colorspaces_conversion_source_curve(d->conversion, 2);
641 const float *const coeffs = dt_colorspaces_conversion_source_coeffs(d->conversion);
642 if(IS_NULL_PTR(curve_r) || IS_NULL_PTR(curve_g) || IS_NULL_PTR(curve_b) || IS_NULL_PTR(coeffs)) goto error;
643
644 dev_r = dt_opencl_copy_host_to_device(devid, (void *)curve_r, 256, 256, sizeof(float));
645 if(IS_NULL_PTR(dev_r)) goto error;
646 dev_g = dt_opencl_copy_host_to_device(devid, (void *)curve_g, 256, 256, sizeof(float));
647 if(IS_NULL_PTR(dev_g)) goto error;
648 dev_b = dt_opencl_copy_host_to_device(devid, (void *)curve_b, 256, 256, sizeof(float));
649 if(IS_NULL_PTR(dev_b)) goto error;
650 dev_coeffs = dt_opencl_copy_host_to_device_constant(devid, sizeof(float) * 3 * 3, (void *)coeffs);
651 if(IS_NULL_PTR(dev_coeffs)) goto error;
652 dt_opencl_set_kernel_arg(devid, kernel, 0, sizeof(cl_mem), (void *)&dev_in);
653 dt_opencl_set_kernel_arg(devid, kernel, 1, sizeof(cl_mem), (void *)&dev_out);
654 dt_opencl_set_kernel_arg(devid, kernel, 2, sizeof(int), (void *)&width);
655 dt_opencl_set_kernel_arg(devid, kernel, 3, sizeof(int), (void *)&height);
656 dt_opencl_set_kernel_arg(devid, kernel, 4, sizeof(cl_mem), (void *)&dev_m);
657 dt_opencl_set_kernel_arg(devid, kernel, 5, sizeof(cl_mem), (void *)&dev_l);
658 dt_opencl_set_kernel_arg(devid, kernel, 6, sizeof(cl_mem), (void *)&dev_r);
659 dt_opencl_set_kernel_arg(devid, kernel, 7, sizeof(cl_mem), (void *)&dev_g);
660 dt_opencl_set_kernel_arg(devid, kernel, 8, sizeof(cl_mem), (void *)&dev_b);
661 dt_opencl_set_kernel_arg(devid, kernel, 9, sizeof(cl_int), (void *)&blue_mapping);
662 dt_opencl_set_kernel_arg(devid, kernel, 10, sizeof(cl_mem), (void *)&dev_coeffs);
663 err = dt_opencl_enqueue_kernel_2d(devid, kernel, sizes);
664 if(err != CL_SUCCESS) goto error;
671
672 return TRUE;
673
674error:
681 dt_print(DT_DEBUG_OPENCL, "[opencl_colorin] couldn't enqueue kernel! %d\n", err);
682 return FALSE;
683}
684#endif
685
686/* A legacy per-pixel tweak: it lifts green out of deep blues to work around a highlight
687 * artefact of the old Lab pipeline. Nothing turns it on for a new edit -- only legacy_params
688 * sets it, for history written by darktable v1 and v2 -- and it is why this module still has
689 * two process variants instead of one. It runs on the values just before the colour
690 * conversion proper, which colorprofiles/conversion.c takes as a hook. */
691static void apply_blue_mapping(const float *const in, float *const out)
692{
693 out[0] = in[0];
694 out[1] = in[1];
695 out[2] = in[2];
696
697 const float YY = out[0] + out[1] + out[2];
698 if(YY > 0.0f)
699 {
700 const float zz = out[2] / YY;
701 const float bound_z = 0.5f, bound_Y = 0.5f;
702 const float amount = 0.11f;
703 if(zz > bound_z)
704 {
705 const float t = (zz - bound_z) / (1.0f - bound_z) * fminf(1.0, YY / bound_Y);
706 out[1] += t * amount;
707 out[2] -= t * amount;
708 }
709 }
710}
711
712int process(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const void *const ivoid,
713 void *const ovoid)
714{
715 const dt_iop_roi_t *const roi_out = &piece->roi_out;
716 const dt_iop_colorin_data_t *const d = (dt_iop_colorin_data_t *)piece->data;
717
718 /* Lab in means Lab out: the pipe already carries it, and there is nothing to convert. A
719 * NULL conversion means commit_params could not build one and disabled the piece. */
720 if(d->type == DT_COLORSPACE_LAB || IS_NULL_PTR(d->conversion))
721 {
722 dt_iop_image_copy_by_size(ovoid, ivoid, roi_out->width, roi_out->height, 4);
723 }
724 else
725 {
726 const gboolean blue_mapping
728 dt_colorspaces_apply_conversion_hooked(d->conversion, (const float *)ivoid, (float *)ovoid,
729 roi_out->width, roi_out->height,
730 blue_mapping ? apply_blue_mapping : NULL);
731 }
732
733 if(pipe->mask_display & DT_DEV_PIXELPIPE_DISPLAY_MASK) dt_iop_alpha_copy(ivoid, ovoid, roi_out->width, roi_out->height);
734 return 0;
735}
736
740{
741 d->type = type;
743 g_strlcpy(d->filename, p->filename, sizeof(d->filename));
744 else
745 d->filename[0] = '\0';
746}
747
748/* The gamut-clipping detour bounds the conversion to one of four sets of primaries before it
749 * reaches the working space. Off by default. */
762
769
771{
774
775 d->type_work = p->type_work;
776 g_strlcpy(d->filename_work, p->filename_work, sizeof(d->filename_work));
777 d->blue_mapping = p->blue_mapping;
778
779 /* Detach before freeing, and never re-read the published field below: both crashes in
780 * issues #1212/#1216 caught this function using a d->conversion that no longer held what
781 * this same call had stored moments earlier. Build through a local, publish once at the
782 * end -- the commit is then immune to a mid-commit clobber of the field, and the final
783 * store overwrites whatever landed there. */
784 dt_colorspaces_conversion_t *stale_conversion = d->conversion;
785 d->conversion = NULL;
786 dt_colorspaces_free_conversion(&stale_conversion);
787 piece->process_cl_ready = 1;
788
789 // commit and resolve working profile first, it is the target output profile of this module
790 dt_iop_order_iccprofile_info_t *work_profile_info
791 = dt_ioppr_set_pipe_work_profile_info(self->dev, pipe, d->type_work, d->filename_work, DT_INTENT_PERCEPTUAL);
792 if(work_profile_info)
793 {
794 d->type_work = work_profile_info->type;
795 g_strlcpy(d->filename_work, work_profile_info->filename, sizeof(d->filename_work));
796 }
797
798 if(p->type == DT_COLORSPACE_LAB)
799 {
801 piece->enabled = 0;
802 return;
803 }
804 piece->enabled = 1;
805
806 /* The six image-derived types are not in the profile list and cannot be named by identity:
807 * their matrices come from THIS image's camera data. imageio resolves them into a container
808 * that carries its own ownership answer, so this module never holds a raw handle next to a
809 * "did I create it" flag -- which is what the old cascade did, across five early returns. */
810 struct dt_colorspaces_color_profile_t *image_profile = NULL;
812 const dt_colorspaces_color_profile_type_t requested_type = p->type;
813
815 {
816 image_profile = dt_image_get_input_profile(pipe->dev->image_storage.id, type,
818 if(IS_NULL_PTR(image_profile)) type = requested_type;
819 }
820
821 if(requested_type == DT_COLORSPACE_STANDARD_MATRIX
824 {
825 dt_print(DT_DEBUG_COLORPROFILE, "[colorin] `%s' color matrix not found!\n", pipe->dev->image_storage.camera_makermodel);
826 dt_control_log(_("`%s' color matrix not found!"), pipe->dev->image_storage.camera_makermodel);
827 }
828
830 dt_colorspaces_endpoint_t clip = { .type = clip_type, .filename = "",
831 .role = DT_PROFILE_ROLE_INPUT };
832 /* WORK, not ANY. DT_COLORSPACE_SRGB is registered twice -- the v4 parametric-curve profile,
833 * valid only as an input profile, and the v2 point-TRC profile, which is the one the
834 * working-profile combo actually lists. The lookup filters on the direction bits before
835 * matching the type and returns the first hit in registration order, and the v4 entry is
836 * registered first, so ANY resolved the working profile to a variant the user was never
837 * offered. */
838 dt_colorspaces_endpoint_t target = { .type = d->type_work, .filename = d->filename_work,
839 .role = DT_PROFILE_ROLE_WORKING };
840 dt_colorspaces_endpoint_t source = { .type = type, .filename = p->filename,
841 .role = DT_PROFILE_ROLE_INPUT,
842 .resolved = image_profile };
843
844 /* This module's kernel decodes the INPUT profile's curves before the matrix and has no
845 * stage for the output side, so a non-linear working profile goes through lcms2. */
847
849 = dt_colorspaces_prepare_conversion(&source, &target,
850 clip_type == DT_COLORSPACE_NONE ? NULL : &clip,
851 NULL, p->intent, flags);
852
853 if(IS_NULL_PTR(conversion))
854 {
855 /* Whatever the user asked for cannot be rendered. Linear Rec709 is the fallback that has
856 * always been here; the clipping detour goes with the profile that needed it. */
857 if(p->type == DT_COLORSPACE_FILE)
859 "[colorin] unsupported input profile `%s' has been replaced by linear Rec709 RGB!\n",
860 p->filename);
861 else
862 dt_print(DT_DEBUG_COLORPROFILE, "[colorin] unsupported input profile has been replaced by linear Rec709 RGB!\n");
863 dt_control_log(_("unsupported input profile has been replaced by linear Rec709 RGB!"));
864
866 source.type = type;
867 source.filename = "";
868 source.resolved = NULL;
869 conversion = dt_colorspaces_prepare_conversion(&source, &target, NULL, NULL, p->intent, flags);
870 }
871
873
874 dt_iop_fmt_log(self, "commit: class=%s matrix_supported=%d requested_input=%d resolved_input=%d blue_mapping=%d",
877 requested_type, type, d->blue_mapping);
878
879 if(IS_NULL_PTR(conversion))
880 {
881 dt_print(DT_DEBUG_COLORPROFILE, "[colorin] input profile could not be generated!\n");
882 dt_control_log(_("input profile could not be generated!"));
884 piece->enabled = 0;
885 return;
886 }
887
888 // Only the vectorised branch has a kernel; the lcms2 one is host-only.
889 if(!dt_colorspaces_conversion_is_matrix(conversion)) piece->process_cl_ready = 0;
890
891 /* The pipe records what space it is being handed, which is the input profile's own
892 * RGB -> XYZ, uncomposed -- not the conversion this module runs. */
893 dt_colormatrix_t input_matrix_for_pipe = { { NAN } };
894 dt_colorspaces_conversion_source_matrix(conversion, input_matrix_for_pipe);
895
896 dt_ioppr_set_pipe_input_profile_info(self->dev, pipe, d->type, d->filename, p->intent,
897 input_matrix_for_pipe);
898
899 /* An lcms2 transform does not retain the profiles it was built from, and the matrix branch
900 * copied out everything it needed, so the container's job ended when the conversion was
901 * built. */
903
904 d->conversion = conversion; // single publication, after the conversion is complete
905}
906
908{
910 piece->data_size = sizeof(dt_iop_colorin_data_t);
911}
912
914{
915 /* init_pipe() may have failed to allocate, and cleanup runs regardless. */
916 if(IS_NULL_PTR(piece->data)) return;
918 dt_colorspaces_free_conversion(&d->conversion);
919
920 dt_free_align(piece->data);
921 piece->data = NULL;
922}
923
924void gui_update(struct dt_iop_module_t *self)
925{
928
929 dt_bauhaus_combobox_set(g->clipping_combobox, p->normalize);
930
931 // working profile
932 int idx = dt_colorspaces_profile_index(DT_PROFILE_ROLE_WORKING, p->type_work, p->filename_work);
933
934 if(idx < 0)
935 {
936 idx = 0;
937 dt_print(DT_DEBUG_COLORPROFILE, "[colorin] could not find requested working profile `%s'!\n",
938 dt_colorspaces_get_name(p->type_work, p->filename_work));
939 }
940 dt_bauhaus_combobox_set(g->work_combobox, idx);
941
942 int image_row = 0;
943 for(const GList *prof = g->image_profiles; prof; prof = g_list_next(prof), image_row++)
944 {
945 const dt_colorprofile_desc_t *pp = (const dt_colorprofile_desc_t *)prof->data;
946 if(pp->type == p->type
948 {
949 dt_bauhaus_combobox_set(g->profile_combobox, image_row);
950 return;
951 }
952 }
953
954 const int in_idx = dt_colorspaces_profile_index(DT_PROFILE_ROLE_INPUT, p->type, p->filename);
955 if(in_idx > -1)
956 {
957 dt_bauhaus_combobox_set(g->profile_combobox, in_idx + g->n_image_profiles);
958 return;
959 }
960
961 // Error happened, otherwise we would have returned earlier
962 dt_bauhaus_combobox_set(g->profile_combobox, 0);
963
964 const gboolean matrix_supported = dt_image_is_matrix_correction_supported(&self->dev->image_storage);
966 && !(dt_colorspaces_is_raw_matrix_profile_type(p->type) && !matrix_supported))
967 {
968 dt_print(DT_DEBUG_COLORPROFILE, "[colorin] could not find requested profile `%s'!\n",
969 dt_colorspaces_get_name(p->type, p->filename));
970
971 dt_control_log(_("The color profile `%s' referenced as input profile has not been found."), dt_colorspaces_get_name(p->type, p->filename));
972 }
973}
974
975// FIXME: update the gui when we add/remove the eprofile or ematrix
977{
978 module->default_enabled = 1;
979 module->hide_enable_button = 1;
980
981 dt_iop_colorin_params_t *d = module->default_params;
982 gboolean new_profile;
983 d->type = dt_image_find_best_color_profile(module->dev->image_storage.id, NULL, &new_profile);
984 dt_iop_fmt_log(module, "reload_defaults: class=%s matrix_supported=%d -> default_input_profile=%d new_profile=%d",
986 dt_image_is_matrix_correction_supported(&module->dev->image_storage), d->type, new_profile);
987 update_profile_list(module);
988}
989
991{
993
994 if(IS_NULL_PTR(g)) return;
995
996 // clear and refill the image profile list
997 g_list_free_full(g->image_profiles, dt_free_gpointer);
998 g->image_profiles = NULL;
999 g->n_image_profiles = 0;
1000
1001 int pos = -1;
1002 // some file formats like jpeg can have an embedded color profile
1003 // currently we only support jpeg, j2k, tiff and png
1004 // dt_image_cache_get() returns NULL for an id it cannot load, and this runs from
1005 // reload_defaults() on a GUI reset -- Sentry 140151023: SIGSEGV on the very next line.
1006 const dt_image_t *cimg = dt_image_cache_get(self->dev->image_storage.id, 'r');
1007 if(!IS_NULL_PTR(cimg) && cimg->profile)
1008 {
1010 g_strlcpy(prof->name, dt_colorspaces_get_name(DT_COLORSPACE_EMBEDDED_ICC, ""), sizeof(prof->name));
1012 g->image_profiles = g_list_append(g->image_profiles, prof);
1013 pos++;
1014 }
1016 // use the matrix embedded in some DNGs and EXRs
1017 if(!isnan(self->dev->image_storage.d65_color_matrix[0]))
1018 {
1020 g_strlcpy(prof->name, dt_colorspaces_get_name(DT_COLORSPACE_EMBEDDED_MATRIX, ""), sizeof(prof->name));
1022 g->image_profiles = g_list_append(g->image_profiles, prof);
1023 pos++;
1024 }
1025
1027 && !(self->dev->image_storage.flags & DT_IMAGE_4BAYER))
1028 {
1030 g_strlcpy(prof->name, dt_colorspaces_get_name(DT_COLORSPACE_STANDARD_MATRIX, ""), sizeof(prof->name));
1032 g->image_profiles = g_list_append(g->image_profiles, prof);
1033 pos++;
1034 }
1035
1036 // darktable built-in, if applicable
1037 for(int k = 0; k < dt_profiled_colormatrix_cnt; k++)
1038 {
1040 {
1042 g_strlcpy(prof->name, dt_colorspaces_get_name(DT_COLORSPACE_ENHANCED_MATRIX, ""), sizeof(prof->name));
1044 g->image_profiles = g_list_append(g->image_profiles, prof);
1045 pos++;
1046 break;
1047 }
1048 }
1049
1050 // darktable vendor matrix, if applicable
1051 for(int k = 0; k < dt_vendor_colormatrix_cnt; k++)
1052 {
1054 {
1056 g_strlcpy(prof->name, dt_colorspaces_get_name(DT_COLORSPACE_VENDOR_MATRIX, ""), sizeof(prof->name));
1058 g->image_profiles = g_list_append(g->image_profiles, prof);
1059 pos++;
1060 break;
1061 }
1062 }
1063
1064 // darktable alternate matrix, if applicable
1065 for(int k = 0; k < dt_alternate_colormatrix_cnt; k++)
1066 {
1068 {
1070 g_strlcpy(prof->name, dt_colorspaces_get_name(DT_COLORSPACE_ALTERNATE_MATRIX, ""), sizeof(prof->name));
1072 g->image_profiles = g_list_append(g->image_profiles, prof);
1073 pos++;
1074 break;
1075 }
1076 }
1077
1078 g->n_image_profiles = pos + 1;
1079
1080 // update the gui
1081 dt_bauhaus_combobox_clear(g->profile_combobox);
1082
1083 for(GList *l = g->image_profiles; l; l = g_list_next(l))
1084 {
1085 const dt_colorprofile_desc_t *prof = (const dt_colorprofile_desc_t *)l->data;
1086 dt_bauhaus_combobox_add(g->profile_combobox, prof->name);
1087 }
1088 gboolean input_system_profile_separator_added = FALSE;
1089 gboolean input_file_profile_separator_added = FALSE;
1090 dt_colorprofile_desc_t *in_profiles = NULL;
1091 const size_t n_in_profiles = dt_colorspaces_enumerate_profiles(DT_PROFILE_ROLE_INPUT, &in_profiles);
1092 for(size_t k = 0; k < n_in_profiles; k++)
1093 {
1094 const dt_colorprofile_desc_t *const prof = &in_profiles[k];
1095
1096 if(g->n_image_profiles > 0 && !input_system_profile_separator_added)
1097 {
1098 dt_bauhaus_combobox_add_separator(g->profile_combobox);
1099 input_system_profile_separator_added = TRUE;
1100 }
1101 if(prof->type == DT_COLORSPACE_FILE && !input_file_profile_separator_added)
1102 {
1103 dt_bauhaus_combobox_add_separator(g->profile_combobox);
1104 input_file_profile_separator_added = TRUE;
1105 }
1106 if(prof->type == DT_COLORSPACE_FILE)
1107 dt_bauhaus_combobox_add_with_tooltip(g->profile_combobox, prof->name, prof->filename);
1108 else
1109 dt_bauhaus_combobox_add(g->profile_combobox, prof->name);
1110 }
1111 dt_free_align(in_profiles);
1112
1113 // working profile
1114 dt_bauhaus_combobox_clear(g->work_combobox);
1115
1116 gboolean work_file_profile_separator_added = FALSE;
1117 dt_colorprofile_desc_t *work_profiles = NULL;
1118 const size_t n_work_profiles = dt_colorspaces_enumerate_profiles(DT_PROFILE_ROLE_WORKING, &work_profiles);
1119 for(size_t k = 0; k < n_work_profiles; k++)
1120 {
1121 const dt_colorprofile_desc_t *const prof = &work_profiles[k];
1122 if(prof->type == DT_COLORSPACE_FILE && !work_file_profile_separator_added)
1123 {
1124 dt_bauhaus_combobox_add_separator(g->work_combobox);
1125 work_file_profile_separator_added = TRUE;
1126 }
1127 if(prof->type == DT_COLORSPACE_FILE)
1128 dt_bauhaus_combobox_add_with_tooltip(g->work_combobox, prof->name, prof->filename);
1129 else
1130 dt_bauhaus_combobox_add(g->work_combobox, prof->name);
1131 }
1132 dt_free_align(work_profiles);
1133}
1134
1135void gui_init(struct dt_iop_module_t *self)
1136{
1138
1139 g->image_profiles = NULL;
1140
1141 char datadir[DT_PATH_MAX] = { 0 };
1142 char confdir[DT_PATH_MAX] = { 0 };
1143 dt_loc_get_datadir(datadir, sizeof(datadir));
1144 dt_loc_get_user_config_dir(confdir, sizeof(confdir));
1145
1146 self->gui->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING);
1147
1148 g->profile_combobox = dt_bauhaus_combobox_new(dt_bauhaus_get_global(), DT_GUI_MODULE(self));
1149 dt_bauhaus_widget_set_label(g->profile_combobox, N_("input profile"));
1150 gtk_box_pack_start(GTK_BOX(self->gui->widget), g->profile_combobox, TRUE, TRUE, 0);
1151
1153 dt_bauhaus_widget_set_label(g->work_combobox, N_("working profile"));
1154 gtk_box_pack_start(GTK_BOX(self->gui->widget), g->work_combobox, TRUE, TRUE, 0);
1155
1156 dt_bauhaus_combobox_set(g->profile_combobox, 0);
1157 {
1158 char *system_profile_dir = g_build_filename(datadir, "color", "in", NULL);
1159 char *user_profile_dir = g_build_filename(confdir, "color", "in", NULL);
1160 char *tooltip = g_strdup_printf(_("ICC profiles in %s or %s"), user_profile_dir, system_profile_dir);
1161 gtk_widget_set_tooltip_text(g->profile_combobox, tooltip);
1162 dt_free(system_profile_dir);
1163 dt_free(user_profile_dir);
1165 }
1166
1167 dt_bauhaus_combobox_set(g->work_combobox, 0);
1168 {
1169 char *system_profile_dir = g_build_filename(datadir, "color", "out", NULL);
1170 char *user_profile_dir = g_build_filename(confdir, "color", "out", NULL);
1171 char *tooltip = g_strdup_printf(_("ICC profiles in %s or %s"), user_profile_dir, system_profile_dir);
1172 gtk_widget_set_tooltip_text(g->work_combobox, tooltip);
1173 dt_free(system_profile_dir);
1174 dt_free(user_profile_dir);
1176 }
1177
1178 g_signal_connect(G_OBJECT(g->profile_combobox), "value-changed", G_CALLBACK(profile_changed), (gpointer)self);
1179 g_signal_connect(G_OBJECT(g->work_combobox), "value-changed", G_CALLBACK(workicc_changed), (gpointer)self);
1180
1181 g->clipping_combobox = dt_bauhaus_combobox_from_params(self, "normalize");
1182 gtk_widget_set_tooltip_text(g->clipping_combobox, _("confine Lab values to gamut of RGB color space"));
1183}
1184
1186{
1188 while(g->image_profiles)
1189 {
1190 dt_free(g->image_profiles->data);
1191 g->image_profiles = g_list_delete_link(g->image_profiles, g->image_profiles);
1192 }
1193
1195}
1196
1197// clang-format off
1198// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
1199// vim: shiftwidth=2 expandtab tabstop=2 cindent
1200// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
1201// 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:1997
int dt_bauhaus_combobox_get(GtkWidget *widget)
Definition bauhaus.c:2136
void dt_bauhaus_combobox_add_separator(GtkWidget *widget)
Definition bauhaus.c:1858
void dt_bauhaus_combobox_set(GtkWidget *widget, const int pos)
Definition bauhaus.c:2090
void dt_bauhaus_widget_set_label(GtkWidget *widget, const char *label)
Definition bauhaus.c:1504
GtkWidget * dt_bauhaus_combobox_new(dt_bauhaus_t *bh, dt_gui_module_t *self)
Definition bauhaus.c:1698
void dt_bauhaus_combobox_add(GtkWidget *widget, const char *text)
Definition bauhaus.c:1824
void dt_bauhaus_combobox_add_with_tooltip(GtkWidget *widget, const char *text, const char *tooltip)
Definition bauhaus.c:1829
static __DT_CLONE_TARGETS__ void normalize(float *const buffer, const size_t width, const size_t height, const float norm)
Definition blurs.c:351
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:770
const char ** description(struct dt_iop_module_t *self)
Definition colorin.c:172
int default_group()
Definition colorin.c:182
static gboolean _is_image_derived(const dt_colorspaces_color_profile_type_t type)
Definition colorin.c:763
void reload_defaults(dt_iop_module_t *module)
Definition colorin.c:976
static void profile_changed(GtkWidget *widget, gpointer user_data)
Definition colorin.c:505
static void apply_blue_mapping(const float *const in, float *const out)
Definition colorin.c:691
void init_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition colorin.c:907
dt_iop_color_normalize_t
Definition colorin.c:113
@ DT_NORMALIZE_SRGB
Definition colorin.c:115
@ DT_NORMALIZE_ADOBE_RGB
Definition colorin.c:116
@ DT_NORMALIZE_LINEAR_REC2020_RGB
Definition colorin.c:118
@ DT_NORMALIZE_OFF
Definition colorin.c:114
@ DT_NORMALIZE_LINEAR_REC709_RGB
Definition colorin.c:117
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:105
void gui_update(struct dt_iop_module_t *self)
Definition colorin.c:924
void gui_init(struct dt_iop_module_t *self)
Definition colorin.c:1135
static dt_colorspaces_color_profile_type_t _clipping_profile_type(const dt_iop_colorin_params_t *p)
Definition colorin.c:750
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:486
static void update_profile_list(dt_iop_module_t *self)
Definition colorin.c:990
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
void gui_cleanup(struct dt_iop_module_t *self)
Definition colorin.c:1185
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:712
void cleanup_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition colorin.c:913
void init_global(dt_iop_module_so_t *module)
Definition colorin.c:476
static void workicc_changed(GtkWidget *widget, gpointer user_data)
Definition colorin.c:549
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:737
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
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:233
static const dt_profiled_colormatrix_t dt_alternate_colormatrices[]
static const int dt_vendor_colormatrix_cnt
static const int dt_alternate_colormatrix_cnt
static const dt_profiled_colormatrix_t dt_vendor_colormatrices[]
static const dt_profiled_colormatrix_t dt_profiled_colormatrices[]
static const int dt_profiled_colormatrix_cnt
dt_iop_order_iccprofile_info_t * dt_colorspaces_add_profile(const dt_colorspaces_color_profile_type_t profile_type, const char *profile_filename, const int intent)
Find-or-build the derived matrix/LUT data for a profile identity, memoised.
const int t
void dt_colorspaces_free_image_profile(struct dt_colorspaces_color_profile_t *profile)
Release a profile container owned by an image, closing the LCMS2 handle inside it if and only if the ...
size_t dt_colorspaces_enumerate_profiles(const dt_colorspaces_profile_role_t role, dt_colorprofile_desc_t **out)
Ordered snapshot of every profile registered for one role.
gboolean dt_colorspaces_profile_exists(const dt_colorspaces_profile_role_t role, const dt_colorspaces_color_profile_type_t type, const char *const filename)
Is this identity registered for this direction?
int dt_colorspaces_profile_index(const dt_colorspaces_profile_role_t role, const dt_colorspaces_color_profile_type_t type, const char *const filename)
Combo position of (type, filename) within direction.
const char * dt_colorspaces_get_name(dt_colorspaces_color_profile_type_t type, const char *filename)
Printable name for a profile identity, without touching the profile list.
gboolean dt_colorspaces_profile_at(const dt_colorspaces_profile_role_t role, const int index, dt_colorprofile_desc_t *const out)
Identity of the profile at index within direction.
gboolean dt_colorspaces_is_profile_equal(const char *fullname, const char *filename)
Do these two names refer to the same profile file?
The colour-profile module's API: which profiles exist, and how to apply one.
struct _GtkWidget GtkWidget
GtkWidget, opaque, spelled exactly as GTK spells it.
Definition colorspaces.h:98
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)
void dt_control_log(const char *msg,...)
Definition control.c:824
const float * dt_colorspaces_conversion_source_coeffs(const dt_colorspaces_conversion_t *const conversion)
The 3x3 power-law fits extrapolating the source curves past white, as one flat array of 9 floats in c...
Definition conversion.c:818
void dt_colorspaces_apply_conversion_hooked(const dt_colorspaces_conversion_t *const conversion, const float *const in, float *const out, const size_t width, const size_t height, const dt_colorspaces_conversion_hook_t hook)
dt_colorspaces_apply_conversion() with a per-pixel hook. See dt_colorspaces_conversion_hook_t for why...
Definition conversion.c:744
gboolean dt_colorspaces_conversion_has_clipping(const dt_colorspaces_conversion_t *const conversion)
Whether the conversion has a gamut-clipping stage, i.e. whether a clip endpoint was given AND survive...
Definition conversion.c:775
gboolean dt_colorspaces_conversion_matrix(const dt_colorspaces_conversion_t *const conversion, dt_colormatrix_t matrix)
The composed source-to-target matrix, row-major.
Definition conversion.c:780
gboolean dt_colorspaces_conversion_is_matrix(const dt_colorspaces_conversion_t *const conversion)
Whether the conversion reduced to matrices and curves, and can therefore be run by a device kernel at...
Definition conversion.c:770
gboolean dt_colorspaces_conversion_source_matrix(const dt_colorspaces_conversion_t *const conversion, dt_colormatrix_t matrix)
The SOURCE profile's own RGB -> XYZ (D50) matrix, before composition.
Definition conversion.c:788
const float * dt_colorspaces_conversion_source_curve(const dt_colorspaces_conversion_t *const conversion, const int channel)
One channel of the source decoding curves, DT_CONVERSION_LUT_SAMPLES entries.
Definition conversion.c:804
void dt_colorspaces_free_conversion(dt_colorspaces_conversion_t **conversion)
Release a conversion and NULL the caller's pointer.
Definition conversion.c:508
gboolean dt_colorspaces_conversion_clip_matrix(const dt_colorspaces_conversion_t *const conversion, dt_colormatrix_t matrix)
The clip-to-target matrix, the second leg of a clipping conversion.
Definition conversion.c:796
dt_colorspaces_conversion_t * dt_colorspaces_prepare_conversion(const dt_colorspaces_endpoint_t *const from, const dt_colorspaces_endpoint_t *const to, const dt_colorspaces_endpoint_t *const clip, const dt_colorspaces_endpoint_t *const proof, const dt_iop_color_intent_t intent, const dt_colorspaces_conversion_flags_t flags)
Build a conversion from from to to. The expensive call; do it once.
Definition conversion.c:216
A PREPARED CONVERSION: everything needed to turn pixels in one colour space into pixels in another,...
dt_colorspaces_conversion_flags_t
What the caller wants, and what the caller can consume.
Definition conversion.h:118
@ DT_CONVERSION_SOURCE_CURVES
The caller can apply the SOURCE profile's decoding curves before the matrix. Without this,...
Definition conversion.h:125
struct dt_bauhaus_t * dt_bauhaus_get_global(void)
Definition darktable.c:646
#define dt_dev_add_history_item(dev, module, enable, redraw)
void dt_iop_params_t
Definition dev_history.h:43
#define dt_dev_pixelpipe_rebuild_all(dev)
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)
@ DT_DEV_PIXELPIPE_DISPLAY_MASK
Definition develop.h:123
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:56
#define DT_GUI_MODULE(x)
const char * tooltip
Definition image.h:310
@ DT_IMAGE_4BAYER
Definition image.h:140
dt_image_t * dt_image_cache_get(const int32_t imgid, char mode)
void dt_image_cache_read_release(const dt_image_t *img)
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:91
struct dt_colorspaces_color_profile_t * dt_image_get_input_profile(const int32_t imgid, const dt_colorspaces_color_profile_type_t requested, const char *camera_makermodel, dt_colorspaces_color_profile_type_t *resolved)
Resolve an image's own input profile into an opaque container, whatever kind it is.
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_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:1893
void dt_iop_request_focus(dt_iop_module_t *module)
Move darkroom focus to module, or clear it with NULL.
#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:535
@ IOP_FLAGS_ALLOW_TILING
Definition imageop.h:188
@ IOP_FLAGS_UNSAFE_COPY
Definition imageop.h:196
@ IOP_FLAGS_ONE_INSTANCE
Definition imageop.h:191
@ IOP_GROUP_TECHNICAL
Definition imageop.h:162
GtkWidget * dt_bauhaus_combobox_from_params(dt_iop_module_t *self, const char *param)
#define IOP_GUI_FREE
Definition imageop_gui.h:96
static dt_iop_gui_data_t * dt_iop_gui_data(const struct dt_iop_module_t *m)
The module's GUI data blob, NULL-safe for headless callers: IOP process() implementations read it for...
Definition imageop_gui.h:81
#define IOP_GUI_ALLOC(module)
Definition imageop_gui.h:93
void *const ovoid
static float kernel(const float *x, const float *y)
_lib_location_type_t type
Definition location.c:1
@ DT_DEBUG_OPENCL
Definition logging.h:57
@ DT_DEBUG_COLORPROFILE
Definition logging.h:79
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.
float *const restrict const size_t k
#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 macros.h:96
float DT_ALIGNED_ARRAY dt_colormatrix_t[4][4]
Definition matrices.h:34
static void pack_3xSSE_to_3x4(const dt_colormatrix_t input, float output[12])
Definition matrices.h:150
#define dt_free_align(ptr)
Release memory from dt_alloc_align() and set ptr to NULL.
Definition mem_alloc.h:214
static void * dt_calloc_align(size_t size)
dt_alloc_align() followed by a zero fill.
Definition mem_alloc.h:225
static void dt_free_gpointer(gpointer ptr)
g_free() one pointer, with the signature GDestroyNotify wants.
Definition mem_alloc.h:184
#define dt_free(ptr)
g_free() ptr and set it to NULL, skipping both if it is already NULL.
Definition mem_alloc.h:171
uint32_t width
Definition mipmap_cache.c:0
uint32_t height
Definition mipmap_cache.c:1
#define DT_MODULE_INTROSPECTION(MODVER, PARAMSTYPE)
DT_MODULE() for a module whose params struct is introspected.
int dt_opencl_enqueue_kernel_2d(const int dev, const int kernel, const size_t *sizes)
Definition opencl.c:2554
int dt_opencl_create_kernel(const int prog, const char *name)
Definition opencl.c:2448
void * dt_opencl_copy_host_to_device_constant(const int devid, const size_t size, void *host)
Definition opencl.c:2750
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:2679
void dt_opencl_free_kernel(const int kernel)
Definition opencl.c:2491
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:2545
void * dt_opencl_copy_host_to_device(const int devid, void *host, const int width, const int height, const int bpp)
Definition opencl.c:2765
void dt_opencl_release_mem_object(cl_mem mem)
Definition opencl.c:2805
#define ROUNDUPDHT(a, b)
Definition opencl.h:86
#define ROUNDUPDWD(a, b)
Definition opencl.h:85
#define DT_PATH_MAX
Buffer size for a filesystem path anywhere in Ansel.
Definition paths.h:57
dt_iop_color_intent_t
ICC rendering intent, as stored in iop params and in conf.
@ DT_INTENT_PERCEPTUAL
#define DT_IOP_COLOR_ICC_LEN
Size of every ICC filename buffer that crosses a module boundary.
dt_colorspaces_color_profile_type_t
@ DT_COLORSPACE_ADOBERGB
@ DT_COLORSPACE_EMBEDDED_MATRIX
@ DT_COLORSPACE_EMBEDDED_ICC
Image-derived profiles: enum 9..14, NOT registered in the list.
@ DT_COLORSPACE_FILE
A user ICC file on disk; the only type whose filename is meaningful.
@ DT_COLORSPACE_SRGB
sRGB – registered TWICE, and the two entries are not interchangeable.
@ DT_COLORSPACE_INFRARED
@ DT_COLORSPACE_LAB
@ DT_COLORSPACE_NONE
No profile / "take it from the image settings". Never matches a list entry.
@ DT_COLORSPACE_ENHANCED_MATRIX
@ DT_COLORSPACE_LIN_REC2020
@ DT_COLORSPACE_STANDARD_MATRIX
@ DT_COLORSPACE_XYZ
@ DT_COLORSPACE_VENDOR_MATRIX
@ DT_COLORSPACE_LIN_REC709
@ DT_COLORSPACE_ALTERNATE_MATRIX
@ DT_COLORSPACES_PROFILE_TYPE_INPUT
@ DT_COLORSPACES_PROFILE_TYPE_WORK
@ DT_PROFILE_ROLE_INPUT
Listed in the input-profile combo (colorin).
@ DT_PROFILE_ROLE_WORKING
Listed in the working-profile combo (colorin).
static gboolean dt_colorspaces_is_raw_matrix_profile_type(const dt_colorspaces_color_profile_type_t type)
Is this one of the four camera-matrix profile kinds?
#define DT_DEBUG_CONTROL_SIGNAL_RAISE(ctlsig, signal,...)
Definition signal.h:386
struct dt_control_signal_t * dt_control_signal_get_global(void)
Definition darktable.c:616
@ 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:245
A profile's public identity: what the GUI displays and stores, and nothing else.
dt_colorspaces_color_profile_type_t type
what to store in params / conf
char name[512]
translated, display-ready
char filename[DT_IOP_COLOR_ICC_LEN]
"" unless type == DT_COLORSPACE_FILE
One registered profile: its identity, its LCMS handle, and where it sits in each combo box.
dt_colorspaces_color_profile_type_t type
filename is only used for type DT_COLORSPACE_FILE
One end of a conversion: a profile, named either by identity or by handing over one this module alrea...
Definition conversion.h:93
const struct dt_colorspaces_color_profile_t * resolved
An already-resolved, image-owned profile, or NULL to resolve type / filename from the registered list...
Definition conversion.h:105
dt_colorspaces_color_profile_type_t type
Profile identity. Ignored when resolved is set, except for tracing.
Definition conversion.h:95
const char * filename
ICC file name, or "" / NULL for a built-in. Ignored when resolved is set.
Definition conversion.h:97
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:225
char camera_makermodel[128]
Definition image.h:382
int32_t flags
Definition image.h:401
float d65_color_matrix[9]
Definition image.h:421
uint8_t * profile
Definition image.h:422
int32_t id
Definition image.h:401
unsigned int channels
Definition format.h:83
dt_iop_buffer_type_t datatype
Definition format.h:85
dt_colorspaces_conversion_t * conversion
Definition colorin.c:158
dt_colorspaces_color_profile_type_t type
Definition colorin.c:160
char filename_work[512]
Definition colorin.c:163
dt_colorspaces_color_profile_type_t type_work
Definition colorin.c:161
GtkWidget * clipping_combobox
Definition colorin.c:135
GtkWidget * profile_combobox
Definition colorin.c:135
GtkWidget * work_combobox
Definition colorin.c:135
dt_colorspaces_color_profile_type_t type
Definition colorin.c:123
dt_iop_color_intent_t intent
Definition colorin.c:125
dt_colorspaces_color_profile_type_t type_work
Definition colorin.c:129
char filename_work[512]
Definition colorin.c:130
dt_iop_color_normalize_t normalize
Definition colorin.c:126
dt_iop_color_intent_t intent
Definition lightroom.c:222
GtkWidget * widget
Definition imageop_gui.h:47
dt_iop_global_data_t * data
Definition imageop.h:238
struct dt_iop_module_gui_t * gui
Definition imageop.h:346
struct dt_develop_t * dev
Definition imageop.h:311
dt_iop_global_data_t * global_data
Definition imageop.h:337
dt_iop_params_t * params
Definition imageop.h:333
A profile reduced to the arithmetic the pixel loop can run: two matrices and six tone-curve LUTs,...
dt_colorspaces_color_profile_type_t type
Profile identity, half of the memo key. DT_COLORSPACE_NONE means "unset" and makes every apply functi...
dt_colormatrix_t matrix_out
XYZ (D50) -> RGB, row-major; the inverse of matrix_in.
char filename[DT_IOP_COLOR_ICC_LEN]
ICC file name, the other half of the memo key; "" for every built-in. Compared with strcmp,...
dt_colormatrix_t matrix_in
RGB -> XYZ (D50), row-major. matrix_in[1][*] is the luminance row. NaN in [0][0] marks the whole prof...
Region of interest passed through the pixelpipe.
Definition format.h:49
int width
Definition format.h:50
int height
Definition format.h:50
Telling the user something happened.
gboolean dt_gui_widgets_suppressed(void)
#define DT_GUI_BOX_SPACING