Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
exposure.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2009-2016, 2018 johannes hanika.
4 Copyright (C) 2010-2011 Bruce Guenter.
5 Copyright (C) 2010-2012 Henrik Andersson.
6 Copyright (C) 2010 José Carlos García Sogo.
7 Copyright (C) 2010 Milan Knížek.
8 Copyright (C) 2010 Stuart Henderson.
9 Copyright (C) 2011 Antony Dovgal.
10 Copyright (C) 2011 Christophe Augier.
11 Copyright (C) 2011 Olivier Tribout.
12 Copyright (C) 2011-2012 Pascal de Bruijn.
13 Copyright (C) 2011 Robert Bieber.
14 Copyright (C) 2011 root.
15 Copyright (C) 2011-2019 Tobias Ellinghaus.
16 Copyright (C) 2011-2014, 2017 Ulrich Pegelow.
17 Copyright (C) 2012 Edouard Gomez.
18 Copyright (C) 2012 Richard Wonka.
19 Copyright (C) 2013, 2020, 2022 Aldric Renaudin.
20 Copyright (C) 2013 Dennis Gnad.
21 Copyright (C) 2013-2014, 2018-2022 Pascal Obry.
22 Copyright (C) 2014-2016 Roman Lebedev.
23 Copyright (C) 2015 Jan Kundrát.
24 Copyright (C) 2015 Pedro Côrte-Real.
25 Copyright (C) 2016 Alexander V. Smal.
26 Copyright (C) 2017 Heiko Bauke.
27 Copyright (C) 2018-2023, 2025-2026 Aurélien PIERRE.
28 Copyright (C) 2018-2019 Edgardo Hoszowski.
29 Copyright (C) 2018 Maurizio Paglia.
30 Copyright (C) 2018 rawfiner.
31 Copyright (C) 2019 Andreas Schneider.
32 Copyright (C) 2019-2020, 2022 Diederik Ter Rahe.
33 Copyright (C) 2020-2022 Chris Elston.
34 Copyright (C) 2020 Ralf Brown.
35 Copyright (C) 2021 Alex Esseling.
36 Copyright (C) 2021 Hubert Kowalski.
37 Copyright (C) 2022 Hanno Schwalm.
38 Copyright (C) 2022 Martin Bařinka.
39 Copyright (C) 2022 Philipp Lutz.
40 Copyright (C) 2023 Luca Zulberti.
41 Copyright (C) 2025 Guillaume Stutin.
42
43 darktable is free software: you can redistribute it and/or modify
44 it under the terms of the GNU General Public License as published by
45 the Free Software Foundation, either version 3 of the License, or
46 (at your option) any later version.
47
48 darktable is distributed in the hope that it will be useful,
49 but WITHOUT ANY WARRANTY; without even the implied warranty of
50 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
51 GNU General Public License for more details.
52
53 You should have received a copy of the GNU General Public License
54 along with darktable. If not, see <http://www.gnu.org/licenses/>.
55*/
56#ifdef HAVE_CONFIG_H
57#include "config.h"
58#endif
59
60#include <assert.h>
61#include <math.h>
62#include <stdint.h>
63#include <stdlib.h>
64#include <string.h>
65
66#include "bauhaus/bauhaus.h"
67#include "common/darktable.h"
68#include "common/histogram.h"
69#include "common/image_cache.h"
70#include "common/mipmap_cache.h"
71#include "common/opencl.h"
72#include "control/control.h"
73#include "develop/develop.h"
74#include "develop/imageop.h"
76#include "develop/imageop_gui.h"
77#include "develop/pixelpipe.h"
78#include "dtgtk/paint.h"
79#include "dtgtk/resetlabel.h"
80
81#include "gui/gtk.h"
82#include "gui/presets.h"
84#include "iop/iop_api.h"
85
86#define exposure2white(x) exp2f(-(x))
87#define white2exposure(x) -dt_log2f(fmaxf(1e-20f, x))
88
90
92{
93 EXPOSURE_MODE_MANUAL, // $DESCRIPTION: "manual"
94 EXPOSURE_MODE_DEFLICKER // $DESCRIPTION: "automatic"
96
103
104// uint16_t pixel can have any value in range [0, 65535], thus, there is
105// 65536 possible values.
106#define DEFLICKER_BINS_COUNT (UINT16_MAX + 1)
107
108typedef struct dt_iop_exposure_params_t
109{
110 dt_iop_exposure_mode_t mode; // $DEFAULT: EXPOSURE_MODE_MANUAL
111 float black; // $MIN: -1.0 $MAX: 1.0 $DEFAULT: 0.0 $DESCRIPTION: "black level correction"
112 float exposure; // $MIN: -18.0 $MAX: 18.0 $DEFAULT: 0.0
113 float deflicker_percentile; // $MIN: 0.0 $MAX: 100.0 $DEFAULT: 50.0 $DESCRIPTION: "percentile"
114 float deflicker_target_level; // $MIN: -18.0 $MAX: 18.0 $DEFAULT: -4.0 $DESCRIPTION: "target level"
115 gboolean compensate_exposure_bias; // $DEFAULT: FALSE $DESCRIPTION: "compensate exposure bias"
117
142
150
155
156
157const char *name()
158{
159 return _("exp_osure");
160}
161
162const char** description(struct dt_iop_module_t *self)
163{
164 return dt_iop_set_description(self,
165 _("redo the exposure of the shot as if you were still in-camera\n"
166 "using a color-safe brightening similar to increasing ISO setting"),
167 _("corrective and creative"),
168 _("linear, RGB, scene-referred"),
169 _("linear, RGB"),
170 _("linear, RGB, scene-referred"));
171}
172
174{
175 return IOP_GROUP_TONES;
176}
177
182
184{
185 return IOP_CS_RGB;
186}
187
188static void _process_common_setup(dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe,
189 const dt_dev_pixelpipe_iop_t *piece);
190
193{
194 default_output_format(self, pipe, piece, dsc);
195}
196
197static void _paint_hue(dt_iop_module_t *self);
198static void _exposure_set_black(struct dt_iop_module_t *self, const float black);
199
200int legacy_params(dt_iop_module_t *self, const void *const old_params, const int old_version,
201 void *new_params, const int new_version)
202{
203 if(old_version == 2 && new_version == 6)
204 {
205 typedef struct dt_iop_exposure_params_v2_t
206 {
207 float black, exposure, gain;
208 } dt_iop_exposure_params_v2_t;
209
210 dt_iop_exposure_params_v2_t *o = (dt_iop_exposure_params_v2_t *)old_params;
213
214 *n = *d; // start with a fresh copy of default parameters
215
216 n->black = o->black;
217 n->exposure = o->exposure;
218 n->compensate_exposure_bias = FALSE;
219 return 0;
220 }
221 if(old_version == 3 && new_version == 6)
222 {
223 typedef struct dt_iop_exposure_params_v3_t
224 {
225 float black, exposure;
226 gboolean deflicker;
227 float deflicker_percentile, deflicker_target_level;
228 } dt_iop_exposure_params_v3_t;
229
230 dt_iop_exposure_params_v3_t *o = (dt_iop_exposure_params_v3_t *)old_params;
233
234 *n = *d; // start with a fresh copy of default parameters
235
236 n->mode = o->deflicker ? EXPOSURE_MODE_DEFLICKER : EXPOSURE_MODE_MANUAL;
237 n->black = o->black;
238 n->exposure = o->exposure;
239 n->deflicker_percentile = o->deflicker_percentile;
240 n->deflicker_target_level = o->deflicker_target_level;
241 n->compensate_exposure_bias = FALSE;
242 return 0;
243 }
244 if(old_version == 4 && new_version == 6)
245 {
246 typedef enum dt_iop_exposure_deflicker_histogram_source_t {
247 DEFLICKER_HISTOGRAM_SOURCE_THUMBNAIL,
248 DEFLICKER_HISTOGRAM_SOURCE_SOURCEFILE
249 } dt_iop_exposure_deflicker_histogram_source_t;
250
251 typedef struct dt_iop_exposure_params_v4_t
252 {
254 float black;
255 float exposure;
256 float deflicker_percentile, deflicker_target_level;
257 dt_iop_exposure_deflicker_histogram_source_t deflicker_histogram_source;
258 } dt_iop_exposure_params_v4_t;
259
260 dt_iop_exposure_params_v4_t *o = (dt_iop_exposure_params_v4_t *)old_params;
263
264 *n = *d; // start with a fresh copy of default parameters
265
266 n->mode = o->mode;
267 n->black = o->black;
268 n->exposure = o->exposure;
269 n->deflicker_percentile = o->deflicker_percentile;
270 n->deflicker_target_level = o->deflicker_target_level;
271 // deflicker_histogram_source is dropped. this does change output,
272 // but deflicker still was not publicly released at that point
273 n->compensate_exposure_bias = FALSE;
274 return 0;
275 }
276 if(old_version == 5 && new_version == 6)
277 {
278 typedef struct dt_iop_exposure_params_v5_t
279 {
281 float black;
282 float exposure;
283 float deflicker_percentile, deflicker_target_level;
284 } dt_iop_exposure_params_v5_t;
285
286 dt_iop_exposure_params_v5_t *o = (dt_iop_exposure_params_v5_t *)old_params;
289
290 *n = *d; // start with a fresh copy of default parameters
291
292 n->mode = o->mode;
293 n->black = o->black;
294 n->exposure = o->exposure;
295 n->deflicker_percentile = o->deflicker_percentile;
296 n->deflicker_target_level = o->deflicker_target_level;
297 n->compensate_exposure_bias = FALSE;
298 return 0;
299 }
300 return 1;
301}
302
304{
305 dt_gui_presets_add_generic(_("magic lantern defaults"), self->op,
306 self->version(),
307 &(dt_iop_exposure_params_t){.mode = EXPOSURE_MODE_DEFLICKER,
308 .black = 0.0f,
309 .exposure = 0.0f,
310 .deflicker_percentile = 50.0f,
311 .deflicker_target_level = -4.0f,
312 .compensate_exposure_bias = FALSE},
314
315
316 // For scene-referred workflow, since filmic doesn't brighten as base curve does,
317 // we need an initial exposure boost. This might be too much in some cases but...
318 // (the preset name is used in develop.c)
319 dt_gui_presets_add_generic(_("scene-referred default"), self->op, self->version(),
320 &(dt_iop_exposure_params_t){.mode = EXPOSURE_MODE_MANUAL,
321 .black = -0.000244140625f,
322 .exposure = 0.7f,
323 .deflicker_percentile = 50.0f,
324 .deflicker_target_level = -4.0f,
325 .compensate_exposure_bias = TRUE},
327
328 dt_gui_presets_update_ldr(_("scene-referred default"), self->op,
329 self->version(), FOR_RAW);
330}
331
332static void _deflicker_prepare_histogram(dt_iop_module_t *self, uint32_t **histogram,
333 dt_dev_histogram_stats_t *histogram_stats)
334{
336 dt_image_t image = *img;
338
339 if(image.dsc.channels != 1 || image.dsc.datatype != TYPE_UINT16) return;
340
343 DT_MIPMAP_BLOCKING, 'r');
344 if(IS_NULL_PTR(buf.buf))
345 {
346 dt_control_log(_("failed to get raw buffer from image `%s'"), image.filename);
348 return;
349 }
350
351 dt_dev_histogram_collection_params_t histogram_params = { 0 };
352
353 dt_histogram_roi_t histogram_roi = {.width = image.width,
354 .height = image.height,
355
356 // FIXME: get those from rawprepare IOP somehow !!!
357 .crop_x = image.crop_x,
358 .crop_y = image.crop_y,
359 .crop_width = image.crop_width,
360 .crop_height = image.crop_height };
361
362 histogram_params.roi = &histogram_roi;
363 histogram_params.bins_count = DEFLICKER_BINS_COUNT;
364
365 dt_histogram_worker(&histogram_params, histogram_stats, buf.buf, histogram,
367 histogram_stats->ch = 1u;
368
370}
371
372/* input: 0 - 65535 (valid range: from black level to white level) */
373/* output: -16 ... 0 */
374static double _raw_to_ev(uint32_t raw, uint32_t black_level, uint32_t white_level)
375{
376 const uint32_t raw_max = white_level - black_level;
377
378 // we are working on data without black clipping,
379 // so we can get values which are lower than the black level !!!
380 const int64_t raw_val = MAX((int64_t)raw - (int64_t)black_level, 1);
381
382 const double raw_ev = -log2(raw_max) + log2(raw_val);
383
384 return raw_ev;
385}
386
388 const dt_dev_pixelpipe_iop_t *piece,
389 const uint32_t *const histogram,
390 const dt_dev_histogram_stats_t *const histogram_stats, float *correction)
391{
392 const dt_iop_exposure_params_t *const p = (const dt_iop_exposure_params_t *const)p1;
393
394 *correction = NAN;
395
396 if(IS_NULL_PTR(histogram)) return;
397
398 const size_t total = (size_t)histogram_stats->ch * histogram_stats->pixels;
399
400 const double thr
401 = CLAMP(((double)total * (double)p->deflicker_percentile / (double)100.0), 0.0, (double)total);
402
403 size_t n = 0;
404 uint32_t raw = 0;
405
406 for(uint32_t i = 0; i < histogram_stats->bins_count; i++)
407 {
408 for(uint32_t k = 0; k < histogram_stats->ch; k++)
409 n += histogram[4 * i + k];
410
411 if((double)n >= thr)
412 {
413 raw = i;
414 break;
415 }
416 }
417
418 const double ev
419 = _raw_to_ev(raw, (uint32_t)piece->dsc_in.rawprepare.raw_black_level,
421
422 *correction = p->deflicker_target_level - ev;
423}
424
426 const dt_dev_pixelpipe_iop_t *piece)
427{
429 dt_iop_exposure_data_t *d = piece->data;
430
431 d->black = d->params.black;
432 float exposure = d->params.exposure;
433
434 if(d->deflicker)
435 {
436 if(!IS_NULL_PTR(g))
437 {
438 // histogram is precomputed and cached
439 _compute_correction(self, &d->params, piece, g->deflicker_histogram, &g->deflicker_histogram_stats,
440 &exposure);
441 }
442 else
443 {
444 uint32_t *histogram = NULL;
445 dt_dev_histogram_stats_t histogram_stats;
446 _deflicker_prepare_histogram(self, &histogram, &histogram_stats);
447 _compute_correction(self, &d->params, piece, histogram, &histogram_stats, &exposure);
448 dt_free(histogram);
449 }
450
451 // second, show computed correction in UI.
452 if(!IS_NULL_PTR(g) && dt_dev_pixelpipe_has_preview_output(self->dev, pipe, NULL))
453 {
455 g->deflicker_computed_exposure = exposure;
457 }
458 }
459
460 const float white = exposure2white(exposure);
461 d->scale = 1.0 / (white - d->black);
462}
463
464#ifdef HAVE_OPENCL
465int 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)
466{
467 const dt_iop_roi_t *const roi_in = &piece->roi_in;
470
471 cl_int err = -999;
472 const int devid = pipe->devid;
473 const int width = roi_in->width;
474 const int height = roi_in->height;
475
476 size_t sizes[] = { ROUNDUPDWD(width, devid), ROUNDUPDHT(height, devid), 1 };
477 dt_opencl_set_kernel_arg(devid, gd->kernel_exposure, 0, sizeof(cl_mem), (void *)&dev_in);
478 dt_opencl_set_kernel_arg(devid, gd->kernel_exposure, 1, sizeof(cl_mem), (void *)&dev_out);
479 dt_opencl_set_kernel_arg(devid, gd->kernel_exposure, 2, sizeof(int), (void *)&width);
480 dt_opencl_set_kernel_arg(devid, gd->kernel_exposure, 3, sizeof(int), (void *)&height);
481 dt_opencl_set_kernel_arg(devid, gd->kernel_exposure, 4, sizeof(float), (void *)&(d->black));
482 dt_opencl_set_kernel_arg(devid, gd->kernel_exposure, 5, sizeof(float), (void *)&(d->scale));
483 err = dt_opencl_enqueue_kernel_2d(devid, gd->kernel_exposure, sizes);
484 if(err != CL_SUCCESS) goto error;
485
486 return TRUE;
487
488error:
489 dt_print(DT_DEBUG_OPENCL, "[opencl_exposure] couldn't enqueue kernel! %d\n", err);
490 return FALSE;
491}
492#endif
493
495int process(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const void *const i, void *const o)
496{
497 const dt_iop_roi_t *const roi_out = &piece->roi_out;
498 const dt_iop_exposure_data_t *const d = (const dt_iop_exposure_data_t *const)piece->data;
499
500 const int ch = piece->dsc_in.channels;
501
502 const float *const restrict in = (float*)i;
503 float *const restrict out = (float*)o;
504 const float black = d->black;
505 const float scale = d->scale;
506 const size_t npixels = (size_t)roi_out->width * roi_out->height;
507 const gboolean use_stream = (ch == 4);
508
509 if(ch == 4)
510 {
511 const dt_aligned_pixel_simd_t black_v = dt_simd_set1(black);
512 const dt_aligned_pixel_simd_t scale_v = dt_simd_set1(scale);
514 for(size_t k = 0; k < npixels; k++)
515 {
516 const size_t p = 4 * k;
517 const dt_aligned_pixel_simd_t in_v = dt_load_simd_aligned(in + p);
518 dt_store_simd_nontemporal(out + p, (in_v - black_v) * scale_v);
519 }
520 }
521 else
522 {
523 __OMP_PARALLEL_FOR_SIMD__(aligned(in, out : 64))
524 for(size_t k = 0; k < ch * npixels; k++)
525 {
526 out[k] = (in[k] - black) * scale;
527 }
528 }
529
530 if(use_stream) dt_omploop_sfence(); // ensure streamed RGB writes complete before alpha copy touches output
531
533 dt_iop_alpha_copy(i, o, roi_out->width, roi_out->height);
534
535 return 0;
536}
537
538static float _get_exposure_bias(const struct dt_iop_module_t *self)
539{
540 float bias = 0.0f;
541
542 // just check that pointers exist and are initialized
543 if(self->dev && self->dev->image_storage.exif_exposure_bias)
545
546 // sanity checks, don't trust exif tags too much
547 if(!isnan(bias))
548 return CLAMP(bias, -5.0f, 5.0f);
549 else
550 return 0.0f;
551}
552
553void autoset(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, const struct dt_dev_pixelpipe_iop_t *piece, const void *i)
554{
555 const dt_iop_roi_t *const roi_out = &piece->roi_out;
557 if(piece->dsc_in.channels != 4) return;
558
560 if(IS_NULL_PTR(input_profile)) return;
561
562 const float *const restrict in = (float*)i;
563 float average_luminance = 0.f;
564 const float norm = 1.f / (float)(roi_out->width * roi_out->height);
565
566 __OMP_PARALLEL_FOR__(reduction(+:average_luminance))
567 for(size_t k = 0; k < roi_out->width * roi_out->height * 4; k += 4)
568 {
569 // Convert each input RGB sample to XYZ to average scene luminance in a profile-aware way.
570 dt_aligned_pixel_t XYZ = { 0.f };
571 dt_ioppr_rgb_matrix_to_xyz(in + k, XYZ, input_profile->matrix_in_transposed, input_profile->lut_in,
572 input_profile->unbounded_coeffs_in, input_profile->lutsize,
573 input_profile->nonlinearlut);
574 average_luminance += XYZ[1] * norm;
575 }
576
577 // Solve the exposure module transfer so the average input luminance lands on middle grey at the output.
578 const float target_lightness = dt_conf_get_float("darkroom/modules/exposure/lightness");
579 const dt_aligned_pixel_t Lab = { target_lightness, 0.f, 0.f, 0.f };
580 dt_aligned_pixel_t XYZ = { 0.f };
582 const float target_luminance = XYZ[1];
583 const float white = p->black + fmaxf(average_luminance - p->black, 1e-6f) / target_luminance;
584 const float exposure = white2exposure(white);
585
586 p->exposure = exposure;
587
588 if(p->compensate_exposure_bias)
589 p->exposure += _get_exposure_bias(self);
590}
591
592
595{
598
599 d->params.black = p->black;
600 d->params.exposure = p->exposure;
601 d->params.deflicker_percentile = p->deflicker_percentile;
602 d->params.deflicker_target_level = p->deflicker_target_level;
603
604 // If exposure bias compensation has been required, add it on top of user exposure correction
605 if(p->compensate_exposure_bias)
606 d->params.exposure -= _get_exposure_bias(self);
607
608 d->deflicker = 0;
609
610 if(p->mode == EXPOSURE_MODE_DEFLICKER
612 && self->dev->image_storage.dsc.channels == 1
614 {
615 d->deflicker = 1;
616 }
617 dt_iop_fmt_log(self, "commit: class=%s needs_rawprepare=%d channels=%i datatype=%i mode=%d -> deflicker=%d",
621 p->mode, d->deflicker);
622
623 _process_common_setup(self, pipe, piece);
624 for(int k = 0; k < 3; k++) piece->dsc_out.processed_maximum[k] = piece->dsc_in.processed_maximum[k] * d->scale;
625}
626
628{
630 piece->data_size = sizeof(dt_iop_exposure_data_t);
631}
632
634{
635 dt_free_align(piece->data);
636 piece->data = NULL;
637}
638
640{
642}
643
644void gui_update(struct dt_iop_module_t *self)
645{
648
650 || self->dev->image_storage.dsc.channels != 1
652 {
653 gtk_widget_set_sensitive(GTK_WIDGET(g->mode), FALSE);
654 }
655 else
656 {
657 gtk_widget_set_sensitive(GTK_WIDGET(g->mode), TRUE);
658 }
659
661
662 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(g->compensate_exposure_bias), p->compensate_exposure_bias);
663 /* xgettext:no-c-format */
664 gchar *label = g_strdup_printf(_("compensate camera exposure (%+.1f EV)"), _get_exposure_bias(self));
665 gtk_button_set_label(GTK_BUTTON(g->compensate_exposure_bias), label);
666 gtk_label_set_ellipsize(GTK_LABEL(gtk_bin_get_child(GTK_BIN(g->compensate_exposure_bias))), PANGO_ELLIPSIZE_MIDDLE);
667 dt_free(label);
668
669 g->spot_RGB[0] = 0.f;
670 g->spot_RGB[1] = 0.f;
671 g->spot_RGB[2] = 0.f;
672 g->spot_RGB[3] = 0.f;
673
674 // get the saved params
676
677 const float lightness = dt_conf_get_float("darkroom/modules/exposure/lightness");
678 dt_bauhaus_slider_set(g->lightness_spot, lightness);
679
681
682 dt_free(g->deflicker_histogram);
683
684 gtk_label_set_text(g->deflicker_used_EC, "");
686 g->deflicker_computed_exposure = NAN;
688
689 switch(p->mode)
690 {
692 _autoexp_disable(self);
693 gtk_stack_set_visible_child_name(GTK_STACK(g->mode_stack), "deflicker");
694 _deflicker_prepare_histogram(self, &g->deflicker_histogram, &g->deflicker_histogram_stats);
695 break;
697 default:
698 gtk_stack_set_visible_child_name(GTK_STACK(g->mode_stack), "manual");
699 break;
700 }
701
703}
704
706{
707 const int program = 2; // from programs.conf: basic.cl
710 module->data = gd;
711 gd->kernel_exposure = dt_opencl_create_kernel(program, "exposure");
712}
713
720
721static void _exposure_set_white(struct dt_iop_module_t *self, const float white)
722{
724
725 const float exposure = white2exposure(white);
726 if(p->exposure == exposure) return;
727
728 p->exposure = exposure;
729 if(p->black >= white) _exposure_set_black(self, white - 0.01);
730
732
734 dt_bauhaus_slider_set(g->exposure, p->exposure);
737}
738
739static void _exposure_set_black(struct dt_iop_module_t *self, const float black)
740{
742
743 if(p->black == black) return;
744
745 p->black = black;
746 if(p->black >= exposure2white(p->exposure))
747 {
748 _exposure_set_white(self, p->black + 0.01);
749 }
750
753 dt_bauhaus_slider_set(g->black, p->black);
756}
757
759{
762
763 // capture gui color picked event.
764 if(self->picked_color_max[0] < self->picked_color_min[0])
765 {
766 dt_print(DT_DEBUG_DEV, "[picker/exposure] rejected invalid min/max min=%g max=%g\n",
767 self->picked_color_min[0], self->picked_color_max[0]);
768 return;
769 }
770 const float *RGB = self->picked_color;
771 dt_print(DT_DEBUG_DEV, "[picker/exposure] RGB=(%g,%g,%g) pipe=%p\n",
772 RGB[0], RGB[1], RGB[2], (void *)pipe);
773
774 // Get input profile, assuming we are before colorin
776 if(IS_NULL_PTR(input_profile))
777 {
778 dt_print(DT_DEBUG_DEV, "[picker/exposure] missing input profile\n");
779 return;
780 }
781
782 // Convert to XYZ
785 dot_product(RGB, input_profile->matrix_in, XYZ);
787 Lab[1] = Lab[2] = 0.f; // make color grey to get only the equivalent lighness
789 dt_XYZ_to_sRGB(XYZ, g->spot_RGB);
790
791 // Convert to Lch for GUI feedback (input)
793 dt_Lab_2_LCH(Lab, Lch);
794
795 // Write report in GUI
797 gtk_label_set_text(GTK_LABEL(g->Lch_origin),
798 g_strdup_printf(_("L : \t%.1f %%"), Lch[0]));
799 gtk_widget_queue_draw(g->origin_spot);
801
802 const dt_spot_mode_t mode = dt_bauhaus_combobox_get(g->spot_mode);
803
804 if(mode == DT_SPOT_MODE_MEASURE)
805 {
806 // get the exposure setting
807 float expo = p->exposure;
808
809 // If the exposure bias compensation is on, we need to add it to the user param
810 if(p->compensate_exposure_bias)
811 expo -= _get_exposure_bias(self);
812
813 const float white = exposure2white(-expo);
814
815 // apply the exposure compensation
816 dt_aligned_pixel_t XYZ_out;
817 for(int c = 0; c < 3; c++)
818 XYZ_out[c] = XYZ[c] * white;
819
820 // Convert to Lab for GUI feedback
821 dt_aligned_pixel_t Lab_out;
822 dt_XYZ_to_Lab(XYZ_out, Lab_out);
823 Lab_out[1] = Lab_out[2] = 0.f; // make it grey
824
825 // Return the values in sliders
827 dt_bauhaus_slider_set(g->lightness_spot, Lab_out[0]);
828 _paint_hue(self);
830
831 dt_conf_set_float("darkroom/modules/exposure/lightness", Lab_out[0]);
832 }
833 else if(mode == DT_SPOT_MODE_CORRECT)
834 {
835 // Get the target color in XYZ space
836 dt_aligned_pixel_t Lch_target = { 0.f };
838 Lch_target[0] = dt_bauhaus_slider_get(g->lightness_spot);
840
841 dt_aligned_pixel_t Lab_target = { 0.f };
842 dt_LCH_2_Lab(Lch_target, Lab_target);
843
844 dt_aligned_pixel_t XYZ_target = { 0.f };
845 dt_Lab_to_XYZ(Lab_target, XYZ_target);
846
847 // Get the ratio
848 float white = XYZ[1] / XYZ_target[1];
849 float expo = -white2exposure(white);
850
851 // If the exposure bias compensation is on, we need to subtract it from the user param
852 if(p->compensate_exposure_bias)
853 expo -= _get_exposure_bias(self);
854
855 white = exposure2white(-expo);
856 _exposure_set_white(self, white);
857 }
858}
859
860
862{
863 (void)picker;
864 (void)piece;
865 if(darktable.gui->reset) return;
866 dt_print(DT_DEBUG_DEV, "[picker/exposure] apply picker=%p pipe=%p\n", (void *)picker, (void *)pipe);
867 _auto_set_exposure(self, pipe);
868}
869
870
871void gui_changed(dt_iop_module_t *self, GtkWidget *w, void *previous)
872{
875
876 if(w == g->mode)
877 {
878 dt_free(g->deflicker_histogram);
879
880 switch(p->mode)
881 {
883 _autoexp_disable(self);
885 || self->dev->image_storage.dsc.channels != 1
887 {
888 p->mode = EXPOSURE_MODE_MANUAL;
889 dt_bauhaus_combobox_set(g->mode, p->mode);
890 gtk_widget_set_sensitive(GTK_WIDGET(g->mode), FALSE);
891 break;
892 }
893 gtk_stack_set_visible_child_name(GTK_STACK(g->mode_stack), "deflicker");
894 _deflicker_prepare_histogram(self, &g->deflicker_histogram, &g->deflicker_histogram_stats);
895 break;
897 default:
898 gtk_stack_set_visible_child_name(GTK_STACK(g->mode_stack), "manual");
899 break;
900 }
901 }
902 else if(w == g->exposure)
903 {
904 const float white = exposure2white(p->exposure);
905 if(p->black >= white)
906 _exposure_set_black(self, white - 0.01);
907 }
908 else if(w == g->black)
909 {
910 const float white = exposure2white(p->exposure);
911 if(p->black >= white)
912 _exposure_set_white(self, p->black + 0.01);
913 }
914}
915
916
917static gboolean _draw(GtkWidget *widget, cairo_t *cr, dt_iop_module_t *self)
918{
919 if(darktable.gui->reset) return FALSE;
920
922
924 if(!isnan(g->deflicker_computed_exposure))
925 {
926 gchar *str = g_strdup_printf(_("%.2f EV"), g->deflicker_computed_exposure);
927
929 gtk_label_set_text(g->deflicker_used_EC, str);
931
932 dt_free(str);
933 }
935 return FALSE;
936}
937
938
939static gboolean _target_color_draw(GtkWidget *widget, cairo_t *crf, gpointer user_data)
940{
941 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
943
944 // Init
945 GtkAllocation allocation;
946 gtk_widget_get_allocation(widget, &allocation);
947 int width = allocation.width, height = allocation.height;
948 cairo_surface_t *cst = dt_cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
949 cairo_t *cr = cairo_create(cst);
950
951 // Margins
952 const float margin = 2. * DT_PIXEL_APPLY_DPI(1.5);
954 height -= 2 * margin;
955
956 // Paint target color
957 dt_aligned_pixel_t RGB = { 0 };
958 dt_aligned_pixel_t Lch = { 0 };
959 dt_aligned_pixel_t Lab = { 0 };
960 dt_aligned_pixel_t XYZ = { 0 };
961 Lch[0] = dt_bauhaus_slider_get(g->lightness_spot);
962 Lch[1] = 0.f;
963 Lch[2] = 0.f;
964 dt_LCH_2_Lab(Lch, Lab);
967
968 cairo_set_source_rgb(cr, RGB[0], RGB[1], RGB[2]);
969 cairo_rectangle(cr, INNER_PADDING, margin, width, height);
970 cairo_fill(cr);
971
972 // Clean
973 cairo_stroke(cr);
974 cairo_destroy(cr);
975 cairo_set_source_surface(crf, cst, 0, 0);
976 cairo_paint(crf);
977 cairo_surface_destroy(cst);
978 return TRUE;
979}
980
981
982static gboolean _origin_color_draw(GtkWidget *widget, cairo_t *crf, gpointer user_data)
983{
984 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
986
987 // Init
988 GtkAllocation allocation;
989 gtk_widget_get_allocation(widget, &allocation);
990 int width = allocation.width;
991 int height = allocation.height;
992 cairo_surface_t *cst = dt_cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
993 cairo_t *cr = cairo_create(cst);
994
995 // Margins
996 const float margin = 2. * DT_PIXEL_APPLY_DPI(1.5);
998 height -= 2 * margin;
999
1000 cairo_set_source_rgb(cr, g->spot_RGB[0], g->spot_RGB[1], g->spot_RGB[2]);
1001 cairo_rectangle(cr, INNER_PADDING, margin, width, height);
1002 cairo_fill(cr);
1003
1004 // Clean
1005 cairo_stroke(cr);
1006 cairo_destroy(cr);
1007 cairo_set_source_surface(crf, cst, 0, 0);
1008 cairo_paint(crf);
1009 cairo_surface_destroy(cst);
1010 return TRUE;
1011}
1012
1013static void _paint_hue(dt_iop_module_t *self)
1014{
1015 // update the fill background color of LCh sliders
1017
1018 const float lightness_min = dt_bauhaus_slider_get_hard_min(g->lightness_spot);
1019 const float lightness_max = dt_bauhaus_slider_get_hard_max(g->lightness_spot);
1020
1021 const float lightness_range = lightness_max - lightness_min;
1022
1023 for(int i = 0; i < DT_BAUHAUS_SLIDER_MAX_STOPS; i++)
1024 {
1025 const float stop = ((float)i / (float)(DT_BAUHAUS_SLIDER_MAX_STOPS - 1));
1026 const float x = lightness_min + stop * lightness_range;
1027 dt_aligned_pixel_t RGB = { 0 };
1028 const dt_aligned_pixel_t Lch = { x, 0.f, 0. };
1029 dt_aligned_pixel_t Lab = { 0 };
1030 dt_aligned_pixel_t XYZ = { 0 };
1031
1032 dt_LCH_2_Lab(Lch, Lab);
1035
1036 dt_bauhaus_slider_set_stop(g->lightness_spot, stop, RGB[0], RGB[1], RGB[2]);
1037 }
1038
1039 gtk_widget_queue_draw(g->lightness_spot);
1040 gtk_widget_queue_draw(g->target_spot);
1041}
1042
1043
1045{
1046 if(darktable.gui->reset) return;
1047
1049
1050 dt_aligned_pixel_t Lch_target = { 0.f };
1051
1052 Lch_target[0] = dt_bauhaus_slider_get(g->lightness_spot);
1053
1054 // Save the color on change
1055 dt_conf_set_float("darkroom/modules/exposure/lightness", Lch_target[0]);
1056
1057 ++darktable.gui->reset;
1058 _paint_hue(self);
1059 --darktable.gui->reset;
1060
1061 // Re-run auto compute only for the module that currently owns the active picker.
1062 const dt_spot_mode_t mode = dt_bauhaus_combobox_get(g->spot_mode);
1063 const gboolean picker_active = dt_iop_color_picker_is_active_module(self);
1064 if(mode == DT_SPOT_MODE_CORRECT && picker_active)
1065 _auto_set_exposure(self, self->dev->pipe);
1066 // else : just record new values and do nothing
1067}
1068
1069void gui_reset(struct dt_iop_module_t *self)
1070{
1072}
1073
1074void gui_init(struct dt_iop_module_t *self)
1075{
1077
1078 g->deflicker_histogram = NULL;
1079
1080 // Start building top level widget
1081 // Note: stupid dt_bauhaus_toggle/combobox/slider_from_params read self directly
1082 // and are hard-coded to pack_start widgets to self->widget.
1083 // So we need to store the main widget first, stupidly update the ref to self->widget,
1084 // as we add boxes and restore it last to the main widget.
1085 // The guy who thought of that should really burn his computer and do everyone a favour.
1086 GtkWidget *main_widget = self->widget = GTK_WIDGET(gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING));
1087
1088 g->mode = dt_bauhaus_combobox_from_params(self, N_("mode"));
1089
1090 g->mode_stack = GTK_STACK(gtk_stack_new());
1091 gtk_stack_set_homogeneous(GTK_STACK(g->mode_stack),FALSE);
1092 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(g->mode_stack), TRUE, TRUE, 0);
1093
1094 GtkWidget *vbox_manual = self->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING);
1095 gtk_stack_add_named(GTK_STACK(g->mode_stack), vbox_manual, "manual");
1096
1097 g->compensate_exposure_bias = dt_bauhaus_toggle_from_params(self, "compensate_exposure_bias");
1098 gtk_widget_set_tooltip_text(g->compensate_exposure_bias, _("automatically remove the camera exposure bias\n"
1099 "this is useful if you exposed the image to the right."));
1100
1101 g->exposure = dt_color_picker_new(self, DT_COLOR_PICKER_AREA,
1102 dt_bauhaus_slider_from_params(self, N_("exposure")));
1103 gtk_widget_set_tooltip_text(g->exposure, _("adjust the exposure correction"));
1104 dt_bauhaus_slider_set_digits(g->exposure, 3);
1105 dt_bauhaus_slider_set_format(g->exposure, _(" EV"));
1106 dt_bauhaus_slider_set_soft_range(g->exposure, -3.0, 4.0);
1107
1108 g->black = dt_bauhaus_slider_from_params(self, "black");
1109 gtk_widget_set_tooltip_text(g->black, _("adjust the black level to unclip negative RGB values.\n"
1110 "you should never use it to add more density in blacks!\n"
1111 "if poorly set, it will clip near-black colors out of gamut\n"
1112 "by pushing RGB values into negatives."));
1114 dt_bauhaus_slider_set_soft_range(g->black, -0.1, 0.1);
1115
1116 GtkWidget *vbox_deflicker = self->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING);
1117 gtk_stack_add_named(GTK_STACK(g->mode_stack), vbox_deflicker, "deflicker");
1118
1119 g->deflicker_percentile = dt_bauhaus_slider_from_params(self, "deflicker_percentile");
1120 dt_bauhaus_slider_set_format(g->deflicker_percentile, "%");
1121 gtk_widget_set_tooltip_text(g->deflicker_percentile,
1122 // xgettext:no-c-format
1123 _("where in the histogram to meter for deflicking. E.g. 50% is median"));
1124
1125 g->deflicker_target_level = dt_bauhaus_slider_from_params(self, "deflicker_target_level");
1126 dt_bauhaus_slider_set_format(g->deflicker_target_level, _(" EV"));
1127 gtk_widget_set_tooltip_text(g->deflicker_target_level,
1128 _("where to place the exposure level for processed pics, EV below overexposure."));
1129
1130 GtkBox *hbox1 = GTK_BOX(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, DT_GUI_BOX_SPACING));
1131 gtk_box_pack_start(GTK_BOX(hbox1), GTK_WIDGET(dt_ui_label_new(_("computed EC: "))), FALSE, FALSE, 0);
1132 g->deflicker_used_EC = GTK_LABEL(dt_ui_label_new("")); // This gets filled in by process
1133 gtk_widget_set_tooltip_text(GTK_WIDGET(g->deflicker_used_EC), _("what exposure correction has actually been used"));
1134 gtk_box_pack_start(GTK_BOX(hbox1), GTK_WIDGET(g->deflicker_used_EC), FALSE, FALSE, 0);
1135
1137 g->deflicker_computed_exposure = NAN;
1139
1140 self->widget = main_widget;
1141
1143 (&g->cs,
1144 "plugins/darkroom/exposure/mapping",
1145 _("spot exposure mapping"),
1146 GTK_BOX(self->widget), GTK_PACK_END);
1147
1148 DT_BAUHAUS_COMBOBOX_NEW_FULL(darktable.bauhaus, g->spot_mode, DT_GUI_MODULE(self), N_("spot mode"),
1149 _("\"correction\" automatically adjust exposure\n"
1150 "such that the input lightness is mapped to the target.\n"
1151 "\"measure\" simply shows how an input color is mapped by the exposure compensation\n"
1152 "and can be used to define a target."),
1153 0, NULL, self,
1154 N_("correction"),
1155 N_("measure"));
1156 gtk_box_pack_start(GTK_BOX(g->cs.container), GTK_WIDGET(g->spot_mode), TRUE, TRUE, 0);
1157 g_signal_connect(G_OBJECT(g->spot_mode), "value-changed", G_CALLBACK(_spot_settings_changed_callback), self);
1158
1159 GtkWidget *hhbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, DT_GUI_BOX_SPACING);
1160 GtkWidget *vvbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING);
1161
1162 gtk_box_pack_start(GTK_BOX(vvbox), dt_ui_section_label_new(_("input")), FALSE, FALSE, 0);
1163
1164 g->origin_spot = GTK_WIDGET(gtk_drawing_area_new());
1165 gtk_widget_set_size_request(g->origin_spot, 2 * DT_PIXEL_APPLY_DPI(darktable.bauhaus->quad_width),
1167 gtk_widget_set_tooltip_text(GTK_WIDGET(g->origin_spot),
1168 _("the input color that should be mapped to the target"));
1169
1170 g_signal_connect(G_OBJECT(g->origin_spot), "draw", G_CALLBACK(_origin_color_draw), self);
1171 gtk_box_pack_start(GTK_BOX(vvbox), g->origin_spot, TRUE, TRUE, 0);
1172
1173 g->Lch_origin = gtk_label_new(_("L : \tN/A"));
1174 gtk_widget_set_tooltip_text(GTK_WIDGET(g->Lch_origin),
1175 _("these LCh coordinates are computed from CIE Lab 1976 coordinates"));
1176 gtk_box_pack_start(GTK_BOX(vvbox), GTK_WIDGET(g->Lch_origin), FALSE, FALSE, 0);
1177
1178 gtk_box_pack_start(GTK_BOX(hhbox), GTK_WIDGET(vvbox), FALSE, FALSE, DT_BAUHAUS_SPACE);
1179
1180 vvbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING);
1181
1182 gtk_box_pack_start(GTK_BOX(vvbox), dt_ui_section_label_new(_("target")), FALSE, TRUE, 0);
1183
1184 g->target_spot = GTK_WIDGET(gtk_drawing_area_new());
1185 gtk_widget_set_size_request(g->target_spot, 2 * DT_PIXEL_APPLY_DPI(darktable.bauhaus->quad_width),
1187 gtk_widget_set_tooltip_text(GTK_WIDGET(g->target_spot),
1188 _("the desired target exposure after mapping"));
1189
1190 g_signal_connect(G_OBJECT(g->target_spot), "draw", G_CALLBACK(_target_color_draw), self);
1191 gtk_box_pack_start(GTK_BOX(vvbox), g->target_spot, TRUE, TRUE, 0);
1192
1193 g->lightness_spot = dt_bauhaus_slider_new_with_range(darktable.bauhaus, DT_GUI_MODULE(self), 0., 100., 0, 0, 1);
1194 dt_bauhaus_widget_set_label(g->lightness_spot, N_("lightness"));
1195 dt_bauhaus_slider_set_format(g->lightness_spot, "%");
1196 dt_bauhaus_slider_set_default(g->lightness_spot, 50.f);
1197 gtk_box_pack_start(GTK_BOX(vvbox), GTK_WIDGET(g->lightness_spot), TRUE, TRUE, 0);
1198 g_signal_connect(G_OBJECT(g->lightness_spot), "value-changed", G_CALLBACK(_spot_settings_changed_callback), self);
1199
1200 gtk_box_pack_start(GTK_BOX(hhbox), GTK_WIDGET(vvbox), TRUE, TRUE, DT_BAUHAUS_SPACE);
1201
1202 gtk_box_pack_start(GTK_BOX(g->cs.container), GTK_WIDGET(hhbox), FALSE, FALSE, 0);
1203
1204 g_signal_connect(G_OBJECT(self->widget), "draw", G_CALLBACK(_draw), self);
1205}
1206
1208{
1210
1211 dt_free(g->deflicker_histogram);
1212
1214}
1215
1216// clang-format off
1217// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
1218// vim: shiftwidth=2 expandtab tabstop=2 cindent
1219// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
1220// 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:1647
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_stop(GtkWidget *widget, float stop, float r, float g, float b)
Definition bauhaus.c:2372
float dt_bauhaus_slider_get(GtkWidget *widget)
Definition bauhaus.c:3483
int dt_bauhaus_combobox_get(GtkWidget *widget)
Definition bauhaus.c:2347
float dt_bauhaus_slider_get_hard_min(GtkWidget *widget)
Definition bauhaus.c:1576
void dt_bauhaus_slider_set(GtkWidget *widget, float pos)
Definition bauhaus.c:3506
void dt_bauhaus_combobox_set(GtkWidget *widget, const int pos)
Definition bauhaus.c:2301
void dt_bauhaus_widget_set_label(GtkWidget *widget, const char *label)
Definition bauhaus.c:1653
GtkWidget * dt_bauhaus_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:1780
void dt_bauhaus_slider_set_format(GtkWidget *widget, const char *format)
Definition bauhaus.c:3598
float dt_bauhaus_slider_get_hard_max(GtkWidget *widget)
Definition bauhaus.c:1601
#define DT_BAUHAUS_SPACE
Definition bauhaus.h:291
#define INTERNAL_PADDING
Definition bauhaus.h:76
#define DT_BAUHAUS_COMBOBOX_NEW_FULL(bauhaus, widget, action, label, tip, pos, callback, data,...)
Definition bauhaus.h:392
#define DT_BAUHAUS_SLIDER_MAX_STOPS
Definition bauhaus.h:71
#define INNER_PADDING
Definition bauhaus.h:79
int width
Definition bilateral.h:1
int height
Definition bilateral.h:1
@ DEVELOP_BLEND_CS_RGB_SCENE
Definition blend.h:60
@ DEVELOP_BLEND_CS_RGB_DISPLAY
Definition blend.h:59
dt_spot_mode_t
static const dt_aligned_pixel_simd_t const dt_adaptation_t const float p
return vector dt_simd_set1(valid ?(scaling+NORM_MIN) :NORM_MIN)
@ IOP_CS_RGB
void dt_iop_color_picker_reset(dt_iop_module_t *module, gboolean keep)
gboolean dt_iop_color_picker_is_active_module(const dt_iop_module_t *module)
Tell whether one module currently owns the active darkroom picker.
GtkWidget * dt_color_picker_new(dt_iop_module_t *module, dt_iop_color_picker_kind_t kind, GtkWidget *w)
@ DT_COLOR_PICKER_AREA
dt_Lab_to_XYZ(Lab, XYZ)
dt_XYZ_to_sRGB(XYZ, result)
static dt_aligned_pixel_t XYZ
static dt_aligned_pixel_t Lab
const dt_colormatrix_t dt_aligned_pixel_t out
dt_XYZ_to_Lab(XYZ, Lab)
static dt_aligned_pixel_t RGB
static dt_aligned_pixel_t Lch
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
void dt_histogram_worker(dt_dev_histogram_collection_params_t *const histogram_params, dt_dev_histogram_stats_t *histogram_stats, const void *const pixel, uint32_t **histogram, const dt_worker Worker, const dt_iop_order_iccprofile_info_t *const profile_info)
void dt_histogram_helper_cs_RAW_uint16(const dt_dev_histogram_collection_params_t *const histogram_params, const void *pixel, uint32_t *histogram, int j, const dt_iop_order_iccprofile_info_t *const profile_info)
dt_image_pipe_class_t dt_image_pipe_class(const dt_image_t *img)
const char * dt_image_pipe_class_name(const dt_image_pipe_class_t klass)
gboolean dt_image_needs_rawprepare(const dt_image_t *img)
void dt_conf_set_float(const char *name, float val)
float dt_conf_get_float(const char *name)
void dt_control_log(const char *msg,...)
Definition control.c:761
darktable_t darktable
Definition darktable.c:181
void dt_print(dt_debug_thread_t thread, const char *msg,...)
Definition darktable.c:1542
#define dt_free_align(ptr)
Definition darktable.h:481
static void * dt_calloc_align(size_t size)
Definition darktable.h:488
@ DT_DEBUG_OPENCL
Definition darktable.h:722
@ DT_DEBUG_DEV
Definition darktable.h:717
#define dt_free(ptr)
Definition darktable.h:456
#define DT_MODULE_INTROSPECTION(MODVER, PARAMSTYPE)
Definition darktable.h:151
#define __DT_CLONE_TARGETS__
Definition darktable.h:367
#define __OMP_PARALLEL_FOR__(...)
Definition darktable.h:258
#define __OMP_PARALLEL_FOR_SIMD__(...)
Definition darktable.h:259
#define 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
gboolean dt_dev_pixelpipe_has_preview_output(const dt_develop_t *dev, const dt_dev_pixelpipe_t *pipe, const dt_iop_roi_t *roi)
Definition develop.c:367
@ DT_DEV_PIXELPIPE_DISPLAY_MASK
Definition develop.h:118
static float _get_exposure_bias(const struct dt_iop_module_t *self)
Definition exposure.c:538
void commit_params(struct dt_iop_module_t *self, dt_iop_params_t *p1, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition exposure.c:593
static gboolean _draw(GtkWidget *widget, cairo_t *cr, dt_iop_module_t *self)
Definition exposure.c:917
const char ** description(struct dt_iop_module_t *self)
Definition exposure.c:162
int default_group()
Definition exposure.c:173
static void _spot_settings_changed_callback(GtkWidget *slider, dt_iop_module_t *self)
Definition exposure.c:1044
static gboolean _origin_color_draw(GtkWidget *widget, cairo_t *crf, gpointer user_data)
Definition exposure.c:982
#define DEFLICKER_BINS_COUNT
Definition exposure.c:106
static double _raw_to_ev(uint32_t raw, uint32_t black_level, uint32_t white_level)
Definition exposure.c:374
#define exposure2white(x)
Definition exposure.c:86
dt_spot_mode_t
Definition exposure.c:98
@ DT_SPOT_MODE_MEASURE
Definition exposure.c:100
@ DT_SPOT_MODE_CORRECT
Definition exposure.c:99
@ DT_SPOT_MODE_LAST
Definition exposure.c:101
static void _auto_set_exposure(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe)
Definition exposure.c:758
void init_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition exposure.c:627
const char * name()
Definition exposure.c:157
static void _exposure_set_black(struct dt_iop_module_t *self, const float black)
Definition exposure.c:739
void output_format(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece, dt_iop_buffer_dsc_t *dsc)
Definition exposure.c:191
void gui_reset(struct dt_iop_module_t *self)
Definition exposure.c:1069
void gui_update(struct dt_iop_module_t *self)
Refresh GUI controls from current params and configuration.
Definition exposure.c:644
static void _exposure_set_white(struct dt_iop_module_t *self, const float white)
Definition exposure.c:721
void gui_init(struct dt_iop_module_t *self)
Definition exposure.c:1074
void gui_changed(dt_iop_module_t *self, GtkWidget *w, void *previous)
Definition exposure.c:871
static void _autoexp_disable(dt_iop_module_t *self)
Definition exposure.c:639
#define white2exposure(x)
Definition exposure.c:87
void cleanup_global(dt_iop_module_so_t *module)
Definition exposure.c:714
static void _compute_correction(dt_iop_module_t *self, dt_iop_params_t *p1, const dt_dev_pixelpipe_iop_t *piece, const uint32_t *const histogram, const dt_dev_histogram_stats_t *const histogram_stats, float *correction)
Definition exposure.c:387
int default_colorspace(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
Definition exposure.c:183
int flags()
Definition exposure.c:178
static void _process_common_setup(dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
Definition exposure.c:425
void gui_cleanup(struct dt_iop_module_t *self)
Definition exposure.c:1207
void init_presets(dt_iop_module_so_t *self)
Definition exposure.c:303
static void _deflicker_prepare_histogram(dt_iop_module_t *self, uint32_t **histogram, dt_dev_histogram_stats_t *histogram_stats)
Definition exposure.c:332
__DT_CLONE_TARGETS__ int process(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const void *const i, void *const o)
Definition exposure.c:495
static void _paint_hue(dt_iop_module_t *self)
Definition exposure.c:1013
void cleanup_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition exposure.c:633
void init_global(dt_iop_module_so_t *module)
Definition exposure.c:705
dt_iop_exposure_mode_t
Definition exposure.c:92
@ EXPOSURE_MODE_MANUAL
Definition exposure.c:93
@ EXPOSURE_MODE_DEFLICKER
Definition exposure.c:94
void autoset(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, const struct dt_dev_pixelpipe_iop_t *piece, const void *i)
Definition exposure.c:553
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 exposure.c:465
static gboolean _target_color_draw(GtkWidget *widget, cairo_t *crf, gpointer user_data)
Definition exposure.c:939
void color_picker_apply(dt_iop_module_t *self, GtkWidget *picker, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition exposure.c:861
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 exposure.c:200
void default_output_format(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece, dt_iop_buffer_dsc_t *dsc)
Definition format.c:75
@ TYPE_UINT16
Definition format.h:47
void dt_gui_new_collapsible_section(dt_gui_collapsible_section_t *cs, const char *confname, const char *label, GtkBox *parent, GtkPackType pack)
Create a collapsible section and pack it into the parent box.
Definition gtk.c:3102
void dt_gui_update_collapsible_section(dt_gui_collapsible_section_t *cs)
Definition gtk.c:3080
static cairo_surface_t * dt_cairo_image_surface_create(cairo_format_t format, int width, int height)
Definition gtk.h:316
static GtkWidget * dt_ui_section_label_new(const gchar *str)
Definition gtk.h:451
#define DT_GUI_BOX_SPACING
Definition gtk.h:109
#define DT_PIXEL_APPLY_DPI(value)
Definition gtk.h:90
static GtkWidget * dt_ui_label_new(const gchar *str)
Definition gtk.h:461
void dt_gui_presets_update_ldr(const char *name, dt_dev_operation_t op, const int32_t version, const int ldrflag)
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)
@ FOR_RAW
Definition gui/presets.h:41
#define DT_GUI_MODULE(x)
void dt_image_cache_read_release(dt_image_cache_t *cache, const dt_image_t *img)
dt_image_t * dt_image_cache_get(dt_image_cache_t *cache, const int32_t imgid, char mode)
const char ** dt_iop_set_description(dt_iop_module_t *module, const char *main_text, const char *purpose, const char *input, const char *process, const char *output)
Definition imageop.c:3141
#define dt_omploop_sfence()
Definition imageop.h:702
#define IOP_GUI_FREE
Definition imageop.h:602
static void dt_iop_gui_enter_critical_section(dt_iop_module_t *const module) ACQUIRE(&module -> gui_lock)
Definition imageop.h:413
#define dt_iop_fmt_log(module, fmt,...)
Debug helper to trace a module's input-format-driven decisions on the -d pipe channel (DT_DEBUG_PIPE)...
Definition imageop.h:453
@ IOP_FLAGS_SUPPORTS_BLENDING
Definition imageop.h:167
@ IOP_FLAGS_ALLOW_TILING
Definition imageop.h:169
static void dt_iop_gui_leave_critical_section(dt_iop_module_t *const module) RELEASE(&module -> gui_lock)
Definition imageop.h:419
@ IOP_GROUP_TONES
Definition imageop.h:137
#define IOP_GUI_ALLOC(module)
Definition imageop.h:599
GtkWidget * dt_bauhaus_toggle_from_params(dt_iop_module_t *self, const char *param)
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)
dt_iop_order_iccprofile_info_t * dt_ioppr_get_pipe_input_profile_info(const struct dt_dev_pixelpipe_t *pipe)
static const float x
float *const restrict const size_t k
float *const restrict const size_t const size_t ch
#define dt_mipmap_cache_get(A, B, C, D, E, F)
@ DT_MIPMAP_BLOCKING
#define dt_mipmap_cache_release(A, B)
@ DT_MIPMAP_FULL
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
struct _GtkWidget GtkWidget
Definition splash.h:29
struct dt_gui_gtk_t * gui
Definition darktable.h:775
struct dt_mipmap_cache_t * mipmap_cache
Definition darktable.h:776
struct dt_bauhaus_t * bauhaus
Definition darktable.h:778
struct dt_image_cache_t * image_cache
Definition darktable.h:777
struct dt_develop_t * develop
Definition darktable.h:770
float quad_width
Definition bauhaus.h:273
const struct dt_histogram_roi_t * roi
Definition pixelpipe.h:56
dt_iop_buffer_dsc_t dsc_out
dt_iop_buffer_dsc_t dsc_in
struct dt_iop_module_t *void * data
dt_image_t image_storage
Definition develop.h:259
struct dt_dev_pixelpipe_t * pipe
Definition develop.h:247
int32_t reset
Definition gtk.h:172
int32_t height
Definition image.h:315
float exif_exposure_bias
Definition image.h:286
int32_t crop_height
Definition image.h:316
int32_t width
Definition image.h:315
int32_t crop_y
Definition image.h:316
int32_t crop_x
Definition image.h:316
dt_iop_buffer_dsc_t dsc
Definition image.h:337
int32_t crop_width
Definition image.h:316
char filename[DT_MAX_FILENAME_LEN]
Definition image.h:304
int32_t id
Definition image.h:319
struct dt_iop_buffer_dsc_t::@29 rawprepare
uint16_t raw_black_level
Definition format.h:74
unsigned int channels
Definition format.h:54
dt_iop_buffer_type_t datatype
Definition format.h:56
dt_aligned_pixel_t processed_maximum
Definition format.h:85
uint16_t raw_white_point
Definition format.h:75
dt_iop_exposure_params_t params
Definition exposure.c:145
GtkWidget * compensate_exposure_bias
Definition exposure.c:129
GtkWidget * deflicker_percentile
Definition exposure.c:124
dt_gui_collapsible_section_t cs
Definition exposure.c:137
dt_dev_histogram_stats_t deflicker_histogram_stats
Definition exposure.c:127
uint32_t * deflicker_histogram
Definition exposure.c:126
dt_aligned_pixel_t spot_RGB
Definition exposure.c:139
GtkWidget * deflicker_target_level
Definition exposure.c:125
dt_iop_exposure_mode_t mode
Definition exposure.c:110
gboolean compensate_exposure_bias
Definition exposure.c:115
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
struct dt_develop_t * dev
Definition imageop.h:296
dt_iop_gui_data_t * gui_data
Definition imageop.h:311
dt_iop_global_data_t * global_data
Definition imageop.h:314
dt_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_colormatrix_t matrix_in_transposed
Definition iop_profile.h:65
Region of interest passed through the pixelpipe.
Definition imageop.h:72
#define MAX(a, b)
Definition thinplate.c:29