Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
negadoctor.c
Go to the documentation of this file.
1/*
2 This file is part of the Ansel project.
3 Copyright (C) 2020 Aldric Renaudin.
4 Copyright (C) 2020, 2022-2023, 2025-2026 Aurélien PIERRE.
5 Copyright (C) 2020-2022 Diederik Ter Rahe.
6 Copyright (C) 2020, 2022 Pascal Obry.
7 Copyright (C) 2020-2021 Ralf Brown.
8 Copyright (C) 2020 Tobias Ellinghaus.
9 Copyright (C) 2021 Chris Elston.
10 Copyright (C) 2021 Dan Torop.
11 Copyright (C) 2021 Hubert Kowalski.
12 Copyright (C) 2022 Hanno Schwalm.
13 Copyright (C) 2022 Martin Bařinka.
14 Copyright (C) 2022 Philipp Lutz.
15 Copyright (C) 2023, 2025 Guillaume Stutin.
16 Copyright (C) 2023 Luca Zulberti.
17
18 Ansel is free software: you can redistribute it and/or modify
19 it under the terms of the GNU General Public License as published by
20 the Free Software Foundation, either version 3 of the License, or
21 (at your option) any later version.
22
23 Ansel is distributed in the hope that it will be useful,
24 but WITHOUT ANY WARRANTY; without even the implied warranty of
25 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 GNU General Public License for more details.
27
28 You should have received a copy of the GNU General Public License
29 along with Ansel. If not, see <http://www.gnu.org/licenses/>.
30*/
31#ifdef HAVE_CONFIG_H
32#include "config.h"
33#endif
34
35#include "bauhaus/bauhaus.h"
36#include "common/darktable.h"
37#include "common/opencl.h"
38#include "control/control.h"
39#include "develop/develop.h"
40#include "develop/imageop.h"
42#include "develop/imageop_gui.h"
44#include "dtgtk/button.h"
45#include "dtgtk/resetlabel.h"
46
47#include "gui/gtk.h"
48#include "gui/presets.h"
50#include "iop/iop_api.h"
51
52#include <glib.h>
53#include <math.h>
54#include <stdlib.h>
55
72 #define THRESHOLD 2.3283064365386963e-10f // -32 EV
73
74
76
77
79{
80 // What kind of emulsion are we working on ?
81 DT_FILMSTOCK_NB = 0, // $DESCRIPTION: "black and white film"
82 DT_FILMSTOCK_COLOR = 1 // $DESCRIPTION: "color film"
84
85
87{
88 dt_iop_negadoctor_filmstock_t film_stock; /* $DEFAULT: DT_FILMSTOCK_COLOR $DESCRIPTION: "film stock" */
89 float Dmin[4]; /* color of film substrate
90 $MIN: 0.00001 $MAX: 1.5 $DEFAULT: 1.0 */
91 float wb_high[4]; /* white balance RGB coeffs (illuminant)
92 $MIN: 0.25 $MAX: 2 $DEFAULT: 1.0 */
93 float wb_low[4]; /* white balance RGB offsets (base light)
94 $MIN: 0.25 $MAX: 2 $DEFAULT: 1.0 */
95 float D_max; /* max density of film
96 $MIN: 0.1 $MAX: 6 $DEFAULT: 2.046 */
97 float offset; /* inversion offset
98 $MIN: -1.0 $MAX: 1.0 $DEFAULT: -0.05 $DESCRIPTION: "scan exposure bias" */
99 float black; /* display black level
100 $MIN: -0.5 $MAX: 0.5 $DEFAULT: 0.0755 $DESCRIPTION: "paper black (density correction)" */
101 float gamma; /* display gamma
102 $MIN: 1.0 $MAX: 8.0 $DEFAULT: 4.0 $DESCRIPTION: "paper grade (gamma)" */
103 float soft_clip; /* highlights roll-off
104 $MIN: 0.0001 $MAX: 1.0 $DEFAULT: 0.75 $DESCRIPTION: "paper gloss (specular highlights)" */
105 float exposure; /* extra exposure
106 $MIN: -2.0 $MAX: 2.0 $DEFAULT: 0.9245 $DESCRIPTION: "print exposure adjustment" */
108
109
111{
112 dt_aligned_pixel_t Dmin; // color of film substrate
113 dt_aligned_pixel_t wb_high; // white balance RGB coeffs / Dmax
114 dt_aligned_pixel_t offset; // inversion offset
115 float black; // display black level
116 float gamma; // display gamma
117 float soft_clip; // highlights roll-off
118 float soft_clip_comp; // 1 - softclip, complement to 1
119 float exposure; // extra exposure
121
122
137
138
143
144
145const char *name()
146{
147 return _("ne_gadoctor");
148}
149
150const char *aliases()
151{
152 return _("film|invert|negative|scan");
153}
154
155const char **description(struct dt_iop_module_t *self)
156{
157 return dt_iop_set_description(self, _("invert film negative scans and simulate printing on paper"),
158 _("corrective and creative"),
159 _("linear, RGB, display-referred"),
160 _("non-linear, RGB"),
161 _("non-linear, RGB, display-referred"));
162}
163
168
169
171{
172 return IOP_GROUP_FILM;
173}
174
175
177{
178 return IOP_CS_RGB;
179}
180
181int legacy_params(dt_iop_module_t *self, const void *const old_params, const int old_version,
182 void *new_params, const int new_version)
183{
184 if(old_version == 1 && new_version == 2)
185 {
186 typedef struct dt_iop_negadoctor_params_v1_t
187 {
189 dt_aligned_pixel_t Dmin; // color of film substrate
190 dt_aligned_pixel_t wb_high; // white balance RGB coeffs (illuminant)
191 dt_aligned_pixel_t wb_low; // white balance RGB offsets (base light)
192 float D_max; // max density of film
193 float offset; // inversion offset
194 float black; // display black level
195 float gamma; // display gamma
196 float soft_clip; // highlights roll-off
197 float exposure; // extra exposure
198 } dt_iop_negadoctor_params_v1_t;
199
200 dt_iop_negadoctor_params_v1_t *o = (dt_iop_negadoctor_params_v1_t *)old_params;
203
204 *n = *d; // start with a fresh copy of default parameters
205
206 // WARNING: when copying the arrays in a for loop, gcc wrongly assumed
207 // that n and o were aligned and used AVX instructions for me,
208 // which segfaulted. let's hope this doesn't get optimized too much.
209 n->film_stock = o->film_stock;
210 n->Dmin[0] = o->Dmin[0];
211 n->Dmin[1] = o->Dmin[1];
212 n->Dmin[2] = o->Dmin[2];
213 n->Dmin[3] = o->Dmin[3];
214 n->wb_high[0] = o->wb_high[0];
215 n->wb_high[1] = o->wb_high[1];
216 n->wb_high[2] = o->wb_high[2];
217 n->wb_high[3] = o->wb_high[3];
218 n->wb_low[0] = o->wb_low[0];
219 n->wb_low[1] = o->wb_low[1];
220 n->wb_low[2] = o->wb_low[2];
221 n->wb_low[3] = o->wb_low[3];
222 n->D_max = o->D_max;
223 n->offset = o->offset;
224 n->black = o->black;
225 n->gamma = o->gamma;
226 n->soft_clip = o->soft_clip;
227 n->exposure = o->exposure;
228
229 return 0;
230 }
231 return 1;
232}
233
236{
239
240 // keep WB_high even in B&W mode to apply sepia or warm tone look
241 // but premultiply it aheard with Dmax to spare one div per pixel
242 for(size_t c = 0; c < 4; c++) d->wb_high[c] = p->wb_high[c] / p->D_max;
243
244 for(size_t c = 0; c < 4; c++) d->offset[c] = p->wb_high[c] * p->offset * p->wb_low[c];
245
246 // ensure we use a monochrome Dmin for B&W film
247 if(p->film_stock == DT_FILMSTOCK_COLOR)
248 for(size_t c = 0; c < 4; c++) d->Dmin[c] = p->Dmin[c];
249 else if(p->film_stock == DT_FILMSTOCK_NB)
250 for(size_t c = 0; c < 4; c++) d->Dmin[c] = p->Dmin[0];
251
252 // arithmetic trick allowing to rewrite the pixel inversion as FMA
253 d->black = -p->exposure * (1.0f + p->black);
254
255 // highlights soft clip
256 d->soft_clip = p->soft_clip;
257 d->soft_clip_comp = 1.0f - p->soft_clip;
258
259 // copy
260 d->exposure = p->exposure;
261 d->gamma = p->gamma;
262}
263
264
266int process(struct dt_iop_module_t *const self, const dt_dev_pixelpipe_t *const pipe,
267 const dt_dev_pixelpipe_iop_t *const piece, const void *const restrict ivoid,
268 void *const restrict ovoid)
269{
270 const dt_iop_roi_t *const restrict roi_out = &piece->roi_out;
271 const dt_iop_negadoctor_data_t *const d = piece->data;
272 const float *const restrict in = (float *)ivoid;
273 float *const restrict out = (float *)ovoid;
274 __OMP_FOR_SIMD__(aligned(in, out:64) collapse(2))
275 for(size_t k = 0; k < (size_t)roi_out->height * roi_out->width * 4; k += 4)
276 {
277 for(size_t c = 0; c < 4; c++)
278 {
279 // Unpack vectors one by one with extra pragmas to be sure the compiler understands they can be vectorized
280 const float *const restrict pix_in = in + k;
281 float *const restrict pix_out = out + k;
282 const float *const restrict Dmin = __builtin_assume_aligned(d->Dmin, 16);
283 const float *const restrict wb_high = __builtin_assume_aligned(d->wb_high, 16);
284 const float *const restrict offset = __builtin_assume_aligned(d->offset, 16);
285
286 // Convert transmission to density using Dmin as a fulcrum
287 const float density = - log10f(Dmin[c] / fmaxf(pix_in[c], THRESHOLD)); // threshold to -32 EV
288
289 // Correct density in log space
290 const float corrected_de = wb_high[c] * density + offset[c];
291
292 // Print density on paper : ((1 - 10^corrected_de + black) * exposure)^gamma rewritten for FMA
293 const float print_linear = -(d->exposure * fast_exp10f(corrected_de) + d->black);
294 const float print_gamma = powf(fmaxf(print_linear, 0.0f), d->gamma); // note : this is always > 0
295
296 // Compress highlights. from https://lists.gnu.org/archive/html/openexr-devel/2005-03/msg00009.html
297 pix_out[c] = (print_gamma > d->soft_clip) ? d->soft_clip + (1.0f - fast_expf(-(print_gamma - d->soft_clip) / d->soft_clip_comp)) * d->soft_clip_comp
298 : print_gamma;
299 }
300 }
301
303 dt_iop_alpha_copy(ivoid, ovoid, roi_out->width, roi_out->height);
304 return 0;
305}
306
307
308#ifdef HAVE_OPENCL
309int process_cl(struct dt_iop_module_t *const self, const dt_dev_pixelpipe_t *const pipe,
310 const dt_dev_pixelpipe_iop_t *const piece, cl_mem dev_in, cl_mem dev_out)
311{
312 const dt_iop_roi_t *const restrict roi_in = &piece->roi_in;
315
316 cl_int err = -999;
317
318 const int devid = pipe->devid;
319 const int width = roi_in->width;
320 const int height = roi_in->height;
321
322 size_t sizes[] = { ROUNDUPDWD(width, devid), ROUNDUPDHT(height, devid), 1 };
323
324 dt_opencl_set_kernel_arg(devid, gd->kernel_negadoctor, 0, sizeof(cl_mem), (void *)&dev_in);
325 dt_opencl_set_kernel_arg(devid, gd->kernel_negadoctor, 1, sizeof(cl_mem), (void *)&dev_out);
326 dt_opencl_set_kernel_arg(devid, gd->kernel_negadoctor, 2, sizeof(int), (void *)&width);
327 dt_opencl_set_kernel_arg(devid, gd->kernel_negadoctor, 3, sizeof(int), (void *)&height);
328 dt_opencl_set_kernel_arg(devid, gd->kernel_negadoctor, 4, 4 * sizeof(float), (void *)&d->Dmin);
329 dt_opencl_set_kernel_arg(devid, gd->kernel_negadoctor, 5, 4 * sizeof(float), (void *)&d->wb_high);
330 dt_opencl_set_kernel_arg(devid, gd->kernel_negadoctor, 6, 4 * sizeof(float), (void *)&d->offset);
331 dt_opencl_set_kernel_arg(devid, gd->kernel_negadoctor, 7, sizeof(float), (void *)&d->exposure);
332 dt_opencl_set_kernel_arg(devid, gd->kernel_negadoctor, 8, sizeof(float), (void *)&d->black);
333 dt_opencl_set_kernel_arg(devid, gd->kernel_negadoctor, 9, sizeof(float), (void *)&d->gamma);
334 dt_opencl_set_kernel_arg(devid, gd->kernel_negadoctor, 10, sizeof(float), (void *)&d->soft_clip);
335 dt_opencl_set_kernel_arg(devid, gd->kernel_negadoctor, 11, sizeof(float), (void *)&d->soft_clip_comp);
336
337 err = dt_opencl_enqueue_kernel_2d(devid, gd->kernel_negadoctor, sizes);
338 if(err != CL_SUCCESS) goto error;
339 return TRUE;
340
341error:
342 dt_print(DT_DEBUG_OPENCL, "[opencl_negadoctor] couldn't enqueue kernel! %d\n", err);
343 return FALSE;
344}
345#endif
346
347
349{
350 dt_iop_default_init(module);
351
352 dt_iop_negadoctor_params_t *d = module->default_params;
353
354 d->Dmin[0] = 1.00f;
355 d->Dmin[1] = 0.45f;
356 d->Dmin[2] = 0.25f;
357}
358
360{
362 .Dmin = { 1.13f, 0.49f, 0.27f, 0.0f},
363 .wb_high = { 1.0f, 1.0f, 1.0f, 0.0f },
364 .wb_low = { 1.0f, 1.0f, 1.0f, 0.0f },
365 .D_max = 1.6f,
366 .offset = -0.05f,
367 .gamma = 4.0f,
368 .soft_clip = 0.75f,
369 .exposure = 0.9245f,
370 .black = 0.0755f };
371
372
373 dt_gui_presets_add_generic(_("color film"), self->op,
374 self->version(), &tmp, sizeof(tmp), 1, DEVELOP_BLEND_CS_RGB_DISPLAY);
375
377 .Dmin = { 1.0f, 1.0f, 1.0f, 0.0f},
378 .wb_high = { 1.0f, 1.0f, 1.0f, 0.0f },
379 .wb_low = { 1.0f, 1.0f, 1.0f, 0.0f },
380 .D_max = 2.2f,
381 .offset = -0.05f,
382 .gamma = 5.0f,
383 .soft_clip = 0.75f,
384 .exposure = 1.f,
385 .black = 0.0755f };
386
387
388 dt_gui_presets_add_generic(_("black and white film"), self->op,
389 self->version(), &tmq, sizeof(tmq), 1, DEVELOP_BLEND_CS_RGB_DISPLAY);
390}
391
393{
396 if(IS_NULL_PTR(gd)) return;
397
398 module->data = gd;
399 const int program = 30; // negadoctor.cl, from programs.conf
400 gd->kernel_negadoctor = dt_opencl_create_kernel(program, "negadoctor");
401}
402
404{
405 dt_iop_negadoctor_global_data_t *gd = module->data;
407 dt_free(module->data);
408}
409
411{
413 piece->data_size = sizeof(dt_iop_negadoctor_data_t);
414}
415
417{
418 dt_free_align(piece->data);
419 piece->data = NULL;
420}
421
422
423/* Global GUI stuff */
424
426{
427 gtk_widget_set_visible(g->Dmin_G, state);
428 gtk_widget_set_visible(g->Dmin_B, state);
429}
430
431
433{
436
437 if(p->film_stock == DT_FILMSTOCK_NB)
438 {
439 // Hide color controls
441 dt_bauhaus_widget_set_label(g->Dmin_R, N_("D min"));
442 }
443 else if(p->film_stock == DT_FILMSTOCK_COLOR)
444 {
445 // Show color controls
447 dt_bauhaus_widget_set_label(g->Dmin_R, N_("D min red component"));
448 }
449 else
450 {
451 // We shouldn't be there
452 fprintf(stderr, "negadoctor film stock: undefined behaviour\n");
453 }
454}
455
456
458{
461
462 GdkRGBA color;
463 color.alpha = 1.0f;
464
465 if(p->film_stock == DT_FILMSTOCK_COLOR)
466 {
467 color.red = p->Dmin[0];
468 color.green = p->Dmin[1];
469 color.blue = p->Dmin[2];
470 }
471 else if(p->film_stock == DT_FILMSTOCK_NB)
472 {
473 color.red = color.green = color.blue = p->Dmin[0];
474 }
475
476 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(g->Dmin_picker), &color);
477}
478
479static void Dmin_picker_callback(GtkColorButton *widget, dt_iop_module_t *self)
480{
481 if(darktable.gui->reset) return;
484
486
487 GdkRGBA c;
488 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(widget), &c);
489 p->Dmin[0] = c.red;
490 p->Dmin[1] = c.green;
491 p->Dmin[2] = c.blue;
492
494 dt_bauhaus_slider_set(g->Dmin_R, p->Dmin[0]);
495 dt_bauhaus_slider_set(g->Dmin_G, p->Dmin[1]);
496 dt_bauhaus_slider_set(g->Dmin_B, p->Dmin[2]);
498
499 Dmin_picker_update(self);
502}
503
505{
508
509 GdkRGBA color;
510 color.alpha = 1.0f;
511
512 dt_aligned_pixel_t WB_low_invert;
513 for(size_t c = 0; c < 3; ++c) WB_low_invert[c] = 2.0f - p->wb_low[c];
514 const float WB_low_max = v_maxf(WB_low_invert);
515 for(size_t c = 0; c < 3; ++c) WB_low_invert[c] /= WB_low_max;
516
517 color.red = WB_low_invert[0];
518 color.green = WB_low_invert[1];
519 color.blue = WB_low_invert[2];
520
521 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(g->WB_low_picker), &color);
522}
523
524static void WB_low_picker_callback(GtkColorButton *widget, dt_iop_module_t *self)
525{
526 if(darktable.gui->reset) return;
529
531
532 GdkRGBA c;
533 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(widget), &c);
534
535 dt_aligned_pixel_t RGB = { 2.0f - c.red, 2.0f - c.green, 2.0f - c.blue };
536
537 float RGB_min = v_minf(RGB);
538 for(size_t k = 0; k < 3; k++) p->wb_low[k] = RGB[k] / RGB_min;
539
541 dt_bauhaus_slider_set(g->wb_low_R, p->wb_low[0]);
542 dt_bauhaus_slider_set(g->wb_low_G, p->wb_low[1]);
543 dt_bauhaus_slider_set(g->wb_low_B, p->wb_low[2]);
545
549}
550
551
553{
556
557 GdkRGBA color;
558 color.alpha = 1.0f;
559
560 dt_aligned_pixel_t WB_high_invert;
561 for(size_t c = 0; c < 3; ++c) WB_high_invert[c] = 2.0f - p->wb_high[c];
562 const float WB_high_max = v_maxf(WB_high_invert);
563 for(size_t c = 0; c < 3; ++c) WB_high_invert[c] /= WB_high_max;
564
565 color.red = WB_high_invert[0];
566 color.green = WB_high_invert[1];
567 color.blue = WB_high_invert[2];
568
569 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(g->WB_high_picker), &color);
570}
571
572static void WB_high_picker_callback(GtkColorButton *widget, dt_iop_module_t *self)
573{
574 if(darktable.gui->reset) return;
577
579
580 GdkRGBA c;
581 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(widget), &c);
582
583 dt_aligned_pixel_t RGB = { 2.0f - c.red, 2.0f - c.green, 2.0f - c.blue };
584 float RGB_min = v_minf(RGB);
585 for(size_t k = 0; k < 3; k++) p->wb_high[k] = RGB[k] / RGB_min;
586
588 dt_bauhaus_slider_set(g->wb_high_R, p->wb_high[0]);
589 dt_bauhaus_slider_set(g->wb_high_G, p->wb_high[1]);
590 dt_bauhaus_slider_set(g->wb_high_B, p->wb_high[2]);
592
596}
597
598static void Wb_low_norm_callback(GtkColorButton *widget, dt_iop_module_t *self)
599{
600 if(darktable.gui->reset) return;
601
604
605
606 const float WB_low_max = v_maxf(p->wb_low);
607 for(size_t c = 0; c < 3; ++c)
608 p->wb_low[c] /= WB_low_max;
609
610
612 dt_bauhaus_slider_set(g->wb_low_R, p->wb_low[0]);
613 dt_bauhaus_slider_set(g->wb_low_G, p->wb_low[1]);
614 dt_bauhaus_slider_set(g->wb_low_B, p->wb_low[2]);
616
620}
621
622static void Wb_high_norm_callback(GtkColorButton *widget, dt_iop_module_t *self)
623{
624 if(darktable.gui->reset) return;
625
628
629 const float WB_high_min = v_minf(p->wb_high);
630 for(size_t c = 0; c < 3; ++c)
631 p->wb_high[c] /= WB_high_min;
632
633
635 dt_bauhaus_slider_set(g->wb_high_R, p->wb_high[0]);
636 dt_bauhaus_slider_set(g->wb_high_G, p->wb_high[1]);
637 dt_bauhaus_slider_set(g->wb_high_B, p->wb_high[2]);
639
643}
644
645/* Color pickers auto-tuners */
646
647// measure Dmin from the film edges first
649{
650 if(darktable.gui->reset) return;
653
654 for(int k = 0; k < 4; k++) p->Dmin[k] = self->picked_color[k];
655
657 dt_bauhaus_slider_set(g->Dmin_R, p->Dmin[0]);
658 dt_bauhaus_slider_set(g->Dmin_G, p->Dmin[1]);
659 dt_bauhaus_slider_set(g->Dmin_B, p->Dmin[2]);
661
662 Dmin_picker_update(self);
665}
666
667// from Dmin, find out the range of density values of the film and compute Dmax
669{
670 if(darktable.gui->reset) return;
673
675 for(int c = 0; c < 3; c++)
676 {
677 RGB[c] = log10f(p->Dmin[c] / fmaxf(self->picked_color_min[c], THRESHOLD));
678 }
679
680 // Take the max(RGB) for safety. Big values unclip whites
681 p->D_max = v_maxf(RGB);
682
684 dt_bauhaus_slider_set(g->D_max, p->D_max);
686
689}
690
691// from Dmax, compute the offset so the range of density is rescaled between [0; 1]
693{
694 if(darktable.gui->reset) return;
697
699 for(int c = 0; c < 3; c++)
700 RGB[c] = log10f(p->Dmin[c] / fmaxf(self->picked_color_max[c], THRESHOLD)) / p->D_max;
701
702 // Take the min(RGB) for safety. Negative values unclip blacks
703 p->offset = v_minf(RGB);
704
706 dt_bauhaus_slider_set(g->offset, p->offset);
708
711}
712
713// from Dmax and offset, compute the white balance correction as multipliers of the offset
714// such that offset x wb[c] make black monochrome
716{
717 if(darktable.gui->reset) return;
720
721 dt_aligned_pixel_t RGB_min;
722 for(int c = 0; c < 3; c++)
723 RGB_min[c] = log10f(p->Dmin[c] / fmaxf(self->picked_color[c], THRESHOLD)) / p->D_max;
724
725 const float RGB_v_min = v_minf(RGB_min); // warning: can be negative
726 for(int c = 0; c < 3; c++) p->wb_low[c] = RGB_v_min / RGB_min[c];
727
729 dt_bauhaus_slider_set(g->wb_low_R, p->wb_low[0]);
730 dt_bauhaus_slider_set(g->wb_low_G, p->wb_low[1]);
731 dt_bauhaus_slider_set(g->wb_low_B, p->wb_low[2]);
733
737}
738
739// from Dmax, offset and white balance multipliers, compute the white balance of the illuminant as multipliers of 1/Dmax
740// such that WB[c] / Dmax make white monochrome
742{
743 if(darktable.gui->reset) return;
746
747 dt_aligned_pixel_t RGB_min;
748 for(int c = 0; c < 3; c++)
749 RGB_min[c] = fabsf(-1.0f / (p->offset * p->wb_low[c] - log10f(p->Dmin[c] / fmaxf(self->picked_color[c], THRESHOLD)) / p->D_max));
750
751 const float RGB_v_min = v_minf(RGB_min); // warning : must be positive
752 for(int c = 0; c < 3; c++) p->wb_high[c] = RGB_min[c] / RGB_v_min;
753
755 dt_bauhaus_slider_set(g->wb_high_R, p->wb_high[0]);
756 dt_bauhaus_slider_set(g->wb_high_G, p->wb_high[1]);
757 dt_bauhaus_slider_set(g->wb_high_B, p->wb_high[2]);
759
763}
764
765// from Dmax, offset and both white balances, compute the print black adjustment
766// such that the printed values range from 0 to + infinity
768{
769 if(darktable.gui->reset) return;
772
774 for(int c = 0; c < 3; c++)
775 {
776 RGB[c] = -log10f(p->Dmin[c] / fmaxf(self->picked_color_max[c], THRESHOLD));
777 RGB[c] *= p->wb_high[c] / p->D_max;
778 RGB[c] += p->wb_low[c] * p->offset * p->wb_high[c];
779 RGB[c] = 0.1f - (1.0f - fast_exp10f(RGB[c])); // actually, remap between -3.32 EV and infinity for safety because gamma comes later
780 }
781 p->black = v_maxf(RGB);
782
784 dt_bauhaus_slider_set(g->black, p->black);
786
789}
790
791// from Dmax, offset, both white balances, and printblack, compute the print exposure adjustment as a scaling factor
792// such that the printed values range from 0 to 1
794{
795 if(darktable.gui->reset) return;
798
800 for(int c = 0; c < 3; c++)
801 {
802 RGB[c] = -log10f(p->Dmin[c] / fmaxf(self->picked_color_min[c], THRESHOLD));
803 RGB[c] *= p->wb_high[c] / p->D_max;
804 RGB[c] += p->wb_low[c] * p->offset;
805 RGB[c] = 0.96f / (1.0f - fast_exp10f(RGB[c]) + p->black); // actually, remap in [0; 0.96] for safety
806 }
807 p->exposure = v_minf(RGB);
808
810 dt_bauhaus_slider_set(g->exposure, log2f(p->exposure));
812
815}
816
817
819{
820 (void)pipe;
821 (void)piece;
822 if(darktable.gui->reset) return;
824
825 if (picker == g->Dmin_sampler)
826 apply_auto_Dmin(self);
827 else if(picker == g->WB_high_sampler)
828 apply_auto_WB_high(self);
829 else if(picker == g->offset)
830 apply_auto_offset(self);
831 else if(picker == g->D_max)
832 apply_auto_Dmax(self);
833 else if(picker == g->WB_low_sampler)
834 apply_auto_WB_low(self);
835 else if(picker == g->exposure)
837 else if(picker == g->black)
838 apply_auto_black(self);
839 else
840 fprintf(stderr, "[negadoctor] unknown color picker\n");
841}
842
844{
846
847 g->notebook = dt_ui_notebook_new();
848
849 // Page FILM PROPERTIES
850 GtkWidget *page1 = self->widget = dt_ui_notebook_page(g->notebook, N_("film properties"), NULL);
851
852 // Dmin
853
854 gtk_box_pack_start(GTK_BOX(page1), dt_ui_section_label_new(_("color of the film base")), FALSE, FALSE, 0);
855
856 GtkWidget *row1 = GTK_WIDGET(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, DT_GUI_BOX_SPACING));
857
858 g->Dmin_picker = gtk_color_button_new();
859 gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(g->Dmin_picker), FALSE);
860 gtk_color_button_set_title(GTK_COLOR_BUTTON(g->Dmin_picker), _("select color of film material from a swatch"));
861 gtk_box_pack_start(GTK_BOX(row1), GTK_WIDGET(g->Dmin_picker), TRUE, TRUE, 0);
862 g_signal_connect(G_OBJECT(g->Dmin_picker), "color-set", G_CALLBACK(Dmin_picker_callback), self);
863
864 g->Dmin_sampler = dt_color_picker_new(self, DT_COLOR_PICKER_AREA, row1);
865 gtk_widget_set_tooltip_text(g->Dmin_sampler , _("pick color of film material from image"));
866
867 gtk_box_pack_start(GTK_BOX(page1), GTK_WIDGET(row1), FALSE, FALSE, 0);
868
869 g->Dmin_R = dt_bauhaus_slider_from_params(self, "Dmin[0]");
871 dt_bauhaus_slider_set_format(g->Dmin_R, "%");
872 dt_bauhaus_slider_set_factor(g->Dmin_R, 100);
873 dt_bauhaus_widget_set_label(g->Dmin_R, N_("D min red component"));
874 gtk_widget_set_tooltip_text(g->Dmin_R, _("adjust the color and shade of the film transparent base.\n"
875 "this value depends on the film material, \n"
876 "the chemical fog produced while developing the film,\n"
877 "and the scanner white balance."));
878
879 g->Dmin_G = dt_bauhaus_slider_from_params(self, "Dmin[1]");
881 dt_bauhaus_slider_set_format(g->Dmin_G, "%");
882 dt_bauhaus_slider_set_factor(g->Dmin_G, 100);
883 dt_bauhaus_widget_set_label(g->Dmin_G, N_("D min green component"));
884 gtk_widget_set_tooltip_text(g->Dmin_G, _("adjust the color and shade of the film transparent base.\n"
885 "this value depends on the film material, \n"
886 "the chemical fog produced while developing the film,\n"
887 "and the scanner white balance."));
888
889 g->Dmin_B = dt_bauhaus_slider_from_params(self, "Dmin[2]");
891 dt_bauhaus_slider_set_format(g->Dmin_B, "%");
892 dt_bauhaus_slider_set_factor(g->Dmin_B, 100);
893 dt_bauhaus_widget_set_label(g->Dmin_B, N_("D min blue component"));
894 gtk_widget_set_tooltip_text(g->Dmin_B, _("adjust the color and shade of the film transparent base.\n"
895 "this value depends on the film material, \n"
896 "the chemical fog produced while developing the film,\n"
897 "and the scanner white balance."));
898
899 // D max and scanner bias
900
901 gtk_box_pack_start(GTK_BOX(page1), dt_ui_section_label_new(_("dynamic range of the film")), FALSE, FALSE, 0);
902
904 dt_bauhaus_slider_set_format(g->D_max, " dB");
905 gtk_widget_set_tooltip_text(g->D_max, _("maximum density of the film, corresponding to white after inversion.\n"
906 "this value depends on the film specifications, the developing process,\n"
907 "the dynamic range of the scene and the scanner exposure settings."));
908
909 gtk_box_pack_start(GTK_BOX(page1), dt_ui_section_label_new(_("scanner exposure settings")), FALSE, FALSE, 0);
910
912 dt_bauhaus_slider_set_format(g->offset, " dB");
913 gtk_widget_set_tooltip_text(g->offset, _("correct the exposure of the scanner, for all RGB channels,\n"
914 "before the inversion, so blacks are neither clipped or too pale."));
915
916 // Page CORRECTIONS
917 GtkWidget *page2 = self->widget = dt_ui_notebook_page(g->notebook, N_("corrections"), NULL);
918
919 // WB shadows
920 gtk_box_pack_start(GTK_BOX(page2), dt_ui_section_label_new(_("shadows color cast")), FALSE, FALSE, 0);
921
922 GtkWidget *row3 = GTK_WIDGET(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, DT_GUI_BOX_SPACING));
923
924 g->WB_low_picker = gtk_color_button_new();
925 gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(g->WB_low_picker), FALSE);
926 gtk_color_button_set_title(GTK_COLOR_BUTTON(g->WB_low_picker), _("select color of shadows from a swatch"));
927 gtk_box_pack_start(GTK_BOX(row3), GTK_WIDGET(g->WB_low_picker), TRUE, TRUE, 0);
928 g_signal_connect(G_OBJECT(g->WB_low_picker), "color-set", G_CALLBACK(WB_low_picker_callback), self);
929
930 g->WB_low_norm = dt_action_button_new((dt_lib_module_t *)self, N_("normalize"), Wb_low_norm_callback, self, _("normalize shadows white balance settings"), 0, 0);
931 gtk_box_pack_start(GTK_BOX(row3), GTK_WIDGET(g->WB_low_norm), FALSE, FALSE, 0);
932
933 g->WB_low_sampler = dt_color_picker_new(self, DT_COLOR_PICKER_AREA, row3);
934 gtk_widget_set_tooltip_text(g->WB_low_sampler, _("pick shadows color from image"));
935
936 gtk_box_pack_start(GTK_BOX(page2), GTK_WIDGET(row3), FALSE, FALSE, 0);
937
938 g->wb_low_R = dt_bauhaus_slider_from_params(self, "wb_low[0]");
939 dt_bauhaus_widget_set_label(g->wb_low_R, N_("shadows red offset"));
940 gtk_widget_set_tooltip_text(g->wb_low_R, _("correct the color cast in shadows so blacks are\n"
941 "truly achromatic. Setting this value before\n"
942 "the highlights illuminant white balance will help\n"
943 "recovering the global white balance in difficult cases."));
944
945 g->wb_low_G = dt_bauhaus_slider_from_params(self, "wb_low[1]");
946 dt_bauhaus_widget_set_label(g->wb_low_G, N_("shadows green offset"));
947 gtk_widget_set_tooltip_text(g->wb_low_G, _("correct the color cast in shadows so blacks are\n"
948 "truly achromatic. Setting this value before\n"
949 "the highlights illuminant white balance will help\n"
950 "recovering the global white balance in difficult cases."));
951
952 g->wb_low_B = dt_bauhaus_slider_from_params(self, "wb_low[2]");
953 dt_bauhaus_widget_set_label(g->wb_low_B, N_("shadows blue offset"));
954 gtk_widget_set_tooltip_text(g->wb_low_B, _("correct the color cast in shadows so blacks are\n"
955 "truly achromatic. Setting this value before\n"
956 "the highlights illuminant white balance will help\n"
957 "recovering the global white balance in difficult cases."));
958
959 // WB highlights
960 gtk_box_pack_start(GTK_BOX(page2), dt_ui_section_label_new(_("highlights white balance")), FALSE, FALSE, 0);
961
962 GtkWidget *row2 = GTK_WIDGET(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, DT_GUI_BOX_SPACING));
963
964 g->WB_high_picker = gtk_color_button_new();
965 gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(g->WB_high_picker), FALSE);
966 gtk_color_button_set_title(GTK_COLOR_BUTTON(g->WB_high_picker), _("select color of illuminant from a swatch"));
967 gtk_box_pack_start(GTK_BOX(row2), GTK_WIDGET(g->WB_high_picker), TRUE, TRUE, 0);
968 g_signal_connect(G_OBJECT(g->WB_high_picker), "color-set", G_CALLBACK(WB_high_picker_callback), self);
969
970 g->WB_high_norm = dt_action_button_new((dt_lib_module_t *)self, N_("normalize"), Wb_high_norm_callback, self, _("normalize highlight white balance settings"), 0, 0);
971 gtk_box_pack_start(GTK_BOX(row2), GTK_WIDGET(g->WB_high_norm), FALSE, FALSE, 0);
972
973 g->WB_high_sampler = dt_color_picker_new(self, DT_COLOR_PICKER_AREA, row2);
974 gtk_widget_set_tooltip_text(g->WB_high_sampler , _("pick illuminant color from image"));
975
976 gtk_box_pack_start(GTK_BOX(page2), GTK_WIDGET(row2), FALSE, FALSE, 0);
977
978 g->wb_high_R = dt_bauhaus_slider_from_params(self, "wb_high[0]");
979 dt_bauhaus_widget_set_label(g->wb_high_R, N_("illuminant red gain"));
980 gtk_widget_set_tooltip_text(g->wb_high_R, _("correct the color of the illuminant so whites are\n"
981 "truly achromatic. Setting this value after\n"
982 "the shadows color cast will help\n"
983 "recovering the global white balance in difficult cases."));
984
985 g->wb_high_G = dt_bauhaus_slider_from_params(self, "wb_high[1]");
986 dt_bauhaus_widget_set_label(g->wb_high_G, N_("illuminant green gain"));
987 gtk_widget_set_tooltip_text(g->wb_high_G, _("correct the color of the illuminant so whites are\n"
988 "truly achromatic. Setting this value after\n"
989 "the shadows color cast will help\n"
990 "recovering the global white balance in difficult cases."));
991
992 g->wb_high_B = dt_bauhaus_slider_from_params(self, "wb_high[2]");
993 dt_bauhaus_widget_set_label(g->wb_high_B, N_("illuminant blue gain"));
994 gtk_widget_set_tooltip_text(g->wb_high_B, _("correct the color of the illuminant so whites are\n"
995 "truly achromatic. Setting this value after\n"
996 "the shadows color cast will help\n"
997 "recovering the global white balance in difficult cases."));
998
999 // Page PRINT PROPERTIES
1000 GtkWidget *page3 = self->widget = dt_ui_notebook_page(g->notebook, N_("print properties"), NULL);
1001
1002 // print corrections
1003 gtk_box_pack_start(GTK_BOX(page3), dt_ui_section_label_new(_("virtual paper properties")), FALSE, FALSE, 0);
1004
1007 dt_bauhaus_slider_set_factor(g->black, 100);
1008 dt_bauhaus_slider_set_format(g->black, "%");
1009 gtk_widget_set_tooltip_text(g->black, _("correct the density of black after the inversion,\n"
1010 "to adjust the global contrast while avoiding clipping shadows."));
1011
1012 g->gamma = dt_bauhaus_slider_from_params(self, "gamma");
1013 dt_bauhaus_widget_set_label(g->gamma, N_("paper grade (gamma)"));
1014 gtk_widget_set_tooltip_text(g->gamma, _("select the grade of the virtual paper, which is actually\n"
1015 "equivalent to applying a gamma. it compensates the film D max\n"
1016 "and recovers the contrast. use a high grade for high D max."));
1017
1018 g->soft_clip = dt_bauhaus_slider_from_params(self, "soft_clip");
1019 dt_bauhaus_slider_set_factor(g->soft_clip, 100);
1020 dt_bauhaus_slider_set_digits(g->soft_clip, 4);
1021 dt_bauhaus_slider_set_format(g->soft_clip, "%");
1022 gtk_widget_set_tooltip_text(g->soft_clip, _("gradually compress specular highlights past this value\n"
1023 "to avoid clipping while pushing the exposure for mid-tones.\n"
1024 "this somewhat reproduces the behaviour of matte paper."));
1025
1026 gtk_box_pack_start(GTK_BOX(page3), dt_ui_section_label_new(_("virtual print emulation")), FALSE, FALSE, 0);
1027
1028 g->exposure = dt_color_picker_new(self, DT_COLOR_PICKER_AREA, dt_bauhaus_slider_from_params(self, "exposure"));
1029 dt_bauhaus_slider_set_soft_min(g->exposure, -1.0);
1030 dt_bauhaus_slider_set_soft_max(g->exposure, 1.0);
1031 dt_bauhaus_slider_set_default(g->exposure, 0.0);
1032 dt_bauhaus_slider_set_format(g->exposure, _(" EV"));
1033 gtk_widget_set_tooltip_text(g->exposure, _("correct the printing exposure after inversion to adjust\n"
1034 "the global contrast and avoid clipping highlights."));
1035
1036 // start building top level widget
1037 self->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING);
1038
1039 // Film emulsion
1040 g->film_stock = dt_bauhaus_combobox_from_params(self, "film_stock");
1041 gtk_widget_set_tooltip_text(g->film_stock, _("toggle on or off the color controls"));
1042
1043 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(g->notebook), FALSE, FALSE, 0);
1044 const int active_page = dt_conf_get_int("plugins/darkroom/negadoctor/gui_page");
1045 gtk_widget_show(gtk_notebook_get_nth_page(g->notebook, active_page));
1046 gtk_notebook_set_current_page(g->notebook, active_page);
1047
1048}
1049
1051{
1053 if(!IS_NULL_PTR(g) && GTK_IS_NOTEBOOK(g->notebook))
1054 dt_conf_set_int("plugins/darkroom/negadoctor/gui_page", gtk_notebook_get_current_page(g->notebook));
1056}
1057
1058void gui_changed(dt_iop_module_t *self, GtkWidget *w, void *previous)
1059{
1062 if(IS_NULL_PTR(w) || w == g->film_stock)
1063 {
1065 Dmin_picker_update(self);
1066 }
1067 else if(w == g->Dmin_R && p->film_stock == DT_FILMSTOCK_NB)
1068 {
1069 dt_bauhaus_slider_set(g->Dmin_G, p->Dmin[0]);
1070 dt_bauhaus_slider_set(g->Dmin_B, p->Dmin[0]);
1071 }
1072 else if(w == g->Dmin_R || w == g->Dmin_G || w == g->Dmin_B)
1073 {
1074 Dmin_picker_update(self);
1075 }
1076 else if(w == g->exposure)
1077 {
1078 p->exposure = powf(2.0f, p->exposure);
1079 }
1080
1081 if(IS_NULL_PTR(w) || w == g->wb_high_R || w == g->wb_high_G || w == g->wb_high_B)
1082 {
1084 }
1085
1086 if(IS_NULL_PTR(w) || w == g->wb_low_R || w == g->wb_low_G || w == g->wb_low_B)
1087 {
1089 }
1090}
1091
1092
1094{
1095 // let gui slider match current parameters:
1098
1100
1101
1102 dt_bauhaus_slider_set(g->exposure, log2f(p->exposure)); // warning: GUI is in EV
1103
1104 // Update custom stuff
1105 gui_changed(self, NULL, NULL);
1106}
1107
1109{
1111}
1112// clang-format off
1113// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
1114// vim: shiftwidth=2 expandtab tabstop=2 cindent
1115// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
1116// 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_digits(GtkWidget *widget, int val)
Definition bauhaus.c:3534
void dt_bauhaus_slider_set_default(GtkWidget *widget, float def)
Definition bauhaus.c:1640
void dt_bauhaus_slider_set_soft_max(GtkWidget *widget, float val)
Definition bauhaus.c:1624
void dt_bauhaus_slider_set_soft_min(GtkWidget *widget, float val)
Definition bauhaus.c:1608
void dt_bauhaus_slider_set(GtkWidget *widget, float pos)
Definition bauhaus.c:3506
void dt_bauhaus_widget_set_label(GtkWidget *widget, const char *label)
Definition bauhaus.c:1653
void dt_bauhaus_slider_set_format(GtkWidget *widget, const char *format)
Definition bauhaus.c:3598
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
@ DEVELOP_BLEND_CS_RGB_DISPLAY
Definition blend.h:59
static const dt_aligned_pixel_simd_t const dt_adaptation_t const float p
@ IOP_CS_RGB
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 float soft_clip(const float x, const float soft_threshold, const float hard_threshold)
const dt_colormatrix_t dt_aligned_pixel_t out
static dt_aligned_pixel_t RGB
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
void dt_conf_set_int(const char *name, int val)
int dt_conf_get_int(const char *name)
void dt_control_queue_redraw_widget(GtkWidget *widget)
threadsafe request of redraw of specific widget. Use this function if you need to redraw a specific w...
Definition control.c:906
darktable_t darktable
Definition darktable.c:181
void dt_print(dt_debug_thread_t thread, const char *msg,...)
Definition darktable.c:1542
static const dt_aligned_pixel_simd_t const dt_aligned_pixel_simd_t row1
Definition darktable.h:623
#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
static const dt_aligned_pixel_simd_t const dt_aligned_pixel_simd_t const dt_aligned_pixel_simd_t row2
Definition darktable.h:624
#define __OMP_FOR_SIMD__(...)
Definition darktable.h:260
#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 * dt_ui_notebook_page(GtkNotebook *notebook, const char *text, const char *tooltip)
Definition gtk.c:2259
GtkNotebook * dt_ui_notebook_new()
Definition gtk.c:2254
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_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, const dt_develop_blend_colorspace_t blend_cst)
void dt_iop_default_init(dt_iop_module_t *module)
Definition imageop.c:316
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_ALLOW_TILING
Definition imageop.h:169
@ IOP_FLAGS_ONE_INSTANCE
Definition imageop.h:172
@ IOP_GROUP_FILM
Definition imageop.h:138
#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
GtkWidget * dt_action_button_new(dt_lib_module_t *self, const gchar *label, gpointer callback, gpointer data, const gchar *tooltip, guint accel_key, GdkModifierType mods)
Definition lib.c:1563
float *const restrict const size_t k
void init(dt_iop_module_t *module)
Definition negadoctor.c:348
const char ** description(struct dt_iop_module_t *self)
Definition negadoctor.c:155
static void WB_high_picker_update(dt_iop_module_t *self)
Definition negadoctor.c:552
int default_group()
Definition negadoctor.c:170
void gui_update(dt_iop_module_t *const self)
Refresh GUI controls from current params and configuration.
void gui_reset(dt_iop_module_t *self)
static void WB_low_picker_callback(GtkColorButton *widget, dt_iop_module_t *self)
Definition negadoctor.c:524
static void Wb_high_norm_callback(GtkColorButton *widget, dt_iop_module_t *self)
Definition negadoctor.c:622
static void toggle_stock_controls(dt_iop_module_t *const self)
Definition negadoctor.c:432
static void WB_high_picker_callback(GtkColorButton *widget, dt_iop_module_t *self)
Definition negadoctor.c:572
__DT_CLONE_TARGETS__ int process(struct dt_iop_module_t *const self, const dt_dev_pixelpipe_t *const pipe, const dt_dev_pixelpipe_iop_t *const piece, const void *const restrict ivoid, void *const restrict ovoid)
Definition negadoctor.c:266
#define THRESHOLD
Definition negadoctor.c:72
static void apply_auto_WB_high(dt_iop_module_t *self)
Definition negadoctor.c:741
dt_iop_negadoctor_filmstock_t
Definition negadoctor.c:79
@ DT_FILMSTOCK_NB
Definition negadoctor.c:81
@ DT_FILMSTOCK_COLOR
Definition negadoctor.c:82
static void apply_auto_WB_low(dt_iop_module_t *self)
Definition negadoctor.c:715
int process_cl(struct dt_iop_module_t *const self, const dt_dev_pixelpipe_t *const pipe, const dt_dev_pixelpipe_iop_t *const piece, cl_mem dev_in, cl_mem dev_out)
Definition negadoctor.c:309
const char * aliases()
Definition negadoctor.c:150
void init_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition negadoctor.c:410
const char * name()
Definition negadoctor.c:145
void gui_init(dt_iop_module_t *self)
Definition negadoctor.c:843
static void setup_color_variables(dt_iop_negadoctor_gui_data_t *const g, const gint state)
Definition negadoctor.c:425
void gui_changed(dt_iop_module_t *self, GtkWidget *w, void *previous)
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 negadoctor.c:234
void cleanup_global(dt_iop_module_so_t *module)
Definition negadoctor.c:403
static void apply_auto_exposure(dt_iop_module_t *self)
Definition negadoctor.c:793
int default_colorspace(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
Definition negadoctor.c:176
int flags()
Definition negadoctor.c:164
static void apply_auto_Dmin(dt_iop_module_t *self)
Definition negadoctor.c:648
void gui_cleanup(struct dt_iop_module_t *self)
static void Dmin_picker_update(dt_iop_module_t *self)
Definition negadoctor.c:457
void init_presets(dt_iop_module_so_t *self)
Definition negadoctor.c:359
static void WB_low_picker_update(dt_iop_module_t *self)
Definition negadoctor.c:504
void cleanup_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition negadoctor.c:416
static void Wb_low_norm_callback(GtkColorButton *widget, dt_iop_module_t *self)
Definition negadoctor.c:598
static void apply_auto_offset(dt_iop_module_t *self)
Definition negadoctor.c:692
static void apply_auto_black(dt_iop_module_t *self)
Definition negadoctor.c:767
void init_global(dt_iop_module_so_t *module)
Definition negadoctor.c:392
static void apply_auto_Dmax(dt_iop_module_t *self)
Definition negadoctor.c:668
void color_picker_apply(dt_iop_module_t *self, GtkWidget *picker, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition negadoctor.c:818
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 negadoctor.c:181
static void Dmin_picker_callback(GtkColorButton *widget, dt_iop_module_t *self)
Definition negadoctor.c:479
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
static float v_maxf(const float vector[3])
static float fast_exp10f(const float x)
static float fast_expf(const float x)
static float v_minf(const float vector[3])
struct _GtkWidget GtkWidget
Definition splash.h:29
const float uint32_t state[4]
struct dt_gui_gtk_t * gui
Definition darktable.h:775
struct dt_develop_t * develop
Definition darktable.h:770
struct dt_iop_module_t *void * data
int32_t reset
Definition gtk.h:172
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
GtkWidget * widget
Definition imageop.h:337
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
dt_aligned_pixel_t wb_high
Definition negadoctor.c:113
dt_aligned_pixel_t offset
Definition negadoctor.c:114
dt_aligned_pixel_t Dmin
Definition negadoctor.c:112
dt_iop_negadoctor_filmstock_t film_stock
Definition negadoctor.c:88
Region of interest passed through the pixelpipe.
Definition imageop.h:72