Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
basicadj.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2019 Andreas Schneider.
4 Copyright (C) 2019-2020, 2023, 2025-2026 Aurélien PIERRE.
5 Copyright (C) 2019 Barna Keresztes.
6 Copyright (C) 2019-2020, 2022 Diederik Ter Rahe.
7 Copyright (C) 2019 Diederik ter Rahe.
8 Copyright (C) 2019 Edgardo Hoszowski.
9 Copyright (C) 2019 Heiko Bauke.
10 Copyright (C) 2019 luzpaz.
11 Copyright (C) 2019-2022 Pascal Obry.
12 Copyright (C) 2019 Philippe Weyland.
13 Copyright (C) 2019 Tobias Ellinghaus.
14 Copyright (C) 2020, 2022 Aldric Renaudin.
15 Copyright (C) 2020-2021 Chris Elston.
16 Copyright (C) 2020 coolcom200.
17 Copyright (C) 2020 Harold le Clément de Saint-Marcq.
18 Copyright (C) 2020 Hubert Kowalski.
19 Copyright (C) 2020-2021 Ralf Brown.
20 Copyright (C) 2021 Roman Lebedev.
21 Copyright (C) 2021 Victor Forsiuk.
22 Copyright (C) 2022 Hanno Schwalm.
23 Copyright (C) 2022 Martin Bařinka.
24 Copyright (C) 2022 Philipp Lutz.
25 Copyright (C) 2023-2024 Alynx Zhou.
26 Copyright (C) 2025-2026 Guillaume Stutin.
27
28 darktable is free software: you can redistribute it and/or modify
29 it under the terms of the GNU General Public License as published by
30 the Free Software Foundation, either version 3 of the License, or
31 (at your option) any later version.
32
33 darktable is distributed in the hope that it will be useful,
34 but WITHOUT ANY WARRANTY; without even the implied warranty of
35 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
36 GNU General Public License for more details.
37
38 You should have received a copy of the GNU General Public License
39 along with darktable. If not, see <http://www.gnu.org/licenses/>.
40*/
41
42/*
43 auto exposure is based on RawTherapee's Auto Levels
44*/
45
46#ifdef HAVE_CONFIG_H
47#include "config.h"
48#endif
49
50#include "bauhaus/bauhaus.h"
51#include "control/control.h"
53#include "common/math.h"
54#include "common/rgb_norms.h"
55#include "develop/imageop.h"
56#include "develop/imageop_gui.h"
57
59#include "develop/tiling.h"
60
62
63#define exposure2white(x) exp2f(-(x))
64
66{
67 float black_point; /* $MIN: -1.0 $MAX: 1.0 $DEFAULT: 0.0
68 $DESCRIPTION:"black level correction" */
69 float exposure; // $MIN: -18.0 $MAX: 18.0 $DEFAULT: 0.0
70 float hlcompr; /* $MIN: 0 $MAX: 500.0 $DEFAULT: 0.0
71 $DESCRIPTION:"highlight compression" */
73 float contrast; // $MIN: -1.0 $MAX: 5.0 $DEFAULT: 0.0
74 dt_iop_rgb_norms_t preserve_colors; /* $DEFAULT: DT_RGB_NORM_LUMINANCE
75 $DESCRIPTION:"preserve colors" */
76 float middle_grey; // $MIN: 0.05 $MAX: 100 $DEFAULT: 18.42 $DESCRIPTION: "middle gray"
77 float brightness; // $MIN: -4.0 $MAX: 4.0 $DEFAULT: 0.0
78 float saturation; // $MIN: -1.0 $MAX: 1.0 $DEFAULT: 0.0
79 float vibrance; // $MIN: -1.0 $MAX: 1.0 $DEFAULT: 0.0
80 float clip; // $MIN: -1.0 $MAX: 1.0 $DEFAULT: 0.0
82
107
114
115int legacy_params(dt_iop_module_t *self, const void *const old_params, const int old_version, void *new_params,
116 const int new_version)
117{
118 if(old_version == 1 && new_version == 2)
119 {
120 typedef struct dt_iop_basicadj_params_v1_t
121 {
122 float black_point;
123 float exposure;
124 float hlcompr;
125 float hlcomprthresh;
126 float contrast;
127 int preserve_colors;
128 float middle_grey;
129 float brightness;
130 float saturation;
131 float clip;
132 } dt_iop_basicadj_params_v1_t;
133
134 const dt_iop_basicadj_params_v1_t *old = old_params;
135 dt_iop_basicadj_params_t *new = new_params;
136
137 new->black_point = old->black_point;
138 new->exposure = old->exposure;
139 new->hlcompr = old->hlcompr;
140 new->hlcomprthresh = old->hlcomprthresh;
141 new->contrast = old->contrast;
142 new->preserve_colors = old->preserve_colors;
143 new->middle_grey = old->middle_grey;
144 new->brightness = old->brightness;
145 new->saturation = old->saturation;
146 new->clip = old->clip;
147 new->vibrance = 0;
148 return 0;
149 }
150 return 1;
151}
152
153const char *deprecated_msg()
154{
155 return _("this module is deprecated. please use the quick access panel instead.");
156}
157
158const char *name()
159{
160 return _("basic adjustments");
161}
162
163const char **description(struct dt_iop_module_t *self)
164{
165 return dt_iop_set_description(self, _("apply usual image adjustments"),
166 _("creative"),
167 _("linear, RGB, scene-referred"),
168 _("non-linear, RGB"),
169 _("non-linear, RGB, scene-referred"));
170}
171
173{
174 return IOP_GROUP_EFFECTS;
175}
176
181
183{
184 return IOP_CS_RGB;
185}
186
188{
190 if(!IS_NULL_PTR(g))
191 {
192 g->button_down = g->draw_selected_region = 0;
193 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(g->bt_select_region), g->draw_selected_region);
194 }
195}
196
202
203void gui_changed(dt_iop_module_t *self, GtkWidget *w, void *previous)
204{
206}
207
209{
211}
212
213static void _auto_levels_callback(GtkButton *button, dt_iop_module_t *self)
214{
215 if(darktable.gui->reset) return;
216
218
220 if(self->off)
221 {
222 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(self->off), 1);
224 }
225
227
229 if(g->call_auto_exposure == 0)
230 {
231 g->box_cood[0] = g->box_cood[1] = g->box_cood[2] = g->box_cood[3] = 0.f;
232 g->call_auto_exposure = 1;
233 }
235
237}
238
239static void _select_region_toggled_callback(GtkToggleButton *togglebutton, dt_iop_module_t *self)
240{
241 if(darktable.gui->reset) return;
242
244
246 if(self->off)
247 {
248 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(self->off), 1);
250 }
251
253
255 if(gtk_toggle_button_get_active(togglebutton))
256 {
257 g->draw_selected_region = 1;
258 }
259 else
260 g->draw_selected_region = 0;
261
262 g->posx_from = g->posx_to = g->posy_from = g->posy_to = 0;
264}
265
266static void _develop_ui_pipe_finished_callback(gpointer instance, gpointer user_data)
267{
268 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
271
272 if(IS_NULL_PTR(g)) return;
273
274 // FIXME: this doesn't seems the right place to update params and GUI ...
275 // update auto levels
277 if(g->call_auto_exposure == 2)
278 {
279 g->call_auto_exposure = -1;
281
282 memcpy(p, &g->params, sizeof(dt_iop_basicadj_params_t));
283
285
287 g->call_auto_exposure = 0;
289
291
292 gui_update(self);
293
295 }
296 else
297 {
299 }
300}
301
302static void _signal_profile_user_changed(gpointer instance, uint8_t profile_type, gpointer user_data)
303{
304 if(profile_type == DT_COLORSPACES_PROFILE_TYPE_WORK)
305 {
306 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
307 if(!self->enabled) return;
308
311
312 const dt_iop_order_iccprofile_info_t *const work_profile
314 const float def_middle_grey
315 = (work_profile) ? (dt_ioppr_get_profile_info_middle_grey(work_profile) * 100.f) : 18.42f;
316
317 if(def->middle_grey != def_middle_grey)
318 {
319 def->middle_grey = def_middle_grey;
320
321 if(!IS_NULL_PTR(g))
322 {
324
325 dt_bauhaus_slider_set_default(g->sl_middle_grey, def_middle_grey);
326
328 }
329 }
330 }
331}
332
333int mouse_moved(struct dt_iop_module_t *self, double x, double y, double pressure, int which)
334{
335 int handled = 0;
337 if(!IS_NULL_PTR(g) && g->draw_selected_region && g->button_down && self->enabled)
338 {
339 float point[2] = { (float)x, (float)y };
342
343 g->posx_to = point[0];
344 g->posy_to = point[1];
345
347
348 handled = 1;
349 }
350
351 return handled;
352}
353
354int button_released(struct dt_iop_module_t *self, double x, double y, int which, uint32_t state)
355{
356 int handled = 0;
358 if(!IS_NULL_PTR(g) && g->draw_selected_region && self->enabled)
359 {
360 if(fabsf(g->posx_from - g->posx_to) > 1 && fabsf(g->posy_from - g->posy_to) > 1)
361 {
362 g->box_cood[0] = g->posx_from;
363 g->box_cood[1] = g->posy_from;
364 g->box_cood[2] = g->posx_to;
365 g->box_cood[3] = g->posy_to;
367
368 g->button_down = 0;
369 g->call_auto_exposure = 1;
370
372 }
373 else
374 g->button_down = 0;
375
376 handled = 1;
377 }
378
379 return handled;
380}
381
382int button_pressed(struct dt_iop_module_t *self, double x, double y, double pressure, int which, int type,
383 uint32_t state)
384{
385 int handled = 0;
387 if(!IS_NULL_PTR(g) && g->draw_selected_region && self->enabled)
388 {
389 if((which == 3) || (which == 1 && type == GDK_2BUTTON_PRESS))
390 {
392
393 handled = 1;
394 }
395 else if(which == 1)
396 {
397 float point[2] = { (float)x, (float)y };
400
401 g->posx_from = g->posx_to = point[0];
402 g->posy_from = g->posy_to = point[1];
403
404 g->button_down = 1;
405
406 handled = 1;
407 }
408 }
409
410 return handled;
411}
412
413void gui_post_expose(struct dt_iop_module_t *self, cairo_t *cr, int32_t width, int32_t height, int32_t pointerx,
414 int32_t pointery)
415{
417 if(IS_NULL_PTR(g) || !self->enabled) return;
418 if(!g->draw_selected_region || !g->button_down) return;
419 if(g->posx_from == g->posx_to && g->posy_from == g->posy_to) return;
420
422 //const float wd = dev->roi.preview_width;
423 //const float ht = dev->roi.preview_height;
424 const float zoom_scale = dt_dev_get_overlay_scale(dev);
425
426 const float posx_from = fmin(g->posx_from, g->posx_to);
427 const float posx_to = fmax(g->posx_from, g->posx_to);
428 const float posy_from = fmin(g->posy_from, g->posy_to);
429 const float posy_to = fmax(g->posy_from, g->posy_to);
430
431 cairo_save(cr);
432 cairo_set_line_width(cr, 1.0 / zoom_scale);
433 cairo_set_source_rgb(cr, .2, .2, .2);
434
435 //cairo_translate(cr, width / 2.0, height / 2.0f);
436 //cairo_scale(cr, zoom_scale, zoom_scale);
437 //cairo_translate(cr, -.5f * wd - dev->roi.x * wd, -.5f * ht - dev->roi.y * ht);
439
440 cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
441
442 cairo_rectangle(cr, posx_from, posy_from, (posx_to - posx_from), (posy_to - posy_from));
443 cairo_stroke(cr);
444 cairo_translate(cr, 1.0 / zoom_scale, 1.0 / zoom_scale);
445 cairo_set_source_rgb(cr, .8, .8, .8);
446 cairo_rectangle(cr, posx_from + 1.0 / zoom_scale, posy_from, (posx_to - posx_from) - 3. / zoom_scale,
447 (posy_to - posy_from) - 2. / zoom_scale);
448 cairo_stroke(cr);
449
450 cairo_restore(cr);
451}
452
454{
455 (void)picker;
456 (void)piece;
457 if(darktable.gui->reset) return;
460
461 const dt_iop_order_iccprofile_info_t *const work_profile = dt_ioppr_get_pipe_current_profile_info(self, pipe);
462 p->middle_grey = (work_profile) ? (dt_ioppr_get_rgb_matrix_luminance(self->picked_color,
463 work_profile->matrix_in,
464 work_profile->lut_in,
465 work_profile->unbounded_coeffs_in,
466 work_profile->lutsize,
467 work_profile->nonlinearlut) * 100.f)
469
471 dt_bauhaus_slider_set(g->sl_middle_grey, p->middle_grey);
473
475}
476
477static inline float get_gamma(const float x, const float gamma)
478{
479 return powf(x, gamma);
480}
481
482static inline float get_lut_gamma(const float x, const float gamma, const float *const lut)
483{
484 return (x > 1.f) ? get_gamma(x, gamma) : lut[CLAMP((int)(x * 0x10000ul), 0, 0xffff)];
485}
486
487static inline float get_contrast(const float x, const float contrast, const float middle_grey,
488 const float inv_middle_grey)
489{
490 return powf(x * inv_middle_grey, contrast) * middle_grey;
491}
492
493static inline float get_lut_contrast(const float x, const float contrast, const float middle_grey,
494 const float inv_middle_grey, const float *const lut)
495{
496 return (x > 1.f) ? get_contrast(x, contrast, middle_grey, inv_middle_grey)
497 : lut[CLAMP((int)(x * 0x10000ul), 0, 0xffff)];
498}
499
500void tiling_callback(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, const struct dt_dev_pixelpipe_iop_t *piece, struct dt_develop_tiling_t *tiling)
501{
502 (void)self;
503 (void)pipe;
504 (void)piece;
505 tiling->factor = 2.0f;
506 tiling->factor_cl = 3.0f;
507 tiling->maxbuf = 1.0f;
508 tiling->maxbuf_cl = 1.0f;
509 tiling->overhead = 0;
510 tiling->overlap = 0;
511 tiling->xalign = 1;
512 tiling->yalign = 1;
513}
516{
519
520 memcpy(&d->params, params, sizeof(dt_iop_basicadj_params_t));
521
522 const float brightness = p->brightness * 2.f;
523 const float gamma = (brightness >= 0.0f) ? 1.0f / (1.0f + brightness) : (1.0f - brightness);
524 const float contrast = p->contrast + 1.0f;
525 const float middle_grey = (p->middle_grey > 0.f) ? (p->middle_grey / 100.f) : 0.1842f;
526 const float inv_middle_grey = 1.f / middle_grey;
527
528 const int process_gamma = (p->brightness != 0.f);
529 const int plain_contrast = (!p->preserve_colors && p->contrast != 0.f);
530
531 // Building the lut for values in the [0,1] range
532 if(process_gamma || plain_contrast)
533 {
534 for(unsigned int i = 0; i < 0x10000; i++)
535 {
536 const float percentage = (float)i / (float)0x10000ul;
537 if(process_gamma) d->lut_gamma[i] = get_gamma(percentage, gamma);
538 if(plain_contrast) d->lut_contrast[i] = get_contrast(percentage, contrast, middle_grey, inv_middle_grey);
539 }
540 }
541}
542
544{
546 piece->data_size = sizeof(dt_iop_basicadj_data_t);
547}
548
550{
551 dt_free_align(piece->data);
552 piece->data = NULL;
553}
554
555void gui_update(struct dt_iop_module_t *self)
556{
558
559 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(g->bt_select_region), g->draw_selected_region);
560}
561
562void gui_focus(struct dt_iop_module_t *self, gboolean in)
563{
564 if(!in) _turn_select_region_off(self);
565}
566
568{
570
571 g->call_auto_exposure = 0;
572 g->draw_selected_region = 0;
573 g->posx_from = g->posx_to = g->posy_from = g->posy_to = 0.f;
574 g->box_cood[0] = g->box_cood[1] = g->box_cood[2] = g->box_cood[3] = 0.f;
575 g->button_down = 0;
576}
577
578void gui_init(struct dt_iop_module_t *self)
579{
581
582 change_image(self);
583
584 self->widget = GTK_WIDGET(gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING));
585
586 g->sl_black_point = dt_bauhaus_slider_from_params(self, "black_point");
587 dt_bauhaus_slider_set_soft_range(g->sl_black_point, -0.1, 0.1);
588 dt_bauhaus_slider_set_digits(g->sl_black_point, 4);
589 gtk_widget_set_tooltip_text(g->sl_black_point, _("adjust the black level to unclip negative RGB values.\n"
590 "you should never use it to add more density in blacks!\n"
591 "if poorly set, it will clip near-black colors out of gamut\n"
592 "by pushing RGB values into negatives"));
593
594 g->sl_exposure = dt_bauhaus_slider_from_params(self, N_("exposure"));
595 dt_bauhaus_slider_set_soft_range(g->sl_exposure, -4.0, 4.0);
596 dt_bauhaus_slider_set_format(g->sl_exposure, _(" EV"));
597 gtk_widget_set_tooltip_text(g->sl_exposure, _("adjust the exposure correction"));
598
599 g->sl_hlcompr = dt_bauhaus_slider_from_params(self, "hlcompr");
600 dt_bauhaus_slider_set_soft_max(g->sl_hlcompr, 100.0);
601 gtk_widget_set_tooltip_text(g->sl_hlcompr, _("highlight compression adjustment"));
602
603 g->sl_contrast = dt_bauhaus_slider_from_params(self, N_("contrast"));
604 dt_bauhaus_slider_set_soft_range(g->sl_contrast, -1.0, 1.0);
605 gtk_widget_set_tooltip_text(g->sl_contrast, _("contrast adjustment"));
606
607 g->cmb_preserve_colors = dt_bauhaus_combobox_from_params(self, "preserve_colors") ;
608 gtk_widget_set_tooltip_text(g->cmb_preserve_colors, _("method to preserve colors when applying contrast"));
609
610 g->sl_middle_grey = dt_color_picker_new(self, DT_COLOR_PICKER_AREA,
611 dt_bauhaus_slider_from_params(self, "middle_grey"));
612 dt_bauhaus_slider_set_format(g->sl_middle_grey, "%");
613 gtk_widget_set_tooltip_text(g->sl_middle_grey, _("middle gray adjustment"));
614 g_signal_connect(G_OBJECT(g->sl_middle_grey), "quad-pressed", G_CALLBACK(_color_picker_callback), self);
615
616 g->sl_brightness = dt_bauhaus_slider_from_params(self, N_("brightness"));
617 dt_bauhaus_slider_set_soft_range(g->sl_brightness, -1.0, 1.0);
618 gtk_widget_set_tooltip_text(g->sl_brightness,_("brightness adjustment"));
619
620 g->sl_saturation = dt_bauhaus_slider_from_params(self, N_("saturation"));
621 gtk_widget_set_tooltip_text(g->sl_saturation,_("saturation adjustment"));
622
623 g->sl_vibrance = dt_bauhaus_slider_from_params(self, N_("vibrance"));
624 gtk_widget_set_tooltip_text(g->sl_vibrance, _("vibrance adjustment"));
625
626 GtkWidget *autolevels_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, DT_GUI_BOX_SPACING);
627
628 g->bt_auto_levels = dt_action_button_new(NULL, N_("auto"), _auto_levels_callback, self, _("apply auto exposure based on the entire image"), 0, 0);
629 gtk_widget_set_size_request(g->bt_auto_levels, -1, DT_PIXEL_APPLY_DPI(24));
630 gtk_box_pack_start(GTK_BOX(autolevels_box), g->bt_auto_levels, TRUE, TRUE, 0);
631
632 g->bt_select_region = dtgtk_togglebutton_new(dtgtk_cairo_paint_colorpicker, 0, NULL);
633
634 gtk_widget_set_tooltip_text(g->bt_select_region,
635 _("apply auto exposure based on a region defined by the user\n"
636 "click and drag to draw the area\n"
637 "right click to cancel"));
638 g_signal_connect(G_OBJECT(g->bt_select_region), "toggled", G_CALLBACK(_select_region_toggled_callback), self);
639 gtk_box_pack_start(GTK_BOX(autolevels_box), g->bt_select_region, TRUE, TRUE, 0);
640
641 gtk_box_pack_start(GTK_BOX(self->widget), autolevels_box, TRUE, TRUE, 0);
642
643 g->sl_clip = dt_bauhaus_slider_from_params(self, N_("clip"));
644 dt_bauhaus_slider_set_digits(g->sl_clip, 3);
645 gtk_widget_set_tooltip_text(g->sl_clip, _("adjusts clipping value for auto exposure calculation"));
646
647 // add signal handler for preview pipe finish
649 G_CALLBACK(_develop_ui_pipe_finished_callback), self);
650 // and profile change
652 G_CALLBACK(_signal_profile_user_changed), self);
653}
654
662
663static inline int64_t doubleToRawLongBits(double d)
664{
665 union {
666 double f;
667 int64_t i;
668 } tmp;
669 tmp.f = d;
670 return tmp.i;
671}
672
673static inline double longBitsToDouble(int64_t i)
674{
675 union {
676 double f;
677 int64_t i;
678 } tmp;
679 tmp.i = i;
680 return tmp.f;
681}
682
683static inline int ilogbp1(double d)
684{
685 const int m = d < 4.9090934652977266E-91;
686 d = m ? 2.037035976334486E90 * d : d;
687 int q = (doubleToRawLongBits(d) >> 52) & 0x7ff;
688 q = m ? q - (300 + 0x03fe) : q - 0x03fe;
689 return q;
690}
691
692// calculate x * 2^q
693static inline double ldexpk(double x, int32_t q)
694{
695 int32_t m = q < 0 ? -1 : 0;
696 m = (((m + q) >> 9) - m) << 7;
697 q = q - (m << 2);
698 double u = longBitsToDouble(((int64_t)(m + 0x3ff)) << 52);
699 double u2 = u * u;
700 u2 = u2 * u2;
701 x = x * u2;
702 u = longBitsToDouble(((int64_t)(q + 0x3ff)) << 52);
703 return x * u;
704}
705
706static inline double xlog(double d)
707{
708 const int e = ilogbp1(d * 0.7071);
709 const double m = ldexpk(d, -e);
710
711 double x = (m - 1) / (m + 1);
712 const double x2 = x * x;
713
714 double t = 0.148197055177935105296783;
715 t = fma(t, x2, 0.153108178020442575739679);
716 t = fma(t, x2, 0.181837339521549679055568);
717 t = fma(t, x2, 0.22222194152736701733275);
718 t = fma(t, x2, 0.285714288030134544449368);
719 t = fma(t, x2, 0.399999999989941956712869);
720 t = fma(t, x2, 0.666666666666685503450651);
721 t = fma(t, x2, 2);
722
723 x = x * t + 0.693147180559945286226764 * e;
724
725 if(!isfinite(d)) x = INFINITY;
726 if(d < 0) x = NAN;
727 if(d == 0) x = -INFINITY;
728
729 return x;
730}
731
732static inline double gamma2(double x)
733{
734 const double sRGBGammaCurve = 2.4;
735 return (x <= 0.00304) ? (x * 12.92) : (1.055 * exp(log(x) / sRGBGammaCurve) - 0.055);
736}
737
738static inline double igamma2(double x)
739{
740 const double sRGBGammaCurve = 2.4;
741 return (x <= 0.03928) ? (x / 12.92) : (exp(log((x + 0.055) / 1.055) * sRGBGammaCurve));
742}
743
745static int _get_auto_exp_histogram(const float *const img, const int width, const int height, int *box_area,
746 uint32_t **_histogram, unsigned int *_hist_size, int *_histcompr)
747{
748 int err = 0;
749 const int ch = 4;
750 const int histcompr = 3;
751 const unsigned int hist_size = 65536 >> histcompr;
752 uint32_t *histogram = NULL;
753 const float mul = hist_size;
754
756 sizeof(uint32_t) * hist_size,
757 0);
758 if(IS_NULL_PTR(histogram))
759 {
760 err = 1;
761 goto cleanup;
762 }
763
764 memset(histogram, 0, sizeof(uint32_t) * hist_size);
765
766 if(box_area[2] > box_area[0] && box_area[3] > box_area[1])
767 {
768 for(int y = box_area[1]; y <= box_area[3]; y++)
769 {
770 const float *const in = img + (size_t)ch * width * y;
771 for(int x = box_area[0]; x <= box_area[2]; x++)
772 {
773 const float *const pixel = in + x * ch;
774
775 for(int c = 0; c < 3; c++)
776 {
777 if(pixel[c] <= 0.f)
778 {
779 histogram[0]++;
780 }
781 else if(pixel[c] >= 1.f)
782 {
783 histogram[hist_size - 1]++;
784 }
785 else
786 {
787 const uint32_t R = (uint32_t)(pixel[c] * mul);
788 histogram[R]++;
789 }
790 }
791 }
792 }
793 }
794 else
795 {
796 for(int i = 0; i < width * height * ch; i += ch)
797 {
798 const float *const pixel = img + i;
799
800 for(int c = 0; c < 3; c++)
801 {
802 if(pixel[c] <= 0.f)
803 {
804 histogram[0]++;
805 }
806 else if(pixel[c] >= 1.f)
807 {
808 histogram[hist_size - 1]++;
809 }
810 else
811 {
812 const uint32_t R = (uint32_t)(pixel[c] * mul);
813 histogram[R]++;
814 }
815 }
816 }
817 }
818
819cleanup:
820 *_histogram = histogram;
821 *_hist_size = hist_size;
822 *_histcompr = histcompr;
823 return err;
824}
825
827static void _get_sum_and_average(const uint32_t *const histogram, const int hist_size, float *_sum, float *_avg)
828{
829 float sum = 0.f;
830 float avg = 0.f;
831
832 for(int i = 0; i < hist_size; i++)
833 {
834 float val = histogram[i];
835 sum += val;
836 avg += i * val;
837 }
838
839 avg /= sum;
840
841 *_sum = sum;
842 *_avg = avg;
843}
844
845static inline float hlcurve(const float level, const float hlcomp, const float hlrange)
846{
847 if(hlcomp > 0.0f)
848 {
849 float val = level + (hlrange - 1.f);
850
851 // to avoid division by zero
852 if(val == 0.0f)
853 {
854 val = 0.000001f;
855 }
856
857 float Y = val / hlrange;
858 Y *= hlcomp;
859
860 // to avoid log(<=0)
861 if(Y <= -1.0f)
862 {
863 Y = -.999999f;
864 }
865
866 float R = hlrange / (val * hlcomp);
867 return log1pf(Y) * R;
868 }
869 else
870 {
871 return 1.f;
872 }
873}
874
876static void _get_auto_exp(const uint32_t *const histogram, const unsigned int hist_size, const int histcompr,
877 const float defgain, const float clip, const float midgray, float *_expcomp,
878 float *_bright, float *_contr, float *_black, float *_hlcompr, float *_hlcomprthresh)
879{
880 float expcomp = 0.f;
881 float black = 0.f;
882 float bright = 0.f;
883 float contr = 0.f;
884 float hlcompr = 0.f;
885 float hlcomprthresh = 0.f;
886
887 float scale = 65536.0f;
888
889 const int imax = 65536 >> histcompr;
890 int overex = 0;
891 float sum = 0.f, hisum = 0.f, losum = 0.f;
892 float ave = 0.f;
893
894 // find average luminance
895 _get_sum_and_average(histogram, hist_size, &sum, &ave);
896
897 // find median of luminance
898 int median = 0, count = histogram[0];
899
900 while(count < sum / 2)
901 {
902 median++;
903 count += histogram[median];
904 }
905
906 if(median == 0 || ave < 1.f) // probably the image is a blackframe
907 {
908 expcomp = 0.f;
909 black = 0.f;
910 bright = 0.f;
911 contr = 0.f;
912 hlcompr = 0.f;
913 hlcomprthresh = 0.f;
914 goto cleanup;
915 }
916
917 // compute std dev on the high and low side of median
918 // and octiles of histogram
919 float octile[8] = { 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f }, ospread = 0.f;
920 count = 0;
921
922 int i = 0;
923
924 for(; i < MIN((int)ave, imax); i++)
925 {
926 if(count < 8)
927 {
928 octile[count] += histogram[i];
929
930 if(octile[count] > sum / 8.f || (count == 7 && octile[count] > sum / 16.f))
931 {
932 octile[count] = xlog(1. + (float)i) / log(2.f);
933 count++;
934 }
935 }
936
937 losum += histogram[i];
938 }
939
940 for(; i < imax; i++)
941 {
942 if(count < 8)
943 {
944 octile[count] += histogram[i];
945
946 if(octile[count] > sum / 8.f || (count == 7 && octile[count] > sum / 16.f))
947 {
948 octile[count] = xlog(1.f + (float)i) / log(2.f);
949 count++;
950 }
951 }
952
953 hisum += histogram[i];
954 }
955
956 // probably the image is a blackframe
957 if(losum == 0.f || hisum == 0.f)
958 {
959 expcomp = 0.f;
960 black = 0.f;
961 bright = 0.f;
962 contr = 0.f;
963 hlcompr = 0.f;
964 hlcomprthresh = 0.f;
965 goto cleanup;
966 }
967
968 // if very overxposed image
969 if(octile[6] > log1pf((float)imax) / log2(2.f)) //*** Is this correct? log2(2) == 1
970 {
971 octile[6] = 1.5f * octile[5] - 0.5f * octile[4];
972 overex = 2;
973 }
974
975 // if overexposed
976 if(octile[7] > log1pf((float)imax) / log2(2.f)) //*** Is this correct? log2(2) == 1
977 {
978 octile[7] = 1.5f * octile[6] - 0.5f * octile[5];
979 overex = 1;
980 }
981
982 // store values of octile[6] and octile[7] for calculation of exposure compensation
983 // if we don't do this and the pixture is underexposed, calculation of exposure compensation assumes
984 // that it's overexposed and calculates the wrong direction
985 float oct6, oct7;
986 oct6 = octile[6];
987 oct7 = octile[7];
988
989 for(int ii = 1; ii < 8; ii++)
990 {
991 if(octile[ii] == 0.0f)
992 {
993 octile[ii] = octile[ii - 1];
994 }
995 }
996
997 // compute weighted average separation of octiles
998 // for future use in contrast setting
999 for(int ii = 1; ii < 6; ii++)
1000 {
1001 ospread += (octile[ii + 1] - octile[ii])
1002 / MAX(0.5f, (ii > 2 ? (octile[ii + 1] - octile[3]) : (octile[3] - octile[ii])));
1003 }
1004
1005 ospread /= 5.f;
1006
1007 // probably the image is a blackframe
1008 if(ospread <= 0.f)
1009 {
1010 expcomp = 0.f;
1011 black = 0.f;
1012 bright = 0.f;
1013 contr = 0.f;
1014 hlcompr = 0.f;
1015 hlcomprthresh = 0.f;
1016 goto cleanup;
1017 }
1018
1019 // compute clipping points based on the original histograms (linear, without exp comp.)
1020 unsigned int clipped = 0;
1021 int rawmax = (imax)-1;
1022
1023 while(histogram[rawmax] + clipped <= 0 && rawmax > 1)
1024 {
1025 clipped += histogram[rawmax];
1026 rawmax--;
1027 }
1028
1029 // compute clipped white point
1030 unsigned int clippable = (int)(sum * clip);
1031 clipped = 0;
1032 int whiteclip = (imax)-1;
1033
1034 while(whiteclip > 1 && (histogram[whiteclip] + clipped) <= clippable)
1035 {
1036 clipped += histogram[whiteclip];
1037 whiteclip--;
1038 }
1039
1040 // compute clipped black point
1041 clipped = 0;
1042 int shc = 0;
1043
1044 while(shc < whiteclip - 1 && histogram[shc] + clipped <= clippable)
1045 {
1046 clipped += histogram[shc];
1047 shc++;
1048 }
1049
1050 // rescale to 65535 max
1051 rawmax <<= histcompr;
1052 whiteclip <<= histcompr;
1053 ave = ave * (1 << histcompr);
1054 median <<= histcompr;
1055 shc <<= histcompr;
1056
1057 // compute exposure compensation as geometric mean of the amount that
1058 // sets the mean or median at middle gray, and the amount that sets the estimated top
1059 // of the histogram at or near clipping.
1060 const float expcomp1 = (logf(midgray * scale / (ave - shc + midgray * shc))) / DT_M_LN2f;
1061 float expcomp2;
1062
1063 if(overex == 0) // image is not overexposed
1064 {
1065 expcomp2 = 0.5f * ((15.5f - histcompr - (2.f * oct7 - oct6)) + logf(scale / rawmax) / DT_M_LN2f);
1066 }
1067 else
1068 {
1069 expcomp2 = 0.5f * ((15.5f - histcompr - (2.f * octile[7] - octile[6])) + logf(scale / rawmax) / DT_M_LN2f);
1070 }
1071
1072 if(fabsf(expcomp1) - fabsf(expcomp2) > 1.f) // for great expcomp
1073 {
1074 expcomp = (expcomp1 * fabsf(expcomp2) + expcomp2 * fabsf(expcomp1)) / (fabsf(expcomp1) + fabsf(expcomp2));
1075 }
1076 else
1077 {
1078 expcomp = 0.5 * (double)expcomp1 + 0.5 * (double)expcomp2; // for small expcomp
1079 }
1080
1081 const float gain = expf(expcomp * DT_M_LN2f);
1082
1083 const float corr = sqrtf(gain * scale / rawmax);
1084 black = shc * corr;
1085
1086 // now tune hlcompr to bring back rawmax to 65535
1087 hlcomprthresh = 0.f;
1088 // this is a series approximation of the actual formula for comp,
1089 // which is a transcendental equation
1090 const float comp = (gain * ((float)whiteclip) / scale - 1.f) * 2.3f; // 2.3 instead of 2 to increase slightly comp
1091 hlcompr = (comp / (fmaxf(0.0f, expcomp) + 1.0f));
1092 hlcompr = fmaxf(0.f, fminf(100.f, hlcompr));
1093
1094 // now find brightness if gain didn't bring ave to midgray using
1095 // the envelope of the actual 'control cage' brightness curve for simplicity
1096 const float midtmp = gain * sqrtf(median * ave) / scale;
1097
1098 if(midtmp < 0.1f)
1099 {
1100 bright = (midgray - midtmp) * 15.0f / (midtmp);
1101 }
1102 else
1103 {
1104 bright = (midgray - midtmp) * 15.0f / (0.10833 - 0.0833f * midtmp);
1105 }
1106
1107 bright = 0.25f * MAX(0.f, bright);
1108
1109 // compute contrast that spreads the average spacing of octiles
1110 contr = (midgray * 100.f) * (1.1f - ospread);
1111 contr = MAX(0.f, MIN(100.f, contr));
1112 // take gamma into account
1113 double whiteclipg = gamma2(whiteclip * corr);
1114
1115 float gavg = 0.f;
1116
1117 float val = 0.f;
1118 const float increment = corr * (1 << histcompr);
1119
1120 for(int ii = 0; ii<65536>> histcompr; ii++)
1121 {
1122 // gavg += histogram[ii] * _get_LUTf(gamma2curve, gamma2curve_size, val);
1123 gavg += histogram[ii] * gamma2(val);
1124 val += increment;
1125 }
1126
1127 gavg /= sum;
1128
1129 if(black < gavg)
1130 {
1131 const int maxwhiteclip = (gavg - black) * 4 / 3
1132 + black; // don't let whiteclip be so large that the histogram average goes above 3/4
1133
1134 if(whiteclipg < maxwhiteclip)
1135 {
1136 whiteclipg = maxwhiteclip;
1137 }
1138 }
1139
1140 whiteclipg
1141 = igamma2(whiteclipg); // need to inverse gamma transform to get correct exposure compensation parameter
1142
1143 // correction with gamma
1144 black = (black / whiteclipg);
1145
1146 expcomp = CLAMP(expcomp, -5.0f, 12.0f);
1147
1148 bright = MAX(-100.f, MIN(bright, 100.f));
1149
1150cleanup:
1151 black /= 100.f;
1152 bright /= 100.f;
1153 contr /= 100.f;
1154
1155 if(isnan(expcomp))
1156 {
1157 expcomp = 0.f;
1158 fprintf(stderr, "[_get_auto_exp] expcomp is NaN!!!\n");
1159 }
1160 if(isnan(black))
1161 {
1162 black = 0.f;
1163 fprintf(stderr, "[_get_auto_exp] black is NaN!!!\n");
1164 }
1165 if(isnan(bright))
1166 {
1167 bright = 0.f;
1168 fprintf(stderr, "[_get_auto_exp] bright is NaN!!!\n");
1169 }
1170 if(isnan(contr))
1171 {
1172 contr = 0.f;
1173 fprintf(stderr, "[_get_auto_exp] contr is NaN!!!\n");
1174 }
1175 if(isnan(hlcompr))
1176 {
1177 hlcompr = 0.f;
1178 fprintf(stderr, "[_get_auto_exp] hlcompr is NaN!!!\n");
1179 }
1180 if(isnan(hlcomprthresh))
1181 {
1182 hlcomprthresh = 0.f;
1183 fprintf(stderr, "[_get_auto_exp] hlcomprthresh is NaN!!!\n");
1184 }
1185
1186 *_expcomp = expcomp;
1187 *_black = black;
1188 *_bright = bright;
1189 *_contr = contr;
1190 *_hlcompr = hlcompr;
1191 *_hlcomprthresh = hlcomprthresh;
1192}
1193
1194static inline __attribute__((always_inline)) int _auto_exposure(const float *const img, const int width, const int height, int *box_area,
1195 const float clip, const float midgray, float *_expcomp, float *_bright, float *_contr,
1196 float *_black, float *_hlcompr, float *_hlcomprthresh)
1197{
1198 uint32_t *histogram = NULL;
1199 unsigned int hist_size = 0;
1200 int histcompr = 0;
1201
1202 const float defGain = 0.0f;
1203
1204 if(_get_auto_exp_histogram(img, width, height, box_area, &histogram, &hist_size, &histcompr))
1205 {
1207 return 1;
1208 }
1209 _get_auto_exp(histogram, hist_size, histcompr, defGain, clip, midgray, _expcomp, _bright, _contr, _black,
1210 _hlcompr, _hlcomprthresh);
1211
1213 return 0;
1214}
1215
1217static void _get_selected_area(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe,
1218 const dt_dev_pixelpipe_iop_t *piece,
1219 dt_iop_basicadj_gui_data_t *g, const dt_iop_roi_t *const roi_in, int *box_out)
1220{
1221 box_out[0] = box_out[1] = box_out[2] = box_out[3] = 0;
1222
1223 if(!IS_NULL_PTR(g))
1224 {
1225 const int width = roi_in->width;
1226 const int height = roi_in->height;
1227 dt_boundingbox_t box_cood = { g->box_cood[0], g->box_cood[1], g->box_cood[2], g->box_cood[3] };
1228
1229 box_cood[0] *= pipe->iwidth;
1230 box_cood[1] *= pipe->iheight;
1231 box_cood[2] *= pipe->iwidth;
1232 box_cood[3] *= pipe->iheight;
1233
1235 box_cood, 2);
1236
1237 box_cood[0] *= roi_in->scale;
1238 box_cood[1] *= roi_in->scale;
1239 box_cood[2] *= roi_in->scale;
1240 box_cood[3] *= roi_in->scale;
1241
1242 box_cood[0] -= roi_in->x;
1243 box_cood[1] -= roi_in->y;
1244 box_cood[2] -= roi_in->x;
1245 box_cood[3] -= roi_in->y;
1246
1247 int box[4];
1248
1249 // re-order edges of bounding box
1250 box[0] = fminf(box_cood[0], box_cood[2]);
1251 box[1] = fminf(box_cood[1], box_cood[3]);
1252 box[2] = fmaxf(box_cood[0], box_cood[2]);
1253 box[3] = fmaxf(box_cood[1], box_cood[3]);
1254
1255 // do not continue if box is completely outside of roi
1256 if(!(box[0] >= width || box[1] >= height || box[2] < 0 || box[3] < 0))
1257 {
1258 // clamp bounding box to roi
1259 for(int k = 0; k < 4; k += 2) box[k] = MIN(width - 1, MAX(0, box[k]));
1260 for(int k = 1; k < 4; k += 2) box[k] = MIN(height - 1, MAX(0, box[k]));
1261
1262 // safety check: area needs to have minimum 1 pixel width and height
1263 if(!(box[2] - box[0] < 1 || box[3] - box[1] < 1))
1264 {
1265 box_out[0] = box[0];
1266 box_out[1] = box[1];
1267 box_out[2] = box[2];
1268 box_out[3] = box[3];
1269 }
1270 }
1271 }
1272}
1273
1275int process(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const void *const ivoid,
1276 void *const ovoid)
1277{
1278 const dt_iop_roi_t *const roi_in = &piece->roi_in;
1279 const dt_iop_roi_t *const roi_out = &piece->roi_out;
1280 const dt_iop_order_iccprofile_info_t *const work_profile = dt_ioppr_get_iop_work_profile_info(self, self->dev->iop);
1281
1282 const int ch = piece->dsc_in.channels;
1286
1287 // process auto levels
1288 if(!IS_NULL_PTR(g) && dt_dev_pixelpipe_has_preview_output(self->dev, pipe, roi_out))
1289 {
1291 if(g->call_auto_exposure == 1 && !darktable.gui->reset)
1292 {
1293 g->call_auto_exposure = -1;
1295
1296 memcpy(&g->params, p, sizeof(dt_iop_basicadj_params_t));
1297
1298 int box[4] = { 0 };
1299 _get_selected_area(self, pipe, piece, g, roi_in, box);
1300 if(_auto_exposure((const float *const)ivoid, roi_in->width, roi_in->height, box, g->params.clip,
1301 g->params.middle_grey / 100.f, &g->params.exposure, &g->params.brightness,
1302 &g->params.contrast, &g->params.black_point, &g->params.hlcompr, &g->params.hlcomprthresh))
1303 {
1304 return 1;
1305 }
1306
1308 g->call_auto_exposure = 2;
1310 }
1311 else
1312 {
1314 }
1315 }
1316
1317 const float black_point = p->black_point;
1318 const float hlcompr = p->hlcompr;
1319 const float hlcomprthresh = p->hlcomprthresh;
1320 const float saturation = p->saturation + 1.0f;
1321 const float vibrance = p->vibrance / 1.4f;
1322 const float contrast = p->contrast + 1.0f;
1323 const float white = exposure2white(p->exposure);
1324 const float scale = 1.0f / (white - p->black_point);
1325 const float middle_grey = (p->middle_grey > 0.f) ? (p->middle_grey / 100.f) : 0.1842f;
1326 const float inv_middle_grey = 1.f / middle_grey;
1327 const float brightness = p->brightness * 2.f;
1328 const float gamma = (brightness >= 0.0f) ? 1.0f / (1.0f + brightness) : (1.0f - brightness);
1329
1330 const float hlcomp = hlcompr / 100.0f;
1331 const float shoulder = ((hlcomprthresh / 100.f) / 8.0f) + 0.1f;
1332 const float hlrange = 1.0f - shoulder;
1333
1334 const int plain_contrast = (!p->preserve_colors && p->contrast != 0.f);
1335 const int preserve_colors = (p->contrast != 0.f) ? p->preserve_colors : 0;
1336 const int process_gamma = (p->brightness != 0.f);
1337 const int process_saturation_vibrance = (p->saturation != 0.f)||(p->vibrance != 0.f);
1338 const int process_hlcompr = (p->hlcompr > 0.f);
1339
1340 const float *const in = (const float *const)ivoid;
1341 float *const out = (float *const)ovoid;
1342 const size_t stride = (size_t)roi_out->height * roi_out->width * ch;
1344 for(size_t k = 0; k < stride; k += ch)
1345 {
1346 for(size_t c = 0; c < 3; c++)
1347 {
1348 // exposure
1349 out[k + c] = (in[k + c] - black_point) * scale;
1350 }
1351
1352 // highlight compression
1353 if(process_hlcompr)
1354 {
1355 const float lum = (work_profile) ? dt_ioppr_get_rgb_matrix_luminance(out + k,
1356 work_profile->matrix_in,
1357 work_profile->lut_in,
1358 work_profile->unbounded_coeffs_in,
1359 work_profile->lutsize,
1360 work_profile->nonlinearlut)
1362 if(lum > 0.f)
1363 {
1364 const float ratio = hlcurve(lum, hlcomp, hlrange);
1365
1366 for(size_t c = 0; c < 3; c++)
1367 {
1368 out[k + c] = (ratio * out[k + c]);
1369 }
1370 }
1371 }
1372
1373 for(size_t c = 0; c < 3; c++)
1374 {
1375 // gamma
1376 if(process_gamma && out[k + c] > 0.f) out[k + c] = get_lut_gamma(out[k + c], gamma, d->lut_gamma);
1377
1378 // contrast
1379 if(plain_contrast && out[k + c] > 0.f)
1380 out[k + c] = get_lut_contrast(out[k + c], contrast, middle_grey, inv_middle_grey, d->lut_contrast);
1381 }
1382
1383 // contrast (with preserve colors)
1384 if(preserve_colors != DT_RGB_NORM_NONE)
1385 {
1386 float ratio = 1.f;
1387 const float lum = dt_rgb_norm(out + k, preserve_colors, work_profile);
1388 if(lum > 0.f)
1389 {
1390 const float contrast_lum = powf(lum * inv_middle_grey, contrast) * middle_grey;
1391 ratio = contrast_lum / lum;
1392 }
1393
1394 for(size_t c = 0; c < 3; c++)
1395 {
1396 out[k + c] = (ratio * out[k + c]);
1397 }
1398 }
1399
1400 // saturation
1401 if(process_saturation_vibrance)
1402 {
1403 const float average = (out[k] + out[k+1] + out[k+2]) / 3;
1404 const float delta = sqrtf( (average-out[k])*(average-out[k])+(average-out[k+1])*(average-out[k+1])+(average-out[k+2])*(average-out[k+2]));
1405 const float P = vibrance * (1 - powf(delta, fabsf(vibrance)));
1406
1407 for(size_t c = 0; c < 3; c++)
1408 {
1409 out[k + c] = average + (saturation + P) * (out[k+c] - average);
1410 }
1411 }
1412
1413 out[k + 3] = in[k + 3];
1414 }
1415 return 0;
1416}
1417
1418#undef exposure2white
1419
1420// clang-format off
1421// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
1422// vim: shiftwidth=2 expandtab tabstop=2 cindent
1423// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
1424// clang-format on
#define TRUE
Definition ashift_lsd.c:162
void cleanup(dt_imageio_module_format_t *self)
Definition avif.c:164
#define m
Definition basecurve.c:278
static float get_lut_gamma(const float x, const float gamma, const float *const lut)
Definition basicadj.c:482
const char ** description(struct dt_iop_module_t *self)
Definition basicadj.c:163
int default_group()
Definition basicadj.c:172
__DT_CLONE_TARGETS__ int process(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const void *const ivoid, void *const ovoid)
Definition basicadj.c:1275
static __DT_CLONE_TARGETS__ void _get_sum_and_average(const uint32_t *const histogram, const int hist_size, float *_sum, float *_avg)
Definition basicadj.c:827
static __DT_CLONE_TARGETS__ void _get_auto_exp(const uint32_t *const histogram, const unsigned int hist_size, const int histcompr, const float defgain, const float clip, const float midgray, float *_expcomp, float *_bright, float *_contr, float *_black, float *_hlcompr, float *_hlcomprthresh)
Definition basicadj.c:876
static void _auto_levels_callback(GtkButton *button, dt_iop_module_t *self)
Definition basicadj.c:213
static double longBitsToDouble(int64_t i)
Definition basicadj.c:673
static float get_gamma(const float x, const float gamma)
Definition basicadj.c:477
static int ilogbp1(double d)
Definition basicadj.c:683
void commit_params(struct dt_iop_module_t *self, dt_iop_params_t *params, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition basicadj.c:514
#define exposure2white(x)
Definition basicadj.c:63
void gui_focus(struct dt_iop_module_t *self, gboolean in)
Definition basicadj.c:562
static float get_contrast(const float x, const float contrast, const float middle_grey, const float inv_middle_grey)
Definition basicadj.c:487
void init_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition basicadj.c:543
static void _signal_profile_user_changed(gpointer instance, uint8_t profile_type, gpointer user_data)
Definition basicadj.c:302
const char * name()
Definition basicadj.c:158
static double xlog(double d)
Definition basicadj.c:706
void gui_update(struct dt_iop_module_t *self)
Definition basicadj.c:555
static float get_lut_contrast(const float x, const float contrast, const float middle_grey, const float inv_middle_grey, const float *const lut)
Definition basicadj.c:493
void change_image(struct dt_iop_module_t *self)
Definition basicadj.c:567
static void _select_region_toggled_callback(GtkToggleButton *togglebutton, dt_iop_module_t *self)
Definition basicadj.c:239
void gui_init(struct dt_iop_module_t *self)
Definition basicadj.c:578
int button_pressed(struct dt_iop_module_t *self, double x, double y, double pressure, int which, int type, uint32_t state)
Definition basicadj.c:382
void gui_changed(dt_iop_module_t *self, GtkWidget *w, void *previous)
Definition basicadj.c:203
static __DT_CLONE_TARGETS__ int _get_auto_exp_histogram(const float *const img, const int width, const int height, int *box_area, uint32_t **_histogram, unsigned int *_hist_size, int *_histcompr)
Definition basicadj.c:745
static double igamma2(double x)
Definition basicadj.c:738
int button_released(struct dt_iop_module_t *self, double x, double y, int which, uint32_t state)
Definition basicadj.c:354
static void _turn_selregion_picker_off(struct dt_iop_module_t *self)
Definition basicadj.c:197
void tiling_callback(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, const struct dt_dev_pixelpipe_iop_t *piece, struct dt_develop_tiling_t *tiling)
Definition basicadj.c:500
static __DT_CLONE_TARGETS__ void _get_selected_area(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, dt_iop_basicadj_gui_data_t *g, const dt_iop_roi_t *const roi_in, int *box_out)
Definition basicadj.c:1217
int default_colorspace(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
Definition basicadj.c:182
static int64_t doubleToRawLongBits(double d)
Definition basicadj.c:663
static double gamma2(double x)
Definition basicadj.c:732
int flags()
Definition basicadj.c:177
void gui_post_expose(struct dt_iop_module_t *self, cairo_t *cr, int32_t width, int32_t height, int32_t pointerx, int32_t pointery)
Definition basicadj.c:413
static void _turn_select_region_off(struct dt_iop_module_t *self)
Definition basicadj.c:187
void gui_cleanup(struct dt_iop_module_t *self)
Definition basicadj.c:655
static void _develop_ui_pipe_finished_callback(gpointer instance, gpointer user_data)
Definition basicadj.c:266
static void _color_picker_callback(GtkWidget *button, dt_iop_module_t *self)
Definition basicadj.c:208
void cleanup_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition basicadj.c:549
const char * deprecated_msg()
Definition basicadj.c:153
int mouse_moved(struct dt_iop_module_t *self, double x, double y, double pressure, int which)
Definition basicadj.c:333
static double ldexpk(double x, int32_t q)
Definition basicadj.c:693
void color_picker_apply(dt_iop_module_t *self, GtkWidget *picker, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition basicadj.c:453
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 basicadj.c:115
static float hlcurve(const float level, const float hlcomp, const float hlrange)
Definition basicadj.c:845
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_soft_max(GtkWidget *widget, float val)
Definition bauhaus.c:1624
void dt_bauhaus_slider_set(GtkWidget *widget, float pos)
Definition bauhaus.c:3506
void dt_bauhaus_slider_set_format(GtkWidget *widget, const char *format)
Definition bauhaus.c:3598
int width
Definition bilateral.h:1
int height
Definition bilateral.h:1
static const dt_aligned_pixel_simd_t const dt_adaptation_t const float p
static float dt_camera_rgb_luminance(const float4 rgb)
@ IOP_CS_RGB
void dt_iop_color_picker_reset(dt_iop_module_t *module, gboolean keep)
GtkWidget * dt_color_picker_new(dt_iop_module_t *module, dt_iop_color_picker_kind_t kind, GtkWidget *w)
@ DT_COLOR_PICKER_AREA
@ DT_COLORSPACES_PROFILE_TYPE_WORK
Definition colorspaces.h:74
const dt_aligned_pixel_t f
const dt_colormatrix_t dt_aligned_pixel_t out
const float delta
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
#define P(V, params)
int type
void dt_control_queue_redraw_center()
request redraw of center window. This redraws the center view within a gdk critical section to preven...
Definition control.c:861
darktable_t darktable
Definition darktable.c:181
#define dt_free_align(ptr)
Definition darktable.h:481
static void * dt_calloc_align(size_t size)
Definition darktable.h:488
float dt_boundingbox_t[4]
Definition darktable.h:709
#define dt_pixelpipe_cache_alloc_align_cache(size, id)
Definition darktable.h:433
float dt_aligned_pixel_simd_t __attribute__((vector_size(16), aligned(16)))
Enable aggressive floating-point arithmetic optimizations, in denormals handling. Set through user pr...
Definition darktable.h:524
#define DT_MODULE_INTROSPECTION(MODVER, PARAMSTYPE)
Definition darktable.h:151
#define dt_pixelpipe_cache_free_align(mem)
Definition darktable.h:453
#define __DT_CLONE_TARGETS__
Definition darktable.h:367
#define __OMP_PARALLEL_FOR__(...)
Definition darktable.h:258
#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
static float dt_rgb_norm(const float4 in, const int norm, const int work_profile, constant dt_colorspaces_iccprofile_info_cl_t *profile_info, read_only image2d_t lut)
@ DT_RGB_NORM_NONE
#define dt_dev_add_history_item(dev, module, enable, redraw)
void dt_iop_params_t
Definition dev_history.h:41
#define dt_dev_pixelpipe_update_history_all(dev)
int dt_dev_distort_transform_plus(const dt_dev_pixelpipe_t *pipe, const double iop_order, const int transf_direction, float *points, size_t points_count)
Definition develop.c:1557
float dt_dev_get_overlay_scale(dt_develop_t *dev)
Get the overlay scale factor in GUI logical coordinates.
Definition develop.c:1712
void dt_dev_coordinates_image_norm_to_preview_abs(dt_develop_t *dev, float *points, size_t num_points)
Definition develop.c:1144
gboolean dt_dev_rescale_roi(dt_develop_t *dev, cairo_t *cr, int32_t width, int32_t height)
Scale the ROI to fit within given width/height, centered.
Definition develop.c:1824
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
void dt_dev_coordinates_widget_to_image_norm(dt_develop_t *dev, float *points, size_t num_points)
Coordinate conversion helpers between widget, normalized image, and absolute image spaces.
Definition develop.c:1003
void dt_dev_coordinates_image_abs_to_raw_norm(dt_develop_t *dev, float *points, size_t num_points)
Definition develop.c:1138
@ DT_DEV_TRANSFORM_DIR_BACK_INCL
Definition develop.h:105
void dtgtk_cairo_paint_colorpicker(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)
#define DT_GUI_BOX_SPACING
Definition gtk.h:109
#define DT_PIXEL_APPLY_DPI(value)
Definition gtk.h:90
void dt_iop_request_focus(dt_iop_module_t *module)
Definition imageop.c:2169
const char ** dt_iop_set_description(dt_iop_module_t *module, const char *main_text, const char *purpose, const char *input, const char *process, const char *output)
Definition imageop.c:3141
#define IOP_GUI_FREE
Definition imageop.h:602
static void dt_iop_gui_enter_critical_section(dt_iop_module_t *const module) ACQUIRE(&module -> gui_lock)
Definition imageop.h:413
@ IOP_FLAGS_DEPRECATED
Definition imageop.h:168
@ 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_EFFECTS
Definition imageop.h:142
#define IOP_GUI_ALLOC(module)
Definition imageop.h:599
GtkWidget * dt_bauhaus_slider_from_params(dt_iop_module_t *self, const char *param)
Definition imageop_gui.c:77
GtkWidget * dt_bauhaus_combobox_from_params(dt_iop_module_t *self, const char *param)
void *const ovoid
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)
dt_iop_order_iccprofile_info_t * dt_ioppr_get_iop_work_profile_info(struct dt_iop_module_t *module, GList *iop_list)
static const float x
const float *const lut
const int t
GtkWidget * dt_action_button_new(dt_lib_module_t *self, const gchar *label, gpointer callback, gpointer data, const gchar *tooltip, guint accel_key, GdkModifierType mods)
Definition lib.c:1563
float *const restrict const size_t k
float *const restrict const size_t const size_t ch
#define R
#define DT_M_LN2f
Definition math.h:55
#define median(a, n)
#define DT_DEBUG_CONTROL_SIGNAL_DISCONNECT(ctlsig, cb, user_data)
Definition signal.h:368
@ DT_SIGNAL_CONTROL_PROFILE_USER_CHANGED
This signal is raised when a profile is changed by the user 1 uint32_t : the profile type that has ch...
Definition signal.h:242
@ DT_SIGNAL_DEVELOP_PREVIEW_PIPE_FINISHED
This signal is raised when develop preview pipe process is finished no param, no returned value.
Definition signal.h:174
#define DT_DEBUG_CONTROL_SIGNAL_CONNECT(ctlsig, signal, cb, user_data)
Definition signal.h:357
struct _GtkWidget GtkWidget
Definition splash.h:29
const float uint32_t state[4]
const float u2
struct dt_gui_gtk_t * gui
Definition darktable.h:775
struct dt_control_signal_t * signals
Definition darktable.h:774
struct dt_develop_t * develop
Definition darktable.h:770
dt_iop_buffer_dsc_t dsc_in
struct dt_iop_module_t *void * data
GList * iop
Definition develop.h:279
int32_t reset
Definition gtk.h:172
float lut_contrast[0x10000]
Definition basicadj.c:112
dt_iop_basicadj_params_t params
Definition basicadj.c:110
float lut_gamma[0x10000]
Definition basicadj.c:111
GtkWidget * cmb_preserve_colors
Definition basicadj.c:100
GtkWidget * sl_black_point
Definition basicadj.c:96
GtkWidget * bt_auto_levels
Definition basicadj.c:93
dt_boundingbox_t box_cood
Definition basicadj.c:90
dt_iop_basicadj_params_t params
Definition basicadj.c:85
GtkWidget * bt_select_region
Definition basicadj.c:94
dt_iop_rgb_norms_t preserve_colors
Definition basicadj.c:74
unsigned int channels
Definition format.h:54
GtkDarktableToggleButton * off
Definition imageop.h:339
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
gboolean enabled
Definition imageop.h:298
dt_aligned_pixel_t picked_color
Definition imageop.h:272
dt_iop_params_t * params
Definition imageop.h:307
Region of interest passed through the pixelpipe.
Definition imageop.h:72
double scale
Definition imageop.h:74
typedef double((*spd)(unsigned long int wavelength, double TempK))
#define MIN(a, b)
Definition thinplate.c:32
#define MAX(a, b)
Definition thinplate.c:29
GtkWidget * dtgtk_togglebutton_new(DTGTKCairoPaintIconFunc paint, gint paintflags, void *paintdata)