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#include "develop/iop_profile.h"
59#include "common/conf.h"
60#endif
61
62#include <assert.h>
63#include <math.h>
64#include <stdint.h>
65#include <stdlib.h>
66#include <string.h>
67
68#include "widgets/bauhaus.h"
69#include "system/macros.h"
70#include "system/openmp.h"
72#include "system/mem_alloc.h"
73#include "system/simd.h"
74#include "common/logging.h"
76#include "common/histogram.h"
77#include "caches/image_cache.h"
78#include "caches/mipmap_cache.h"
79#include "common/opencl.h"
81#include "develop/develop.h"
82#include "develop/imageop.h"
85#include "develop/imageop_gui.h"
86#include "develop/pixelpipe.h"
87
88#include "gui/presets.h"
90#include "iop/iop_api.h"
91#include "widgets/label.h"
92#include "gui/screen_metrics.h"
93
94#define exposure2white(x) exp2f(-(x))
95#define white2exposure(x) -dt_log2f(fmaxf(1e-20f, x))
96
98
100{
101 EXPOSURE_MODE_MANUAL, // $DESCRIPTION: "manual"
102 EXPOSURE_MODE_DEFLICKER // $DESCRIPTION: "automatic"
104
111
112// uint16_t pixel can have any value in range [0, 65535], thus, there is
113// 65536 possible values.
114#define DEFLICKER_BINS_COUNT (UINT16_MAX + 1)
115
116typedef struct dt_iop_exposure_params_t
117{
118 dt_iop_exposure_mode_t mode; // $DEFAULT: EXPOSURE_MODE_MANUAL
119 float black; // $MIN: -1.0 $MAX: 1.0 $DEFAULT: 0.0 $DESCRIPTION: "black level correction"
120 float exposure; // $MIN: -18.0 $MAX: 18.0 $DEFAULT: 0.0
121 float deflicker_percentile; // $MIN: 0.0 $MAX: 100.0 $DEFAULT: 50.0 $DESCRIPTION: "percentile"
122 float deflicker_target_level; // $MIN: -18.0 $MAX: 18.0 $DEFAULT: -4.0 $DESCRIPTION: "target level"
123 gboolean compensate_exposure_bias; // $DEFAULT: FALSE $DESCRIPTION: "compensate exposure bias"
125
150
158
163
164
165const char *name()
166{
167 return _("exp_osure");
168}
169
170const char** description(struct dt_iop_module_t *self)
171{
172 return dt_iop_set_description(self,
173 _("redo the exposure of the shot as if you were still in-camera\n"
174 "using a color-safe brightening similar to increasing ISO setting"),
175 _("corrective and creative"),
176 _("linear, RGB, scene-referred"),
177 _("linear, RGB"),
178 _("linear, RGB, scene-referred"));
179}
180
182{
183 return IOP_GROUP_TONES;
184}
185
190
192{
193 return IOP_CS_RGB;
194}
195
196static void _process_common_setup(dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe,
197 const dt_dev_pixelpipe_iop_t *piece);
198
201{
202 default_output_format(self, pipe, piece, dsc);
203}
204
205static void _paint_hue(dt_iop_module_t *self);
206static void _exposure_set_black(struct dt_iop_module_t *self, const float black);
207
208int legacy_params(dt_iop_module_t *self, const void *const old_params, const int old_version,
209 void *new_params, const int new_version)
210{
211 if(old_version == 2 && new_version == 6)
212 {
213 typedef struct dt_iop_exposure_params_v2_t
214 {
215 float black, exposure, gain;
216 } dt_iop_exposure_params_v2_t;
217
218 dt_iop_exposure_params_v2_t *o = (dt_iop_exposure_params_v2_t *)old_params;
221
222 *n = *d; // start with a fresh copy of default parameters
223
224 n->black = o->black;
225 n->exposure = o->exposure;
226 n->compensate_exposure_bias = FALSE;
227 return 0;
228 }
229 if(old_version == 3 && new_version == 6)
230 {
231 typedef struct dt_iop_exposure_params_v3_t
232 {
233 float black, exposure;
234 gboolean deflicker;
235 float deflicker_percentile, deflicker_target_level;
236 } dt_iop_exposure_params_v3_t;
237
238 dt_iop_exposure_params_v3_t *o = (dt_iop_exposure_params_v3_t *)old_params;
241
242 *n = *d; // start with a fresh copy of default parameters
243
244 n->mode = o->deflicker ? EXPOSURE_MODE_DEFLICKER : EXPOSURE_MODE_MANUAL;
245 n->black = o->black;
246 n->exposure = o->exposure;
247 n->deflicker_percentile = o->deflicker_percentile;
248 n->deflicker_target_level = o->deflicker_target_level;
249 n->compensate_exposure_bias = FALSE;
250 return 0;
251 }
252 if(old_version == 4 && new_version == 6)
253 {
254 typedef enum dt_iop_exposure_deflicker_histogram_source_t {
255 DEFLICKER_HISTOGRAM_SOURCE_THUMBNAIL,
256 DEFLICKER_HISTOGRAM_SOURCE_SOURCEFILE
257 } dt_iop_exposure_deflicker_histogram_source_t;
258
259 typedef struct dt_iop_exposure_params_v4_t
260 {
262 float black;
263 float exposure;
264 float deflicker_percentile, deflicker_target_level;
265 dt_iop_exposure_deflicker_histogram_source_t deflicker_histogram_source;
266 } dt_iop_exposure_params_v4_t;
267
268 dt_iop_exposure_params_v4_t *o = (dt_iop_exposure_params_v4_t *)old_params;
271
272 *n = *d; // start with a fresh copy of default parameters
273
274 n->mode = o->mode;
275 n->black = o->black;
276 n->exposure = o->exposure;
277 n->deflicker_percentile = o->deflicker_percentile;
278 n->deflicker_target_level = o->deflicker_target_level;
279 // deflicker_histogram_source is dropped. this does change output,
280 // but deflicker still was not publicly released at that point
281 n->compensate_exposure_bias = FALSE;
282 return 0;
283 }
284 if(old_version == 5 && new_version == 6)
285 {
286 typedef struct dt_iop_exposure_params_v5_t
287 {
289 float black;
290 float exposure;
291 float deflicker_percentile, deflicker_target_level;
292 } dt_iop_exposure_params_v5_t;
293
294 dt_iop_exposure_params_v5_t *o = (dt_iop_exposure_params_v5_t *)old_params;
297
298 *n = *d; // start with a fresh copy of default parameters
299
300 n->mode = o->mode;
301 n->black = o->black;
302 n->exposure = o->exposure;
303 n->deflicker_percentile = o->deflicker_percentile;
304 n->deflicker_target_level = o->deflicker_target_level;
305 n->compensate_exposure_bias = FALSE;
306 return 0;
307 }
308 return 1;
309}
310
312{
313 dt_gui_presets_add_generic(_("magic lantern defaults"), self->op,
314 self->version(),
315 &(dt_iop_exposure_params_t){.mode = EXPOSURE_MODE_DEFLICKER,
316 .black = 0.0f,
317 .exposure = 0.0f,
318 .deflicker_percentile = 50.0f,
319 .deflicker_target_level = -4.0f,
320 .compensate_exposure_bias = FALSE},
321 sizeof(dt_iop_exposure_params_t), 1);
322
323
324 // For scene-referred workflow, since filmic doesn't brighten as base curve does,
325 // we need an initial exposure boost. This might be too much in some cases but...
326 // (the preset name is used in develop.c)
327 dt_gui_presets_add_generic(_("scene-referred default"), self->op, self->version(),
328 &(dt_iop_exposure_params_t){.mode = EXPOSURE_MODE_MANUAL,
329 .black = -0.000244140625f,
330 .exposure = 0.7f,
331 .deflicker_percentile = 50.0f,
332 .deflicker_target_level = -4.0f,
333 .compensate_exposure_bias = TRUE},
334 sizeof(dt_iop_exposure_params_t), 1);
335
336 dt_gui_presets_update_ldr(_("scene-referred default"), self->op,
337 self->version(), FOR_RAW);
338}
339
340static void _deflicker_prepare_histogram(dt_iop_module_t *self, uint32_t **histogram,
341 dt_dev_histogram_stats_t *histogram_stats)
342{
343 const dt_image_t *img = dt_image_cache_get(self->dev->image_storage.id, 'r');
344 dt_image_t image = *img;
346
347 if(image.dsc.channels != 1 || image.dsc.datatype != TYPE_UINT16) return;
348
351 DT_MIPMAP_BLOCKING, 'r');
352 if(IS_NULL_PTR(buf.buf))
353 {
354 dt_control_log(_("failed to get raw buffer from image `%s'"), image.filename);
356 return;
357 }
358
359 dt_dev_histogram_collection_params_t histogram_params = { 0 };
360
361 dt_histogram_roi_t histogram_roi = {.width = image.width,
362 .height = image.height,
363
364 // FIXME: get those from rawprepare IOP somehow !!!
365 .crop_x = image.crop_x,
366 .crop_y = image.crop_y,
367 .crop_width = image.crop_width,
368 .crop_height = image.crop_height };
369
370 histogram_params.roi = &histogram_roi;
371 histogram_params.bins_count = DEFLICKER_BINS_COUNT;
372
373 dt_histogram_worker(&histogram_params, histogram_stats, buf.buf, histogram,
375 histogram_stats->ch = 1u;
376
378}
379
380/* input: 0 - 65535 (valid range: from black level to white level) */
381/* output: -16 ... 0 */
382static double _raw_to_ev(uint32_t raw, uint32_t black_level, uint32_t white_level)
383{
384 const uint32_t raw_max = white_level - black_level;
385
386 // we are working on data without black clipping,
387 // so we can get values which are lower than the black level !!!
388 const int64_t raw_val = MAX((int64_t)raw - (int64_t)black_level, 1);
389
390 const double raw_ev = -log2(raw_max) + log2(raw_val);
391
392 return raw_ev;
393}
394
396 const dt_dev_pixelpipe_iop_t *piece,
397 const uint32_t *const histogram,
398 const dt_dev_histogram_stats_t *const histogram_stats, float *correction)
399{
400 const dt_iop_exposure_params_t *const p = (const dt_iop_exposure_params_t *const)p1;
401
402 *correction = NAN;
403
404 if(IS_NULL_PTR(histogram)) return;
405
406 const size_t total = (size_t)histogram_stats->ch * histogram_stats->pixels;
407
408 const double thr
409 = CLAMP(((double)total * (double)p->deflicker_percentile / (double)100.0), 0.0, (double)total);
410
411 size_t n = 0;
412 uint32_t raw = 0;
413
414 for(uint32_t i = 0; i < histogram_stats->bins_count; i++)
415 {
416 for(uint32_t k = 0; k < histogram_stats->ch; k++)
417 n += histogram[4 * i + k];
418
419 if((double)n >= thr)
420 {
421 raw = i;
422 break;
423 }
424 }
425
426 const double ev
427 = _raw_to_ev(raw, (uint32_t)piece->dsc_in.rawprepare.raw_black_level,
429
430 *correction = p->deflicker_target_level - ev;
431}
432
434 const dt_dev_pixelpipe_iop_t *piece)
435{
437 dt_iop_exposure_data_t *d = piece->data;
438
439 d->black = d->params.black;
440 float exposure = d->params.exposure;
441
442 if(d->deflicker)
443 {
444 if(!IS_NULL_PTR(g))
445 {
446 // histogram is precomputed and cached
447 _compute_correction(self, &d->params, piece, g->deflicker_histogram, &g->deflicker_histogram_stats,
448 &exposure);
449 }
450 else
451 {
452 uint32_t *histogram = NULL;
453 dt_dev_histogram_stats_t histogram_stats;
454 _deflicker_prepare_histogram(self, &histogram, &histogram_stats);
455 _compute_correction(self, &d->params, piece, histogram, &histogram_stats, &exposure);
456 dt_free(histogram);
457 }
458
459 // second, show computed correction in UI.
460 if(!IS_NULL_PTR(g) && dt_dev_pixelpipe_has_preview_output(self->dev, pipe, NULL))
461 {
463 g->deflicker_computed_exposure = exposure;
465 }
466 }
467
468 const float white = exposure2white(exposure);
469 d->scale = 1.0 / (white - d->black);
470}
471
472#ifdef HAVE_OPENCL
473int 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)
474{
475 const dt_iop_roi_t *const roi_in = &piece->roi_in;
478
479 cl_int err = -999;
480 const int devid = pipe->devid;
481 const int width = roi_in->width;
482 const int height = roi_in->height;
483
484 size_t sizes[] = { ROUNDUPDWD(width, devid), ROUNDUPDHT(height, devid), 1 };
485 dt_opencl_set_kernel_arg(devid, gd->kernel_exposure, 0, sizeof(cl_mem), (void *)&dev_in);
486 dt_opencl_set_kernel_arg(devid, gd->kernel_exposure, 1, sizeof(cl_mem), (void *)&dev_out);
487 dt_opencl_set_kernel_arg(devid, gd->kernel_exposure, 2, sizeof(int), (void *)&width);
488 dt_opencl_set_kernel_arg(devid, gd->kernel_exposure, 3, sizeof(int), (void *)&height);
489 dt_opencl_set_kernel_arg(devid, gd->kernel_exposure, 4, sizeof(float), (void *)&(d->black));
490 dt_opencl_set_kernel_arg(devid, gd->kernel_exposure, 5, sizeof(float), (void *)&(d->scale));
491 err = dt_opencl_enqueue_kernel_2d(devid, gd->kernel_exposure, sizes);
492 if(err != CL_SUCCESS) goto error;
493
494 return TRUE;
495
496error:
497 dt_print(DT_DEBUG_OPENCL, "[opencl_exposure] couldn't enqueue kernel! %d\n", err);
498 return FALSE;
499}
500#endif
501
503int 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)
504{
505 const dt_iop_roi_t *const roi_out = &piece->roi_out;
506 const dt_iop_exposure_data_t *const d = (const dt_iop_exposure_data_t *const)piece->data;
507
508 const int ch = piece->dsc_in.channels;
509
510 const float *const restrict in = (float*)i;
511 float *const restrict out = (float*)o;
512 const float black = d->black;
513 const float scale = d->scale;
514 const size_t npixels = (size_t)roi_out->width * roi_out->height;
515 const gboolean use_stream = (ch == 4);
516
517 if(ch == 4)
518 {
519 const dt_aligned_pixel_simd_t black_v = dt_simd_set1(black);
520 const dt_aligned_pixel_simd_t scale_v = dt_simd_set1(scale);
522 for(size_t k = 0; k < npixels; k++)
523 {
524 const size_t p = 4 * k;
525 const dt_aligned_pixel_simd_t in_v = dt_load_simd_aligned(in + p);
526 dt_store_simd_nontemporal(out + p, (in_v - black_v) * scale_v);
527 }
528 }
529 else
530 {
531 __OMP_PARALLEL_FOR_SIMD__(aligned(in, out : 64))
532 for(size_t k = 0; k < ch * npixels; k++)
533 {
534 out[k] = (in[k] - black) * scale;
535 }
536 }
537
538 if(use_stream) dt_omploop_sfence(); // ensure streamed RGB writes complete before alpha copy touches output
539
541 dt_iop_alpha_copy(i, o, roi_out->width, roi_out->height);
542
543 return 0;
544}
545
546static float _get_exposure_bias(const struct dt_iop_module_t *self)
547{
548 float bias = 0.0f;
549
550 // just check that pointers exist and are initialized
551 if(self->dev && self->dev->image_storage.exif_exposure_bias)
553
554 // sanity checks, don't trust exif tags too much
555 if(!isnan(bias))
556 return CLAMP(bias, -5.0f, 5.0f);
557 else
558 return 0.0f;
559}
560
561void 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)
562{
563 const dt_iop_roi_t *const roi_out = &piece->roi_out;
565 if(piece->dsc_in.channels != 4) return;
566
567 const dt_iop_order_iccprofile_info_t *const input_profile = dt_ioppr_get_pipe_current_profile_info(self, pipe);
568 if(IS_NULL_PTR(input_profile)) return;
569
570 const float *const restrict in = (float*)i;
571 float average_luminance = 0.f;
572 const float norm = 1.f / (float)(roi_out->width * roi_out->height);
573
574 __OMP_PARALLEL_FOR__(reduction(+:average_luminance))
575 for(size_t k = 0; k < roi_out->width * roi_out->height * 4; k += 4)
576 {
577 // Convert each input RGB sample to XYZ to average scene luminance in a profile-aware way.
578 dt_aligned_pixel_t XYZ = { 0.f };
579 dt_ioppr_rgb_matrix_to_xyz(in + k, XYZ, input_profile->matrix_in_transposed, input_profile->lut_in,
580 input_profile->unbounded_coeffs_in, input_profile->lutsize,
581 input_profile->nonlinearlut);
582 average_luminance += XYZ[1] * norm;
583 }
584
585 // Solve the exposure module transfer so the average input luminance lands on middle grey at the output.
586 const float target_lightness = dt_conf_get_float("darkroom/modules/exposure/lightness");
587 const dt_aligned_pixel_t Lab = { target_lightness, 0.f, 0.f, 0.f };
588 dt_aligned_pixel_t XYZ = { 0.f };
590 const float target_luminance = XYZ[1];
591 const float white = p->black + fmaxf(average_luminance - p->black, 1e-6f) / target_luminance;
592 const float exposure = white2exposure(white);
593
594 p->exposure = exposure;
595
596 if(p->compensate_exposure_bias)
597 p->exposure += _get_exposure_bias(self);
598}
599
600
603{
606
607 d->params.black = p->black;
608 d->params.exposure = p->exposure;
609 d->params.deflicker_percentile = p->deflicker_percentile;
610 d->params.deflicker_target_level = p->deflicker_target_level;
611
612 // If exposure bias compensation has been required, add it on top of user exposure correction
613 if(p->compensate_exposure_bias)
614 d->params.exposure -= _get_exposure_bias(self);
615
616 d->deflicker = 0;
617
618 if(p->mode == EXPOSURE_MODE_DEFLICKER
620 && self->dev->image_storage.dsc.channels == 1
622 {
623 d->deflicker = 1;
624 }
625 dt_iop_fmt_log(self, "commit: class=%s needs_rawprepare=%d channels=%i datatype=%i mode=%d -> deflicker=%d",
629 p->mode, d->deflicker);
630
631 _process_common_setup(self, pipe, piece);
632 for(int k = 0; k < 3; k++) piece->dsc_out.processed_maximum[k] = piece->dsc_in.processed_maximum[k] * d->scale;
633}
634
636{
638 piece->data_size = sizeof(dt_iop_exposure_data_t);
639}
640
642{
643 dt_free_align(piece->data);
644 piece->data = NULL;
645}
646
648{
650}
651
652void gui_update(struct dt_iop_module_t *self)
653{
656
658 || self->dev->image_storage.dsc.channels != 1
660 {
661 gtk_widget_set_sensitive(GTK_WIDGET(g->mode), FALSE);
662 }
663 else
664 {
665 gtk_widget_set_sensitive(GTK_WIDGET(g->mode), TRUE);
666 }
667
669
670 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(g->compensate_exposure_bias), p->compensate_exposure_bias);
671 /* xgettext:no-c-format */
672 gchar *label = g_strdup_printf(_("compensate camera exposure (%+.1f EV)"), _get_exposure_bias(self));
673 gtk_button_set_label(GTK_BUTTON(g->compensate_exposure_bias), label);
674 gtk_label_set_ellipsize(GTK_LABEL(gtk_bin_get_child(GTK_BIN(g->compensate_exposure_bias))), PANGO_ELLIPSIZE_MIDDLE);
675 dt_free(label);
676
677 g->spot_RGB[0] = 0.f;
678 g->spot_RGB[1] = 0.f;
679 g->spot_RGB[2] = 0.f;
680 g->spot_RGB[3] = 0.f;
681
682 // get the saved params
684
685 const float lightness = dt_conf_get_float("darkroom/modules/exposure/lightness");
686 dt_bauhaus_slider_set(g->lightness_spot, lightness);
687
689
690 dt_free(g->deflicker_histogram);
691
692 gtk_label_set_text(g->deflicker_used_EC, "");
694 g->deflicker_computed_exposure = NAN;
696
697 switch(p->mode)
698 {
700 _autoexp_disable(self);
701 gtk_stack_set_visible_child_name(GTK_STACK(g->mode_stack), "deflicker");
702 _deflicker_prepare_histogram(self, &g->deflicker_histogram, &g->deflicker_histogram_stats);
703 break;
705 default:
706 gtk_stack_set_visible_child_name(GTK_STACK(g->mode_stack), "manual");
707 break;
708 }
709
711}
712
714{
715 const int program = 2; // from programs.conf: basic.cl
718 module->data = gd;
719 gd->kernel_exposure = dt_opencl_create_kernel(program, "exposure");
720}
721
728
729static void _exposure_set_white(struct dt_iop_module_t *self, const float white)
730{
732
733 const float exposure = white2exposure(white);
734 if(p->exposure == exposure) return;
735
736 p->exposure = exposure;
737 if(p->black >= white) _exposure_set_black(self, white - 0.01);
738
740
742 dt_bauhaus_slider_set(g->exposure, p->exposure);
744 dt_dev_add_history_item(self->dev, self, TRUE, TRUE);
745}
746
747static void _exposure_set_black(struct dt_iop_module_t *self, const float black)
748{
750
751 if(p->black == black) return;
752
753 p->black = black;
754 if(p->black >= exposure2white(p->exposure))
755 {
756 _exposure_set_white(self, p->black + 0.01);
757 }
758
761 dt_bauhaus_slider_set(g->black, p->black);
763 dt_dev_add_history_item(self->dev, self, TRUE, TRUE);
764}
765
767{
770
771 // capture gui color picked event.
772 if(self->picked_color_max[0] < self->picked_color_min[0])
773 {
774 dt_print(DT_DEBUG_DEV, "[picker/exposure] rejected invalid min/max min=%g max=%g\n",
775 self->picked_color_min[0], self->picked_color_max[0]);
776 return;
777 }
778 const float *RGB = self->picked_color;
779 dt_print(DT_DEBUG_DEV, "[picker/exposure] RGB=(%g,%g,%g) pipe=%p\n",
780 RGB[0], RGB[1], RGB[2], (void *)pipe);
781
782 // Get the profile of whatever colorspace the picked sample actually lives in: exposure's
783 // iop-order is user-configurable, so its input can be raw camera RGB (before colorin) or
784 // already-managed RGB (if reordered after colorin) -- see dt_ioppr_get_pipe_current_profile_info.
785 const dt_iop_order_iccprofile_info_t *const input_profile = dt_ioppr_get_pipe_current_profile_info(self, pipe);
786 if(IS_NULL_PTR(input_profile))
787 {
788 dt_print(DT_DEBUG_DEV, "[picker/exposure] missing input profile\n");
789 return;
790 }
791
792 // Convert to XYZ. Some profiles (e.g. camera input profiles with a parametric TRC, or a
793 // non-linear work profile) need their input curve applied before the matrix -- a bare
794 // dot_product against matrix_in would silently skip that curve and produce garbage XYZ
795 // for any such profile. dt_ioppr_rgb_matrix_to_xyz (same helper autoset() above uses) applies
796 // the curve first whenever profile_info->nonlinearlut says it's needed.
799 dt_ioppr_rgb_matrix_to_xyz(RGB, XYZ, input_profile->matrix_in_transposed, input_profile->lut_in,
800 input_profile->unbounded_coeffs_in, input_profile->lutsize,
801 input_profile->nonlinearlut);
803 Lab[1] = Lab[2] = 0.f; // make color grey to get only the equivalent lighness
805 dt_XYZ_to_sRGB(XYZ, g->spot_RGB);
806
807 // Convert to Lch for GUI feedback (input)
809 dt_Lab_2_LCH(Lab, Lch);
810
811 // Write report in GUI
813 gtk_label_set_text(GTK_LABEL(g->Lch_origin),
814 g_strdup_printf(_("L : \t%.1f %%"), Lch[0]));
815 gtk_widget_queue_draw(g->origin_spot);
817
818 const dt_spot_mode_t mode = dt_bauhaus_combobox_get(g->spot_mode);
819
820 if(mode == DT_SPOT_MODE_MEASURE)
821 {
822 // get the exposure setting
823 float expo = p->exposure;
824
825 // If the exposure bias compensation is on, we need to add it to the user param
826 if(p->compensate_exposure_bias)
827 expo -= _get_exposure_bias(self);
828
829 const float white = exposure2white(-expo);
830
831 // apply the exposure compensation
832 dt_aligned_pixel_t XYZ_out;
833 for(int c = 0; c < 3; c++)
834 XYZ_out[c] = XYZ[c] * white;
835
836 // Convert to Lab for GUI feedback
837 dt_aligned_pixel_t Lab_out;
838 dt_XYZ_to_Lab(XYZ_out, Lab_out);
839 Lab_out[1] = Lab_out[2] = 0.f; // make it grey
840
841 // Return the values in sliders
843 dt_bauhaus_slider_set(g->lightness_spot, Lab_out[0]);
844 _paint_hue(self);
846
847 dt_conf_set_float("darkroom/modules/exposure/lightness", Lab_out[0]);
848 }
849 else if(mode == DT_SPOT_MODE_CORRECT)
850 {
851 // Get the target color in XYZ space
852 dt_aligned_pixel_t Lch_target = { 0.f };
854 Lch_target[0] = dt_bauhaus_slider_get(g->lightness_spot);
856
857 dt_aligned_pixel_t Lab_target = { 0.f };
858 dt_LCH_2_Lab(Lch_target, Lab_target);
859
860 dt_aligned_pixel_t XYZ_target = { 0.f };
861 dt_Lab_to_XYZ(Lab_target, XYZ_target);
862
863 // Get the ratio
864 float white = XYZ[1] / XYZ_target[1];
865 float expo = -white2exposure(white);
866
867 // If the exposure bias compensation is on, we need to subtract it from the user param
868 if(p->compensate_exposure_bias)
869 expo -= _get_exposure_bias(self);
870
871 white = exposure2white(-expo);
872 _exposure_set_white(self, white);
873 }
874}
875
876
878{
879 (void)picker;
880 (void)piece;
881 if(dt_gui_widgets_suppressed()) return;
882 dt_print(DT_DEBUG_DEV, "[picker/exposure] apply picker=%p pipe=%p\n", (void *)picker, (void *)pipe);
883 _auto_set_exposure(self, pipe);
884}
885
886
887void gui_changed(dt_iop_module_t *self, GtkWidget *w, void *previous)
888{
891
892 if(w == g->mode)
893 {
894 dt_free(g->deflicker_histogram);
895
896 /* The exposure picker lives on the "manual" stack page. Switching mode can hide
897 that page while the picker stays active, sampling/drawing on the image for a
898 control the user can no longer see or turn off from this widget. */
900
901 switch(p->mode)
902 {
904 _autoexp_disable(self);
906 || self->dev->image_storage.dsc.channels != 1
908 {
909 p->mode = EXPOSURE_MODE_MANUAL;
910 dt_bauhaus_combobox_set(g->mode, p->mode);
911 gtk_widget_set_sensitive(GTK_WIDGET(g->mode), FALSE);
912 break;
913 }
914 gtk_stack_set_visible_child_name(GTK_STACK(g->mode_stack), "deflicker");
915 _deflicker_prepare_histogram(self, &g->deflicker_histogram, &g->deflicker_histogram_stats);
916 break;
918 default:
919 gtk_stack_set_visible_child_name(GTK_STACK(g->mode_stack), "manual");
920 break;
921 }
922 }
923 else if(w == g->exposure)
924 {
925 const float white = exposure2white(p->exposure);
926 if(p->black >= white)
927 _exposure_set_black(self, white - 0.01);
928 }
929 else if(w == g->black)
930 {
931 const float white = exposure2white(p->exposure);
932 if(p->black >= white)
933 _exposure_set_white(self, p->black + 0.01);
934 }
935}
936
937
938static gboolean _draw(GtkWidget *widget, cairo_t *cr, dt_iop_module_t *self)
939{
940 if(dt_gui_widgets_suppressed()) return FALSE;
941
943
945 if(!isnan(g->deflicker_computed_exposure))
946 {
947 gchar *str = g_strdup_printf(_("%.2f EV"), g->deflicker_computed_exposure);
948
950 gtk_label_set_text(g->deflicker_used_EC, str);
952
953 dt_free(str);
954 }
956 return FALSE;
957}
958
959
960static gboolean _target_color_draw(GtkWidget *widget, cairo_t *crf, gpointer user_data)
961{
962 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
964
965 // Init
966 GtkAllocation allocation;
967 gtk_widget_get_allocation(widget, &allocation);
968 int width = allocation.width, height = allocation.height;
969 cairo_surface_t *cst = dt_cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
970 cairo_t *cr = cairo_create(cst);
971
972 // Margins
973 const float margin = 2. * DT_PIXEL_APPLY_DPI(1.5);
975 height -= 2 * margin;
976
977 // Paint target color
978 dt_aligned_pixel_t RGB = { 0 };
979 dt_aligned_pixel_t Lch = { 0 };
980 dt_aligned_pixel_t Lab = { 0 };
981 dt_aligned_pixel_t XYZ = { 0 };
982 Lch[0] = dt_bauhaus_slider_get(g->lightness_spot);
983 Lch[1] = 0.f;
984 Lch[2] = 0.f;
985 dt_LCH_2_Lab(Lch, Lab);
988
989 cairo_set_source_rgb(cr, RGB[0], RGB[1], RGB[2]);
990 cairo_rectangle(cr, INNER_PADDING, margin, width, height);
991 cairo_fill(cr);
992
993 // Clean
994 cairo_stroke(cr);
995 cairo_destroy(cr);
996 cairo_set_source_surface(crf, cst, 0, 0);
997 cairo_paint(crf);
998 cairo_surface_destroy(cst);
999 return TRUE;
1000}
1001
1002
1003static gboolean _origin_color_draw(GtkWidget *widget, cairo_t *crf, gpointer user_data)
1004{
1005 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
1007
1008 // Init
1009 GtkAllocation allocation;
1010 gtk_widget_get_allocation(widget, &allocation);
1011 int width = allocation.width;
1012 int height = allocation.height;
1013 cairo_surface_t *cst = dt_cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
1014 cairo_t *cr = cairo_create(cst);
1015
1016 // Margins
1017 const float margin = 2. * DT_PIXEL_APPLY_DPI(1.5);
1019 height -= 2 * margin;
1020
1021 cairo_set_source_rgb(cr, g->spot_RGB[0], g->spot_RGB[1], g->spot_RGB[2]);
1022 cairo_rectangle(cr, INNER_PADDING, margin, width, height);
1023 cairo_fill(cr);
1024
1025 // Clean
1026 cairo_stroke(cr);
1027 cairo_destroy(cr);
1028 cairo_set_source_surface(crf, cst, 0, 0);
1029 cairo_paint(crf);
1030 cairo_surface_destroy(cst);
1031 return TRUE;
1032}
1033
1034static void _paint_hue(dt_iop_module_t *self)
1035{
1036 // update the fill background color of LCh sliders
1038
1039 const float lightness_min = dt_bauhaus_slider_get_hard_min(g->lightness_spot);
1040 const float lightness_max = dt_bauhaus_slider_get_hard_max(g->lightness_spot);
1041
1042 const float lightness_range = lightness_max - lightness_min;
1043
1044 for(int i = 0; i < DT_BAUHAUS_SLIDER_MAX_STOPS; i++)
1045 {
1046 const float stop = ((float)i / (float)(DT_BAUHAUS_SLIDER_MAX_STOPS - 1));
1047 const float x = lightness_min + stop * lightness_range;
1048 dt_aligned_pixel_t RGB = { 0 };
1049 const dt_aligned_pixel_t Lch = { x, 0.f, 0. };
1050 dt_aligned_pixel_t Lab = { 0 };
1051 dt_aligned_pixel_t XYZ = { 0 };
1052
1053 dt_LCH_2_Lab(Lch, Lab);
1056
1057 dt_bauhaus_slider_set_stop(g->lightness_spot, stop, RGB[0], RGB[1], RGB[2]);
1058 }
1059
1060 gtk_widget_queue_draw(g->lightness_spot);
1061 gtk_widget_queue_draw(g->target_spot);
1062}
1063
1064
1066{
1067 if(dt_gui_widgets_suppressed()) return;
1068
1070
1071 dt_aligned_pixel_t Lch_target = { 0.f };
1072
1073 Lch_target[0] = dt_bauhaus_slider_get(g->lightness_spot);
1074
1075 // Save the color on change
1076 dt_conf_set_float("darkroom/modules/exposure/lightness", Lch_target[0]);
1077
1079 _paint_hue(self);
1081
1082 // Re-run auto compute only for the module that currently owns the active picker.
1083 const dt_spot_mode_t mode = dt_bauhaus_combobox_get(g->spot_mode);
1084 const gboolean picker_active = dt_iop_color_picker_is_active_module(self);
1085 if(mode == DT_SPOT_MODE_CORRECT && picker_active)
1086 _auto_set_exposure(self, self->dev->pipe);
1087 // else : just record new values and do nothing
1088}
1089
1090void gui_reset(struct dt_iop_module_t *self)
1091{
1093}
1094
1095void gui_init(struct dt_iop_module_t *self)
1096{
1098
1099 g->deflicker_histogram = NULL;
1100
1101 // Start building top level widget
1102 // Note: stupid dt_bauhaus_toggle/combobox/slider_from_params read self directly
1103 // and are hard-coded to pack_start widgets to self->widget.
1104 // So we need to store the main widget first, stupidly update the ref to self->widget,
1105 // as we add boxes and restore it last to the main widget.
1106 // The guy who thought of that should really burn his computer and do everyone a favour.
1107 GtkWidget *main_widget = self->gui->widget = GTK_WIDGET(gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING));
1108
1109 g->mode = dt_bauhaus_combobox_from_params(self, N_("mode"));
1110
1111 g->mode_stack = GTK_STACK(gtk_stack_new());
1112 gtk_stack_set_homogeneous(GTK_STACK(g->mode_stack),FALSE);
1113 gtk_box_pack_start(GTK_BOX(self->gui->widget), GTK_WIDGET(g->mode_stack), TRUE, TRUE, 0);
1114
1115 GtkWidget *vbox_manual = self->gui->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING);
1116 gtk_stack_add_named(GTK_STACK(g->mode_stack), vbox_manual, "manual");
1117
1118 g->compensate_exposure_bias = dt_bauhaus_toggle_from_params(self, "compensate_exposure_bias");
1119 gtk_widget_set_tooltip_text(g->compensate_exposure_bias, _("automatically remove the camera exposure bias\n"
1120 "this is useful if you exposed the image to the right."));
1121
1122 g->exposure = dt_color_picker_new(self, DT_COLOR_PICKER_AREA,
1123 dt_bauhaus_slider_from_params(self, N_("exposure")));
1124 gtk_widget_set_tooltip_text(g->exposure, _("adjust the exposure correction"));
1125 dt_bauhaus_slider_set_digits(g->exposure, 3);
1126 dt_bauhaus_slider_set_format(g->exposure, _(" EV"));
1127 dt_bauhaus_slider_set_soft_range(g->exposure, -3.0, 4.0);
1128
1129 g->black = dt_bauhaus_slider_from_params(self, "black");
1130 gtk_widget_set_tooltip_text(g->black, _("adjust the black level to unclip negative RGB values.\n"
1131 "you should never use it to add more density in blacks!\n"
1132 "if poorly set, it will clip near-black colors out of gamut\n"
1133 "by pushing RGB values into negatives."));
1135 dt_bauhaus_slider_set_soft_range(g->black, -0.1, 0.1);
1136
1137 GtkWidget *vbox_deflicker = self->gui->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING);
1138 gtk_stack_add_named(GTK_STACK(g->mode_stack), vbox_deflicker, "deflicker");
1139
1140 g->deflicker_percentile = dt_bauhaus_slider_from_params(self, "deflicker_percentile");
1141 dt_bauhaus_slider_set_format(g->deflicker_percentile, "%");
1142 gtk_widget_set_tooltip_text(g->deflicker_percentile,
1143 // xgettext:no-c-format
1144 _("where in the histogram to meter for deflicking. E.g. 50% is median"));
1145
1146 g->deflicker_target_level = dt_bauhaus_slider_from_params(self, "deflicker_target_level");
1147 dt_bauhaus_slider_set_format(g->deflicker_target_level, _(" EV"));
1148 gtk_widget_set_tooltip_text(g->deflicker_target_level,
1149 _("where to place the exposure level for processed pics, EV below overexposure."));
1150
1151 GtkBox *hbox1 = GTK_BOX(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, DT_GUI_BOX_SPACING));
1152 gtk_box_pack_start(GTK_BOX(hbox1), GTK_WIDGET(dt_ui_label_new(_("computed EC: "))), FALSE, FALSE, 0);
1153 g->deflicker_used_EC = GTK_LABEL(dt_ui_label_new("")); // This gets filled in by process
1154 gtk_widget_set_tooltip_text(GTK_WIDGET(g->deflicker_used_EC), _("what exposure correction has actually been used"));
1155 gtk_box_pack_start(GTK_BOX(hbox1), GTK_WIDGET(g->deflicker_used_EC), FALSE, FALSE, 0);
1156
1158 g->deflicker_computed_exposure = NAN;
1160
1161 self->gui->widget = main_widget;
1162
1164 (&g->cs,
1165 "plugins/darkroom/exposure/mapping",
1166 _("spot exposure mapping"),
1167 GTK_BOX(self->gui->widget), GTK_PACK_END);
1168
1169 DT_BAUHAUS_COMBOBOX_NEW_FULL(dt_bauhaus_get_global(), g->spot_mode, DT_GUI_MODULE(self), N_("spot mode"),
1170 _("\"correction\" automatically adjust exposure\n"
1171 "such that the input lightness is mapped to the target.\n"
1172 "\"measure\" simply shows how an input color is mapped by the exposure compensation\n"
1173 "and can be used to define a target."),
1174 0, NULL, self,
1175 N_("correction"),
1176 N_("measure"));
1177 gtk_box_pack_start(GTK_BOX(g->cs.container), GTK_WIDGET(g->spot_mode), TRUE, TRUE, 0);
1178 g_signal_connect(G_OBJECT(g->spot_mode), "value-changed", G_CALLBACK(_spot_settings_changed_callback), self);
1179
1180 GtkWidget *hhbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, DT_GUI_BOX_SPACING);
1181 GtkWidget *vvbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING);
1182
1183 gtk_box_pack_start(GTK_BOX(vvbox), dt_ui_section_label_new(_("input")), FALSE, FALSE, 0);
1184
1185 g->origin_spot = GTK_WIDGET(gtk_drawing_area_new());
1186 gtk_widget_set_size_request(g->origin_spot, 2 * DT_PIXEL_APPLY_DPI(dt_bauhaus_get_global()->quad_width),
1188 gtk_widget_set_tooltip_text(GTK_WIDGET(g->origin_spot),
1189 _("the input color that should be mapped to the target"));
1190
1191 g_signal_connect(G_OBJECT(g->origin_spot), "draw", G_CALLBACK(_origin_color_draw), self);
1192 gtk_box_pack_start(GTK_BOX(vvbox), g->origin_spot, TRUE, TRUE, 0);
1193
1194 g->Lch_origin = gtk_label_new(_("L : \tN/A"));
1195 gtk_widget_set_tooltip_text(GTK_WIDGET(g->Lch_origin),
1196 _("these LCh coordinates are computed from CIE Lab 1976 coordinates"));
1197 gtk_box_pack_start(GTK_BOX(vvbox), GTK_WIDGET(g->Lch_origin), FALSE, FALSE, 0);
1198
1199 gtk_box_pack_start(GTK_BOX(hhbox), GTK_WIDGET(vvbox), FALSE, FALSE, DT_BAUHAUS_SPACE);
1200
1201 vvbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING);
1202
1203 gtk_box_pack_start(GTK_BOX(vvbox), dt_ui_section_label_new(_("target")), FALSE, TRUE, 0);
1204
1205 g->target_spot = GTK_WIDGET(gtk_drawing_area_new());
1206 gtk_widget_set_size_request(g->target_spot, 2 * DT_PIXEL_APPLY_DPI(dt_bauhaus_get_global()->quad_width),
1208 gtk_widget_set_tooltip_text(GTK_WIDGET(g->target_spot),
1209 _("the desired target exposure after mapping"));
1210
1211 g_signal_connect(G_OBJECT(g->target_spot), "draw", G_CALLBACK(_target_color_draw), self);
1212 gtk_box_pack_start(GTK_BOX(vvbox), g->target_spot, TRUE, TRUE, 0);
1213
1214 g->lightness_spot = dt_bauhaus_slider_new_with_range(dt_bauhaus_get_global(), DT_GUI_MODULE(self), 0., 100., 0, 0, 1);
1215 dt_bauhaus_widget_set_label(g->lightness_spot, N_("lightness"));
1216 dt_bauhaus_slider_set_format(g->lightness_spot, "%");
1217 dt_bauhaus_slider_set_default(g->lightness_spot, 50.f);
1218 gtk_box_pack_start(GTK_BOX(vvbox), GTK_WIDGET(g->lightness_spot), TRUE, TRUE, 0);
1219 g_signal_connect(G_OBJECT(g->lightness_spot), "value-changed", G_CALLBACK(_spot_settings_changed_callback), self);
1220
1221 gtk_box_pack_start(GTK_BOX(hhbox), GTK_WIDGET(vvbox), TRUE, TRUE, DT_BAUHAUS_SPACE);
1222
1223 gtk_box_pack_start(GTK_BOX(g->cs.container), GTK_WIDGET(hhbox), FALSE, FALSE, 0);
1224
1225 g_signal_connect(G_OBJECT(self->gui->widget), "draw", G_CALLBACK(_draw), self);
1226}
1227
1229{
1231
1232 dt_free(g->deflicker_histogram);
1233
1235}
1236
1237// clang-format off
1238// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
1239// vim: shiftwidth=2 expandtab tabstop=2 cindent
1240// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
1241// clang-format on
static void error(char *msg)
Definition ashift_lsd.c:202
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
void dt_bauhaus_slider_set_soft_range(GtkWidget *widget, float soft_min, float soft_max)
Definition bauhaus.c:1498
void dt_bauhaus_slider_set_digits(GtkWidget *widget, int val)
Definition bauhaus.c:3343
void dt_bauhaus_slider_set_default(GtkWidget *widget, float def)
Definition bauhaus.c:1491
void dt_bauhaus_slider_set_stop(GtkWidget *widget, float stop, float r, float g, float b)
Definition bauhaus.c:2161
float dt_bauhaus_slider_get(GtkWidget *widget)
Definition bauhaus.c:3280
int dt_bauhaus_combobox_get(GtkWidget *widget)
Definition bauhaus.c:2136
float dt_bauhaus_slider_get_hard_min(GtkWidget *widget)
Definition bauhaus.c:1425
void dt_bauhaus_slider_set(GtkWidget *widget, float pos)
Definition bauhaus.c:3331
void dt_bauhaus_combobox_set(GtkWidget *widget, const int pos)
Definition bauhaus.c:2090
void dt_bauhaus_widget_set_label(GtkWidget *widget, const char *label)
Definition bauhaus.c:1504
GtkWidget * dt_bauhaus_slider_new_with_range(dt_bauhaus_t *bh, dt_gui_module_t *self, float min, float max, float step, float defval, int digits)
Definition bauhaus.c:1632
void dt_bauhaus_slider_set_format(GtkWidget *widget, const char *format)
Definition bauhaus.c:3407
float dt_bauhaus_slider_get_hard_max(GtkWidget *widget)
Definition bauhaus.c:1450
#define DT_BAUHAUS_SPACE
Definition bauhaus.h:291
#define INTERNAL_PADDING
Definition bauhaus.h:78
#define DT_BAUHAUS_COMBOBOX_NEW_FULL(bauhaus, widget, action, label, tip, pos, callback, data,...)
Definition bauhaus.h:379
#define DT_BAUHAUS_SLIDER_MAX_STOPS
Definition bauhaus.h:73
#define INNER_PADDING
Definition bauhaus.h:81
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
dt_spot_mode_t
return vector dt_simd_set1(valid ?(scaling+NORM_MIN) :NORM_MIN)
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.
void dt_gui_update_collapsible_section(dt_gui_collapsible_section_t *cs)
@ 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
static const float x
struct _GtkWidget GtkWidget
GtkWidget, opaque, spelled exactly as GTK spells it.
Definition colorspaces.h:98
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
void dt_conf_set_float(const char *name, float val)
float dt_conf_get_float(const char *name)
Float for name, clamped to its declared bounds.
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_control_log(const char *msg,...)
Definition control.c:824
struct dt_bauhaus_t * dt_bauhaus_get_global(void)
Definition darktable.c:646
#define dt_dev_add_history_item(dev, module, enable, redraw)
void dt_iop_params_t
Definition dev_history.h:43
void default_output_format(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece, dt_iop_buffer_dsc_t *dsc)
dt_iop_order_iccprofile_info_t * dt_ioppr_get_pipe_current_profile_info(dt_iop_module_t *module, const struct dt_dev_pixelpipe_t *pipe)
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:402
@ DT_DEV_PIXELPIPE_DISPLAY_MASK
Definition develop.h:123
static float _get_exposure_bias(const struct dt_iop_module_t *self)
Definition exposure.c:546
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:601
static gboolean _draw(GtkWidget *widget, cairo_t *cr, dt_iop_module_t *self)
Definition exposure.c:938
const char ** description(struct dt_iop_module_t *self)
Definition exposure.c:170
int default_group()
Definition exposure.c:181
static void _spot_settings_changed_callback(GtkWidget *slider, dt_iop_module_t *self)
Definition exposure.c:1065
static gboolean _origin_color_draw(GtkWidget *widget, cairo_t *crf, gpointer user_data)
Definition exposure.c:1003
#define DEFLICKER_BINS_COUNT
Definition exposure.c:114
static double _raw_to_ev(uint32_t raw, uint32_t black_level, uint32_t white_level)
Definition exposure.c:382
#define exposure2white(x)
Definition exposure.c:94
dt_spot_mode_t
Definition exposure.c:106
@ DT_SPOT_MODE_MEASURE
Definition exposure.c:108
@ DT_SPOT_MODE_CORRECT
Definition exposure.c:107
@ DT_SPOT_MODE_LAST
Definition exposure.c:109
static void _auto_set_exposure(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe)
Definition exposure.c:766
void init_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition exposure.c:635
const char * name()
Definition exposure.c:165
static void _exposure_set_black(struct dt_iop_module_t *self, const float black)
Definition exposure.c:747
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:199
void gui_reset(struct dt_iop_module_t *self)
Definition exposure.c:1090
void gui_update(struct dt_iop_module_t *self)
Refresh GUI controls from current params and configuration.
Definition exposure.c:652
static void _exposure_set_white(struct dt_iop_module_t *self, const float white)
Definition exposure.c:729
void gui_init(struct dt_iop_module_t *self)
Definition exposure.c:1095
void gui_changed(dt_iop_module_t *self, GtkWidget *w, void *previous)
Definition exposure.c:887
static void _autoexp_disable(dt_iop_module_t *self)
Definition exposure.c:647
#define white2exposure(x)
Definition exposure.c:95
void cleanup_global(dt_iop_module_so_t *module)
Definition exposure.c:722
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:395
int default_colorspace(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
Definition exposure.c:191
int flags()
Definition exposure.c:186
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:433
void gui_cleanup(struct dt_iop_module_t *self)
Definition exposure.c:1228
void init_presets(dt_iop_module_so_t *self)
Definition exposure.c:311
static void _deflicker_prepare_histogram(dt_iop_module_t *self, uint32_t **histogram, dt_dev_histogram_stats_t *histogram_stats)
Definition exposure.c:340
__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:503
static void _paint_hue(dt_iop_module_t *self)
Definition exposure.c:1034
void cleanup_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition exposure.c:641
void init_global(dt_iop_module_so_t *module)
Definition exposure.c:713
dt_iop_exposure_mode_t
Definition exposure.c:100
@ EXPOSURE_MODE_MANUAL
Definition exposure.c:101
@ EXPOSURE_MODE_DEFLICKER
Definition exposure.c:102
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:561
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:473
static gboolean _target_color_draw(GtkWidget *widget, cairo_t *crf, gpointer user_data)
Definition exposure.c:960
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:877
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:208
@ TYPE_UINT16
Definition format.h:57
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)
#define DT_GUI_MODULE(x)
@ FOR_RAW
dt_image_t * dt_image_cache_get(const int32_t imgid, char mode)
void dt_image_cache_read_release(const dt_image_t *img)
const char ** dt_iop_set_description(dt_iop_module_t *module, const char *main_text, const char *purpose, const char *input, const char *process, const char *output)
Definition imageop.c:1893
void dt_iop_gui_leave_critical_section(dt_iop_module_t *const module)
Release what dt_iop_gui_enter_critical_section() took. Also a no-op headless.
#define dt_iop_fmt_log(module, fmt,...)
Debug helper to trace a module's input-format-driven decisions on the -d pipe channel (DT_DEBUG_PIPE)...
Definition imageop.h:535
@ IOP_FLAGS_SUPPORTS_BLENDING
Definition imageop.h:186
@ IOP_FLAGS_ALLOW_TILING
Definition imageop.h:188
void dt_iop_gui_enter_critical_section(dt_iop_module_t *const module)
Take the module's GUI lock, serialising access to its dt_iop_gui_data_t.
@ IOP_GROUP_TONES
Definition imageop.h:156
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)
GtkWidget * dt_bauhaus_combobox_from_params(dt_iop_module_t *self, const char *param)
#define IOP_GUI_FREE
Definition imageop_gui.h:96
static dt_iop_gui_data_t * dt_iop_gui_data(const struct dt_iop_module_t *m)
The module's GUI data blob, NULL-safe for headless callers: IOP process() implementations read it for...
Definition imageop_gui.h:81
#define IOP_GUI_ALLOC(module)
Definition imageop_gui.h:93
GtkWidget * dt_ui_section_label_new(const gchar *str)
Definition label.c:114
GtkWidget * dt_ui_label_new(const gchar *str)
Definition label.c:125
@ DT_DEBUG_OPENCL
Definition logging.h:57
@ DT_DEBUG_DEV
Definition logging.h:53
void dt_print(dt_debug_thread_t thread, const char *msg,...) __attribute__((format(printf
Print to stdout when thread is enabled, prefixed with seconds since startup.
float *const restrict const size_t k
float *const restrict const size_t const size_t ch
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
Definition macros.h:96
#define dt_free_align(ptr)
Release memory from dt_alloc_align() and set ptr to NULL.
Definition mem_alloc.h:214
static void * dt_calloc_align(size_t size)
dt_alloc_align() followed by a zero fill.
Definition mem_alloc.h:225
#define dt_free(ptr)
g_free() ptr and set it to NULL, skipping both if it is already NULL.
Definition mem_alloc.h:171
uint32_t width
Definition mipmap_cache.c:0
uint32_t height
Definition mipmap_cache.c:1
@ DT_MIPMAP_BLOCKING
@ DT_MIPMAP_FULL
#define dt_mipmap_cache_get(B, C, D, E, F)
#define dt_mipmap_cache_release(B)
#define DT_MODULE_INTROSPECTION(MODVER, PARAMSTYPE)
DT_MODULE() for a module whose params struct is introspected.
int dt_opencl_enqueue_kernel_2d(const int dev, const int kernel, const size_t *sizes)
Definition opencl.c:2554
int dt_opencl_create_kernel(const int prog, const char *name)
Definition opencl.c:2448
void dt_opencl_free_kernel(const int kernel)
Definition opencl.c:2491
int dt_opencl_set_kernel_arg(const int dev, const int kernel, const int num, const size_t size, const void *arg)
Definition opencl.c:2545
#define ROUNDUPDHT(a, b)
Definition opencl.h:86
#define ROUNDUPDWD(a, b)
Definition opencl.h:85
#define dt_omploop_sfence()
Definition openmp.h:164
#define __OMP_PARALLEL_FOR__(...)
Definition openmp.h:95
#define __OMP_PARALLEL_FOR_SIMD__(...)
Definition openmp.h:96
static cairo_surface_t * dt_cairo_image_surface_create(cairo_format_t format, int width, int height)
DT_ALIGNED_PIXEL float dt_aligned_pixel_t[4]
Definition simd.h:53
const struct dt_histogram_roi_t * roi
Definition pixelpipe.h:60
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:225
struct dt_dev_pixelpipe_t * pipe
Definition develop.h:214
int32_t height
Definition image.h:397
float exif_exposure_bias
Definition image.h:368
int32_t crop_height
Definition image.h:398
int32_t width
Definition image.h:397
int32_t crop_y
Definition image.h:398
int32_t crop_x
Definition image.h:398
dt_iop_buffer_dsc_t dsc
Definition image.h:419
int32_t crop_width
Definition image.h:398
char filename[DT_MAX_FILENAME_LEN]
Definition image.h:386
int32_t id
Definition image.h:401
uint16_t raw_black_level
Definition format.h:103
unsigned int channels
Definition format.h:83
struct dt_iop_buffer_dsc_t::@55 rawprepare
dt_iop_buffer_type_t datatype
Definition format.h:85
dt_aligned_pixel_t processed_maximum
Definition format.h:114
uint16_t raw_white_point
Definition format.h:104
dt_iop_exposure_params_t params
Definition exposure.c:153
GtkWidget * compensate_exposure_bias
Definition exposure.c:137
GtkWidget * deflicker_percentile
Definition exposure.c:132
dt_gui_collapsible_section_t cs
Definition exposure.c:145
dt_dev_histogram_stats_t deflicker_histogram_stats
Definition exposure.c:135
uint32_t * deflicker_histogram
Definition exposure.c:134
dt_aligned_pixel_t spot_RGB
Definition exposure.c:147
GtkWidget * deflicker_target_level
Definition exposure.c:133
dt_iop_exposure_mode_t mode
Definition exposure.c:118
gboolean compensate_exposure_bias
Definition exposure.c:123
GtkWidget * widget
Definition imageop_gui.h:47
dt_dev_operation_t op
Definition imageop.h:235
dt_iop_global_data_t * data
Definition imageop.h:238
dt_iop_params_t * default_params
Definition imageop.h:333
struct dt_iop_module_gui_t * gui
Definition imageop.h:346
struct dt_develop_t * dev
Definition imageop.h:311
dt_iop_global_data_t * global_data
Definition imageop.h:337
dt_aligned_pixel_t picked_color_min
Definition imageop.h:287
dt_aligned_pixel_t picked_color_max
Definition imageop.h:287
dt_aligned_pixel_t picked_color
Definition imageop.h:287
dt_iop_params_t * params
Definition imageop.h:333
A profile reduced to the arithmetic the pixel loop can run: two matrices and six tone-curve LUTs,...
int nonlinearlut
Non-zero when the profile has tone curves at all; tested as a boolean everywhere, but it is really th...
int lutsize
Entry count of each of the six LUTs. Always 65536 in practice: both callers of dt_ioppr_init_profile_...
float * lut_in[3]
Per-channel encoded -> linear tone curve, lutsize entries each, sampled over [0,1]....
Region of interest passed through the pixelpipe.
Definition format.h:49
int width
Definition format.h:50
int height
Definition format.h:50
#define __DT_CLONE_TARGETS__
#define MAX(a, b)
Definition thinplate.c:29
Telling the user something happened.
gboolean dt_gui_widgets_suppressed(void)
#define dt_gui_freeze_begin()
#define dt_gui_freeze_end()
#define DT_GUI_BOX_SPACING
#define DT_PIXEL_APPLY_DPI(value)