Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
colorbalance.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2013-2016 Roman Lebedev.
4 Copyright (C) 2013-2014, 2016-2019 Tobias Ellinghaus.
5 Copyright (C) 2013-2014 Ulrich Pegelow.
6 Copyright (C) 2015 Pedro Côrte-Real.
7 Copyright (C) 2016 johannes hanika.
8 Copyright (C) 2017 Heiko Bauke.
9 Copyright (C) 2018-2020, 2022-2023, 2025-2026 Aurélien PIERRE.
10 Copyright (C) 2018-2019 Edgardo Hoszowski.
11 Copyright (C) 2018 Matthieu Moy.
12 Copyright (C) 2018 Maurizio Paglia.
13 Copyright (C) 2018-2022 Pascal Obry.
14 Copyright (C) 2018 rawfiner.
15 Copyright (C) 2019 Andreas Schneider.
16 Copyright (C) 2019-2020, 2022 Diederik Ter Rahe.
17 Copyright (C) 2019 Diederik ter Rahe.
18 Copyright (C) 2019 luzpaz.
19 Copyright (C) 2019 msdm.
20 Copyright (C) 2020 Aldric Renaudin.
21 Copyright (C) 2020-2021 Chris Elston.
22 Copyright (C) 2020 Marco.
23 Copyright (C) 2020-2021 Ralf Brown.
24 Copyright (C) 2021 Dan Torop.
25 Copyright (C) 2021 Hubert Kowalski.
26 Copyright (C) 2021 Miloš Komarčević.
27 Copyright (C) 2022 Hanno Schwalm.
28 Copyright (C) 2022 Martin Bařinka.
29 Copyright (C) 2022 Nicolas Auffray.
30 Copyright (C) 2022 Philipp Lutz.
31 Copyright (C) 2022 Victor Forsiuk.
32 Copyright (C) 2023 Luca Zulberti.
33
34 darktable is free software: you can redistribute it and/or modify
35 it under the terms of the GNU General Public License as published by
36 the Free Software Foundation, either version 3 of the License, or
37 (at your option) any later version.
38
39 darktable is distributed in the hope that it will be useful,
40 but WITHOUT ANY WARRANTY; without even the implied warranty of
41 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
42 GNU General Public License for more details.
43
44 You should have received a copy of the GNU General Public License
45 along with darktable. If not, see <http://www.gnu.org/licenses/>.
46*/
47/*
48http://www.youtube.com/watch?v=JVoUgR6bhBc
49 */
50
51#ifdef HAVE_CONFIG_H
52#include "common/darktable.h"
53#include "config.h"
54#endif
55// our includes go first:
56#include "bauhaus/bauhaus.h"
57#include "common/exif.h"
59#include "common/opencl.h"
60#include "develop/blend.h"
61#include "develop/imageop.h"
63#include "develop/imageop_gui.h"
65
66#include "gui/gtk.h"
67#include "gui/presets.h"
69#include "iop/iop_api.h"
70
71//#include <gtk/gtk.h>
72#include <stdlib.h>
73
74// these are not in a state to be useful. but they look nice. too bad i couldn't map the enhanced mode with
75// negative values to the wheels :(
76//#define SHOW_COLOR_WHEELS
77
79
80/*
81
82 Meaning of the values:
83 0 --> 100%
84 -1 --> 0%
85 1 --> 200%
86 */
87
89{
90 LIFT_GAMMA_GAIN = 0, // $DESCRIPTION: "lift, gamma, gain (ProPhoto RGB)"
91 SLOPE_OFFSET_POWER = 1, // $DESCRIPTION: "slope, offset, power (ProPhoto RGB)"
92 LEGACY = 2 // $DESCRIPTION: "lift, gamma, gain (sRGB)"
94
103
111
118
125
127{
128 dt_iop_colorbalance_mode_t mode; // $DEFAULT: SLOPE_OFFSET_POWER
129 float lift[CHANNEL_SIZE], gamma[CHANNEL_SIZE], gain[CHANNEL_SIZE]; // $MIN: 0.0 $MAX: 2.0 $DEFAULT: 1.0
130 float saturation; // $MIN: 0.0 $MAX: 2.0 $DEFAULT: 1.0 $DESCRIPTION: "input saturation"
131 float contrast; // $MIN: 0.01 $MAX: 1.99 $DEFAULT: 1.0
132 float grey; // $MIN: 0.1 $MAX: 100.0 $DEFAULT: 18.0 $DESCRIPTION: "contrast fulcrum"
133 float saturation_out; // $MIN: 0.0 $MAX: 2.0 $DEFAULT: 1.0 $DESCRIPTION: "output saturation"
135
160
167
174
175
176const char *name()
177{
178 return _("color balance (legacy)");
179}
180
181const char *aliases()
182{
183 return _("lift gamma gain|cdl|color grading|contrast|saturation|hue");
184}
185
186const char **description(struct dt_iop_module_t *self)
187{
188 return dt_iop_set_description(self, _("affect color, brightness and contrast"),
189 _("corrective or creative"),
190 _("linear, Lab, scene-referred"),
191 _("non-linear, RGB"),
192 _("non-linear, Lab, scene-referred"));
193}
194
199
201{
202 return IOP_GROUP_COLOR;
203}
204
206{
207 return IOP_CS_LAB;
208}
209
212{
213 default_input_format(self, pipe, piece, dsc);
214 dsc->channels = 4;
215 dsc->datatype = TYPE_FLOAT;
216}
217
218int legacy_params(dt_iop_module_t *self, const void *const old_params, const int old_version, void *new_params,
219 const int new_version)
220{
221 if(old_version == 1 && new_version == 3)
222 {
223 typedef struct dt_iop_colorbalance_params_v1_t
224 {
225 float lift[CHANNEL_SIZE], gamma[CHANNEL_SIZE], gain[CHANNEL_SIZE];
226 } dt_iop_colorbalance_params_v1_t;
227
228 dt_iop_colorbalance_params_v1_t *o = (dt_iop_colorbalance_params_v1_t *)old_params;
231
232 *n = *d; // start with a fresh copy of default parameters
233
234 for(int i = 0; i < CHANNEL_SIZE; i++)
235 {
236 n->lift[i] = o->lift[i];
237 n->gamma[i] = o->gamma[i];
238 n->gain[i] = o->gain[i];
239 }
240 n->mode = LEGACY;
241 return 0;
242 }
243
244 if(old_version == 2 && new_version == 3)
245 {
246 typedef struct dt_iop_colorbalance_params_v2_t
247 {
249 float lift[CHANNEL_SIZE], gamma[CHANNEL_SIZE], gain[CHANNEL_SIZE];
250 float saturation, contrast, grey;
251 } dt_iop_colorbalance_params_v2_t;
252
253 dt_iop_colorbalance_params_v2_t *o = (dt_iop_colorbalance_params_v2_t *)old_params;
256
257 *n = *d; // start with a fresh copy of default parameters
258
259 for(int i = 0; i < CHANNEL_SIZE; i++)
260 {
261 n->lift[i] = o->lift[i];
262 n->gamma[i] = o->gamma[i];
263 n->gain[i] = o->gain[i];
264 }
265 n->mode = o->mode;
266 n->contrast = o->contrast;
267 n->saturation = o->saturation;
268 n->contrast = o->contrast;
269 n->grey = o->grey;
270 return 0;
271 }
272 return 1;
273}
274
275// taken from denoiseprofile.c
276static void add_preset(dt_iop_module_so_t *self, const char *name,
277 const char *pi, const int version, const char *bpi, const int blendop_version)
278{
279 int len, blen;
280 uint8_t *p = dt_exif_xmp_decode(pi, strlen(pi), &len);
281 uint8_t *bp = dt_exif_xmp_decode(bpi, strlen(bpi), &blen);
282 if(blendop_version != dt_develop_blend_version())
283 {
284 // update to current blendop params format
285 void *bp_new = malloc(sizeof(dt_develop_blend_params_t));
286
287 if(dt_develop_blend_legacy_params_from_so(self, bp, blendop_version, bp_new, dt_develop_blend_version(),
288 blen) == 0)
289 {
290 dt_free(bp);
291 bp = bp_new;
292 blen = sizeof(dt_develop_blend_params_t);
293 }
294 else
295 {
296 dt_free(bp);
297 dt_free(bp_new);
298 bp = NULL;
299 }
300 }
301
302 if(p && bp)
303 dt_gui_presets_add_with_blendop(name, self->op, version, p, len, bp, 1);
304 dt_free(bp);
305 dt_free(p);
306}
307
309{
310 // these blobs were exported as dtstyle and copied from there:
311 add_preset(self, _("split-toning teal-orange (2nd instance)"),
312 "gz02eJxjZGBg8HhYZX99cYN9kkCDfdCOOnsGhgZ7ruvN9m8CK+yXFNTaz5w50z5PqBku9u9/PVjNv//9jqfP+NgDAHs0HIc=", 3,
313 "gz05eJxjZWBgYGUAgRNODFDAzszAxMBQ5cwI4Tow4AUNdkBsD8E3gGwue9x8uB6q8s+c8bEF8Z9Y9Nnt2f3bbluCN03tg/EBIBckVg==", 8);
314 add_preset(self, _("split-toning teal-orange (1st instance)"),
315 "gz02eJxjZACBBvugHXX2E3fU219f3GAP4n/TqLFvfd1oL8HZaH/2jI/9prn1cLHUtDSwGgaGCY7//tfbAwBRixpm", 3,
316 "gz04eJxjZWBgYGUAgRNODFDApgwiq5wZIVyHD4E7bBnwggZ7CIYBRiBbBA8fXT1l/P5DX21i+pnA/Pfv8uw6OzzIMq9I5rgtSH//4wii1AMASbIlcw==", 8);
317
318 add_preset(self, _("generic film"),
319 "gz02eJxjZACBBntN5gb7op/19u5AGsSX3dFgr+jYaL+vttb+0NcM+1Pnq+3XyFTZr/rYBJZPS0sD0hMcQDQA29kXSQ==", 3,
320 "gz11eJxjYGBgkGAAgRNODGiAEV0AJ2iwh+CRxQcA5qIZBA==", 8);
321
322 add_preset(self, _("similar to Kodak Portra"),
323 "gz02eJxjZACBBnsQfh3YYK8VU28P43s8rLKP6W+yP/Q1w36deyMYLymoBcsZGxcDaQGHs2d87AGnphWu", 3,
324 "gz11eJxjYGBgkGAAgRNODGiAEV0AJ2iwh+CRxQcA5qIZBA==", 8);
325
326 add_preset(self, _("similar to Kodak Ektar"),
327 "gz02eJxjZACBBvvrixvsrXIb7IN21NnD+CA2iOa6nmxvZFxsX15ebp+e1gaWNwbyGRgEHNLS0uwBE7wWhw==", 3,
328 "gz11eJxjYGBgkGAAgRNODGiAEV0AJ2iwh+CRxQcA5qIZBA==", 8);
329
330 add_preset(self, _("similar to Kodachrome"),
331 "gz02eJxjZACBBvvrixvsrXIb7IN21NnD+CA2iG59HWhvZFxsX15ebp+e1gaWT0tLA9ICDrNmRtoDACjOF7c=", 3,
332 "gz11eJxjYGBgkGAAgRNODGiAEV0AJ2iwh+CRxQcA5qIZBA==", 8);
333}
334
335static inline float CDL(float x, float slope, float offset, float power)
336{
337 float out;
338 out = slope * x + offset;
339 out = (out <= 0.0f) ? 0.0f : powf(out, power);
340 return out;
341}
342
343// see http://www.brucelindbloom.com/Eqn_RGB_XYZ_Matrix.html for the transformation matrices
345int process(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const void *const ivoid,
346 void *const ovoid)
347{
348 const dt_iop_roi_t *const roi_in = &piece->roi_in;
349 const dt_iop_roi_t *const roi_out = &piece->roi_out;
351 const int ch = 4;
352
353 // these are RGB values!
354 const dt_aligned_pixel_t gain = { d->gain[CHANNEL_RED] * d->gain[CHANNEL_FACTOR],
355 d->gain[CHANNEL_GREEN] * d->gain[CHANNEL_FACTOR],
356 d->gain[CHANNEL_BLUE] * d->gain[CHANNEL_FACTOR] };
357 const float contrast = (d->contrast != 0.0f) ? 1.0f / d->contrast : 1000000.0f,
358 grey = d->grey / 100.0f;
359
360 // For neutral parameters, skip the computations doing x^1 or (x-a)*1 + a to save time
361 const int run_contrast = (d->contrast == 1.0f) ? 0 : 1;
362 const int run_saturation = (d->saturation == 1.0f) ? 0: 1;
363 const int run_saturation_out = (d->saturation_out == 1.0f) ? 0: 1;
364
365 switch (d->mode)
366 {
367 case LEGACY:
368 {
369 // these are RGB values!
370 const dt_aligned_pixel_t lift = { 2.0 - (d->lift[CHANNEL_RED] * d->lift[CHANNEL_FACTOR]),
371 2.0 - (d->lift[CHANNEL_GREEN] * d->lift[CHANNEL_FACTOR]),
372 2.0 - (d->lift[CHANNEL_BLUE] * d->lift[CHANNEL_FACTOR]) },
373 gamma = { d->gamma[CHANNEL_RED] * d->gamma[CHANNEL_FACTOR],
374 d->gamma[CHANNEL_GREEN] * d->gamma[CHANNEL_FACTOR],
375 d->gamma[CHANNEL_BLUE] * d->gamma[CHANNEL_FACTOR] },
376 gamma_inv = { (gamma[0] != 0.0) ? 1.0 / gamma[0] : 1000000.0,
377 (gamma[1] != 0.0) ? 1.0 / gamma[1] : 1000000.0,
378 (gamma[2] != 0.0) ? 1.0 / gamma[2] : 1000000.0 };
380 for(size_t k = 0; k < (size_t)ch * roi_in->width * roi_out->height; k += ch)
381 {
382 float *in = ((float *)ivoid) + k;
383 float *out = ((float *)ovoid) + k;
384
385 // transform the pixel to sRGB:
386 // Lab -> XYZ
387 dt_aligned_pixel_t XYZ = { 0.0f };
388 dt_Lab_to_XYZ(in, XYZ);
389
390 // XYZ -> sRGB
391 dt_aligned_pixel_t rgb = { 0.0f };
393
394 // do the calculation in RGB space
395 for(int c = 0; c < 3; c++)
396 {
397 // lift gamma gain
398 rgb[c] = ((( rgb[c] - 1.0f) * lift[c]) + 1.0f) * gain[c];
399 rgb[c] = (rgb[c] < 0.0f) ? 0.0f : powf(rgb[c], gamma_inv[c]);
400 }
401
402 // transform the result back to Lab
403 // sRGB -> XYZ
404 dt_sRGB_to_XYZ(rgb, XYZ);
405
406 // XYZ -> Lab
408 }
409 break;
410 }
411 case LIFT_GAMMA_GAIN:
412 {
413 // these are RGB values!
414 const dt_aligned_pixel_t lift = { 2.0 - (d->lift[CHANNEL_RED] * d->lift[CHANNEL_FACTOR]),
415 2.0 - (d->lift[CHANNEL_GREEN] * d->lift[CHANNEL_FACTOR]),
416 2.0 - (d->lift[CHANNEL_BLUE] * d->lift[CHANNEL_FACTOR]) },
417 gamma = { d->gamma[CHANNEL_RED] * d->gamma[CHANNEL_FACTOR],
418 d->gamma[CHANNEL_GREEN] * d->gamma[CHANNEL_FACTOR],
419 d->gamma[CHANNEL_BLUE] * d->gamma[CHANNEL_FACTOR] },
420 gamma_inv = { (gamma[0] != 0.0) ? 1.0 / gamma[0] : 1000000.0,
421 (gamma[1] != 0.0) ? 1.0 / gamma[1] : 1000000.0,
422 (gamma[2] != 0.0) ? 1.0 / gamma[2] : 1000000.0 };
424 for(size_t k = 0; k < (size_t)ch * roi_in->width * roi_out->height; k += ch)
425 {
426 float *in = ((float *)ivoid) + k;
427 float *out = ((float *)ovoid) + k;
428
429 // transform the pixel to sRGB:
430 // Lab -> XYZ
431 dt_aligned_pixel_t XYZ = { 0.0f };
432 dt_Lab_to_XYZ(in, XYZ);
433
434 // XYZ -> sRGB
435 dt_aligned_pixel_t rgb = { 0.0f };
437
438 float luma = XYZ[1]; // the Y channel is the relative luminance
439
440 // do the calculation in RGB space
441 for(int c = 0; c < 3; c++)
442 {
443 // main saturation input
444 if (run_saturation) rgb[c] = luma + d->saturation * (rgb[c] - luma);
445
446 // RGB gamma correction
447 rgb[c] = (rgb[c] <= 0.0f) ? 0.0f : powf(rgb[c], 1.0f/2.2f);
448
449 // lift gamma gain
450 rgb[c] = ((( rgb[c] - 1.0f) * lift[c]) + 1.0f) * gain[c];
451 rgb[c] = (rgb[c] <= 0.0f) ? 0.0f : powf(rgb[c], gamma_inv[c] * 2.2f);
452 }
453
454 // main saturation output
455 if (run_saturation_out)
456 {
458 luma = XYZ[1];
459 for(int c = 0; c < 3; c++) rgb[c] = luma + d->saturation_out * (rgb[c] - luma);
460 }
461
462 // fulcrum contrat
463 if (run_contrast) for(int c = 0; c < 3; c++) rgb[c] = (rgb[c] <= 0.0f) ? 0.0f : powf(rgb[c] / grey, contrast) * grey;
464
465 // transform the result back to Lab
466 // sRGB -> XYZ
468
469 // XYZ -> Lab
471 }
472 break;
473 }
475 {
476 // these are RGB values!
477
478 const dt_aligned_pixel_t lift = { ( d->lift[CHANNEL_RED] + d->lift[CHANNEL_FACTOR] - 2.0f),
479 ( d->lift[CHANNEL_GREEN] + d->lift[CHANNEL_FACTOR] - 2.0f),
480 ( d->lift[CHANNEL_BLUE] + d->lift[CHANNEL_FACTOR] - 2.0f)},
481 gamma = { (2.0f - d->gamma[CHANNEL_RED]) * (2.0f - d->gamma[CHANNEL_FACTOR]),
482 (2.0f - d->gamma[CHANNEL_GREEN]) * (2.0f - d->gamma[CHANNEL_FACTOR]),
483 (2.0f - d->gamma[CHANNEL_BLUE]) * (2.0f - d->gamma[CHANNEL_FACTOR])};
485 for(size_t k = 0; k < (size_t)ch * roi_in->width * roi_out->height; k += ch)
486 {
487 float *in = ((float *)ivoid) + k;
488 float *out = ((float *)ovoid) + k;
489
490 // transform the pixel to RGB:
491 // Lab -> XYZ
493 dt_Lab_to_XYZ(in, XYZ);
494
495 // XYZ -> RGB
498
499 float luma = XYZ[1]; // the Y channel is the RGB luminance
500
501 // do the calculation in RGB space
502 for(int c = 0; c < 3; c++)
503 {
504 // main saturation input
505 if (run_saturation) rgb[c] = luma + d->saturation * (rgb[c] - luma);
506
507 // channel CDL
508 rgb[c] = CDL(rgb[c], gain[c], lift[c], gamma[c]);
509 }
510
511 // main saturation output
512 if (run_saturation_out)
513 {
515 luma = XYZ[1];
516 for(int c = 0; c < 3; c++) rgb[c] = luma + d->saturation_out * (rgb[c] - luma);
517 }
518
519 // fulcrum contrat
520 if (run_contrast) for(int c = 0; c < 3; c++) rgb[c] = (rgb[c] <= 0.0f) ? 0.0f : powf(rgb[c] / grey, contrast) * grey;
521
522 // transform the result back to Lab
523 // sRGB -> XYZ
525
526 // XYZ -> Lab
528 }
529 break;
530 }
531 }
532 if(pipe->mask_display & DT_DEV_PIXELPIPE_DISPLAY_MASK) dt_iop_alpha_copy(ivoid, ovoid, roi_out->width, roi_out->height);
533 return 0;
534}
535
536#ifdef HAVE_OPENCL
537int 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)
538{
539 const dt_iop_roi_t *const roi_in = &piece->roi_in;
542
543 cl_int err = -999;
544 const int devid = pipe->devid;
545 const int width = roi_in->width;
546 const int height = roi_in->height;
547 size_t sizes[] = { ROUNDUPDWD(width, devid), ROUNDUPDHT(height, devid), 1 };
548
549 switch (d->mode)
550 {
551 case LEGACY:
552 {
553 const float lift[4] = { 2.0f - (d->lift[CHANNEL_RED] * d->lift[CHANNEL_FACTOR]),
554 2.0f - (d->lift[CHANNEL_GREEN] * d->lift[CHANNEL_FACTOR]),
555 2.0f - (d->lift[CHANNEL_BLUE] * d->lift[CHANNEL_FACTOR]), 0.0f },
556 gamma[4] = { d->gamma[CHANNEL_RED] * d->gamma[CHANNEL_FACTOR],
557 d->gamma[CHANNEL_GREEN] * d->gamma[CHANNEL_FACTOR],
558 d->gamma[CHANNEL_BLUE] * d->gamma[CHANNEL_FACTOR], 0.0f },
559 gamma_inv[4] = { (gamma[0] != 0.0f) ? 1.0f / gamma[0] : 1000000.0f,
560 (gamma[1] != 0.0f) ? 1.0f / gamma[1] : 1000000.0f,
561 (gamma[2] != 0.0f) ? 1.0f / gamma[2] : 1000000.0f, 0.0f },
562 gain[4] = { d->gain[CHANNEL_RED] * d->gain[CHANNEL_FACTOR],
563 d->gain[CHANNEL_GREEN] * d->gain[CHANNEL_FACTOR],
564 d->gain[CHANNEL_BLUE] * d->gain[CHANNEL_FACTOR], 0.0f },
565 contrast = (d->contrast != 0.0f) ? 1.0f / d->contrast : 1000000.0f,
566 grey = d->grey / 100.0f,
567 saturation = d->saturation;
568
569 dt_opencl_set_kernel_arg(devid, gd->kernel_colorbalance, 0, sizeof(cl_mem), (void *)&dev_in);
570 dt_opencl_set_kernel_arg(devid, gd->kernel_colorbalance, 1, sizeof(cl_mem), (void *)&dev_out);
571 dt_opencl_set_kernel_arg(devid, gd->kernel_colorbalance, 2, sizeof(int), (void *)&width);
572 dt_opencl_set_kernel_arg(devid, gd->kernel_colorbalance, 3, sizeof(int), (void *)&height);
573 dt_opencl_set_kernel_arg(devid, gd->kernel_colorbalance, 4, 4 * sizeof(float), (void *)&lift);
574 dt_opencl_set_kernel_arg(devid, gd->kernel_colorbalance, 5, 4 * sizeof(float), (void *)&gain);
575 dt_opencl_set_kernel_arg(devid, gd->kernel_colorbalance, 6, 4 * sizeof(float), (void *)&gamma_inv);
576 dt_opencl_set_kernel_arg(devid, gd->kernel_colorbalance, 7, sizeof(float), (void *)&saturation);
577 dt_opencl_set_kernel_arg(devid, gd->kernel_colorbalance, 8, sizeof(float), (void *)&contrast);
578 dt_opencl_set_kernel_arg(devid, gd->kernel_colorbalance, 9, sizeof(float), (void *)&grey);
579 err = dt_opencl_enqueue_kernel_2d(devid, gd->kernel_colorbalance, sizes);
580 if(err != CL_SUCCESS) goto error;
581 return TRUE;
582
583 break;
584 }
585 case LIFT_GAMMA_GAIN:
586 {
587 const float lift[4] = { 2.0f - (d->lift[CHANNEL_RED] * d->lift[CHANNEL_FACTOR]),
588 2.0f - (d->lift[CHANNEL_GREEN] * d->lift[CHANNEL_FACTOR]),
589 2.0f - (d->lift[CHANNEL_BLUE] * d->lift[CHANNEL_FACTOR]), 0.0f },
590 gamma[4] = { d->gamma[CHANNEL_RED] * d->gamma[CHANNEL_FACTOR],
591 d->gamma[CHANNEL_GREEN] * d->gamma[CHANNEL_FACTOR],
592 d->gamma[CHANNEL_BLUE] * d->gamma[CHANNEL_FACTOR], 0.0f },
593 gamma_inv[4] = { (gamma[0] != 0.0f) ? 1.0f / gamma[0] : 1000000.0f,
594 (gamma[1] != 0.0f) ? 1.0f / gamma[1] : 1000000.0f,
595 (gamma[2] != 0.0f) ? 1.0f / gamma[2] : 1000000.0f, 0.0f },
596 gain[4] = { d->gain[CHANNEL_RED] * d->gain[CHANNEL_FACTOR],
597 d->gain[CHANNEL_GREEN] * d->gain[CHANNEL_FACTOR],
598 d->gain[CHANNEL_BLUE] * d->gain[CHANNEL_FACTOR], 0.0f },
599 contrast = (d->contrast != 0.0f) ? 1.0f / d->contrast : 1000000.0f,
600 grey = d->grey / 100.0f,
601 saturation = d->saturation,
602 saturation_out = d->saturation_out;
603
604 dt_opencl_set_kernel_arg(devid, gd->kernel_colorbalance_lgg, 0, sizeof(cl_mem), (void *)&dev_in);
605 dt_opencl_set_kernel_arg(devid, gd->kernel_colorbalance_lgg, 1, sizeof(cl_mem), (void *)&dev_out);
606 dt_opencl_set_kernel_arg(devid, gd->kernel_colorbalance_lgg, 2, sizeof(int), (void *)&width);
607 dt_opencl_set_kernel_arg(devid, gd->kernel_colorbalance_lgg, 3, sizeof(int), (void *)&height);
608 dt_opencl_set_kernel_arg(devid, gd->kernel_colorbalance_lgg, 4, 4 * sizeof(float), (void *)&lift);
609 dt_opencl_set_kernel_arg(devid, gd->kernel_colorbalance_lgg, 5, 4 * sizeof(float), (void *)&gain);
610 dt_opencl_set_kernel_arg(devid, gd->kernel_colorbalance_lgg, 6, 4 * sizeof(float), (void *)&gamma_inv);
611 dt_opencl_set_kernel_arg(devid, gd->kernel_colorbalance_lgg, 7, sizeof(float), (void *)&saturation);
612 dt_opencl_set_kernel_arg(devid, gd->kernel_colorbalance_lgg, 8, sizeof(float), (void *)&contrast);
613 dt_opencl_set_kernel_arg(devid, gd->kernel_colorbalance_lgg, 9, sizeof(float), (void *)&grey);
614 dt_opencl_set_kernel_arg(devid, gd->kernel_colorbalance_lgg, 10, sizeof(float), (void *)&saturation_out);
616 if(err != CL_SUCCESS) goto error;
617 return TRUE;
618
619 break;
620 }
622 {
623 const float lift[4] = { ( d->lift[CHANNEL_RED] + d->lift[CHANNEL_FACTOR] - 2.0f ),
624 ( d->lift[CHANNEL_GREEN] + d->lift[CHANNEL_FACTOR] - 2.0f ),
625 ( d->lift[CHANNEL_BLUE] + d->lift[CHANNEL_FACTOR] - 2.0f ),
626 0.0f },
627 gamma[4] = { (2.0f - d->gamma[CHANNEL_RED]) * (2.0f - d->gamma[CHANNEL_FACTOR]),
628 (2.0f - d->gamma[CHANNEL_GREEN]) * (2.0f - d->gamma[CHANNEL_FACTOR]),
629 (2.0f - d->gamma[CHANNEL_BLUE]) * (2.0f - d->gamma[CHANNEL_FACTOR]),
630 0.0f },
631 gain[4] = { d->gain[CHANNEL_RED] * d->gain[CHANNEL_FACTOR],
632 d->gain[CHANNEL_GREEN] * d->gain[CHANNEL_FACTOR],
633 d->gain[CHANNEL_BLUE] * d->gain[CHANNEL_FACTOR],
634 0.0f },
635 contrast = (d->contrast != 0.0f) ? 1.0f / d->contrast : 1000000.0f,
636 grey = d->grey / 100.0f,
637 saturation = d->saturation,
638 saturation_out = d->saturation_out;
639
640 dt_opencl_set_kernel_arg(devid, gd->kernel_colorbalance_cdl, 0, sizeof(cl_mem), (void *)&dev_in);
641 dt_opencl_set_kernel_arg(devid, gd->kernel_colorbalance_cdl, 1, sizeof(cl_mem), (void *)&dev_out);
642 dt_opencl_set_kernel_arg(devid, gd->kernel_colorbalance_cdl, 2, sizeof(int), (void *)&width);
643 dt_opencl_set_kernel_arg(devid, gd->kernel_colorbalance_cdl, 3, sizeof(int), (void *)&height);
644 dt_opencl_set_kernel_arg(devid, gd->kernel_colorbalance_cdl, 4, 4 * sizeof(float), (void *)&lift);
645 dt_opencl_set_kernel_arg(devid, gd->kernel_colorbalance_cdl, 5, 4 * sizeof(float), (void *)&gain);
646 dt_opencl_set_kernel_arg(devid, gd->kernel_colorbalance_cdl, 6, 4 * sizeof(float), (void *)&gamma);
647 dt_opencl_set_kernel_arg(devid, gd->kernel_colorbalance_cdl, 7, sizeof(float), (void *)&saturation);
648 dt_opencl_set_kernel_arg(devid, gd->kernel_colorbalance_cdl, 8, sizeof(float), (void *)&contrast);
649 dt_opencl_set_kernel_arg(devid, gd->kernel_colorbalance_cdl, 9, sizeof(float), (void *)&grey);
650 dt_opencl_set_kernel_arg(devid, gd->kernel_colorbalance_cdl, 10, sizeof(float), (void *)&saturation_out);
652 if(err != CL_SUCCESS) goto error;
653 return TRUE;
654
655 break;
656 }
657 }
658
659error:
660 dt_print(DT_DEBUG_OPENCL, "[opencl_colorbalance] couldn't enqueue kernel! %d\n", err);
661 return FALSE;
662}
663#endif
664
665static inline void update_saturation_slider_color(GtkWidget *slider, float hue)
666{
668 if(hue != -1)
669 {
670 hsl2rgb(rgb, hue, 1.0, 0.5);
671 dt_bauhaus_slider_set_stop(slider, 1.0, rgb[0], rgb[1], rgb[2]);
672 hsl2rgb(rgb, hue, 0.0, 0.5);
673 dt_bauhaus_slider_set_stop(slider, 0.0, rgb[0], rgb[1], rgb[2]);
674 gtk_widget_queue_draw(GTK_WIDGET(slider));
675 }
676}
677
678static inline void set_RGB_sliders(GtkWidget *R, GtkWidget *G, GtkWidget *B, float hsl[3], float *p, int mode)
679{
680
681 dt_aligned_pixel_t rgb = { 0.0f };
682 hsl2rgb(rgb, hsl[0], hsl[1], hsl[2]);
683
684 if(hsl[0] != -1)
685 {
686 p[CHANNEL_RED] = rgb[0] * 2.0f;
687 p[CHANNEL_GREEN] = rgb[1] * 2.0f;
688 p[CHANNEL_BLUE] = rgb[2] * 2.0f;
689
695 }
696}
697
698static inline void set_HSL_sliders(GtkWidget *hue, GtkWidget *sat, float RGB[4])
699{
704 dt_aligned_pixel_t RGB_norm = { (RGB[CHANNEL_RED] / 2.0f), (RGB[CHANNEL_GREEN] / 2.0f), (RGB[CHANNEL_BLUE] / 2.0f) };
705
706 float h, s, l;
707 rgb2hsl(RGB_norm, &h, &s, &l);
708
709 if(h != -1.0f)
710 {
711 dt_bauhaus_slider_set(hue, h * 360.0f);
712 dt_bauhaus_slider_set(sat, s * 100.0f);
713 update_saturation_slider_color(GTK_WIDGET(sat), h);
714 gtk_widget_queue_draw(GTK_WIDGET(sat));
715 }
716 else
717 {
718 dt_bauhaus_slider_set(hue, -1.0f);
719 dt_bauhaus_slider_set(sat, 0.0f);
720 gtk_widget_queue_draw(GTK_WIDGET(sat));
721 }
722}
723
725{
727
728 if(g->luma_patches_flags[GAIN] == USER_SELECTED && g->luma_patches_flags[GAMMA] == USER_SELECTED
729 && g->luma_patches_flags[LIFT] == USER_SELECTED)
730 dt_bauhaus_widget_set_label(g->auto_luma, N_("optimize luma from patches"));
731 else
732 dt_bauhaus_widget_set_label(g->auto_luma, N_("optimize luma"));
733
734 if(g->color_patches_flags[GAIN] == USER_SELECTED && g->color_patches_flags[GAMMA] == USER_SELECTED
735 && g->color_patches_flags[LIFT] == USER_SELECTED)
736 dt_bauhaus_widget_set_label(g->auto_color, N_("neutralize colors from patches"));
737 else
738 dt_bauhaus_widget_set_label(g->auto_color, N_("neutralize colors"));
739}
740
741
743{
744 if(darktable.gui->reset) return;
747
748 dt_aligned_pixel_t XYZ = { 0.0f };
749 dt_aligned_pixel_t rgb = { 0.0f };
750 dt_Lab_to_XYZ((const float *)self->picked_color, XYZ);
751 dt_XYZ_to_prophotorgb((const float *)XYZ, rgb);
752
753 const dt_aligned_pixel_t lift
754 = { (p->lift[CHANNEL_RED] + p->lift[CHANNEL_FACTOR] - 2.0f),
755 (p->lift[CHANNEL_GREEN] + p->lift[CHANNEL_FACTOR] - 2.0f),
756 (p->lift[CHANNEL_BLUE] + p->lift[CHANNEL_FACTOR] - 2.0f) },
757 gamma
758 = { p->gamma[CHANNEL_RED] * p->gamma[CHANNEL_FACTOR],
759 p->gamma[CHANNEL_GREEN] * p->gamma[CHANNEL_FACTOR],
760 p->gamma[CHANNEL_BLUE] * p->gamma[CHANNEL_FACTOR] },
761 gain = { p->gain[CHANNEL_RED] * p->gain[CHANNEL_FACTOR], p->gain[CHANNEL_GREEN] * p->gain[CHANNEL_FACTOR],
762 p->gain[CHANNEL_BLUE] * p->gain[CHANNEL_FACTOR] };
763
764 for(int c = 0; c < 3; c++)
765 {
766 rgb[c] = CDL(rgb[c], gain[c], lift[c], 2.0f - gamma[c]);
767 rgb[c] = CLAMP(rgb[c], 0.0f, 1.0f);
768 }
769
770 dt_prophotorgb_to_XYZ((const float *)rgb, XYZ);
771
772 p->grey = XYZ[1] * 100.0f;
773
775 dt_bauhaus_slider_set(g->grey, p->grey);
777
779}
780
782{
783 if(darktable.gui->reset) return;
786
787 dt_aligned_pixel_t XYZ = { 0.0f };
788 dt_Lab_to_XYZ((const float *)self->picked_color, XYZ);
789 dt_aligned_pixel_t RGB = { 0.0f };
790 dt_XYZ_to_prophotorgb((const float *)XYZ, RGB);
791
792// Save the patch color for the optimization
793 for(int c = 0; c < 3; ++c) g->color_patches_lift[c] = RGB[c];
794 g->color_patches_flags[LIFT] = USER_SELECTED;
795
796 // Compute the RGB values after the CDL factors
797 for(int c = 0; c < 3; ++c)
798 RGB[c] = CDL(RGB[c], p->gain[CHANNEL_FACTOR], p->lift[CHANNEL_FACTOR] - 1.0f, 2.0f - p->gamma[CHANNEL_FACTOR]);
799
800 // Compute the luminance of the average grey
801 dt_XYZ_to_prophotorgb((const float *)XYZ, RGB);
802
803 // Get the parameter
804 for(int c = 0; c < 3; ++c) RGB[c] = powf(XYZ[1], 1.0f/(2.0f - p->gamma[c+1])) - RGB[c] * p->gain[c+1];
805
806 p->lift[CHANNEL_RED] = RGB[0] + 1.0f;
807 p->lift[CHANNEL_GREEN] = RGB[1] + 1.0f;
808 p->lift[CHANNEL_BLUE] = RGB[2] + 1.0f;
809
811 dt_bauhaus_slider_set(g->lift_r, p->lift[CHANNEL_RED]);
812 dt_bauhaus_slider_set(g->lift_g, p->lift[CHANNEL_GREEN]);
813 dt_bauhaus_slider_set(g->lift_b, p->lift[CHANNEL_BLUE]);
814 set_HSL_sliders(g->hue_lift, g->sat_lift, p->lift);
816
818}
819
821{
822 if(darktable.gui->reset) return;
825
826 dt_aligned_pixel_t XYZ = { 0.0f };
827 dt_Lab_to_XYZ((const float *)self->picked_color, XYZ);
828 dt_aligned_pixel_t RGB = { 0.0f };
829 dt_XYZ_to_prophotorgb((const float *)XYZ, RGB);
830
831// Save the patch color for the optimization
832 for(int c = 0; c < 3; ++c) g->color_patches_gamma[c] = RGB[c];
833 g->color_patches_flags[GAMMA] = USER_SELECTED;
834
835 // Compute the RGB values after the CDL factors
836 for(int c = 0; c < 3; ++c)
837 RGB[c] = CDL(RGB[c], p->gain[CHANNEL_FACTOR], p->lift[CHANNEL_FACTOR] - 1.0f, 2.0f - p->gamma[CHANNEL_FACTOR]);
838
839 // Compute the luminance of the average grey
840 dt_XYZ_to_prophotorgb((const float *)XYZ, RGB);
841
842 // Get the parameter
843 for(int c = 0; c < 3; ++c) RGB[c] = logf(XYZ[1])/ logf(RGB[c] * p->gain[c + 1] + p->lift[c + 1] - 1.0f);
844
845 p->gamma[CHANNEL_RED] = CLAMP(2.0 - RGB[0], 0.0001f, 2.0f);
846 p->gamma[CHANNEL_GREEN] = CLAMP(2.0 - RGB[1], 0.0001f, 2.0f);
847 p->gamma[CHANNEL_BLUE] = CLAMP(2.0 - RGB[2], 0.0001f, 2.0f);
848
850 dt_bauhaus_slider_set(g->gamma_r, p->gamma[CHANNEL_RED]);
851 dt_bauhaus_slider_set(g->gamma_g, p->gamma[CHANNEL_GREEN]);
852 dt_bauhaus_slider_set(g->gamma_b, p->gamma[CHANNEL_BLUE]);
853 set_HSL_sliders(g->hue_gamma, g->sat_gamma, p->gamma);
855
857}
858
860{
861 if(darktable.gui->reset) return;
864
865 dt_aligned_pixel_t XYZ = { 0.0f };
866 dt_Lab_to_XYZ((const float *)self->picked_color, XYZ);
867 dt_aligned_pixel_t RGB = { 0.0f };
868 dt_XYZ_to_prophotorgb((const float *)XYZ, RGB);
869
870// Save the patch color for the optimization
871 for(int c = 0; c < 3; c++) g->color_patches_gain[c] = RGB[c];
872 g->color_patches_flags[GAIN] = USER_SELECTED;
873
874 // Compute the RGB values after the CDL factors
875 for(int c = 0; c < 3; ++c)
876 RGB[c] = CDL(RGB[c], p->gain[CHANNEL_FACTOR], p->lift[CHANNEL_FACTOR] - 1.0f, 2.0f - p->gamma[CHANNEL_FACTOR]);
877
878 // Compute the luminance of the average grey
879 dt_XYZ_to_prophotorgb((const float *)XYZ, RGB);
880
881 // Get the parameter
882 for(int c = 0; c < 3; ++c) RGB[c] = (powf(XYZ[1], 1.0f/(2.0f - p->gamma[c+1])) - p->lift[c+1] + 1.0f) / MAX(RGB[c], 0.000001f);
883
884 p->gain[CHANNEL_RED] = RGB[0];
885 p->gain[CHANNEL_GREEN] = RGB[1];
886 p->gain[CHANNEL_BLUE] = RGB[2];
887
889 dt_bauhaus_slider_set(g->gain_r, p->gain[CHANNEL_RED]);
890 dt_bauhaus_slider_set(g->gain_g, p->gain[CHANNEL_GREEN]);
891 dt_bauhaus_slider_set(g->gain_b, p->gain[CHANNEL_BLUE]);
892 set_HSL_sliders(g->hue_gain, g->sat_gain, p->gain);
894
896}
897
899{
900 if(darktable.gui->reset) return;
903
904 dt_aligned_pixel_t XYZ = { 0.0f };
905 dt_Lab_to_XYZ((const float *)self->picked_color_min, XYZ);
906
907 g->luma_patches[LIFT] = XYZ[1];
908 g->luma_patches_flags[LIFT] = USER_SELECTED;
909
910 dt_aligned_pixel_t RGB = { 0.0f };
911 dt_XYZ_to_prophotorgb((const float *)XYZ, RGB);
912
913 p->lift[CHANNEL_FACTOR] = -p->gain[CHANNEL_FACTOR] * XYZ[1] + 1.0f;
914
916 dt_bauhaus_slider_set(g->lift_factor, p->lift[CHANNEL_FACTOR]);
918
920}
921
923{
924 if(darktable.gui->reset) return;
927
928 dt_aligned_pixel_t XYZ = { 0.0f };
929 dt_Lab_to_XYZ((const float *)self->picked_color, XYZ);
930
931 g->luma_patches[GAMMA] = XYZ[1];
932 g->luma_patches_flags[GAMMA] = USER_SELECTED;
933
934 dt_aligned_pixel_t RGB = { 0.0f };
935 dt_XYZ_to_prophotorgb((const float *)XYZ, RGB);
936
937 p->gamma[CHANNEL_FACTOR]
938 = 2.0f - logf(0.1842f) / logf(MAX(p->gain[CHANNEL_FACTOR] * XYZ[1] + p->lift[CHANNEL_FACTOR] - 1.0f, 0.000001f));
939
941 dt_bauhaus_slider_set(g->gamma_factor, p->gamma[CHANNEL_FACTOR]);
943
945}
946
948{
949 if(darktable.gui->reset) return;
952
953 dt_aligned_pixel_t XYZ = { 0.0f };
954 dt_Lab_to_XYZ((const float *)self->picked_color_max, XYZ);
955
956 g->luma_patches[GAIN] = XYZ[1];
957 g->luma_patches_flags[GAIN] = USER_SELECTED;
958
959 dt_aligned_pixel_t RGB = { 0.0f };
960 dt_XYZ_to_prophotorgb((const float *)XYZ, RGB);
961
962 p->gain[CHANNEL_FACTOR] = p->lift[CHANNEL_FACTOR] / (XYZ[1]);
963
965 dt_bauhaus_slider_set(g->gain_factor, p->gain[CHANNEL_FACTOR]);
967
969}
970
972{
975
976 if(g->color_patches_flags[GAIN] == INVALID || g->color_patches_flags[GAMMA] == INVALID
977 || g->color_patches_flags[LIFT] == INVALID)
978 {
979 /*
980 * Some color patches were not picked by the user. Take a
981 * picture-wide patch for these.
982 */
983 dt_aligned_pixel_t XYZ = { 0.0f };
984 dt_Lab_to_XYZ((const float *)self->picked_color, XYZ);
985 dt_aligned_pixel_t RGB = { 0.0f };
986 dt_XYZ_to_prophotorgb((const float *)XYZ, RGB);
987
988 // Save the patch color for the optimization
989 if(g->color_patches_flags[LIFT] == INVALID)
990 {
991 for(int c = 0; c < 3; c++) g->color_patches_lift[c] = RGB[c];
992 g->color_patches_flags[LIFT] = AUTO_SELECTED;
993 }
994 if(g->color_patches_flags[GAMMA] == INVALID)
995 {
996 for(int c = 0; c < 3; c++) g->color_patches_gamma[c] = RGB[c];
997 g->color_patches_flags[GAMMA] = AUTO_SELECTED;
998 }
999 if(g->color_patches_flags[GAIN] == INVALID)
1000 {
1001 for(int c = 0; c < 3; c++) g->color_patches_gain[c] = RGB[c];
1002 g->color_patches_flags[GAIN] = AUTO_SELECTED;
1003 }
1004 }
1005
1007
1008 // Build the CDL-corrected samples (after the factors)
1009 dt_aligned_pixel_t samples_lift = { 0.f };
1010 dt_aligned_pixel_t samples_gamma = { 0.f };
1011 dt_aligned_pixel_t samples_gain = { 0.f };
1012
1013 for (int c = 0; c < 3; ++c)
1014 {
1015 samples_lift[c] = CDL(g->color_patches_lift[c], p->gain[CHANNEL_FACTOR], p->lift[CHANNEL_FACTOR] - 1.0f, 2.0f - p->gamma[CHANNEL_FACTOR]);
1016 samples_gamma[c] = CDL(g->color_patches_gamma[c], p->gain[CHANNEL_FACTOR], p->lift[CHANNEL_FACTOR] - 1.0f, 2.0f - p->gamma[CHANNEL_FACTOR]);
1017 samples_gain[c] = CDL(g->color_patches_gain[c], p->gain[CHANNEL_FACTOR], p->lift[CHANNEL_FACTOR] - 1.0f, 2.0f - p->gamma[CHANNEL_FACTOR]);
1018 }
1019
1020 // Get the average patches luma value (= neutral grey equivalents) after the CDL factors
1021 dt_aligned_pixel_t greys = { 0.0 };
1022 dt_aligned_pixel_t XYZ = { 0.0 };
1023 dt_prophotorgb_to_XYZ((const float *)samples_lift, (float *)XYZ);
1024 greys[0] = XYZ[1];
1025 dt_prophotorgb_to_XYZ((const float *)samples_gamma, (float *)XYZ);
1026 greys[1] = XYZ[1];
1027 dt_prophotorgb_to_XYZ((const float *)samples_gain, (float *)XYZ);
1028 greys[2] = XYZ[1];
1029
1030 // Get the current params
1031 dt_aligned_pixel_t RGB_lift = { p->lift[CHANNEL_RED] - 1.0f, p->lift[CHANNEL_GREEN] - 1.0f, p->lift[CHANNEL_BLUE] - 1.0f };
1032 dt_aligned_pixel_t RGB_gamma = { p->gamma[CHANNEL_RED], p->gamma[CHANNEL_GREEN], p->gamma[CHANNEL_BLUE] };
1033 dt_aligned_pixel_t RGB_gain = { p->gain[CHANNEL_RED], p->gain[CHANNEL_GREEN], p->gain[CHANNEL_BLUE] };
1034
1047 for (int runs = 0 ; runs < 1000 ; ++runs)
1048 {
1049 // compute RGB slope/gain (powf(XYZ[1], 1.0f/(2.0f - p->gamma[c+1])) - p->lift[c+1] + 1.0f) / MAX(RGB[c], 0.000001f);
1050 for (int c = 0; c < 3; ++c) RGB_gain[c] = CLAMP((powf(greys[GAIN], 1.0f / (2.0f - RGB_gamma[c])) - RGB_lift[c]) / MAX(samples_gain[c], 0.000001f), 0.75f, 1.25f);
1051 // compute RGB offset/lift powf(XYZ[1], 1.0f/(2.0f - p->gamma[c+1])) - RGB[c] * p->gain[c+1];
1052 for (int c = 0; c < 3; ++c) RGB_lift[c] = CLAMP(powf(greys[LIFT], 1.0f / (2.0f - RGB_gamma[c])) - samples_lift[c] * RGB_gain[c], -0.025f, 0.025f);
1053 // compute power/gamma 2.0f - logf(0.1842f) / logf(MAX(p->gain[CHANNEL_FACTOR] * XYZ[1] + p->lift[CHANNEL_FACTOR] - 1.0f, 0.000001f));
1054 for (int c = 0; c < 3; ++c) RGB_gamma[c] = 2.0f - CLAMP(logf(MAX(greys[GAMMA], 0.000001f)) / logf(MAX(RGB_gain[c] * samples_gamma[c] + RGB_lift[c], 0.000001f)), 0.75f, 1.25f);
1055 }
1056
1057 // save
1058 p->lift[CHANNEL_RED] = RGB_lift[0] + 1.0f;
1059 p->lift[CHANNEL_GREEN] = RGB_lift[1] + 1.0f;
1060 p->lift[CHANNEL_BLUE] = RGB_lift[2] + 1.0f;
1061 p->gamma[CHANNEL_RED] = RGB_gamma[0];
1062 p->gamma[CHANNEL_GREEN] = RGB_gamma[1];
1063 p->gamma[CHANNEL_BLUE] = RGB_gamma[2];
1064 p->gain[CHANNEL_RED] = RGB_gain[0];
1065 p->gain[CHANNEL_GREEN] = RGB_gain[1];
1066 p->gain[CHANNEL_BLUE] = RGB_gain[2];
1067
1068 ++darktable.gui->reset;
1069 dt_bauhaus_slider_set(g->lift_r, p->lift[CHANNEL_RED]);
1070 dt_bauhaus_slider_set(g->lift_g, p->lift[CHANNEL_GREEN]);
1071 dt_bauhaus_slider_set(g->lift_b, p->lift[CHANNEL_BLUE]);
1072
1073 dt_bauhaus_slider_set(g->gamma_r, p->gamma[CHANNEL_RED]);
1074 dt_bauhaus_slider_set(g->gamma_g, p->gamma[CHANNEL_GREEN]);
1075 dt_bauhaus_slider_set(g->gamma_b, p->gamma[CHANNEL_BLUE]);
1076
1077 dt_bauhaus_slider_set(g->gain_r, p->gain[CHANNEL_RED]);
1078 dt_bauhaus_slider_set(g->gain_g, p->gain[CHANNEL_GREEN]);
1079 dt_bauhaus_slider_set(g->gain_b, p->gain[CHANNEL_BLUE]);
1080
1081 set_HSL_sliders(g->hue_lift, g->sat_lift, p->lift);
1082 set_HSL_sliders(g->hue_gamma, g->sat_gamma, p->gamma);
1083 set_HSL_sliders(g->hue_gain, g->sat_gain, p->gain);
1084 --darktable.gui->reset;
1085
1087}
1088
1090{
1093
1094 /*
1095 * If some luma patches were not picked by the user, take a
1096 * picture-wide patch for these.
1097 */
1098 if(g->luma_patches_flags[LIFT] == INVALID)
1099 {
1100 dt_aligned_pixel_t XYZ = { 0.0f };
1101 dt_Lab_to_XYZ((const float *)self->picked_color_min, XYZ);
1102 g->luma_patches[LIFT] = XYZ[1];
1103 g->luma_patches_flags[LIFT] = AUTO_SELECTED;
1104 }
1105 if(g->luma_patches_flags[GAMMA] == INVALID)
1106 {
1107 dt_aligned_pixel_t XYZ = { 0.0f };
1108 dt_Lab_to_XYZ((const float *)self->picked_color, XYZ);
1109 g->luma_patches[GAMMA] = XYZ[1];
1110 g->luma_patches_flags[GAMMA] = AUTO_SELECTED;
1111 }
1112 if(g->luma_patches_flags[GAIN] == INVALID)
1113 {
1114 dt_aligned_pixel_t XYZ = { 0.0f };
1115 dt_Lab_to_XYZ((const float *)self->picked_color_max, XYZ);
1116 g->luma_patches[GAIN] = XYZ[1];
1117 g->luma_patches_flags[GAIN] = AUTO_SELECTED;
1118 }
1119
1121
1125 for (int runs = 0 ; runs < 100 ; ++runs)
1126 {
1127 p->gain[CHANNEL_FACTOR] = CLAMP(p->lift[CHANNEL_FACTOR] / g->luma_patches[GAIN], 0.0f, 2.0f);
1128 p->lift[CHANNEL_FACTOR] = CLAMP(-p->gain[CHANNEL_FACTOR] * g->luma_patches[LIFT] + 1.0f, 0.0f, 2.0f);
1129 p->gamma[CHANNEL_FACTOR] = CLAMP(2.0f - logf(0.1842f) / logf(MAX(p->gain[CHANNEL_FACTOR] * g->luma_patches[GAMMA] + p->lift[CHANNEL_FACTOR] - 1.0f, 0.000001f)), 0.0f, 2.0f);
1130 }
1131
1132 ++darktable.gui->reset;
1133 dt_bauhaus_slider_set(g->lift_factor, p->lift[CHANNEL_FACTOR]);
1134 dt_bauhaus_slider_set(g->gamma_factor, p->gamma[CHANNEL_FACTOR]);
1135 dt_bauhaus_slider_set(g->gain_factor, p->gain[CHANNEL_FACTOR]);
1136 --darktable.gui->reset;
1137
1139}
1140
1142{
1144 if (picker == g->hue_lift)
1146 else if(picker == g->hue_gamma)
1148 else if(picker == g->hue_gain)
1150 else if(picker == g->lift_factor)
1151 apply_lift_auto(self);
1152 else if(picker == g->gamma_factor)
1153 apply_gamma_auto(self);
1154 else if(picker == g->gain_factor)
1155 apply_gain_auto(self);
1156 else if(picker == g->grey)
1157 apply_autogrey(self);
1158 else if(picker == g->auto_luma)
1159 apply_autoluma(self);
1160 else if(picker == g->auto_color)
1161 apply_autocolor(self);
1162 else
1163 fprintf(stderr, "[colorbalance] unknown color picker\n");
1164
1166}
1167
1169{
1170 const int program = 8; // extended.cl, from programs.conf
1173 module->data = gd;
1174 gd->kernel_colorbalance = dt_opencl_create_kernel(program, "colorbalance");
1175 gd->kernel_colorbalance_lgg = dt_opencl_create_kernel(program, "colorbalance_lgg");
1176 gd->kernel_colorbalance_cdl = dt_opencl_create_kernel(program, "colorbalance_cdl");
1177}
1178
1187
1190{
1193
1194 d->mode = p->mode;
1195
1196 const dt_aligned_pixel_t lift = { p->lift[CHANNEL_RED], p->lift[CHANNEL_GREEN], p->lift[CHANNEL_BLUE] };
1197 const dt_aligned_pixel_t gamma = { p->gamma[CHANNEL_RED], p->gamma[CHANNEL_GREEN], p->gamma[CHANNEL_BLUE] };
1198 const dt_aligned_pixel_t gain = { p->gain[CHANNEL_RED], p->gain[CHANNEL_GREEN], p->gain[CHANNEL_BLUE] };
1199
1200 switch(d->mode)
1201 {
1202 case SLOPE_OFFSET_POWER:
1203 {
1204 // Correct the luminance in RGB parameters so we don't affect it
1206
1208 d->lift[CHANNEL_FACTOR] = p->lift[CHANNEL_FACTOR];
1209 d->lift[CHANNEL_RED] = (p->lift[CHANNEL_RED] - XYZ[1]) + 1.f;
1210 d->lift[CHANNEL_GREEN] = (p->lift[CHANNEL_GREEN] - XYZ[1]) + 1.f;
1211 d->lift[CHANNEL_BLUE] = (p->lift[CHANNEL_BLUE] - XYZ[1]) + 1.f;
1212
1213 dt_prophotorgb_to_XYZ(gamma, XYZ);
1214 d->gamma[CHANNEL_FACTOR] = p->gamma[CHANNEL_FACTOR];
1215 d->gamma[CHANNEL_RED] = (p->gamma[CHANNEL_RED] - XYZ[1]) + 1.f;
1216 d->gamma[CHANNEL_GREEN] = (p->gamma[CHANNEL_GREEN] - XYZ[1]) + 1.f;
1217 d->gamma[CHANNEL_BLUE] = (p->gamma[CHANNEL_BLUE] - XYZ[1]) + 1.f;
1218
1220 d->gain[CHANNEL_FACTOR] = p->gain[CHANNEL_FACTOR];
1221 d->gain[CHANNEL_RED] = (p->gain[CHANNEL_RED] - XYZ[1]) + 1.f;
1222 d->gain[CHANNEL_GREEN] = (p->gain[CHANNEL_GREEN] - XYZ[1]) + 1.f;
1223 d->gain[CHANNEL_BLUE] = (p->gain[CHANNEL_BLUE] - XYZ[1]) + 1.f;
1224
1225 break;
1226 }
1227
1228 case LEGACY:
1229 {
1230 // Luminance is not corrected in lift/gamma/gain for compatibility
1231 for(int i = 0; i < CHANNEL_SIZE; i++)
1232 {
1233 d->lift[i] = p->lift[i];
1234 d->gamma[i] = p->gamma[i];
1235 d->gain[i] = p->gain[i];
1236 }
1237
1238 break;
1239 }
1240
1241 case LIFT_GAMMA_GAIN:
1242 {
1243 // Correct the luminance in RGB parameters so we don't affect it
1245
1247 d->lift[CHANNEL_FACTOR] = p->lift[CHANNEL_FACTOR];
1248 d->lift[CHANNEL_RED] = (p->lift[CHANNEL_RED] - XYZ[1]) + 1.f;
1249 d->lift[CHANNEL_GREEN] = (p->lift[CHANNEL_GREEN] - XYZ[1]) + 1.f;
1250 d->lift[CHANNEL_BLUE] = (p->lift[CHANNEL_BLUE] - XYZ[1]) + 1.f;
1251
1252 dt_prophotorgb_to_XYZ(gamma, XYZ);
1253 d->gamma[CHANNEL_FACTOR] = p->gamma[CHANNEL_FACTOR];
1254 d->gamma[CHANNEL_RED] = (p->gamma[CHANNEL_RED] - XYZ[1]) + 1.f;
1255 d->gamma[CHANNEL_GREEN] = (p->gamma[CHANNEL_GREEN] - XYZ[1]) + 1.f;
1256 d->gamma[CHANNEL_BLUE] = (p->gamma[CHANNEL_BLUE] - XYZ[1]) + 1.f;
1257
1259 d->gain[CHANNEL_FACTOR] = p->gain[CHANNEL_FACTOR];
1260 d->gain[CHANNEL_RED] = (p->gain[CHANNEL_RED] - XYZ[1]) + 1.f;
1261 d->gain[CHANNEL_GREEN] = (p->gain[CHANNEL_GREEN] - XYZ[1]) + 1.f;
1262 d->gain[CHANNEL_BLUE] = (p->gain[CHANNEL_BLUE] - XYZ[1]) + 1.f;
1263
1264 break;
1265 }
1266 }
1267
1268 d->grey = p->grey;
1269 d->saturation = p->saturation;
1270 d->saturation_out = p->saturation_out;
1271 d->contrast = p->contrast;
1272}
1273
1279
1281{
1282 dt_free_align(piece->data);
1283 piece->data = NULL;
1284}
1285
1287{
1288 const int mode = dt_bauhaus_combobox_get(g->mode);
1289 const int control_mode = dt_bauhaus_combobox_get(g->controls);
1290
1291 gtk_widget_set_visible(g->master_box, mode != LEGACY);
1292
1293 dt_conf_set_string("plugins/darkroom/colorbalance/controls",
1294 control_mode == RGBL ? "RGBL" :
1295 control_mode == BOTH ? "BOTH" : "HSL");
1296 gboolean show_rgbl = (control_mode == RGBL) || (control_mode == BOTH);
1297 gboolean show_hsl = (control_mode == HSL) || (control_mode == BOTH);
1298
1299 gtk_widget_set_visible(g->lift_r, show_rgbl);
1300 gtk_widget_set_visible(g->lift_g, show_rgbl);
1301 gtk_widget_set_visible(g->lift_b, show_rgbl);
1302 gtk_widget_set_visible(g->gamma_r, show_rgbl);
1303 gtk_widget_set_visible(g->gamma_g, show_rgbl);
1304 gtk_widget_set_visible(g->gamma_b, show_rgbl);
1305 gtk_widget_set_visible(g->gain_r, show_rgbl);
1306 gtk_widget_set_visible(g->gain_g, show_rgbl);
1307 gtk_widget_set_visible(g->gain_b, show_rgbl);
1308
1309 gtk_widget_set_visible(g->hue_lift, show_hsl);
1310 gtk_widget_set_visible(g->sat_lift, show_hsl);
1311 gtk_widget_set_visible(g->hue_gamma, show_hsl);
1312 gtk_widget_set_visible(g->sat_gamma, show_hsl);
1313 gtk_widget_set_visible(g->hue_gain, show_hsl);
1314 gtk_widget_set_visible(g->sat_gain, show_hsl);
1315
1316 gtk_widget_set_visible(g->optimizer_box, mode == SLOPE_OFFSET_POWER);
1317}
1318
1320{
1323
1324 gui_changed(self, NULL, NULL);
1325}
1326
1328{
1330
1331 for (int k=0; k<LEVELS; k++)
1332 {
1333 g->color_patches_flags[k] = INVALID;
1334 g->luma_patches_flags[k] = INVALID;
1335 }
1337
1338 dt_bauhaus_combobox_set(g->controls, HSL);
1339
1341
1343}
1344
1345static void _configure_slider_blocks(gpointer instance, dt_iop_module_t *self);
1346
1347void gui_changed(dt_iop_module_t *self, GtkWidget *w, void *previous)
1348{
1351
1352 if(IS_NULL_PTR(w) || w == g->mode)
1353 {
1355 _configure_slider_blocks(NULL, self);
1356 }
1357
1358 ++darktable.gui->reset;
1359
1360 if(IS_NULL_PTR(w) || w == g->lift_r || w == g->lift_g || w == g->lift_b)
1361 set_HSL_sliders(g->hue_lift, g->sat_lift, p->lift);
1362 if(IS_NULL_PTR(w) || w == g->gamma_r || w == g->gamma_g || w == g->gamma_b)
1363 set_HSL_sliders(g->hue_gamma, g->sat_gamma, p->gamma);
1364 if(IS_NULL_PTR(w) || w == g->gain_r || w == g->gain_g || w == g->gain_b)
1365 set_HSL_sliders(g->hue_gain, g->sat_gain, p->gain);
1366
1367 --darktable.gui->reset;
1368}
1369
1371{
1372 if(darktable.gui->reset) return;
1373
1375
1377
1379}
1380
1381#ifdef SHOW_COLOR_WHEELS
1382static gboolean dt_iop_area_draw(GtkWidget *widget, cairo_t *cr, dt_iop_module_t *self)
1383{
1384 float flt_bg = 0.5;
1385 if(gtk_widget_get_state_flags(widget) & GTK_STATE_FLAG_SELECTED) flt_bg = 0.6;
1386 float flt_dark = flt_bg / 1.5, flt_light = flt_bg * 1.5;
1387
1388 uint32_t bg = ((255 << 24) | ((int)floor(flt_bg * 255 + 0.5) << 16) | ((int)floor(flt_bg * 255 + 0.5) << 8)
1389 | (int)floor(flt_bg * 255 + 0.5));
1390 // bg = 0xffffffff;
1391 // uint32_t dark = ((255 << 24) |
1392 // ((int)floor(flt_dark * 255 + 0.5) << 16) |
1393 // ((int)floor(flt_dark * 255 + 0.5) << 8) |
1394 // (int)floor(flt_dark * 255 + 0.5));
1395 uint32_t light = ((255 << 24) | ((int)floor(flt_light * 255 + 0.5) << 16)
1396 | ((int)floor(flt_light * 255 + 0.5) << 8) | (int)floor(flt_light * 255 + 0.5));
1397
1398 GtkAllocation allocation;
1399 gtk_widget_get_allocation(widget, &allocation);
1400 int width = allocation.width, height = allocation.height;
1401 if(width % 2 == 0) width--;
1402 if(height % 2 == 0) height--;
1403 double center_x = (float)width / 2.0, center_y = (float)height / 2.0;
1404 double diameter = MIN(width, height) - 4;
1405 double r_outside = diameter / 2.0, r_inside = r_outside * 0.87;
1406 double r_outside_2 = r_outside * r_outside, r_inside_2 = r_inside * r_inside;
1407
1408 // clear the background
1409 cairo_set_source_rgb(cr, flt_bg, flt_bg, flt_bg);
1410 cairo_paint(cr);
1411
1412 /* Create an image initialized with the ring colors */
1413 gint stride = cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, width);
1414 guint32 *buf = (guint32 *)malloc(sizeof(guint32) * height * stride / 4);
1415
1416 for(int y = 0; y < height; y++)
1417 {
1418 guint32 *p = buf + y * width;
1419
1420 double dy = -(y + 0.5 - center_y);
1421
1422 for(int x = 0; x < width; x++)
1423 {
1424 double dx = x + 0.5 - center_x;
1425 double dist = dx * dx + dy * dy;
1426 if(dist < r_inside_2 || dist > r_outside_2)
1427 {
1428 uint32_t col = bg;
1429 if((abs(dx) < 1 && abs(dy) < 3) || (abs(dx) < 3 && abs(dy) < 1)) col = light;
1430 *p++ = col;
1431 continue;
1432 }
1433
1434 double angle = atan2(dy, dx) - M_PI_2;
1435 if(angle < 0.0) angle += 2.0 * M_PI;
1436
1437 double hue = angle / (2.0 * M_PI);
1438
1440 hsl2rgb(rgb, hue, 1.0, 0.5);
1441
1442 *p++ = (((int)floor(rgb[0] * 255 + 0.5) << 16) | ((int)floor(rgb[1] * 255 + 0.5) << 8)
1443 | (int)floor(rgb[2] * 255 + 0.5));
1444 }
1445 }
1446
1447 cairo_surface_t *source
1448 = cairo_image_surface_create_for_data((unsigned char *)buf, CAIRO_FORMAT_RGB24, width, height, stride);
1449
1450 cairo_set_source_surface(cr, source, 0.0, 0.0);
1451 cairo_paint(cr);
1452 dt_free(buf);
1453
1454 // draw border
1455 float line_width = 1;
1456 cairo_set_line_width(cr, line_width);
1457
1458 cairo_set_source_rgb(cr, flt_bg, flt_bg, flt_bg);
1459 cairo_new_path(cr);
1460 cairo_arc(cr, center_x, center_y, r_outside, 0.0, 2.0 * M_PI);
1461 cairo_stroke(cr);
1462 cairo_arc(cr, center_x, center_y, r_inside, 0.0, 2.0 * M_PI);
1463 cairo_stroke(cr);
1464
1465 cairo_set_source_rgb(cr, flt_dark, flt_dark, flt_dark);
1466 cairo_new_path(cr);
1467 cairo_arc(cr, center_x, center_y, r_outside, M_PI, 1.5 * M_PI);
1468 cairo_stroke(cr);
1469 cairo_arc(cr, center_x, center_y, r_inside, 0.0, 0.5 * M_PI);
1470 cairo_stroke(cr);
1471
1472 cairo_set_source_rgb(cr, flt_light, flt_light, flt_light);
1473 cairo_new_path(cr);
1474 cairo_arc(cr, center_x, center_y, r_outside, 0.0, 0.5 * M_PI);
1475 cairo_stroke(cr);
1476 cairo_arc(cr, center_x, center_y, r_inside, M_PI, 1.5 * M_PI);
1477 cairo_stroke(cr);
1478
1479 // draw selector
1480 double r = 255 / 255.0, g = 155 / 255.0, b = 40 / 255.0;
1481 double h, s, v;
1482
1483 gtk_rgb_to_hsv(r, g, b, &h, &s, &v);
1484
1485 cairo_save(cr);
1486 cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.7);
1487
1488 cairo_translate(cr, center_x, center_y);
1489 cairo_rotate(cr, h * 2.0 * M_PI - M_PI_2);
1490
1491 cairo_arc(cr, r_inside * v, 0.0, 3.0, 0, 2.0 * M_PI);
1492 cairo_stroke(cr);
1493
1494 cairo_restore(cr);
1495
1496 cairo_surface_destroy(source);
1497
1498 return TRUE;
1499}
1500#endif
1501
1502static void _configure_slider_blocks(gpointer instance, dt_iop_module_t *self)
1503{
1505
1506 GtkWidget *new_container = NULL;
1507 GtkWidget *old_container = gtk_bin_get_child(GTK_BIN(g->main_box));
1508
1509 for(int i=0; i<3; i++)
1510 {
1511 g_object_ref(G_OBJECT(g->blocks[i]));
1512 if(old_container) gtk_container_remove(GTK_CONTAINER(old_container), g->blocks[i]);
1513 }
1514
1515 if(old_container) gtk_widget_destroy(old_container);
1516
1517 const gchar *long_label[]
1518 = { N_("shadows: lift / offset"),
1519 N_("mid-tones: gamma / power"),
1520 N_("highlights: gain / slope") };
1521
1522 gchar *layout = dt_conf_get_string("plugins/darkroom/colorbalance/layout");
1523 new_container = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING);
1524
1525 for(int i=0; i<3; i++)
1526 {
1527 if(i == 0)
1528 gtk_label_set_text(GTK_LABEL(g->main_label), _(long_label[0]));
1529 else
1530 {
1531 GtkWidget *label = dt_ui_section_label_new(_(long_label[i]));
1532 gtk_container_add(GTK_CONTAINER(new_container), label);
1533 if(old_container) gtk_widget_show(label);
1534 }
1535
1536 gtk_container_add(GTK_CONTAINER(new_container), g->blocks[i]);
1537 }
1538
1539 dt_free(layout);
1540
1541 for(int i=0; i<3; i++) g_object_unref(G_OBJECT(g->blocks[i]));
1542
1543 gtk_container_add(GTK_CONTAINER(g->main_box), new_container);
1544 if(old_container) gtk_widget_show(new_container);
1545}
1546
1547static void _cycle_layout_callback(GtkWidget *label, GdkEventButton *event, dt_iop_module_t *self)
1548{
1549 _configure_slider_blocks(NULL, self);
1550}
1551
1552#define HSL_CALLBACK(which) \
1553static void which##_callback(GtkWidget *slider, gpointer user_data) \
1554{ \
1555 dt_iop_module_t *self = (dt_iop_module_t *)user_data; \
1556 dt_iop_colorbalance_params_t *p = (dt_iop_colorbalance_params_t *)self->params; \
1557 dt_iop_colorbalance_gui_data_t *g = (dt_iop_colorbalance_gui_data_t *)self->gui_data; \
1558 \
1559 if(darktable.gui->reset) return; \
1560 \
1561 dt_iop_color_picker_reset(self, TRUE); \
1562 \
1563 float hsl[3] = {dt_bauhaus_slider_get(g->hue_##which) / 360.0f, \
1564 dt_bauhaus_slider_get(g->sat_##which) / 100.0f, \
1565 0.5f}; \
1566 \
1567 if(slider == g->hue_##which) \
1568 update_saturation_slider_color(g->sat_##which, hsl[0]); \
1569 set_RGB_sliders(g->which##_r, g->which##_g, g->which##_b, hsl, p->which, p->mode); \
1570 dt_dev_add_history_item(darktable.develop, self, TRUE, TRUE); \
1571}
1572
1576
1578{
1580
1581 g->mode = NULL;
1582
1583 for (int k=0; k<LEVELS; k++)
1584 {
1585 g->color_patches_flags[k] = INVALID;
1586 g->luma_patches_flags[k] = INVALID;
1587 }
1588
1589 GtkWidget *mode_box = self->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING);
1590
1591 // mode choice
1592 g->mode = dt_bauhaus_combobox_from_params(self, N_("mode"));
1593 gtk_widget_set_tooltip_text(g->mode, _("color-grading mapping method"));
1594
1595 // control choice
1597 dt_bauhaus_widget_set_label(g->controls, N_("color control sliders"));
1598 dt_bauhaus_combobox_add(g->controls, _("HSL"));
1599 dt_bauhaus_combobox_add(g->controls, _("RGBL"));
1600 dt_bauhaus_combobox_add(g->controls, _("both"));
1601 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(g->controls), TRUE, TRUE, 0);
1602 gtk_widget_set_tooltip_text(g->controls, _("color-grading mapping method"));
1603 g_signal_connect(G_OBJECT(g->controls), "value-changed", G_CALLBACK(controls_callback), self);
1604
1605 const char *mode = dt_conf_get_string_const("plugins/darkroom/colorbalance/controls");
1606 dt_bauhaus_combobox_set(g->controls, !g_strcmp0(mode, "RGBL") ? RGBL :
1607 !g_strcmp0(mode, "BOTH") ? BOTH : HSL);
1608
1609 g->master_box = self->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING);
1610
1611 gtk_box_pack_start(GTK_BOX(g->master_box), dt_ui_section_label_new(_("master")), FALSE, FALSE, 0);
1612
1613 g->saturation = dt_bauhaus_slider_from_params(self, "saturation");
1614 dt_bauhaus_slider_set_soft_range(g->saturation, 0.5f, 1.5f);
1615 dt_bauhaus_slider_set_digits(g->saturation, 4);
1616 dt_bauhaus_slider_set_format(g->saturation, "%");
1617 gtk_widget_set_tooltip_text(g->saturation, _("saturation correction before the color balance"));
1618
1619 g->saturation_out = dt_bauhaus_slider_from_params(self, "saturation_out");
1620 dt_bauhaus_slider_set_soft_range(g->saturation_out, 0.5f, 1.5f);
1621 dt_bauhaus_slider_set_digits(g->saturation_out, 4);
1622 dt_bauhaus_slider_set_format(g->saturation_out, "%");
1623 gtk_widget_set_tooltip_text(g->saturation_out, _("saturation correction after the color balance"));
1624
1626 dt_bauhaus_slider_from_params(self, "grey"));
1627 dt_bauhaus_slider_set_format(g->grey, "%");
1628 gtk_widget_set_tooltip_text(g->grey, _("adjust to match a neutral tone"));
1629
1630 g->contrast = dt_bauhaus_slider_from_params(self, N_("contrast"));
1631 dt_bauhaus_slider_set_soft_range(g->contrast, 0.5f, 1.5f);
1632 dt_bauhaus_slider_set_digits(g->contrast, 4);
1633 dt_bauhaus_slider_set_factor(g->contrast, -100.0f);
1634 dt_bauhaus_slider_set_offset(g->contrast, 100.0f);
1635 dt_bauhaus_slider_set_format(g->contrast, "%");
1636 gtk_widget_set_tooltip_text(g->contrast, _("contrast"));
1637
1638#ifdef SHOW_COLOR_WHEELS
1639 GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, DT_GUI_BOX_SPACING);
1640 gtk_box_pack_start(GTK_BOX(self->widget), hbox, FALSE, FALSE, 0);
1641
1643 gtk_box_pack_start(GTK_BOX(hbox), area, TRUE, TRUE, 0);
1644
1645 // gtk_widget_add_events(g->area,
1646 // GDK_POINTER_MOTION_MASK |
1647 // GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_LEAVE_NOTIFY_MASK);
1648 g_signal_connect(G_OBJECT(area), "draw", G_CALLBACK(dt_iop_area_draw), self);
1649 // g_signal_connect (G_OBJECT (area), "button-press-event",
1650 // G_CALLBACK (dt_iop_colorbalance_button_press), self);
1651 // g_signal_connect (G_OBJECT (area), "motion-notify-event",
1652 // G_CALLBACK (dt_iop_colorbalance_motion_notify), self);
1653 // g_signal_connect (G_OBJECT (area), "leave-notify-event",
1654 // G_CALLBACK (dt_iop_colorbalance_leave_notify), self);
1655
1657 gtk_box_pack_start(GTK_BOX(hbox), area, TRUE, TRUE, 0);
1658
1659 // gtk_widget_add_events(g->area,
1660 // GDK_POINTER_MOTION_MASK |
1661 // GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_LEAVE_NOTIFY_MASK);
1662 g_signal_connect(G_OBJECT(area), "draw", G_CALLBACK(dt_iop_area_draw), self);
1663 // g_signal_connect (G_OBJECT (area), "button-press-event",
1664 // G_CALLBACK (dt_iop_colorbalance_button_press), self);
1665 // g_signal_connect (G_OBJECT (area), "motion-notify-event",
1666 // G_CALLBACK (dt_iop_colorbalance_motion_notify), self);
1667 // g_signal_connect (G_OBJECT (area), "leave-notify-event",
1668 // G_CALLBACK (dt_iop_colorbalance_leave_notify), self);
1669
1671 gtk_box_pack_start(GTK_BOX(hbox), area, TRUE, TRUE, 0);
1672
1673 // gtk_widget_add_events(g->area,
1674 // GDK_POINTER_MOTION_MASK |
1675 // GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_LEAVE_NOTIFY_MASK);
1676 g_signal_connect(G_OBJECT(area), "draw", G_CALLBACK(dt_iop_area_draw), self);
1677// g_signal_connect (G_OBJECT (area), "button-press-event",
1678// G_CALLBACK (dt_iop_colorbalance_button_press), self);
1679// g_signal_connect (G_OBJECT (area), "motion-notify-event",
1680// G_CALLBACK (dt_iop_colorbalance_motion_notify), self);
1681// g_signal_connect (G_OBJECT (area), "leave-notify-event",
1682// G_CALLBACK (dt_iop_colorbalance_leave_notify), self);
1683#endif
1684
1685 g->main_label = dt_ui_section_label_new(""); // is set in _configure_slider_blocks
1686 gtk_widget_set_tooltip_text(g->main_label, _("click to cycle layout"));
1687 GtkWidget *main_label_box = gtk_event_box_new();
1688 gtk_container_add(GTK_CONTAINER(main_label_box), g->main_label);
1689 g_signal_connect(G_OBJECT(main_label_box), "button-release-event", G_CALLBACK(_cycle_layout_callback), self);
1690
1691 g->main_box = gtk_event_box_new(); // is filled in _configure_slider_blocks
1692
1693 char field_name[10];
1694
1695#define ADD_CHANNEL(which, section, c, n, N, text, span) \
1696 sprintf(field_name, "%s[%d]", #which, CHANNEL_##N); \
1697 g->which##_##c = dt_bauhaus_slider_from_params(self, field_name); \
1698 dt_bauhaus_slider_set_soft_range(g->which##_##c, -span+1.0, span+1.0); \
1699 dt_bauhaus_slider_set_digits(g->which##_##c, 5); \
1700 dt_bauhaus_slider_set_offset(g->which##_##c, -1.0); \
1701 dt_bauhaus_slider_set_feedback(g->which##_##c, 0); \
1702 gtk_widget_set_tooltip_text(g->which##_##c, _(text[CHANNEL_##N])); \
1703 dt_bauhaus_widget_set_label(g->which##_##c, #n); \
1704
1705#define ADD_BLOCK(blk, which, section, text, span, satspan) \
1706 g->blocks[blk] = self->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING); \
1707 \
1708 sprintf(field_name, "%s[%d]", #which, CHANNEL_FACTOR); \
1709 g->which##_factor = dt_color_picker_new(self, DT_COLOR_PICKER_AREA, \
1710 dt_bauhaus_slider_from_params(self, field_name)); \
1711 dt_bauhaus_slider_set_soft_range(g->which##_factor, -span+1.0, span+1.0); \
1712 dt_bauhaus_slider_set_digits(g->which##_factor, 4); \
1713 dt_bauhaus_slider_set_factor(g->which##_factor, 100.0); \
1714 dt_bauhaus_slider_set_offset(g->which##_factor, - 100.0); \
1715 dt_bauhaus_slider_set_format(g->which##_factor,"%"); \
1716 dt_bauhaus_slider_set_feedback(g->which##_factor, 0); \
1717 dt_bauhaus_slider_set_stop(g->which##_factor, 0.0, 0.0, 0.0, 0.0); \
1718 dt_bauhaus_slider_set_stop(g->which##_factor, 1.0, 1.0, 1.0, 1.0); \
1719 gtk_widget_set_tooltip_text(g->which##_factor, _(text[CHANNEL_FACTOR])); \
1720 dt_bauhaus_widget_set_label(g->which##_factor, N_("factor")); \
1721 \
1722 g->hue_##which = dt_color_picker_new(self, DT_COLOR_PICKER_AREA, \
1723 dt_bauhaus_slider_new_with_range_and_feedback(darktable.bauhaus, DT_GUI_MODULE(self), \
1724 0.0f, 360.0f, 0, 0.0f, 2, 0)); \
1725 dt_bauhaus_widget_set_label(g->hue_##which, N_("hue")); \
1726 dt_bauhaus_slider_set_format(g->hue_##which, "\302\260"); \
1727 dt_bauhaus_slider_set_stop(g->hue_##which, 0.0f, 1.0f, 0.0f, 0.0f); \
1728 dt_bauhaus_slider_set_stop(g->hue_##which, 0.166f, 1.0f, 1.0f, 0.0f); \
1729 dt_bauhaus_slider_set_stop(g->hue_##which, 0.322f, 0.0f, 1.0f, 0.0f); \
1730 dt_bauhaus_slider_set_stop(g->hue_##which, 0.498f, 0.0f, 1.0f, 1.0f); \
1731 dt_bauhaus_slider_set_stop(g->hue_##which, 0.664f, 0.0f, 0.0f, 1.0f); \
1732 dt_bauhaus_slider_set_stop(g->hue_##which, 0.830f, 1.0f, 0.0f, 1.0f); \
1733 dt_bauhaus_slider_set_stop(g->hue_##which, 1.0f, 1.0f, 0.0f, 0.0f); \
1734 gtk_widget_set_tooltip_text(g->hue_##which, _("select the hue")); \
1735 g_signal_connect(G_OBJECT(g->hue_##which), "value-changed", \
1736 G_CALLBACK(which##_callback), self); \
1737 gtk_box_pack_start(GTK_BOX(self->widget), g->hue_##which, TRUE, TRUE, 0); \
1738 \
1739 g->sat_##which = dt_bauhaus_slider_new_with_range_and_feedback(darktable.bauhaus, DT_GUI_MODULE(self), \
1740 0.0f, 100.0f, 0, 0.0f, 2, 0); \
1741 dt_bauhaus_slider_set_soft_max(g->sat_##which, satspan); \
1742 dt_bauhaus_widget_set_label(g->sat_##which, N_("saturation")); \
1743 dt_bauhaus_slider_set_format(g->sat_##which, "%"); \
1744 dt_bauhaus_slider_set_stop(g->sat_##which, 0.0f, 0.2f, 0.2f, 0.2f); \
1745 dt_bauhaus_slider_set_stop(g->sat_##which, 1.0f, 1.0f, 1.0f, 1.0f); \
1746 gtk_widget_set_tooltip_text(g->sat_##which, _("select the saturation")); \
1747 g_signal_connect(G_OBJECT(g->sat_##which), "value-changed", \
1748 G_CALLBACK(which##_callback), self); \
1749 gtk_box_pack_start(GTK_BOX(self->widget), g->sat_##which, TRUE, TRUE, 0); \
1750 \
1751 ADD_CHANNEL(which, section, r, red, RED, text, span) \
1752 dt_bauhaus_slider_set_stop(g->which##_r, 0.0, 0.0, 1.0, 1.0); \
1753 dt_bauhaus_slider_set_stop(g->which##_r, 0.5, 1.0, 1.0, 1.0); \
1754 dt_bauhaus_slider_set_stop(g->which##_r, 1.0, 1.0, 0.0, 0.0); \
1755 ADD_CHANNEL(which, section, g, green, GREEN, text, span) \
1756 dt_bauhaus_slider_set_stop(g->which##_g, 0.0, 1.0, 0.0, 1.0); \
1757 dt_bauhaus_slider_set_stop(g->which##_g, 0.5, 1.0, 1.0, 1.0); \
1758 dt_bauhaus_slider_set_stop(g->which##_g, 1.0, 0.0, 1.0, 0.0); \
1759 ADD_CHANNEL(which, section, b, blue, BLUE, text, span) \
1760 dt_bauhaus_slider_set_stop(g->which##_b, 0.0, 1.0, 1.0, 0.0); \
1761 dt_bauhaus_slider_set_stop(g->which##_b, 0.5, 1.0, 1.0, 1.0); \
1762 dt_bauhaus_slider_set_stop(g->which##_b, 1.0, 0.0, 0.0, 1.0); \
1763
1764 static const char *lift_messages[]
1765 = { N_("factor of lift/offset"),
1766 N_("factor of red for lift/offset"),
1767 N_("factor of green for lift/offset"),
1768 N_("factor of blue for lift/offset") };
1769
1770 static const char *gamma_messages[]
1771 = { N_("factor of gamma/power"),
1772 N_("factor of red for gamma/power"),
1773 N_("factor of green for gamma/power"),
1774 N_("factor of blue for gamma/power") };
1775
1776 static const char *gain_messages[]
1777 = { N_("factor of gain/slope"),
1778 N_("factor of red for gain/slope"),
1779 N_("factor of green for gain/slope"),
1780 N_("factor of blue for gain/slope") };
1781
1782 ADD_BLOCK(0, lift, N_("shadows"), lift_messages, 0.05f, 5.0f)
1783 ADD_BLOCK(1, gamma, N_("mid-tones"), gamma_messages, 0.5f, 20.0f)
1784 ADD_BLOCK(2, gain, N_("highlights"), gain_messages, 0.5f, 25.0f)
1785 _configure_slider_blocks(NULL, self);
1786
1787 g->optimizer_box = self->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING);
1788
1789 gtk_box_pack_start(GTK_BOX(self->widget), dt_ui_section_label_new(_("auto optimizers")), FALSE, FALSE, 0);
1790
1791 g->auto_luma = dt_color_picker_new(self, DT_COLOR_PICKER_AREA,
1793 dt_bauhaus_widget_set_label(g->auto_luma, N_("optimize luma"));
1794 gtk_widget_set_tooltip_text(g->auto_luma, _("fit the whole histogram and center the average luma"));
1795 gtk_box_pack_start(GTK_BOX(self->widget), g->auto_luma, FALSE, FALSE, 0);
1796
1797 g->auto_color = dt_color_picker_new(self, DT_COLOR_PICKER_AREA,
1799 dt_bauhaus_widget_set_label(g->auto_color, N_("neutralize colors"));
1800 gtk_widget_set_tooltip_text(g->auto_color, _("optimize the RGB curves to remove color casts"));
1801 gtk_box_pack_start(GTK_BOX(self->widget), g->auto_color, FALSE, FALSE, 0);
1802
1803 // start building top level widget
1804 self->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING);
1805
1806 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(mode_box), TRUE, TRUE, 0);
1807 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(g->master_box), TRUE, TRUE, 0);
1808 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(main_label_box), TRUE, TRUE, 0);
1809 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(g->main_box), TRUE, TRUE, 0);
1810 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(g->optimizer_box), TRUE, TRUE, 0);
1811
1813 G_CALLBACK(_configure_slider_blocks), (gpointer)self);
1814}
1815
1822
1823// clang-format off
1824// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
1825// vim: shiftwidth=2 expandtab tabstop=2 cindent
1826// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
1827// clang-format on
static double dist(double x1, double y1, double x2, double y2)
Definition ashift_lsd.c:250
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_slider_set_soft_range(GtkWidget *widget, float soft_min, float soft_max)
Definition bauhaus.c:1647
void dt_bauhaus_slider_set_digits(GtkWidget *widget, int val)
Definition bauhaus.c:3534
void dt_bauhaus_slider_set_stop(GtkWidget *widget, float stop, float r, float g, float b)
Definition bauhaus.c:2372
int dt_bauhaus_combobox_get(GtkWidget *widget)
Definition bauhaus.c:2347
void dt_bauhaus_slider_set_offset(GtkWidget *widget, float offset)
Definition bauhaus.c:3618
void dt_bauhaus_slider_set(GtkWidget *widget, float pos)
Definition bauhaus.c:3506
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_slider_set_format(GtkWidget *widget, const char *format)
Definition bauhaus.c:3598
void dt_bauhaus_combobox_add(GtkWidget *widget, const char *text)
Definition bauhaus.c:2016
void dt_bauhaus_slider_set_factor(GtkWidget *widget, float factor)
Definition bauhaus.c:3611
int width
Definition bilateral.h:1
int height
Definition bilateral.h:1
int dt_develop_blend_legacy_params_from_so(dt_iop_module_so_t *module_so, const void *const old_params, const int old_version, void *new_params, const int new_version, const int length)
Definition blend.c:2180
int dt_develop_blend_version(void)
Definition blend.c:1630
#define CHANNEL_SIZE
static const dt_aligned_pixel_simd_t const dt_adaptation_t const float p
@ IOP_CS_LAB
void dt_iop_color_picker_reset(dt_iop_module_t *module, gboolean keep)
GtkWidget * dt_color_picker_new(dt_iop_module_t *module, dt_iop_color_picker_kind_t kind, GtkWidget *w)
@ DT_COLOR_PICKER_AREA
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)
const char ** description(struct dt_iop_module_t *self)
int default_group()
static void _check_tuner_picker_labels(dt_iop_module_t *self)
__DT_CLONE_TARGETS__ 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)
void gui_reset(dt_iop_module_t *self)
static void apply_autocolor(dt_iop_module_t *self)
static void apply_lift_auto(dt_iop_module_t *self)
static void add_preset(dt_iop_module_so_t *self, const char *name, const char *pi, const int version, const char *bpi, const int blendop_version)
static void apply_gain_neutralize(dt_iop_module_t *self)
void gui_update(dt_iop_module_t *self)
static void apply_autoluma(dt_iop_module_t *self)
static void _configure_slider_blocks(gpointer instance, dt_iop_module_t *self)
static float CDL(float x, float slope, float offset, float power)
static void apply_gamma_auto(dt_iop_module_t *self)
const char * aliases()
static void _cycle_layout_callback(GtkWidget *label, GdkEventButton *event, dt_iop_module_t *self)
dt_iop_colorbalance_mode_t
@ LEGACY
@ SLOPE_OFFSET_POWER
@ LIFT_GAMMA_GAIN
_controls_t
@ BOTH
@ RGBL
@ HSL
const char * name()
static void set_HSL_sliders(GtkWidget *hue, GtkWidget *sat, float RGB[4])
static void apply_gain_auto(dt_iop_module_t *self)
_colorbalance_patch_t
@ AUTO_SELECTED
@ USER_SELECTED
@ INVALID
static void apply_gamma_neutralize(dt_iop_module_t *self)
void gui_init(dt_iop_module_t *self)
static void apply_lift_neutralize(dt_iop_module_t *self)
_colorbalance_channel_t
@ CHANNEL_BLUE
@ CHANNEL_SIZE
@ CHANNEL_GREEN
@ CHANNEL_FACTOR
@ CHANNEL_RED
void gui_changed(dt_iop_module_t *self, GtkWidget *w, void *previous)
#define HSL_CALLBACK(which)
static void set_RGB_sliders(GtkWidget *R, GtkWidget *G, GtkWidget *B, float hsl[3], float *p, int mode)
void cleanup_global(dt_iop_module_so_t *module)
struct dt_iop_colorbalance_global_data_t dt_iop_colorbalance_global_data_t
void cleanup_pipe(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
int default_colorspace(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
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)
int flags()
#define ADD_BLOCK(blk, which, section, text, span, satspan)
static void update_saturation_slider_color(GtkWidget *slider, float hue)
void gui_cleanup(struct dt_iop_module_t *self)
void init_presets(dt_iop_module_so_t *self)
void init_pipe(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
void set_visible_widgets(dt_iop_colorbalance_gui_data_t *g)
static void apply_autogrey(dt_iop_module_t *self)
void init_global(dt_iop_module_so_t *module)
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)
_colorbalance_levels_t
@ LIFT
@ LEVELS
@ GAMMA
@ GAIN
static void controls_callback(GtkWidget *combo, dt_iop_module_t *self)
void color_picker_apply(dt_iop_module_t *self, GtkWidget *picker, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
int legacy_params(dt_iop_module_t *self, const void *const old_params, const int old_version, void *new_params, const int new_version)
#define B(y, x)
void rgb2hsl(const dt_aligned_pixel_t rgb, float *h, float *s, float *l)
void hsl2rgb(dt_aligned_pixel_t rgb, float h, float s, float l)
dt_prophotorgb_to_XYZ(rgb, XYZ)
static dt_aligned_pixel_t rgb
dt_Lab_to_XYZ(Lab, XYZ)
dt_XYZ_to_sRGB(XYZ, result)
dt_XYZ_to_prophotorgb(XYZ, rgb)
static dt_aligned_pixel_t XYZ
const dt_colormatrix_t dt_aligned_pixel_t out
dt_XYZ_to_Lab(XYZ, Lab)
static dt_aligned_pixel_t RGB
gchar * dt_conf_get_string(const char *name)
void dt_conf_set_string(const char *name, const char *val)
const char * dt_conf_get_string_const(const char *name)
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
@ DT_DEBUG_OPENCL
Definition darktable.h:722
#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_SIMD__(...)
Definition darktable.h:259
#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
@ DT_DEV_PIXELPIPE_DISPLAY_MASK
Definition develop.h:118
GtkWidget * dtgtk_drawing_area_new_with_aspect_ratio(double aspect)
Definition drawingarea.c:54
unsigned char * dt_exif_xmp_decode(const char *input, const int len, int *output_len)
Definition exif.cc:2337
void default_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 format.c:57
@ TYPE_FLOAT
Definition format.h:46
static GtkWidget * dt_ui_section_label_new(const gchar *str)
Definition gtk.h:451
#define DT_GUI_BOX_SPACING
Definition gtk.h:109
void dt_gui_presets_add_with_blendop(const char *name, dt_dev_operation_t op, const int32_t version, const void *params, const int32_t params_size, const void *blend_params, const int32_t enabled)
#define DT_GUI_MODULE(x)
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 IOP_GUI_FREE
Definition imageop.h:602
@ IOP_FLAGS_INCLUDE_IN_STYLES
Definition imageop.h:166
@ IOP_FLAGS_DEPRECATED
Definition imageop.h:168
@ IOP_FLAGS_SUPPORTS_BLENDING
Definition imageop.h:167
@ IOP_GROUP_COLOR
Definition imageop.h:139
#define IOP_GUI_ALLOC(module)
Definition imageop.h:599
GtkWidget * dt_bauhaus_slider_from_params(dt_iop_module_t *self, const char *param)
Definition imageop_gui.c:77
GtkWidget * dt_bauhaus_combobox_from_params(dt_iop_module_t *self, const char *param)
void *const ovoid
static const float x
const float v
float *const restrict const size_t k
float *const restrict const size_t const size_t ch
#define R
#define M_PI
Definition math.h:45
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_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
#define ROUNDUPDHT(a, b)
Definition opencl.h:82
#define ROUNDUPDWD(a, b)
Definition opencl.h:81
#define DT_DEBUG_CONTROL_SIGNAL_DISCONNECT(ctlsig, cb, user_data)
Definition signal.h:368
@ DT_SIGNAL_PREFERENCES_CHANGE
This signal is raised after preferences have been changed no parameters no return.
Definition signal.h:273
#define DT_DEBUG_CONTROL_SIGNAL_CONNECT(ctlsig, signal, cb, user_data)
Definition signal.h:357
struct _GtkWidget GtkWidget
Definition splash.h:29
const float r
struct dt_gui_gtk_t * gui
Definition darktable.h:775
struct dt_control_signal_t * signals
Definition darktable.h:774
struct dt_bauhaus_t * bauhaus
Definition darktable.h:778
struct dt_develop_t * develop
Definition darktable.h:770
struct dt_iop_module_t *void * data
int32_t reset
Definition gtk.h:172
unsigned int channels
Definition format.h:54
dt_iop_buffer_type_t datatype
Definition format.h:56
float gain[CHANNEL_SIZE]
float lift[CHANNEL_SIZE]
dt_iop_colorbalance_mode_t mode
float gamma[CHANNEL_SIZE]
_colorbalance_patch_t color_patches_flags[LEVELS]
_colorbalance_patch_t luma_patches_flags[LEVELS]
dt_iop_colorbalance_mode_t mode
float lift[CHANNEL_SIZE]
float gain[CHANNEL_SIZE]
float gamma[CHANNEL_SIZE]
GModule *dt_dev_operation_t op
Definition imageop.h:230
dt_iop_global_data_t * data
Definition imageop.h:233
dt_iop_params_t * default_params
Definition imageop.h:307
dt_iop_gui_data_t * gui_data
Definition imageop.h:311
dt_iop_global_data_t * global_data
Definition imageop.h:314
dt_aligned_pixel_t picked_color_min
Definition imageop.h:272
dt_aligned_pixel_t picked_color_max
Definition imageop.h:272
dt_aligned_pixel_t picked_color
Definition imageop.h:272
dt_iop_params_t * params
Definition imageop.h:307
Region of interest passed through the pixelpipe.
Definition imageop.h:72
#define MIN(a, b)
Definition thinplate.c:32
#define MAX(a, b)
Definition thinplate.c:29