Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
filmic.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2018-2020, 2023, 2025-2026 Aurélien PIERRE.
4 Copyright (C) 2018-2019 Edgardo Hoszowski.
5 Copyright (C) 2018 Matthieu Moy.
6 Copyright (C) 2018-2021 Pascal Obry.
7 Copyright (C) 2018 Philippe Weyland.
8 Copyright (C) 2019 Andreas Schneider.
9 Copyright (C) 2019-2020, 2022 Diederik Ter Rahe.
10 Copyright (C) 2019 luzpaz.
11 Copyright (C) 2019 Tobias Ellinghaus.
12 Copyright (C) 2020, 2022 Aldric Renaudin.
13 Copyright (C) 2020 Marco.
14 Copyright (C) 2020-2021 Ralf Brown.
15 Copyright (C) 2021 Chris Elston.
16 Copyright (C) 2021 Dan Torop.
17 Copyright (C) 2021 Hubert Kowalski.
18 Copyright (C) 2021 Victor Forsiuk.
19 Copyright (C) 2022 Hanno Schwalm.
20 Copyright (C) 2022 Martin Bařinka.
21 Copyright (C) 2022 Nicolas Auffray.
22 Copyright (C) 2022 Philipp Lutz.
23
24 darktable is free software: you can redistribute it and/or modify
25 it under the terms of the GNU General Public License as published by
26 the Free Software Foundation, either version 3 of the License, or
27 (at your option) any later version.
28
29 darktable is distributed in the hope that it will be useful,
30 but WITHOUT ANY WARRANTY; without even the implied warranty of
31 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32 GNU General Public License for more details.
33
34 You should have received a copy of the GNU General Public License
35 along with darktable. If not, see <http://www.gnu.org/licenses/>.
36*/
37#ifdef HAVE_CONFIG_H
38#include "config.h"
40#endif
41#include "develop/imageop_gui.h"
42#include "widgets/bauhaus.h"
43#include "system/macros.h"
44#include "system/openmp.h"
46#include "system/mem_alloc.h"
47#include "system/simd.h"
48#include "common/logging.h"
50#include "math/math.h"
51#include "common/opencl.h"
52#include "develop/develop.h"
54#include "widgets/expander.h"
55#include "widgets/paint.h"
56
57#include "gui/presets.h"
59#include "iop/iop_api.h"
60
61
62#include "develop/imageop.h"
63#include "widgets/draw.h"
64
65#include <assert.h>
66#include <math.h>
67#include <stdlib.h>
68#include <string.h>
69#include "widgets/label.h"
70#include "widgets/scroll_wrap.h"
71#include "gui/screen_metrics.h"
73
74#define DT_GUI_CURVE_EDITOR_INSET DT_PIXEL_APPLY_DPI(1)
75
76
78
79
126
151
153{
154 float table[0x10000]; // precomputed look-up table
155 float table_temp[0x10000]; // precomputed look-up for the optimized interpolation
156 float grad_2[0x10000];
157 float max_grad;
164 float contrast;
169
171{
172 int nodes;
173 float y[5];
174 float x[5];
176
182
183
184const char *name()
185{
186 return _("filmic (legacy)");
187}
188
190{
191 return IOP_GROUP_TONES;
192}
193
198
199const char *deprecated_msg()
200{
201 return _("this module is deprecated. better use filmic rgb module instead.");
202}
203
205{
206 return IOP_CS_LAB;
207}
208
211{
212 default_input_format(self, pipe, piece, dsc);
213 dsc->channels = 4;
214 dsc->datatype = TYPE_FLOAT;
215}
216
217int legacy_params(dt_iop_module_t *self, const void *const old_params, const int old_version, void *new_params,
218 const int new_version)
219{
220 if(old_version == 1 && new_version == 3)
221 {
222 typedef struct dt_iop_filmic_params_v1_t
223 {
224 float grey_point_source;
225 float black_point_source;
226 float white_point_source;
227 float security_factor;
228 float grey_point_target;
229 float black_point_target;
230 float white_point_target;
231 float output_power;
232 float latitude_stops;
233 float contrast;
234 float saturation;
235 float balance;
236 int interpolator;
237 } dt_iop_filmic_params_v1_t;
238
239 dt_iop_filmic_params_v1_t *o = (dt_iop_filmic_params_v1_t *)old_params;
242
243 *n = *d; // start with a fresh copy of default parameters
244
245 n->grey_point_source = o->grey_point_source;
246 n->white_point_source = o->white_point_source;
247 n->black_point_source = o->black_point_source;
248 n->security_factor = o->security_factor;
249 n->grey_point_target = o->grey_point_target;
250 n->black_point_target = o->black_point_target;
251 n->white_point_target = o->white_point_target;
252 n->output_power = o->output_power;
253 n->latitude_stops = o->latitude_stops;
254 n->contrast = o->contrast;
255 n->saturation = o->saturation;
256 n->balance = o->balance;
257 n->interpolator = o->interpolator;
258 n->preserve_color = 0;
259 n->global_saturation = 100;
260 return 0;
261 }
262
263 if (old_version == 2 && new_version == 3)
264 {
265 typedef struct dt_iop_filmic_params_v2_t
266 {
267 float grey_point_source;
268 float black_point_source;
269 float white_point_source;
270 float security_factor;
271 float grey_point_target;
272 float black_point_target;
273 float white_point_target;
274 float output_power;
275 float latitude_stops;
276 float contrast;
277 float saturation;
278 float balance;
279 int interpolator;
280 int preserve_color;
281 } dt_iop_filmic_params_v2_t;
282
283 dt_iop_filmic_params_v2_t *o = (dt_iop_filmic_params_v2_t *)old_params;
286
287 *n = *d; // start with a fresh copy of default parameters
288
289 n->grey_point_source = o->grey_point_source;
290 n->white_point_source = o->white_point_source;
291 n->black_point_source = o->black_point_source;
292 n->security_factor = o->security_factor;
293 n->grey_point_target = o->grey_point_target;
294 n->black_point_target = o->black_point_target;
295 n->white_point_target = o->white_point_target;
296 n->output_power = o->output_power;
297 n->latitude_stops = o->latitude_stops;
298 n->contrast = o->contrast;
299 n->saturation = o->saturation;
300 n->balance = o->balance;
301 n->interpolator = o->interpolator;
302 n->preserve_color = o->preserve_color;
303 n->global_saturation = 100;
304 return 0;
305 }
306 return 1;
307}
308
310{
312 memset(&p, 0, sizeof(p));
313
314 // Fine-tune settings, no use here
315 p.interpolator = CUBIC_SPLINE;
316
317 // Output - standard display, gamma 2.2
318 p.output_power = 2.2f;
319 p.white_point_target = 100.0f;
320 p.black_point_target = 0.0f;
321 p.grey_point_target = 18.0f;
322
323 // Input - standard raw picture
324 p.security_factor = 0.0f;
325 p.contrast = 1.618f;
326 p.preserve_color = 1;
327 p.balance = -12.0f;
328 p.saturation = 60.0f;
329 p.global_saturation = 70.0f;
330
331 // Presets low-key
332 p.grey_point_source = 25.4f;
333 p.latitude_stops = 2.25f;
334 p.white_point_source = 1.95f;
335 p.black_point_source = -7.05f;
336 dt_gui_presets_add_generic(_("09 EV (low-key)"), self->op,
337 self->version(), &p, sizeof(p), 1);
338
339 // Presets indoors
340 p.grey_point_source = 18.0f;
341 p.latitude_stops = 2.75f;
342 p.white_point_source = 2.45f;
343 p.black_point_source = -7.55f;
344 dt_gui_presets_add_generic(_("10 EV (indoors)"), self->op,
345 self->version(), &p, sizeof(p), 1);
346
347 // Presets dim-outdoors
348 p.grey_point_source = 12.77f;
349 p.latitude_stops = 3.0f;
350 p.white_point_source = 2.95f;
351 p.black_point_source = -8.05f;
352 dt_gui_presets_add_generic(_("11 EV (dim outdoors)"), self->op,
353 self->version(), &p, sizeof(p), 1);
354
355 // Presets outdoors
356 p.grey_point_source = 9.0f;
357 p.latitude_stops = 3.5f;
358 p.white_point_source = 3.45f;
359 p.black_point_source = -8.55f;
360 dt_gui_presets_add_generic(_("12 EV (outdoors)"), self->op,
361 self->version(), &p, sizeof(p), 1);
362
363 // Presets outdoors
364 p.grey_point_source = 6.38f;
365 p.latitude_stops = 3.75f;
366 p.white_point_source = 3.95f;
367 p.black_point_source = -9.05f;
368 dt_gui_presets_add_generic(_("13 EV (bright outdoors)"), self->op,
369 self->version(), &p, sizeof(p), 1);
370
371 // Presets backlighting
372 p.grey_point_source = 4.5f;
373 p.latitude_stops = 4.25f;
374 p.white_point_source = 4.45f;
375 p.black_point_source = -9.55f;
376 dt_gui_presets_add_generic(_("14 EV (backlighting)"), self->op,
377 self->version(), &p, sizeof(p), 1);
378
379 // Presets sunset
380 p.grey_point_source = 3.19f;
381 p.latitude_stops = 4.50f;
382 p.white_point_source = 4.95f;
383 p.black_point_source = -10.05f;
384 dt_gui_presets_add_generic(_("15 EV (sunset)"), self->op,
385 self->version(), &p, sizeof(p), 1);
386
387 // Presets HDR
388 p.grey_point_source = 2.25f;
389 p.latitude_stops = 5.0f;
390 p.white_point_source = 5.45f;
391 p.black_point_source = -10.55f;
392 dt_gui_presets_add_generic(_("16 EV (HDR)"), self->op,
393 self->version(), &p, sizeof(p), 1);
394
395 // Presets HDR+
396 p.grey_point_source = 1.125f;
397 p.latitude_stops = 6.0f;
398 p.white_point_source = 6.45f;
399 p.black_point_source = -11.55f;
400 dt_gui_presets_add_generic(_("18 EV (HDR++)"), self->op,
401 self->version(), &p, sizeof(p), 1);
402}
403
404static inline float gaussian(float x, float std)
405{
406 return expf(- (x * x) / (2.0f * std * std)) / (std * powf(2.0f * M_PI, 0.5f));
407}
408
411 const void *const ivoid, void *const ovoid)
412{
413 const dt_iop_roi_t *const roi_out = &piece->roi_out;
414 dt_iop_filmic_data_t *const data = (dt_iop_filmic_data_t *)piece->data;
415
416 const int ch = 4;
417
425 const float EPS = powf(2.0f, -16);
426 const int preserve_color = data->preserve_color;
427
428 // If saturation == 100, we have a no-op. Disable the op then.
429 const int desaturate = (data->global_saturation == 100.0f) ? FALSE : TRUE;
430 const float saturation = data->global_saturation / 100.0f;
432 for(size_t k = 0; k < (size_t)roi_out->height * roi_out->width * ch; k += ch)
433 {
434 float *in = ((float *)ivoid) + k;
435 float *out = ((float *)ovoid) + k;
436
438 dt_Lab_to_XYZ(in, XYZ);
439
440 dt_aligned_pixel_t rgb = { 0.0f };
442
443 float concavity, luma;
444
445 // Global desaturation
446 if (desaturate)
447 {
448 luma = XYZ[1];
449
450 for(int c = 0; c < 3; c++)
451 {
452 rgb[c] = luma + saturation * (rgb[c] - luma);
453 }
454 }
455
456 if (preserve_color)
457 {
458 int index;
459 dt_aligned_pixel_t ratios;
460 float max = fmaxf(fmaxf(rgb[0], rgb[1]), rgb[2]);
461
462 // Save the ratios
463 for (int c = 0; c < 3; ++c) ratios[c] = rgb[c] / max;
464
465 // Log tone-mapping
466 max = max / data->grey_source;
467 max = (max > EPS) ? (fastlog2(max) - data->black_source) / data->dynamic_range : EPS;
468 max = CLAMP(max, 0.0f, 1.0f);
469
470 // Filmic S curve on the max RGB
471 index = CLAMP(max * 0x10000ul, 0, 0xffff);
472 max = data->table[index];
473 concavity = data->grad_2[index];
474
475 // Re-apply ratios
476 for (int c = 0; c < 3; ++c) rgb[c] = ratios[c] * max;
477
478 luma = max;
479 }
480 else
481 {
482 int DT_ALIGNED_ARRAY index[4];
483
484 for(int c = 0; c < 3; c++)
485 {
486 // Log tone-mapping on RGB
487 rgb[c] = rgb[c] / data->grey_source;
488 rgb[c] = (rgb[c] > EPS) ? (fastlog2(rgb[c]) - data->black_source) / data->dynamic_range : EPS;
489 rgb[c] = CLAMP(rgb[c], 0.0f, 1.0f);
490
491 // Store the index of the LUT
492 index[c] = CLAMP(rgb[c] * 0x10000ul, 0, 0xffff);
493 }
494
495 // Concavity
497 concavity = data->grad_2[(int)CLAMP(XYZ[1] * 0x10000ul, 0, 0xffff)];
498
499 // Filmic S curve
500 for(int c = 0; c < 3; c++) rgb[c] = data->table[index[c]];
501
503 luma = XYZ[1];
504 }
505
506 // Desaturate on the non-linear parts of the curve
507 for(int c = 0; c < 3; c++)
508 {
509 // Desaturate on the non-linear parts of the curve
510 rgb[c] = luma + concavity * (rgb[c] - luma);
511
512 // Apply the transfer function of the display
513 rgb[c] = powf(CLAMP(rgb[c], 0.0f, 1.0f), data->output_power);
514 }
515
516 // transform the result back to Lab
517 // sRGB -> XYZ
518 dt_prophotorgb_to_Lab(rgb, out);
519 }
520
522 dt_iop_alpha_copy(ivoid, ovoid, roi_out->width, roi_out->height);
523 return 0;
524}
525
526
527#ifdef HAVE_OPENCL
528int 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)
529{
530 const dt_iop_roi_t *const roi_in = &piece->roi_in;
533
534 cl_int err = -999;
535 const int devid = pipe->devid;
536 const int width = roi_in->width;
537 const int height = roi_in->height;
538
539 size_t sizes[] = { ROUNDUPDWD(width, devid), ROUNDUPDHT(height, devid), 1 };
540
541 cl_mem dev_table = NULL;
542 cl_mem diff_table = NULL;
543
544 dev_table = dt_opencl_copy_host_to_device(devid, d->table, 256, 256, sizeof(float));
545 if(IS_NULL_PTR(dev_table)) goto error;
546
547 diff_table = dt_opencl_copy_host_to_device(devid, d->grad_2, 256, 256, sizeof(float));
548 if(IS_NULL_PTR(diff_table)) goto error;
549
550 const float dynamic_range = d->dynamic_range;
551 const float shadows_range = d->black_source;
552 const float grey = d->grey_source;
553 const float contrast = d->contrast;
554 const float power = d->output_power;
555 const int preserve_color = d->preserve_color;
556 const float saturation = d->global_saturation / 100.0f;
557
558 dt_opencl_set_kernel_arg(devid, gd->kernel_filmic, 0, sizeof(cl_mem), (void *)&dev_in);
559 dt_opencl_set_kernel_arg(devid, gd->kernel_filmic, 1, sizeof(cl_mem), (void *)&dev_out);
560 dt_opencl_set_kernel_arg(devid, gd->kernel_filmic, 2, sizeof(int), (void *)&width);
561 dt_opencl_set_kernel_arg(devid, gd->kernel_filmic, 3, sizeof(int), (void *)&height);
562 dt_opencl_set_kernel_arg(devid, gd->kernel_filmic, 4, sizeof(float), (void *)&dynamic_range);
563 dt_opencl_set_kernel_arg(devid, gd->kernel_filmic, 5, sizeof(float), (void *)&shadows_range);
564 dt_opencl_set_kernel_arg(devid, gd->kernel_filmic, 6, sizeof(float), (void *)&grey);
565 dt_opencl_set_kernel_arg(devid, gd->kernel_filmic, 7, sizeof(cl_mem), (void *)&dev_table);
566 dt_opencl_set_kernel_arg(devid, gd->kernel_filmic, 8, sizeof(cl_mem), (void *)&diff_table);
567 dt_opencl_set_kernel_arg(devid, gd->kernel_filmic, 9, sizeof(float), (void *)&contrast);
568 dt_opencl_set_kernel_arg(devid, gd->kernel_filmic, 10, sizeof(float), (void *)&power);
569 dt_opencl_set_kernel_arg(devid, gd->kernel_filmic, 11, sizeof(int), (void *)&preserve_color);
570 dt_opencl_set_kernel_arg(devid, gd->kernel_filmic, 12, sizeof(int), (void *)&saturation);
571
572 err = dt_opencl_enqueue_kernel_2d(devid, gd->kernel_filmic, sizes);
573 if(err != CL_SUCCESS) goto error;
576 return TRUE;
577
578error:
581 dt_print(DT_DEBUG_OPENCL, "[opencl_filmic] couldn't enqueue kernel! %d\n", err);
582 return FALSE;
583}
584#endif
585
587{
588 if (p->latitude_stops > (p->white_point_source - p->black_point_source) * 0.99f)
589 {
590 // The film latitude is its linear part
591 // it can never be higher than the dynamic range
592 p->latitude_stops = (p->white_point_source - p->black_point_source) * 0.99f;
594 dt_bauhaus_slider_set(g->latitude_stops, p->latitude_stops);
596 }
597}
598
600{
601 if(dt_gui_widgets_suppressed()) return;
604
605 dt_aligned_pixel_t XYZ = { 0.0f };
607
608 const float grey = XYZ[1];
609 const float prev_grey = p->grey_point_source;
610 p->grey_point_source = 100.f * grey;
611 const float grey_var = Log2(prev_grey / p->grey_point_source);
612 p->black_point_source = p->black_point_source - grey_var;
613 p->white_point_source = p->white_point_source + grey_var;
614
616 dt_bauhaus_slider_set(g->grey_point_source, p->grey_point_source);
617 dt_bauhaus_slider_set(g->black_point_source, p->black_point_source);
618 dt_bauhaus_slider_set(g->white_point_source, p->white_point_source);
620
621 dt_dev_add_history_item(self->dev, self, TRUE, TRUE);
622 gtk_widget_queue_draw(self->gui->widget);
623}
624
626{
627 if(dt_gui_widgets_suppressed()) return;
630
631 const float noise = powf(2.0f, -16.0f);
632 dt_aligned_pixel_t XYZ = { 0.0f };
633
634 // Black
636 const float black = XYZ[1];
637 float EVmin = Log2Thres(black / (p->grey_point_source / 100.0f), noise);
638 EVmin *= (1.0f + p->security_factor / 100.0f);
639
640 p->black_point_source = EVmin;
641
643 dt_bauhaus_slider_set(g->black_point_source, p->black_point_source);
645
647
648 dt_dev_add_history_item(self->dev, self, TRUE, TRUE);
649 gtk_widget_queue_draw(self->gui->widget);
650}
651
652
654{
655 if(dt_gui_widgets_suppressed()) return;
658
659 const float noise = powf(2.0f, -16.0f);
660 dt_aligned_pixel_t XYZ = { 0.0f };
661
662 // White
664 const float white = XYZ[1];
665 float EVmax = Log2Thres(white / (p->grey_point_source / 100.0f), noise);
666 EVmax *= (1.0f + p->security_factor / 100.0f);
667
668 p->white_point_source = EVmax;
669
671 dt_bauhaus_slider_set(g->white_point_source, p->white_point_source);
673
675
676 dt_dev_add_history_item(self->dev, self, TRUE, TRUE);
677 gtk_widget_queue_draw(self->gui->widget);
678}
679
680static void security_threshold_callback(GtkWidget *slider, gpointer user_data)
681{
682 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
683 if(dt_gui_widgets_suppressed()) return;
686
687 float previous = p->security_factor;
688 p->security_factor = dt_bauhaus_slider_get(slider);
689 float ratio = (p->security_factor - previous) / (previous + 100.0f);
690
691 float EVmin = p->black_point_source;
692 EVmin = EVmin + ratio * EVmin;
693
694 float EVmax = p->white_point_source;
695 EVmax = EVmax + ratio * EVmax;
696
697 p->white_point_source = EVmax;
698 p->black_point_source = EVmin;
699
701 dt_bauhaus_slider_set(g->white_point_source, p->white_point_source);
702 dt_bauhaus_slider_set(g->black_point_source, p->black_point_source);
704
706
708
709 dt_dev_add_history_item(self->dev, self, TRUE, TRUE);
710 gtk_widget_queue_draw(self->gui->widget);
711}
712
714{
717
718 const float noise = powf(2.0f, -16.0f);
719 dt_aligned_pixel_t XYZ = { 0.0f };
720
721 // Grey
723 const float grey = XYZ[1];
724 p->grey_point_source = 100.f * grey;
725
726 // Black
728 const float black = XYZ[1];
729 float EVmin = Log2Thres(black / (p->grey_point_source / 100.0f), noise);
730 EVmin *= (1.0f + p->security_factor / 100.0f);
731
732 // White
734 const float white = XYZ[1];
735 float EVmax = Log2Thres(white / (p->grey_point_source / 100.0f), noise);
736 EVmax *= (1.0f + p->security_factor / 100.0f);
737
738 p->black_point_source = EVmin;
739 p->white_point_source = EVmax;
740
742 dt_bauhaus_slider_set(g->grey_point_source, p->grey_point_source);
743 dt_bauhaus_slider_set(g->black_point_source, p->black_point_source);
744 dt_bauhaus_slider_set(g->white_point_source, p->white_point_source);
746
748
749 dt_dev_add_history_item(self->dev, self, TRUE, TRUE);
750 gtk_widget_queue_draw(self->gui->widget);
751}
752
754{
756 if (picker == g->grey_point_source)
757 apply_auto_grey(self);
758 else if(picker == g->black_point_source)
759 apply_auto_black(self);
760 else if(picker == g->white_point_source)
762 else if(picker == g->auto_button)
763 apply_autotune(self);
764 else
765 fprintf(stderr, "[filmic] unknown color picker\n");
766}
767
768static void grey_point_source_callback(GtkWidget *slider, gpointer user_data)
769{
770 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
771 if(dt_gui_widgets_suppressed()) return;
774 float prev_grey = p->grey_point_source;
775 p->grey_point_source = dt_bauhaus_slider_get(slider);
776
777 float grey_var = Log2(prev_grey / p->grey_point_source);
778 p->black_point_source = p->black_point_source - grey_var;
779 p->white_point_source = p->white_point_source + grey_var;
780
782 dt_bauhaus_slider_set(g->white_point_source, p->white_point_source);
783 dt_bauhaus_slider_set(g->black_point_source, p->black_point_source);
785
787
788 dt_dev_add_history_item(self->dev, self, TRUE, TRUE);
789 gtk_widget_queue_draw(self->gui->widget);
790}
791
792static void white_point_source_callback(GtkWidget *slider, gpointer user_data)
793{
794 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
795 if(dt_gui_widgets_suppressed()) return;
798 p->white_point_source = dt_bauhaus_slider_get(slider);
799
801
803
804 dt_dev_add_history_item(self->dev, self, TRUE, TRUE);
805 gtk_widget_queue_draw(self->gui->widget);
806}
807
808static void black_point_source_callback(GtkWidget *slider, gpointer user_data)
809{
810 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
811 if(dt_gui_widgets_suppressed()) return;
814 p->black_point_source = dt_bauhaus_slider_get(slider);
815
817
819
820 dt_dev_add_history_item(self->dev, self, TRUE, TRUE);
821 gtk_widget_queue_draw(self->gui->widget);
822}
823
824static void grey_point_target_callback(GtkWidget *slider, gpointer user_data)
825{
826 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
827 if(dt_gui_widgets_suppressed()) return;
829 p->grey_point_target = dt_bauhaus_slider_get(slider);
831 dt_dev_add_history_item(self->dev, self, TRUE, TRUE);
832 gtk_widget_queue_draw(self->gui->widget);
833}
834
835static void latitude_stops_callback(GtkWidget *slider, gpointer user_data)
836{
837 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
838 if(dt_gui_widgets_suppressed()) return;
841
842 p->latitude_stops = dt_bauhaus_slider_get(slider);
843
845
847 dt_dev_add_history_item(self->dev, self, TRUE, TRUE);
848 gtk_widget_queue_draw(self->gui->widget);
849}
850
851static void contrast_callback(GtkWidget *slider, gpointer user_data)
852{
853 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
854 if(dt_gui_widgets_suppressed()) return;
856 p->contrast = dt_bauhaus_slider_get(slider);
858 dt_dev_add_history_item(self->dev, self, TRUE, TRUE);
859 gtk_widget_queue_draw(self->gui->widget);
860}
861
862static void saturation_callback(GtkWidget *slider, gpointer user_data)
863{
864 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
865 if(dt_gui_widgets_suppressed()) return;
867 p->saturation = logf(9.0f * dt_bauhaus_slider_get(slider)/100.0 + 1.0f) / logf(10.0f) * 100.0f;
869 dt_dev_add_history_item(self->dev, self, TRUE, TRUE);
870}
871
872static void global_saturation_callback(GtkWidget *slider, gpointer user_data)
873{
874 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
875 if(dt_gui_widgets_suppressed()) return;
877 p->global_saturation = dt_bauhaus_slider_get(slider);
879 dt_dev_add_history_item(self->dev, self, TRUE, TRUE);
880}
881
882static void white_point_target_callback(GtkWidget *slider, gpointer user_data)
883{
884 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
885 if(dt_gui_widgets_suppressed()) return;
887 p->white_point_target = dt_bauhaus_slider_get(slider);
889 dt_dev_add_history_item(self->dev, self, TRUE, TRUE);
890 gtk_widget_queue_draw(self->gui->widget);
891}
892
893static void black_point_target_callback(GtkWidget *slider, gpointer user_data)
894{
895 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
896 if(dt_gui_widgets_suppressed()) return;
898 p->black_point_target = dt_bauhaus_slider_get(slider);
900 dt_dev_add_history_item(self->dev, self, TRUE, TRUE);
901 gtk_widget_queue_draw(self->gui->widget);
902}
903
904static void output_power_callback(GtkWidget *slider, gpointer user_data)
905{
906 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
907 if(dt_gui_widgets_suppressed()) return;
909 p->output_power = dt_bauhaus_slider_get(slider);
911 dt_dev_add_history_item(self->dev, self, TRUE, TRUE);
912 gtk_widget_queue_draw(self->gui->widget);
913}
914
915static void balance_callback(GtkWidget *slider, gpointer user_data)
916{
917 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
918 if(dt_gui_widgets_suppressed()) return;
920 p->balance = dt_bauhaus_slider_get(slider);
922 dt_dev_add_history_item(self->dev, self, TRUE, TRUE);
923 gtk_widget_queue_draw(self->gui->widget);
924}
925
927{
928 if(dt_gui_widgets_suppressed()) return;
931 const int combo = dt_bauhaus_combobox_get(widget);
932
933 switch (combo)
934 {
935 case CUBIC_SPLINE:
936 {
937 p->interpolator = CUBIC_SPLINE;
938 break;
939 }
940 case CATMULL_ROM:
941 {
942 p->interpolator = CATMULL_ROM;
943 break;
944 }
945 case MONOTONE_HERMITE:
946 {
947 p->interpolator = MONOTONE_HERMITE;
948 break;
949 }
950 case 3:
951 {
952 p->interpolator = 3; // Optimized
953 break;
954 }
955 default:
956 {
957 p->interpolator = CUBIC_SPLINE;
958 break;
959 }
960 }
961
962 dt_dev_add_history_item(self->dev, self, TRUE, TRUE);
963 gtk_widget_queue_draw(self->gui->widget);
964}
965
967{
968 if(dt_gui_widgets_suppressed()) return;
970 p->preserve_color = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
971 dt_dev_add_history_item(self->dev, self, TRUE, TRUE);
972}
973
974void compute_curve_lut(dt_iop_filmic_params_t *p, float *table, float *table_temp, int res,
976{
977 dt_draw_curve_t *curve;
978
979 const float white_source = p->white_point_source;
980 const float black_source = p->black_point_source;
981 const float dynamic_range = white_source - black_source;
982
983 // luminance after log encoding
984 const float black_log = 0.0f; // assumes user set log as in the autotuner
985 const float grey_log = fabsf(p->black_point_source) / dynamic_range;
986 const float white_log = 1.0f; // assumes user set log as in the autotuner
987
988 // target luminance desired after filmic curve
989 const float black_display = CLAMP(p->black_point_target, 0.0f, p->grey_point_target) / 100.0f; // in %
990 const float grey_display = powf(CLAMP(p->grey_point_target, p->black_point_target, p->white_point_target) / 100.0f, 1.0f / (p->output_power));
991 const float white_display = CLAMP(p->white_point_target, p->grey_point_target, 100.0f) / 100.0f; // in %
992
993 const float latitude = CLAMP(p->latitude_stops, 0.01f, dynamic_range * 0.99f);
994 const float balance = CLAMP(p->balance, -50.0f, 50.0f) / 100.0f; // in %
995
996 const float contrast = p->contrast;
997
998 // nodes for mapping from log encoding to desired target luminance
999 // X coordinates
1000 float toe_log = grey_log - latitude/dynamic_range * fabsf(black_source/dynamic_range);
1001 float shoulder_log = grey_log + latitude/dynamic_range * white_source/dynamic_range;
1002
1003
1004 // interception
1005 float linear_intercept = grey_display - (contrast * grey_log);
1006
1007 // y coordinates
1008 float toe_display = (toe_log * contrast + linear_intercept);
1009 float shoulder_display = (shoulder_log * contrast + linear_intercept);
1010
1011 // Apply the highlights/shadows balance as a shift along the contrast slope
1012 const float norm = powf(powf(contrast, 2.0f) + 1.0f, 0.5f);
1013
1014 // negative values drag to the left and compress the shadows, on the UI negative is the inverse
1015 const float coeff = -(dynamic_range - latitude) / dynamic_range * balance;
1016
1017 toe_display += coeff * contrast /norm;
1018 shoulder_display += coeff * contrast /norm;
1019 toe_log += coeff /norm;
1020 shoulder_log += coeff /norm;
1021
1022 // Sanitize pass 1
1023 toe_log = CLAMP(toe_log, 0.0f, grey_log);
1024 shoulder_log = CLAMP(shoulder_log, grey_log, 1.0f);
1025 toe_display = CLAMP(toe_display, black_display, grey_display);
1026 shoulder_display = CLAMP(shoulder_display, grey_display, white_display);
1027
1038 // sanitize pass 2
1039 int TOE_LOST = FALSE;
1040 int SHOULDER_LOST = FALSE;
1041
1042 if ((toe_log == grey_log && toe_display == grey_display) || (toe_log == 0.0f && toe_display == black_display))
1043 {
1044 TOE_LOST = TRUE;
1045 }
1046 if ((shoulder_log == grey_log && shoulder_display == grey_display) || (shoulder_log == 1.0f && shoulder_display == white_display))
1047 {
1048 SHOULDER_LOST = TRUE;
1049 }
1050
1051 // Build the curve from the nodes
1052
1053 if (SHOULDER_LOST && !TOE_LOST)
1054 {
1055 // shoulder only broke - we remove it
1056 nodes_data->nodes = 4;
1057 nodes_data->x[0] = black_log;
1058 nodes_data->x[1] = toe_log;
1059 nodes_data->x[2] = grey_log;
1060 nodes_data->x[3] = white_log;
1061
1062 nodes_data->y[0] = black_display;
1063 nodes_data->y[1] = toe_display;
1064 nodes_data->y[2] = grey_display;
1065 nodes_data->y[3] = white_display;
1066
1067 if(!IS_NULL_PTR(d))
1068 {
1069 d->latitude_min = toe_log;
1070 d->latitude_max = white_log;
1071 }
1072
1073 //dt_control_log(_("filmic curve using 4 nodes - highlights lost"));
1074
1075 }
1076 else if (TOE_LOST && !SHOULDER_LOST)
1077 {
1078 // toe only broke - we remove it
1079 nodes_data->nodes = 4;
1080
1081 nodes_data->x[0] = black_log;
1082 nodes_data->x[1] = grey_log;
1083 nodes_data->x[2] = shoulder_log;
1084 nodes_data->x[3] = white_log;
1085
1086 nodes_data->y[0] = black_display;
1087 nodes_data->y[1] = grey_display;
1088 nodes_data->y[2] = shoulder_display;
1089 nodes_data->y[3] = white_display;
1090
1091 if(!IS_NULL_PTR(d))
1092 {
1093 d->latitude_min = black_log;
1094 d->latitude_max = shoulder_log;
1095 }
1096
1097 //dt_control_log(_("filmic curve using 4 nodes - shadows lost"));
1098
1099 }
1100 else if (TOE_LOST && SHOULDER_LOST)
1101 {
1102 // toe and shoulder both broke - we remove them
1103 nodes_data->nodes = 3;
1104
1105 nodes_data->x[0] = black_log;
1106 nodes_data->x[1] = grey_log;
1107 nodes_data->x[2] = white_log;
1108
1109 nodes_data->y[0] = black_display;
1110 nodes_data->y[1] = grey_display;
1111 nodes_data->y[2] = white_display;
1112
1113 if(!IS_NULL_PTR(d))
1114 {
1115 d->latitude_min = black_log;
1116 d->latitude_max = white_log;
1117 }
1118
1119 //dt_control_log(_("filmic curve using 3 nodes - highlights & shadows lost"));
1120
1121 }
1122 else
1123 {
1124 // everything OK
1125 nodes_data->nodes = 4;
1126
1127 nodes_data->x[0] = black_log;
1128 nodes_data->x[1] = toe_log;
1129 //nodes_data->x[2] = grey_log,
1130 nodes_data->x[2] = shoulder_log;
1131 nodes_data->x[3] = white_log;
1132
1133 nodes_data->y[0] = black_display;
1134 nodes_data->y[1] = toe_display;
1135 //nodes_data->y[2] = grey_display,
1136 nodes_data->y[2] = shoulder_display;
1137 nodes_data->y[3] = white_display;
1138
1139 if(!IS_NULL_PTR(d))
1140 {
1141 d->latitude_min = toe_log;
1142 d->latitude_max = shoulder_log;
1143 }
1144
1145 //dt_control_log(_("filmic curve using 5 nodes - everything alright"));
1146 }
1147
1148 if (p->interpolator != 3)
1149 {
1150 // Compute the interpolation
1151
1152 // Catch bad interpolators exceptions (errors in saved params)
1153 int interpolator = CUBIC_SPLINE;
1154 if (p->interpolator > CUBIC_SPLINE && p->interpolator <= MONOTONE_HERMITE) interpolator = p->interpolator;
1155
1156 curve = dt_draw_curve_new(0.0, 1.0, interpolator);
1157 for(int k = 0; k < nodes_data->nodes; k++) (void)dt_draw_curve_add_point(curve, nodes_data->x[k], nodes_data->y[k]);
1158
1159 // Compute the LUT
1160 dt_draw_curve_calc_values(curve, 0.0f, 1.0f, res, NULL, table);
1161 dt_draw_curve_destroy(curve);
1162
1163 }
1164 else
1165 {
1166 // Compute the monotonic interpolation
1167 curve = dt_draw_curve_new(0.0, 1.0, MONOTONE_HERMITE);
1168 for(int k = 0; k < nodes_data->nodes; k++) (void)dt_draw_curve_add_point(curve, nodes_data->x[k], nodes_data->y[k]);
1169 dt_draw_curve_calc_values(curve, 0.0f, 1.0f, res, NULL, table_temp);
1170 dt_draw_curve_destroy(curve);
1171
1172 // Compute the cubic spline interpolation
1173 curve = dt_draw_curve_new(0.0, 1.0, CUBIC_SPLINE);
1174 for(int k = 0; k < nodes_data->nodes; k++) (void)dt_draw_curve_add_point(curve, nodes_data->x[k], nodes_data->y[k]);
1175 dt_draw_curve_calc_values(curve, 0.0f, 1.0f, res, NULL, table);
1176 dt_draw_curve_destroy(curve);
1177
1178 // Average both LUT
1180 for(int k = 0; k < res; k++) table[k] = (table[k] + table_temp[k]) / 2.0f;
1181 }
1182
1183}
1184
1187{
1190
1191 d->preserve_color = p->preserve_color;
1192
1193 // source luminance - Used only in the log encoding
1194 const float white_source = p->white_point_source;
1195 const float grey_source = p->grey_point_source / 100.0f; // in %
1196 const float black_source = p->black_point_source;
1197 const float dynamic_range = white_source - black_source;
1198
1199 // luminance after log encoding
1200 const float grey_log = fabsf(p->black_point_source) / dynamic_range;
1201
1202 // target luminance desired after filmic curve
1203 const float grey_display = powf(p->grey_point_target / 100.0f, 1.0f / (p->output_power));
1204
1205 float contrast = p->contrast;
1206 if (contrast < grey_display / grey_log)
1207 {
1208 // We need grey_display - (contrast * grey_log) <= 0.0
1209 contrast = 1.0001f * grey_display / grey_log;
1210 }
1211
1212 // commitproducts with no low-pass filter, you will increase the contrast of nois
1213 d->dynamic_range = dynamic_range;
1214 d->black_source = black_source;
1215 d->grey_source = grey_source;
1216 d->output_power = p->output_power;
1217 d->saturation = p->saturation;
1218 d->global_saturation = p->global_saturation;
1219 d->contrast = contrast;
1220
1221 // compute the curves and their LUT
1222 dt_iop_filmic_nodes_t *nodes_data = (dt_iop_filmic_nodes_t *)malloc(sizeof(dt_iop_filmic_nodes_t));
1223 compute_curve_lut(p, d->table, d->table_temp, 0x10000, d, nodes_data);
1224 dt_free(nodes_data);
1225
1226 // Build a window function based on the log.
1227 // This will be used to selectively desaturate the non-linear parts
1228 // to avoid over-saturation in the toe and shoulder.
1229
1230 const float latitude = d->latitude_max - d->latitude_min;
1231 const float center = (d->latitude_max + d->latitude_min)/2.0f;
1232 const float saturation = d->saturation / 100.0f;
1233 const float sigma = saturation * saturation * latitude * latitude;
1235 for(int k = 0; k < 65536; k++)
1236 {
1237 const float x = ((float)k) / 65536.0f;
1238 if (sigma != 0.0f)
1239 {
1240 d->grad_2[k] = expf(-0.5f * (center - x) * (center - x) / sigma);
1241 }
1242 else
1243 {
1244 d->grad_2[k] = 0.0f;
1245 }
1246 }
1247
1248}
1249
1251{
1252 piece->data = dt_calloc_align(sizeof(dt_iop_filmic_data_t));
1253 piece->data_size = sizeof(dt_iop_filmic_data_t);
1254}
1255
1257{
1258 dt_free_align(piece->data);
1259 piece->data = NULL;
1260}
1261
1263{
1264 dt_iop_module_t *module = (dt_iop_module_t *)self;
1266 dt_iop_filmic_params_t *p = (dt_iop_filmic_params_t *)module->params;
1267
1269
1270 dt_bauhaus_slider_set(g->white_point_source, p->white_point_source);
1271 dt_bauhaus_slider_set(g->grey_point_source, p->grey_point_source);
1272 dt_bauhaus_slider_set(g->black_point_source, p->black_point_source);
1273 dt_bauhaus_slider_set(g->security_factor, p->security_factor);
1274 dt_bauhaus_slider_set(g->white_point_target, p->white_point_target);
1275 dt_bauhaus_slider_set(g->grey_point_target, p->grey_point_target);
1276 dt_bauhaus_slider_set(g->black_point_target, p->black_point_target);
1277 dt_bauhaus_slider_set(g->output_power, p->output_power);
1278 dt_bauhaus_slider_set(g->latitude_stops, p->latitude_stops);
1279 dt_bauhaus_slider_set(g->contrast, p->contrast);
1280 dt_bauhaus_slider_set(g->global_saturation, p->global_saturation);
1281 dt_bauhaus_slider_set(g->saturation, (powf(10.0f, p->saturation/100.0f) - 1.0f) / 9.0f * 100.0f);
1282 dt_bauhaus_slider_set(g->balance, p->balance);
1283
1284 dt_bauhaus_combobox_set(g->interpolator, p->interpolator);
1285 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(g->preserve_color), p->preserve_color);
1286
1288 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(g->extra_toggle)));
1289
1290 gtk_widget_queue_draw(self->gui->widget);
1291
1292}
1293
1295{
1296 module->params = calloc(1, sizeof(dt_iop_filmic_params_t));
1297 module->default_params = calloc(1, sizeof(dt_iop_filmic_params_t));
1298 module->default_enabled = 0;
1299 module->params_size = sizeof(dt_iop_filmic_params_t);
1300
1303 .grey_point_source = 18, // source grey
1304 .black_point_source = -8.65, // source black
1305 .white_point_source = 2.45, // source white
1306 .security_factor = 0.0, // security factor
1307 .grey_point_target = 18.0, // target grey
1308 .black_point_target = 0.0, // target black
1309 .white_point_target = 100.0, // target white
1310 .output_power = 2.2, // target power (~ gamma)
1311 .latitude_stops = 2.0, // intent latitude
1312 .contrast = 1.5, // intent contrast
1313 .saturation = 100.0, // intent saturation
1314 .global_saturation = 100.0,
1315 .balance = 0.0, // balance shadows/highlights
1316 .interpolator = CUBIC_SPLINE, //interpolator
1317 .preserve_color = 0, // run the saturated variant
1318 };
1319}
1320
1322{
1323 const int program = 22; // filmic.cl, from programs.conf
1326
1327 module->data = gd;
1328 gd->kernel_filmic = dt_opencl_create_kernel(program, "filmic");
1329}
1330
1332{
1333 dt_free(module->params);
1334 dt_free(module->default_params);
1335}
1336
1343
1345{
1350 CPF_DIRECTION_LEFT, NULL);
1351 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(g->extra_toggle), FALSE);
1352}
1353
1354static gboolean dt_iop_tonecurve_draw(GtkWidget *widget, cairo_t *crf, gpointer user_data)
1355{
1356 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
1359 dt_iop_filmic_nodes_t *nodes_data = (dt_iop_filmic_nodes_t *)malloc(sizeof(dt_iop_filmic_nodes_t));
1360 compute_curve_lut(p, c->table, c->table_temp, 256, NULL, nodes_data);
1361
1362 const int inset = DT_GUI_CURVE_EDITOR_INSET;
1363 GtkAllocation allocation;
1364 gtk_widget_get_allocation(widget, &allocation);
1365 int width = allocation.width, height = allocation.height;
1366 cairo_surface_t *cst = dt_cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
1367 cairo_t *cr = cairo_create(cst);
1368
1369 // clear bg
1370 cairo_set_source_rgb(cr, .2, .2, .2);
1371 cairo_paint(cr);
1372
1373 cairo_translate(cr, inset, inset);
1374 width -= 2 * inset;
1375 height -= 2 * inset;
1376
1377 cairo_set_source_rgb(cr, .3, .3, .3);
1378 cairo_rectangle(cr, 0, 0, width, height);
1379 cairo_fill(cr);
1380
1381 // draw grid
1382 cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(.4));
1383 cairo_set_source_rgb(cr, .1, .1, .1);
1384 dt_draw_grid(cr, 4, 0, 0, width, height);
1385
1386 // solve the equations for the rescaling parameters
1387 const float DR = (p->white_point_source - p->black_point_source);
1388 const float grey = -p->black_point_source / DR;
1389 int rescale = FALSE;
1390
1391 float a, b, d;
1392 a = DR;
1393 b = Log2( 1.0f / (-1 + powf(2.0f, a)));
1394 d = - powf(2.0f, b);
1395
1396 if (grey > powf(p->grey_point_target / 100.0f, p->output_power))
1397 {
1398 // The x-coordinate rescaling is valid only when the log grey value (dynamic range center)
1399 // is greater or equal to the destination grey value
1400 rescale = TRUE;
1401
1402 for (int i = 0; i < 50; ++i)
1403 { // Optimization loop for the non-linear problem
1404 a = Log2((0.5f - d) / (1.0f - d)) / (grey - 1.0f);
1405 b = Log2( 1.0f / (-1 + powf(2.0f, a)));
1406 d = - powf(2.0f, b);
1407 }
1408 }
1409
1410 const float gamma = (logf(p->grey_point_target / 100.0f) / logf(0.5f)) / p->output_power;
1411
1412 // draw nodes
1413 cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(1.));
1414 cairo_set_source_rgb(cr, 0.9, 0.9, 0.9);
1415
1416 for(int k = 0; k < nodes_data->nodes; k++)
1417 {
1418 /*
1419 * Use double precision locally to avoid cancellation effect on
1420 * the "+ d" operation.
1421 */
1422 const float x = (rescale) ? powf(2.0f, (double)a * nodes_data->x[k] + b) + d : nodes_data->x[k];
1423 const float y = powf(nodes_data->y[k], 1.0f / gamma);
1424
1425 cairo_arc(cr, x * width, (1.0 - y) * (double)height, DT_PIXEL_APPLY_DPI(3), 0, 2. * M_PI);
1426 cairo_stroke_preserve(cr);
1427 cairo_fill(cr);
1428 cairo_stroke(cr);
1429 }
1430 dt_free(nodes_data);
1431
1432 // draw curve
1433 cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(2.));
1434 cairo_set_source_rgb(cr, .9, .9, .9);
1435 cairo_move_to(cr, 0, height * (1.0 - c->table[0]));
1436
1437 for(int k = 1; k < 256; k++)
1438 {
1439 /*
1440 * Use double precision locally to avoid cancellation effect on
1441 * the "+ d" operation.
1442 */
1443 const float x = (rescale) ? powf(2.0f, (double)a * k / 255.0f + b) + d : k / 255.0f;
1444 const float y = powf(c->table[k], 1.0f / gamma);
1445 cairo_line_to(cr, x * width, (double)height * (1.0 - y));
1446 }
1447 cairo_stroke(cr);
1448 cairo_destroy(cr);
1449 cairo_set_source_surface(crf, cst, 0, 0);
1450 cairo_paint(crf);
1451 cairo_surface_destroy(cst);
1452 return TRUE;
1453}
1454
1455static void _extra_options_button_changed(GtkDarktableToggleButton *widget, gpointer user_data)
1456{
1457 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
1459 const gboolean active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(g->extra_toggle));
1460 dtgtk_expander_set_expanded(DTGTK_EXPANDER(g->extra_expander), active);
1462 (active ? CPF_DIRECTION_DOWN : CPF_DIRECTION_LEFT), NULL);
1463}
1464
1466{
1469
1470 self->gui->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING);
1471
1472 // read-only graph; modest default height, user-resizable via its grip
1473 g->area = GTK_DRAWING_AREA(gtk_drawing_area_new());
1474 gtk_widget_set_hexpand(GTK_WIDGET(g->area), TRUE);
1475 gtk_widget_set_tooltip_text(GTK_WIDGET(g->area), _("read-only graph, use the parameters below to set the nodes"));
1476 gtk_box_pack_start(GTK_BOX(self->gui->widget),
1477 dt_ui_resizable_drawing_area(GTK_WIDGET(g->area),
1478 "plugins/darkroom/filmic/graphheight", 200, 100),
1479 FALSE, FALSE, 0);
1480 g_signal_connect(G_OBJECT(g->area), "draw", G_CALLBACK(dt_iop_tonecurve_draw), self);
1481
1482 gtk_box_pack_start(GTK_BOX(self->gui->widget), dt_ui_section_label_new(_("logarithmic shaper")), FALSE, FALSE, 0);
1483
1484 // grey_point_source slider
1485 g->grey_point_source = dt_bauhaus_slider_new_with_range(dt_bauhaus_get_global(), DT_GUI_MODULE(self), 0.0, 100., 0, p->grey_point_source, 2);
1486 dt_bauhaus_slider_set_soft_range(g->grey_point_source, 0.1, 36.0);
1487 dt_bauhaus_widget_set_label(g->grey_point_source, N_("middle gray luminance"));
1488 gtk_box_pack_start(GTK_BOX(self->gui->widget), g->grey_point_source, TRUE, TRUE, 0);
1489 dt_bauhaus_slider_set_format(g->grey_point_source, "%");
1490 gtk_widget_set_tooltip_text(g->grey_point_source, _("adjust to match the average luminance of the subject.\n"
1491 "except in back-lighting situations, this should be around 18%."));
1492 g_signal_connect(G_OBJECT(g->grey_point_source), "value-changed", G_CALLBACK(grey_point_source_callback), self);
1493 dt_color_picker_new(self, DT_COLOR_PICKER_AREA, g->grey_point_source);
1494
1495 // White slider
1496 g->white_point_source = dt_bauhaus_slider_new_with_range(dt_bauhaus_get_global(), DT_GUI_MODULE(self), 0.0, 16.0, 0, p->white_point_source, 2);
1497 dt_bauhaus_slider_set_soft_range(g->white_point_source, 2.0, 8.0);
1498 dt_bauhaus_widget_set_label(g->white_point_source, N_("white relative exposure"));
1499 gtk_box_pack_start(GTK_BOX(self->gui->widget), g->white_point_source, TRUE, TRUE, 0);
1500 dt_bauhaus_slider_set_format(g->white_point_source, _(" EV"));
1501 gtk_widget_set_tooltip_text(g->white_point_source, _("number of stops between middle gray and pure white.\n"
1502 "this is a reading a lightmeter would give you on the scene.\n"
1503 "adjust so highlights clipping is avoided"));
1504 g_signal_connect(G_OBJECT(g->white_point_source), "value-changed", G_CALLBACK(white_point_source_callback), self);
1505 dt_color_picker_new(self, DT_COLOR_PICKER_AREA, g->white_point_source);
1506
1507 // Black slider
1508 g->black_point_source = dt_bauhaus_slider_new_with_range(dt_bauhaus_get_global(), DT_GUI_MODULE(self), -16.0, -0.1, 0, p->black_point_source, 2);
1509 dt_bauhaus_slider_set_soft_range(g->black_point_source, -14.0, -3.0);
1510 dt_bauhaus_widget_set_label(g->black_point_source, N_("black relative exposure"));
1511 gtk_box_pack_start(GTK_BOX(self->gui->widget), g->black_point_source, TRUE, TRUE, 0);
1512 dt_bauhaus_slider_set_format(g->black_point_source, _(" EV"));
1513 gtk_widget_set_tooltip_text(g->black_point_source, _("number of stops between middle gray and pure black.\n"
1514 "this is a reading a lightmeter would give you on the scene.\n"
1515 "increase to get more contrast.\ndecrease to recover more details in low-lights."));
1516 g_signal_connect(G_OBJECT(g->black_point_source), "value-changed", G_CALLBACK(black_point_source_callback), self);
1517 dt_color_picker_new(self, DT_COLOR_PICKER_AREA, g->black_point_source);
1518
1519 // Security factor
1520 g->security_factor = dt_bauhaus_slider_new_with_range(dt_bauhaus_get_global(), DT_GUI_MODULE(self), -50., 50., 0, p->security_factor, 2);
1521 dt_bauhaus_widget_set_label(g->security_factor, N_("safety factor"));
1522 gtk_box_pack_start(GTK_BOX(self->gui->widget), g->security_factor, TRUE, TRUE, 0);
1523 dt_bauhaus_slider_set_format(g->security_factor, "%");
1524 gtk_widget_set_tooltip_text(g->security_factor, _("enlarge or shrink the computed dynamic range.\n"
1525 "useful in conjunction with \"auto tune levels\"."));
1526 g_signal_connect(G_OBJECT(g->security_factor), "value-changed", G_CALLBACK(security_threshold_callback), self);
1527
1528 // Auto tune slider
1530 dt_bauhaus_widget_set_label(g->auto_button, N_("auto tune levels"));
1531 dt_color_picker_new(self, DT_COLOR_PICKER_AREA, g->auto_button);
1532 gtk_widget_set_tooltip_text(g->auto_button, _("try to optimize the settings with some guessing.\n"
1533 "this will fit the luminance range inside the histogram bounds.\n"
1534 "works better for landscapes and evenly-lit pictures\nbut fails for high-keys and low-keys." ));
1535 gtk_box_pack_start(GTK_BOX(self->gui->widget), g->auto_button, TRUE, TRUE, 0);
1536
1537 gtk_box_pack_start(GTK_BOX(self->gui->widget), dt_ui_section_label_new(_("filmic S curve")), FALSE, FALSE, 0);
1538
1539 // contrast slider
1540 g->contrast = dt_bauhaus_slider_new_with_range(dt_bauhaus_get_global(), DT_GUI_MODULE(self), 0., 5., 0, p->contrast, 3);
1541 dt_bauhaus_slider_set_soft_range(g->contrast, 1.0, 2.0);
1542 dt_bauhaus_widget_set_label(g->contrast, N_("contrast"));
1543 gtk_box_pack_start(GTK_BOX(self->gui->widget), g->contrast, TRUE, TRUE, 0);
1544 gtk_widget_set_tooltip_text(g->contrast, _("slope of the linear part of the curve\n"
1545 "affects mostly the mid-tones"));
1546 g_signal_connect(G_OBJECT(g->contrast), "value-changed", G_CALLBACK(contrast_callback), self);
1547
1548 // latitude slider
1549 g->latitude_stops = dt_bauhaus_slider_new_with_range(dt_bauhaus_get_global(), DT_GUI_MODULE(self), 0.01, 16.0, 0, p->latitude_stops, 3);
1550 dt_bauhaus_slider_set_soft_range(g->latitude_stops, 2, 8.0);
1551 dt_bauhaus_widget_set_label(g->latitude_stops, N_("latitude"));
1552 dt_bauhaus_slider_set_format(g->latitude_stops, _(" EV"));
1553 gtk_box_pack_start(GTK_BOX(self->gui->widget), g->latitude_stops, TRUE, TRUE, 0);
1554 gtk_widget_set_tooltip_text(g->latitude_stops, _("width of the linear domain in the middle of the curve.\n"
1555 "increase to get more contrast at the extreme luminances.\n"
1556 "this has no effect on mid-tones."));
1557 g_signal_connect(G_OBJECT(g->latitude_stops), "value-changed", G_CALLBACK(latitude_stops_callback), self);
1558
1559 // balance slider
1560 g->balance = dt_bauhaus_slider_new_with_range(dt_bauhaus_get_global(), DT_GUI_MODULE(self), -50., 50., 0, p->balance, 2);
1561 dt_bauhaus_widget_set_label(g->balance, N_("shadows/highlights balance"));
1562 gtk_box_pack_start(GTK_BOX(self->gui->widget), g->balance, TRUE, TRUE, 0);
1563 dt_bauhaus_slider_set_format(g->balance, "%");
1564 gtk_widget_set_tooltip_text(g->balance, _("slides the latitude along the slope\nto give more room to shadows or highlights.\n"
1565 "use it if you need to protect the details\nat one extremity of the histogram."));
1566 g_signal_connect(G_OBJECT(g->balance), "value-changed", G_CALLBACK(balance_callback), self);
1567
1568 // saturation slider
1569 g->global_saturation = dt_bauhaus_slider_new_with_range(dt_bauhaus_get_global(), DT_GUI_MODULE(self), 0., 1000., 0, p->global_saturation, 2);
1570 dt_bauhaus_widget_set_label(g->global_saturation, N_("global saturation"));
1571 dt_bauhaus_slider_set_soft_range(g->global_saturation, 0.0, 200.0);
1572 dt_bauhaus_slider_set_format(g->global_saturation, "%");
1573 gtk_box_pack_start(GTK_BOX(self->gui->widget), g->global_saturation, TRUE, TRUE, 0);
1574 gtk_widget_set_tooltip_text(g->global_saturation, _("desaturates the input of the module globally.\n"
1575 "you need to set this value below 100%\nif the chrominance preservation is enabled."));
1576 g_signal_connect(G_OBJECT(g->global_saturation), "value-changed", G_CALLBACK(global_saturation_callback), self);
1577
1578 // saturation slider
1579 g->saturation = dt_bauhaus_slider_new_with_range(dt_bauhaus_get_global(), DT_GUI_MODULE(self), 0., 1000., 0, (powf(10.0f, p->saturation/100.0f) - 1.0f) / 9.0f *100.0f, 2);
1580 dt_bauhaus_widget_set_label(g->saturation, N_("extreme luminance saturation"));
1581 dt_bauhaus_slider_set_soft_range(g->saturation, 0.0, 200.0);
1582 dt_bauhaus_slider_set_format(g->saturation, "%");
1583 gtk_box_pack_start(GTK_BOX(self->gui->widget), g->saturation, TRUE, TRUE, 0);
1584 gtk_widget_set_tooltip_text(g->saturation, _("desaturates the output of the module\nspecifically at extreme luminances.\n"
1585 "decrease if shadows and/or highlights are over-saturated."));
1586 g_signal_connect(G_OBJECT(g->saturation), "value-changed", G_CALLBACK(saturation_callback), self);
1587
1588 /* From src/common/curve_tools.h :
1589 #define CUBIC_SPLINE 0
1590 #define CATMULL_ROM 1
1591 #define MONOTONE_HERMITE 2
1592 */
1594 dt_bauhaus_widget_set_label(g->interpolator, N_("intent"));
1595 dt_bauhaus_combobox_add(g->interpolator, _("contrasted")); // cubic spline
1596 dt_bauhaus_combobox_add(g->interpolator, _("faded")); // centripetal spline
1597 dt_bauhaus_combobox_add(g->interpolator, _("linear")); // monotonic spline
1598 dt_bauhaus_combobox_add(g->interpolator, _("optimized")); // monotonic spline
1599 gtk_box_pack_start(GTK_BOX(self->gui->widget), g->interpolator , TRUE, TRUE, 0);
1600 gtk_widget_set_tooltip_text(g->interpolator, _("change this method if you see reversed contrast or faded blacks"));
1601 g_signal_connect(G_OBJECT(g->interpolator), "value-changed", G_CALLBACK(interpolator_callback), self);
1602
1603 // Preserve color
1604 g->preserve_color = gtk_check_button_new_with_label(_("preserve the chrominance"));
1605 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(g->preserve_color), p->preserve_color);
1606 gtk_widget_set_tooltip_text(g->preserve_color, _("ensure the original color are preserved.\n"
1607 "may reinforce chromatic aberrations.\n"
1608 "you need to manually tune the saturation when using this mode."));
1609 gtk_box_pack_start(GTK_BOX(self->gui->widget), g->preserve_color , TRUE, TRUE, 0);
1610 g_signal_connect(G_OBJECT(g->preserve_color), "toggled", G_CALLBACK(preserve_color_callback), self);
1611
1612
1613 // add collapsible section for those extra options that are generally not to be used
1614
1615 GtkWidget *destdisp_head = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, DT_GUI_BOX_SPACING);
1616 GtkWidget *destdisp = dt_ui_section_label_new(_("destination/display"));
1618 GtkWidget *extra_options = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING);
1619 gtk_box_pack_start(GTK_BOX(destdisp_head), destdisp, TRUE, TRUE, 0);
1620 gtk_box_pack_start(GTK_BOX(destdisp_head), g->extra_toggle, FALSE, FALSE, 0);
1621 gtk_widget_set_visible(extra_options, FALSE);
1622 g->extra_expander = dtgtk_expander_new(destdisp_head, extra_options);
1624 gtk_box_pack_start(GTK_BOX(self->gui->widget), g->extra_expander, FALSE, FALSE, 0);
1625
1626
1627 g_signal_connect(G_OBJECT(g->extra_toggle), "toggled", G_CALLBACK(_extra_options_button_changed), (gpointer)self);
1628
1629 // Black slider
1630 g->black_point_target = dt_bauhaus_slider_new_with_range(dt_bauhaus_get_global(), DT_GUI_MODULE(self), 0.0, 100.0, 0, p->black_point_target, 2);
1631 dt_bauhaus_widget_set_label(g->black_point_target, N_("target black luminance"));
1632 gtk_box_pack_start(GTK_BOX(extra_options), g->black_point_target, FALSE, FALSE, 0);
1633 dt_bauhaus_slider_set_format(g->black_point_target, "%");
1634 gtk_widget_set_tooltip_text(g->black_point_target, _("luminance of output pure black, "
1635 "this should be 0%\nexcept if you want a faded look"));
1636 g_signal_connect(G_OBJECT(g->black_point_target), "value-changed", G_CALLBACK(black_point_target_callback), self);
1637
1638 // grey_point_source slider
1639 g->grey_point_target = dt_bauhaus_slider_new_with_range(dt_bauhaus_get_global(), DT_GUI_MODULE(self), 0.1, 50., 0, p->grey_point_target, 2);
1640 dt_bauhaus_widget_set_label(g->grey_point_target, N_("target middle gray"));
1641 gtk_box_pack_start(GTK_BOX(extra_options), g->grey_point_target, FALSE, FALSE, 0);
1642 dt_bauhaus_slider_set_format(g->grey_point_target, "%");
1643 gtk_widget_set_tooltip_text(g->grey_point_target, _("middle gray value of the target display or color space.\n"
1644 "you should never touch that unless you know what you are doing."));
1645 g_signal_connect(G_OBJECT(g->grey_point_target), "value-changed", G_CALLBACK(grey_point_target_callback), self);
1646
1647 // White slider
1648 g->white_point_target = dt_bauhaus_slider_new_with_range(dt_bauhaus_get_global(), DT_GUI_MODULE(self), 0.0, 100.0, 0, p->white_point_target, 2);
1649 dt_bauhaus_widget_set_label(g->white_point_target, N_("target white luminance"));
1650 gtk_box_pack_start(GTK_BOX(extra_options), g->white_point_target, FALSE, FALSE, 0);
1651 dt_bauhaus_slider_set_format(g->white_point_target, "%");
1652 gtk_widget_set_tooltip_text(g->white_point_target, _("luminance of output pure white, "
1653 "this should be 100%\nexcept if you want a faded look"));
1654 g_signal_connect(G_OBJECT(g->white_point_target), "value-changed", G_CALLBACK(white_point_target_callback), self);
1655
1656 // power/gamma slider
1657 g->output_power = dt_bauhaus_slider_new_with_range(dt_bauhaus_get_global(), DT_GUI_MODULE(self), 1.0, 2.4, 0, p->output_power, 2);
1658 dt_bauhaus_widget_set_label(g->output_power, N_("target gamma"));
1659 gtk_box_pack_start(GTK_BOX(extra_options), g->output_power, FALSE, FALSE, 0);
1660 gtk_widget_set_tooltip_text(g->output_power, _("power or gamma of the transfer function\nof the display or color space.\n"
1661 "you should never touch that unless you know what you are doing."));
1662 g_signal_connect(G_OBJECT(g->output_power), "value-changed", G_CALLBACK(output_power_callback), self);
1663}
1664
1665
1666// clang-format off
1667// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
1668// vim: shiftwidth=2 expandtab tabstop=2 cindent
1669// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
1670// 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_slider_set_soft_range(GtkWidget *widget, float soft_min, float soft_max)
Definition bauhaus.c:1498
float dt_bauhaus_slider_get(GtkWidget *widget)
Definition bauhaus.c:3280
int dt_bauhaus_combobox_get(GtkWidget *widget)
Definition bauhaus.c:2136
void dt_bauhaus_slider_set(GtkWidget *widget, float pos)
Definition bauhaus.c:3331
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_slider_new_with_range(dt_bauhaus_t *bh, dt_gui_module_t *self, float min, float max, float step, float defval, int digits)
Definition bauhaus.c:1632
GtkWidget * dt_bauhaus_combobox_new(dt_bauhaus_t *bh, dt_gui_module_t *self)
Definition bauhaus.c:1698
void dt_bauhaus_slider_set_format(GtkWidget *widget, const char *format)
Definition bauhaus.c:3407
void dt_bauhaus_combobox_add(GtkWidget *widget, const char *text)
Definition bauhaus.c:1824
@ 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
static const float x
const float *const const float coeff[3]
struct _GtkWidget GtkWidget
GtkWidget, opaque, spelled exactly as GTK spells it.
Definition colorspaces.h:98
dt_prophotorgb_to_XYZ(rgb, XYZ)
static dt_aligned_pixel_t rgb
dt_Lab_to_XYZ(Lab, XYZ)
dt_XYZ_to_prophotorgb(XYZ, rgb)
static dt_aligned_pixel_t XYZ
const float max
const dt_colormatrix_t dt_aligned_pixel_t out
#define CATMULL_ROM
Definition curve_tools.h:35
#define CUBIC_SPLINE
Definition curve_tools.h:34
#define MONOTONE_HERMITE
Definition curve_tools.h:36
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
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)
@ DT_DEV_PIXELPIPE_DISPLAY_MASK
Definition develop.h:123
static void dt_draw_curve_calc_values(dt_draw_curve_t *c, const float min, const float max, const int res, float *x, float *y)
Definition draw.h:324
static void dt_draw_grid(cairo_t *cr, const int num, const int left, const int top, const int right, const int bottom)
Definition draw.h:158
static void dt_draw_curve_destroy(dt_draw_curve_t *c)
Definition draw.h:297
static int dt_draw_curve_add_point(dt_draw_curve_t *c, const float x, const float y)
Definition draw.h:379
static dt_draw_curve_t * dt_draw_curve_new(const float min, const float max, unsigned int type)
Definition draw.h:281
const int res
Definition dtpthread.h:351
void dtgtk_expander_set_expanded(GtkDarktableExpander *expander, gboolean expanded)
Definition expander.c:70
GtkWidget * dtgtk_expander_new(GtkWidget *header, GtkWidget *body)
Definition expander.c:101
#define DTGTK_EXPANDER(obj)
Definition expander.h:31
static void preserve_color_callback(GtkWidget *widget, dt_iop_module_t *self)
Definition filmic.c:966
void init(dt_iop_module_t *module)
Definition filmic.c:1294
static void white_point_target_callback(GtkWidget *slider, gpointer user_data)
Definition filmic.c:882
int default_group()
Definition filmic.c:189
void gui_reset(dt_iop_module_t *self)
Definition filmic.c:1344
static void sanitize_latitude(dt_iop_filmic_params_t *p, dt_iop_filmic_gui_data_t *g)
Definition filmic.c:586
static void contrast_callback(GtkWidget *slider, gpointer user_data)
Definition filmic.c:851
static void interpolator_callback(GtkWidget *widget, dt_iop_module_t *self)
Definition filmic.c:926
static gboolean dt_iop_tonecurve_draw(GtkWidget *widget, cairo_t *crf, gpointer user_data)
Definition filmic.c:1354
static void output_power_callback(GtkWidget *slider, gpointer user_data)
Definition filmic.c:904
static void latitude_stops_callback(GtkWidget *slider, gpointer user_data)
Definition filmic.c:835
void gui_update(dt_iop_module_t *self)
Refresh GUI controls from current params and configuration.
Definition filmic.c:1262
__DT_CLONE_TARGETS__ int process(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 filmic.c:410
#define DT_GUI_CURVE_EDITOR_INSET
Definition filmic.c:74
static void security_threshold_callback(GtkWidget *slider, gpointer user_data)
Definition filmic.c:680
static void apply_autotune(dt_iop_module_t *self)
Definition filmic.c:713
void cleanup(dt_iop_module_t *module)
Definition filmic.c:1331
static void balance_callback(GtkWidget *slider, gpointer user_data)
Definition filmic.c:915
const char * name()
Definition filmic.c:184
void gui_init(dt_iop_module_t *self)
Definition filmic.c:1465
static void grey_point_target_callback(GtkWidget *slider, gpointer user_data)
Definition filmic.c:824
static void grey_point_source_callback(GtkWidget *slider, gpointer user_data)
Definition filmic.c:768
void commit_params(dt_iop_module_t *self, dt_iop_params_t *p1, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition filmic.c:1185
static float gaussian(float x, float std)
Definition filmic.c:404
void cleanup_global(dt_iop_module_so_t *module)
Definition filmic.c:1337
static void _extra_options_button_changed(GtkDarktableToggleButton *widget, gpointer user_data)
Definition filmic.c:1455
void cleanup_pipe(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition filmic.c:1256
int default_colorspace(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
Definition filmic.c:204
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 filmic.c:209
int flags()
Definition filmic.c:194
static void apply_auto_white_point_source(dt_iop_module_t *self)
Definition filmic.c:653
static void global_saturation_callback(GtkWidget *slider, gpointer user_data)
Definition filmic.c:872
void init_presets(dt_iop_module_so_t *self)
Definition filmic.c:309
static void saturation_callback(GtkWidget *slider, gpointer user_data)
Definition filmic.c:862
static void black_point_target_callback(GtkWidget *slider, gpointer user_data)
Definition filmic.c:893
void init_pipe(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition filmic.c:1250
static void white_point_source_callback(GtkWidget *slider, gpointer user_data)
Definition filmic.c:792
static void black_point_source_callback(GtkWidget *slider, gpointer user_data)
Definition filmic.c:808
void compute_curve_lut(dt_iop_filmic_params_t *p, float *table, float *table_temp, int res, dt_iop_filmic_data_t *d, dt_iop_filmic_nodes_t *nodes_data)
Definition filmic.c:974
static void apply_auto_black(dt_iop_module_t *self)
Definition filmic.c:625
void init_global(dt_iop_module_so_t *module)
Definition filmic.c:1321
const char * deprecated_msg()
Definition filmic.c:199
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 filmic.c:528
static void apply_auto_grey(dt_iop_module_t *self)
Definition filmic.c:599
void color_picker_apply(dt_iop_module_t *self, GtkWidget *picker, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition filmic.c:753
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 filmic.c:217
@ TYPE_FLOAT
Definition format.h:56
void dt_gui_presets_add_generic(const char *name, dt_dev_operation_t op, const int32_t version, const void *params, const int32_t params_size, const int32_t enabled)
#define DT_GUI_MODULE(x)
@ IOP_FLAGS_INCLUDE_IN_STYLES
Definition imageop.h:185
@ IOP_FLAGS_DEPRECATED
Definition imageop.h:187
@ IOP_FLAGS_SUPPORTS_BLENDING
Definition imageop.h:186
@ IOP_FLAGS_ALLOW_TILING
Definition imageop.h:188
@ IOP_GROUP_TONES
Definition imageop.h:156
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
GtkWidget * dt_ui_section_label_new(const gchar *str)
Definition label.c:114
@ DT_DEBUG_OPENCL
Definition logging.h:57
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
float *const restrict const size_t const size_t ch
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
Definition macros.h:96
static float fastlog2(float x)
Definition math.h:124
static float Log2(float x)
Definition math.h:113
static float Log2Thres(float x, float Thres)
Definition math.h:118
#define M_PI
Definition math.h:47
#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
#define DT_ALIGNED_ARRAY
Align an object on a cacheline boundary, so AVX2 can load it whole.
Definition mem_alloc.h:80
#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_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 __OMP_PARALLEL_FOR_SIMD__(...)
Definition openmp.h:96
static cairo_surface_t * dt_cairo_image_surface_create(cairo_format_t format, int width, int height)
GtkWidget * dt_ui_resizable_drawing_area(GtkWidget *area, char *config_str, int default_height, int min_height)
Make a self-drawing widget (typically a GtkDrawingArea graph or scope) vertically resizable.
DT_ALIGNED_PIXEL float dt_aligned_pixel_t[4]
Definition simd.h:53
const float sigma
const float noise
struct dt_iop_module_t *void * data
unsigned int channels
Definition format.h:83
dt_iop_buffer_type_t datatype
Definition format.h:85
float table_temp[0x10000]
Definition filmic.c:155
float grad_2[0x10000]
Definition filmic.c:156
float global_saturation
Definition filmic.c:162
float table[0x10000]
Definition filmic.c:154
GtkWidget * contrast
Definition filmic.c:139
GtkWidget * saturation
Definition filmic.c:141
GtkWidget * extra_toggle
Definition filmic.c:146
GtkWidget * extra_expander
Definition filmic.c:145
GtkWidget * preserve_color
Definition filmic.c:144
GtkWidget * black_point_target
Definition filmic.c:136
GtkDrawingArea * area
Definition filmic.c:147
GtkWidget * global_saturation
Definition filmic.c:140
GtkWidget * black_point_source
Definition filmic.c:131
GtkWidget * auto_button
Definition filmic.c:133
GtkWidget * output_power
Definition filmic.c:137
float table_temp[256]
Definition filmic.c:149
GtkWidget * white_point_target
Definition filmic.c:135
GtkWidget * grey_point_source
Definition filmic.c:130
GtkWidget * white_point_source
Definition filmic.c:129
GtkWidget * grey_point_target
Definition filmic.c:134
GtkWidget * interpolator
Definition filmic.c:143
GtkWidget * security_factor
Definition filmic.c:132
GtkWidget * latitude_stops
Definition filmic.c:138
GtkWidget * balance
Definition filmic.c:142
GtkWidget * widget
Definition imageop_gui.h:47
dt_dev_operation_t op
Definition imageop.h:235
dt_iop_global_data_t * data
Definition imageop.h:238
dt_iop_params_t * default_params
Definition imageop.h:333
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_aligned_pixel_t picked_color_min
Definition imageop.h:287
dt_aligned_pixel_t picked_color_max
Definition imageop.h:287
dt_aligned_pixel_t picked_color
Definition imageop.h:287
dt_iop_params_t * params
Definition imageop.h:333
Region of interest passed through the pixelpipe.
Definition format.h:49
int width
Definition format.h:50
int height
Definition format.h:50
#define __DT_CLONE_TARGETS__
void dtgtk_togglebutton_set_paint(GtkDarktableToggleButton *button, DTGTKCairoPaintIconFunc paint, gint paintflags, void *paintdata)
GtkWidget * dtgtk_togglebutton_new(DTGTKCairoPaintIconFunc paint, gint paintflags, void *paintdata)
#define DTGTK_TOGGLEBUTTON(obj)
gboolean dt_gui_widgets_suppressed(void)
#define dt_gui_freeze_begin()
#define dt_gui_freeze_end()
#define DT_GUI_BOX_SPACING
#define DT_PIXEL_APPLY_DPI(value)
void dtgtk_cairo_paint_solid_arrow(cairo_t *cr, gint x, int y, gint w, gint h, gint flags, void *data)
@ CPF_DIRECTION_LEFT
@ CPF_DIRECTION_DOWN