Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
channelmixer.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2010-2011 Bruce Guenter.
4 Copyright (C) 2010-2012 Henrik Andersson.
5 Copyright (C) 2010-2013, 2016 johannes hanika.
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 Brian Teague.
11 Copyright (C) 2011 Olivier Tribout.
12 Copyright (C) 2011 Robert Bieber.
13 Copyright (C) 2011-2014, 2016, 2019 Tobias Ellinghaus.
14 Copyright (C) 2012 Alexandre Prokoudine.
15 Copyright (C) 2012 Richard Wonka.
16 Copyright (C) 2012, 2014, 2016-2017 Ulrich Pegelow.
17 Copyright (C) 2013 hal.
18 Copyright (C) 2013-2016 Roman Lebedev.
19 Copyright (C) 2013 Simon Spannagel.
20 Copyright (C) 2013 Thomas Pryds.
21 Copyright (C) 2015 Pedro Côrte-Real.
22 Copyright (C) 2017 Heiko Bauke.
23 Copyright (C) 2017 Matthieu Moy.
24 Copyright (C) 2018, 2020, 2022-2023, 2025-2026 Aurélien PIERRE.
25 Copyright (C) 2018 Edgardo Hoszowski.
26 Copyright (C) 2018 Maurizio Paglia.
27 Copyright (C) 2018-2022 Pascal Obry.
28 Copyright (C) 2018 rawfiner.
29 Copyright (C) 2019 Andreas Schneider.
30 Copyright (C) 2019 Diederik ter Rahe.
31 Copyright (C) 2020 Aldric Renaudin.
32 Copyright (C) 2020-2021 Chris Elston.
33 Copyright (C) 2020, 2022 Diederik Ter Rahe.
34 Copyright (C) 2020 Harold le Clément de Saint-Marcq.
35 Copyright (C) 2020-2021 Ralf Brown.
36 Copyright (C) 2022 Hanno Schwalm.
37 Copyright (C) 2022 Martin Bařinka.
38 Copyright (C) 2022 Philipp Lutz.
39
40 darktable is free software: you can redistribute it and/or modify
41 it under the terms of the GNU General Public License as published by
42 the Free Software Foundation, either version 3 of the License, or
43 (at your option) any later version.
44
45 darktable is distributed in the hope that it will be useful,
46 but WITHOUT ANY WARRANTY; without even the implied warranty of
47 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
48 GNU General Public License for more details.
49
50 You should have received a copy of the GNU General Public License
51 along with darktable. If not, see <http://www.gnu.org/licenses/>.
52*/
53#ifdef HAVE_CONFIG_H
54#include "config.h"
55#endif
56#include "bauhaus/bauhaus.h"
57#include "common/colorspaces.h"
58#include "common/debug.h"
59#include "common/math.h"
60#include "common/opencl.h"
61#include "control/control.h"
62#include "develop/develop.h"
63#include "develop/imageop.h"
66
67#include "gui/gtk.h"
68#include "gui/presets.h"
69#include "iop/iop_api.h"
70
71#include <assert.h>
72#include <gtk/gtk.h>
73#include <inttypes.h>
74#include <math.h>
75#include <stdlib.h>
76#include <string.h>
77
92
112
118
120{
122 float red[CHANNEL_SIZE]; // $MIN: -1.0 $MAX: 1.0
124 float green[CHANNEL_SIZE]; // $MIN: -1.0 $MAX: 1.0
126 float blue[CHANNEL_SIZE]; // $MIN: -1.0 $MAX: 1.0
130
137
145
152
153const char *name()
154{
155 return _("channel mixer");
156}
157
158const char *deprecated_msg()
159{
160 return _("this module is deprecated. please use the color calibration module instead.");
161}
162
163const char **description(struct dt_iop_module_t *self)
164{
165 return dt_iop_set_description(self, _("perform color space corrections\n"
166 "such as white balance, channels mixing\n"
167 "and conversions to monochrome emulating film"),
168 _("corrective or creative"),
169 _("linear, RGB, display-referred"),
170 _("linear, RGB"),
171 _("linear, RGB, display-referred"));
172}
173
174
179
181{
182 return IOP_GROUP_COLOR;
183}
184
186{
187 return IOP_CS_RGB;
188}
189
190int legacy_params(dt_iop_module_t *self, const void *const old_params, const int old_version, void *new_params,
191 const int new_version)
192{
193 if(old_version == 1 && new_version == 2)
194 {
195 typedef struct dt_iop_channelmixer_params_v1_t
196 {
197 float red[7];
198 float green[7];
199 float blue[7];
200 } dt_iop_channelmixer_params_v1_t;
201
202 const dt_iop_channelmixer_params_v1_t *old = (dt_iop_channelmixer_params_v1_t *)old_params;
205
206 *new = *defaults; // start with a fresh copy of default parameters
208
209 // copy gray mixing parameters
210 new->red[CHANNEL_GRAY] = old->red[6];
211 new->green[CHANNEL_GRAY] = old->green[6];
212 new->blue[CHANNEL_GRAY] = old->blue[6];
213
214 // version 1 does not use RGB mixing when gray is enabled
215 if(new->red[CHANNEL_GRAY] == 0.0f && new->green[CHANNEL_GRAY] == 0.0f && new->blue[CHANNEL_GRAY] == 0.0f)
216 {
217 for(int i = 0; i < 3; i++)
218 {
219 new->red[CHANNEL_RED + i] = old->red[3 + i];
220 new->green[CHANNEL_RED + i] = old->green[3 + i];
221 new->blue[CHANNEL_RED + i] = old->blue[3 + i];
222 }
223 }
224
225 // copy HSL mixing parameters
226 for(int i = 0; i < 3; i++)
227 {
228 new->red[i] = old->red[i];
229 new->green[i] = old->green[i];
230 new->blue[i] = old->blue[i];
231 }
232 return 0;
233 }
234 return 1;
235}
236
238static void process_hsl_v1(const dt_dev_pixelpipe_iop_t *piece, const float *const restrict in,
239 float *const restrict out, const dt_iop_roi_t *const roi_out)
240{
242 const float *const restrict hsl_matrix = data->hsl_matrix;
243 const float *const restrict rgb_matrix = data->rgb_matrix;
244 const int ch = piece->dsc_in.channels;
245 const size_t pixel_count = (size_t)ch * roi_out->width * roi_out->height;
247 for(size_t k = 0; k < pixel_count; k += ch)
248 {
249 float h, s, l, hmix, smix, lmix;
251
252 // Calculate the HSL mix
253 hmix = clamp_simd(in[k + 0] * hsl_matrix[0]) + (in[k + 1] * hsl_matrix[1]) + (in[k + 2] * hsl_matrix[2]);
254 smix = clamp_simd(in[k + 0] * hsl_matrix[3]) + (in[k + 1] * hsl_matrix[4]) + (in[k + 2] * hsl_matrix[5]);
255 lmix = clamp_simd(in[k + 0] * hsl_matrix[6]) + (in[k + 1] * hsl_matrix[7]) + (in[k + 2] * hsl_matrix[8]);
256
257 // If HSL mix is used apply to out[]
258 if(hmix != 0.0f || smix != 0.0f || lmix != 0.0f)
259 {
260 // mix into HSL output channels
261 rgb2hsl(&(in[k]), &h, &s, &l);
262 h = (hmix != 0.0f) ? hmix : h;
263 s = (smix != 0.0f) ? smix : s;
264 l = (lmix != 0.0f) ? lmix : l;
265 hsl2rgb(rgb, h, s, l);
266 }
267 else // no HSL copy in[] to out[]
268 {
269 for_each_channel(c,aligned(rgb,in)) rgb[c] = in[k + c];
270 }
271
272 // Calculate RGB mix
273 for(int i = 0, j = 0; i < 3; i++, j += 3)
274 {
275 out[k + i] = clamp_simd(rgb_matrix[j + 0] * rgb[0]
276 + rgb_matrix[j + 1] * rgb[1]
277 + rgb_matrix[j + 2] * rgb[2]);
278 }
279 }
280}
281
283static void process_hsl_v2(const dt_dev_pixelpipe_iop_t *piece, const float *const restrict in,
284 float *const restrict out, const dt_iop_roi_t *const roi_out)
285{
287 const float *const restrict hsl_matrix = data->hsl_matrix;
288 const float *const restrict rgb_matrix = data->rgb_matrix;
289 const int ch = piece->dsc_in.channels;
290 const size_t pixel_count = (size_t)ch * roi_out->width * roi_out->height;
292 for(size_t k = 0; k < pixel_count; k += ch)
293 {
294 dt_aligned_pixel_t rgb = { in[k], in[k + 1], in[k + 2] };
295
296 dt_aligned_pixel_t hsl_mix;
297 for(int i = 0, j = 0; i < 3; i++, j += 3)
298 {
299 hsl_mix[i] = clamp_simd(hsl_matrix[j + 0] * rgb[0]
300 + hsl_matrix[j + 1] * rgb[1]
301 + hsl_matrix[j + 2] * rgb[2]);
302 }
303
304 // If HSL mix is used apply to out[]
305 if(hsl_mix[0] != 0.0 || hsl_mix[1] != 0.0 || hsl_mix[2] != 0.0)
306 {
308 // rgb2hsl expects all values to be clipped
310 {
311 rgb[c] = clamp_simd(rgb[c]);
312 }
313 // mix into HSL output channels
314 rgb2hsl(rgb, &hsl[0], &hsl[1], &hsl[2]);
315 for(int i = 0; i < 3; i++)
316 {
317 hsl[i] = (hsl_mix[i] != 0.0f) ? hsl_mix[i] : hsl[i];
318 }
319 hsl2rgb(rgb, hsl[0], hsl[1], hsl[2]);
320 }
321
322 // Calculate RGB mix
323 for(int i = 0, j = 0; i < 3; i++, j += 3)
324 {
325 out[k + i] = fmaxf(rgb_matrix[j + 0] * rgb[0]
326 + rgb_matrix[j + 1] * rgb[1]
327 + rgb_matrix[j + 2] * rgb[2], 0.0f);
328 }
329 }
330}
331
333static void process_rgb(const dt_dev_pixelpipe_iop_t *piece, const float *const restrict in,
334 float *const restrict out, const dt_iop_roi_t *const roi_out)
335{
337 const float *const restrict rgb_matrix = data->rgb_matrix;
338 const int ch = piece->dsc_in.channels;
339 const size_t pixel_count = (size_t)ch * roi_out->width * roi_out->height;
341 for(size_t k = 0; k < pixel_count; k += ch)
342 {
343 for(int i = 0, j = 0; i < 3; i++, j += 3)
344 {
345 out[k + i] = fmaxf(rgb_matrix[j + 0] * in[k + 0]
346 + rgb_matrix[j + 1] * in[k + 1]
347 + rgb_matrix[j + 2] * in[k + 2], 0.0f);
348 }
349 }
350}
351
353static void process_gray(const dt_dev_pixelpipe_iop_t *piece, const float *const restrict in,
354 float *const restrict out, const dt_iop_roi_t *const roi_out)
355{
357 const float *const restrict rgb_matrix = data->rgb_matrix;
358 const int ch = piece->dsc_in.channels;
359 const size_t pixel_count = (size_t)ch * roi_out->width * roi_out->height;
361 for(size_t k = 0; k < pixel_count; k += ch)
362 {
363 float gray = fmaxf(rgb_matrix[0] * in[k + 0]
364 + rgb_matrix[1] * in[k + 1]
365 + rgb_matrix[2] * in[k + 2], 0.0f);
366 out[k + 0] = gray;
367 out[k + 1] = gray;
368 out[k + 2] = gray;
369 }
370}
371
372int process(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const void *const ivoid,
373 void *const ovoid)
374{
375 const dt_iop_roi_t *const roi_out = &piece->roi_out;
377 switch (data->operation_mode)
378 {
380 process_rgb(piece, (const float *const restrict)ivoid, (float *const restrict)ovoid, roi_out);
381 break;
383 process_gray(piece, (const float *const restrict)ivoid, (float *const restrict)ovoid, roi_out);
384 break;
386 process_hsl_v1(piece, (const float *const restrict)ivoid, (float *const restrict)ovoid, roi_out);
387 break;
389 process_hsl_v2(piece, (const float *const restrict)ivoid, (float *const restrict)ovoid, roi_out);
390 break;
391 default:
392 break;
393 }
394 if(pipe->mask_display & DT_DEV_PIXELPIPE_DISPLAY_MASK) dt_iop_alpha_copy(ivoid, ovoid, roi_out->width, roi_out->height);
395 return 0;
396}
397
398static void red_callback(GtkWidget *slider, gpointer user_data)
399{
400 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
401 if(darktable.gui->reset) return;
404 const int output_channel_index = dt_bauhaus_combobox_get(g->output_channel);
405 const float value = dt_bauhaus_slider_get(slider);
406 if(output_channel_index >= 0 && value != p->red[output_channel_index])
407 {
408 p->red[output_channel_index] = value;
410 }
411}
412
413static void green_callback(GtkWidget *slider, gpointer user_data)
414{
415 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
416 if(darktable.gui->reset) return;
419 const int output_channel_index = dt_bauhaus_combobox_get(g->output_channel);
420 const float value = dt_bauhaus_slider_get(slider);
421 if(output_channel_index >= 0 && value != p->green[output_channel_index])
422 {
423 p->green[output_channel_index] = value;
425 }
426}
427
428static void blue_callback(GtkWidget *slider, gpointer user_data)
429{
430 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
431 if(darktable.gui->reset) return;
434 const int output_channel_index = dt_bauhaus_combobox_get(g->output_channel);
435 const float value = dt_bauhaus_slider_get(slider);
436 if(output_channel_index >= 0 && value != p->blue[output_channel_index])
437 {
438 p->blue[output_channel_index] = value;
440 }
441}
442
443static void output_callback(GtkComboBox *combo, gpointer user_data)
444{
445 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
446 if(darktable.gui->reset) return;
449
450 const int output_channel_index = dt_bauhaus_combobox_get(g->output_channel);
451 if(output_channel_index >= 0)
452 {
453 dt_bauhaus_slider_set(g->scale_red, p->red[output_channel_index]);
454 dt_bauhaus_slider_set_default(g->scale_red, output_channel_index == CHANNEL_RED ? 1.0 : 0.0);
455 dt_bauhaus_slider_set(g->scale_green, p->green[output_channel_index]);
456 dt_bauhaus_slider_set_default(g->scale_green, output_channel_index == CHANNEL_GREEN ? 1.0 : 0.0);
457 dt_bauhaus_slider_set(g->scale_blue, p->blue[output_channel_index]);
458 dt_bauhaus_slider_set_default(g->scale_blue, output_channel_index == CHANNEL_BLUE ? 1.0 : 0.0);
459 }
460}
461
464{
467
468 // HSL mixer matrix
469 gboolean hsl_mix_mode = FALSE;
470 for(int i = CHANNEL_HUE, k = 0; i <= CHANNEL_LIGHTNESS; i++, k += 3)
471 {
472 d->hsl_matrix[k + 0] = p->red[i];
473 d->hsl_matrix[k + 1] = p->green[i];
474 d->hsl_matrix[k + 2] = p->blue[i];
475 hsl_mix_mode |= p->red[i] != 0.0f || p->green[i] != 0.0f || p->blue[i] != 0.0f;
476 }
477
478 // RGB mixer matrix
479 for(int i = CHANNEL_RED, k = 0; i <= CHANNEL_BLUE; i++, k += 3)
480 {
481 d->rgb_matrix[k + 0] = p->red[i];
482 d->rgb_matrix[k + 1] = p->green[i];
483 d->rgb_matrix[k + 2] = p->blue[i];
484 }
485
486 // Gray
487 dt_aligned_pixel_t graymix = { p->red[CHANNEL_GRAY], p->green[CHANNEL_GRAY], p->blue[CHANNEL_GRAY] };
488 const gboolean gray_mix_mode = (graymix[0] != 0.0f || graymix[1] != 0.0f || graymix[2] != 0.0f) ? TRUE : FALSE;
489
490 // Recompute the 3x3 RGB matrix
491 if(gray_mix_mode)
492 {
493 dt_aligned_pixel_t mixed_gray;
494 for(int i = 0; i < 3; i++)
495 {
496 mixed_gray[i] = (graymix[0] * d->rgb_matrix[i]
497 + graymix[1] * d->rgb_matrix[i + 3]
498 + graymix[2] * d->rgb_matrix[i + 6]);
499 }
500 for(int i = 0; i < 9; i += 3)
501 {
502 for(int j = 0; j < 3; j++)
503 {
504 d->rgb_matrix[i + j] = mixed_gray[j];
505 }
506 }
507 }
508
509 if(p->algorithm_version == CHANNEL_MIXER_VERSION_1)
510 {
511 d->operation_mode = OPERATION_MODE_HSL_V1;
512 }
513 else if(hsl_mix_mode)
514 {
515 d->operation_mode = OPERATION_MODE_HSL_V2;
516 }
517 else if(gray_mix_mode)
518 {
519 d->operation_mode = OPERATION_MODE_GRAY;
520 }
521 else
522 {
523 d->operation_mode = OPERATION_MODE_RGB;
524 }
525}
526
532
534{
535 dt_free_align(piece->data);
536 piece->data = NULL;
537}
538
539void gui_update(struct dt_iop_module_t *self)
540{
543
544 const int output_channel_index = dt_bauhaus_combobox_get(g->output_channel);
545 if(output_channel_index >= 0)
546 {
547 dt_bauhaus_slider_set(g->scale_red, p->red[output_channel_index]);
548 dt_bauhaus_slider_set(g->scale_green, p->green[output_channel_index]);
549 dt_bauhaus_slider_set(g->scale_blue, p->blue[output_channel_index]);
550 }
551}
552
554{
555 dt_iop_default_init(module);
556
557 dt_iop_channelmixer_params_t *d = module->default_params;
558
560 d->red[CHANNEL_RED] = d->green[CHANNEL_GREEN] = d->blue[CHANNEL_BLUE] = 1.0;
561}
562
563void gui_init(struct dt_iop_module_t *self)
564{
567
568 self->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING);
569
570 /* output */
571 g->output_channel = dt_bauhaus_combobox_new(darktable.bauhaus, DT_GUI_MODULE(self));
572 dt_bauhaus_widget_set_label(g->output_channel, N_("destination"));
573 dt_bauhaus_combobox_add(g->output_channel, _("hue"));
574 dt_bauhaus_combobox_add(g->output_channel, _("saturation"));
575 dt_bauhaus_combobox_add(g->output_channel, _("lightness"));
576 dt_bauhaus_combobox_add(g->output_channel, _("red"));
577 dt_bauhaus_combobox_add(g->output_channel, _("green"));
578 dt_bauhaus_combobox_add(g->output_channel, _("blue"));
579 dt_bauhaus_combobox_add(g->output_channel, C_("channelmixer", "gray"));
580 dt_bauhaus_combobox_set(g->output_channel, CHANNEL_RED);
581 g_signal_connect(G_OBJECT(g->output_channel), "value-changed", G_CALLBACK(output_callback), self);
582
583 /* red */
584 g->scale_red = dt_bauhaus_slider_new_with_range(darktable.bauhaus, DT_GUI_MODULE(self), -2.0, 2.0, 0, p->red[CHANNEL_RED], 3);
585 gtk_widget_set_tooltip_text(g->scale_red, _("amount of red channel in the output channel"));
586 dt_bauhaus_widget_set_label(g->scale_red, N_("red"));
587 g_signal_connect(G_OBJECT(g->scale_red), "value-changed", G_CALLBACK(red_callback), self);
588
589 /* green */
590 g->scale_green = dt_bauhaus_slider_new_with_range(darktable.bauhaus, DT_GUI_MODULE(self), -2.0, 2.0, 0, p->green[CHANNEL_RED], 3);
591 gtk_widget_set_tooltip_text(g->scale_green, _("amount of green channel in the output channel"));
592 dt_bauhaus_widget_set_label(g->scale_green, N_("green"));
593 g_signal_connect(G_OBJECT(g->scale_green), "value-changed", G_CALLBACK(green_callback), self);
594
595 /* blue */
596 g->scale_blue = dt_bauhaus_slider_new_with_range(darktable.bauhaus, DT_GUI_MODULE(self), -2.0, 2.0, 0, p->blue[CHANNEL_RED], 3);
597 gtk_widget_set_tooltip_text(g->scale_blue, _("amount of blue channel in the output channel"));
598 dt_bauhaus_widget_set_label(g->scale_blue, N_("blue"));
599 g_signal_connect(G_OBJECT(g->scale_blue), "value-changed", G_CALLBACK(blue_callback), self);
600
601
602 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(g->output_channel), TRUE, TRUE, 0);
603
604 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(g->scale_red), TRUE, TRUE, 0);
605 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(g->scale_green), TRUE, TRUE, 0);
606 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(g->scale_blue), TRUE, TRUE, 0);
607}
608
610{
612
613 dt_gui_presets_add_generic(_("swap R and B"), self->op, self->version(),
614 &(dt_iop_channelmixer_params_t){ { 0, 0, 0, 0, 0, 1, 0 },
615 { 0, 0, 0, 0, 1, 0, 0 },
616 { 0, 0, 0, 1, 0, 0, 0 },
619 dt_gui_presets_add_generic(_("swap G and B"), self->op, self->version(),
620 &(dt_iop_channelmixer_params_t){ { 0, 0, 0, 1, 0, 0, 0 },
621 { 0, 0, 0, 0, 0, 1, 0 },
622 { 0, 0, 0, 0, 1, 0, 0 },
625 dt_gui_presets_add_generic(_("color contrast boost"), self->op, self->version(),
626 &(dt_iop_channelmixer_params_t){ { 0, 0, 0.8, 1, 0, 0, 0 },
627 { 0, 0, 0.1, 0, 1, 0, 0 },
628 { 0, 0, 0.1, 0, 0, 1, 0 },
631 dt_gui_presets_add_generic(_("color details boost"), self->op, self->version(),
632 &(dt_iop_channelmixer_params_t){ { 0, 0, 0.1, 1, 0, 0, 0 },
633 { 0, 0, 0.8, 0, 1, 0, 0 },
634 { 0, 0, 0.1, 0, 0, 1, 0 },
637 dt_gui_presets_add_generic(_("color artifacts boost"), self->op, self->version(),
638 &(dt_iop_channelmixer_params_t){ { 0, 0, 0.1, 1, 0, 0, 0 },
639 { 0, 0, 0.1, 0, 1, 0, 0 },
640 { 0, 0, 0.8, 0, 0, 1, 0 },
643 dt_gui_presets_add_generic(_("B/W luminance-based"), self->op, self->version(),
644 &(dt_iop_channelmixer_params_t){ { 0, 0, 0, 1, 0, 0, 0.21 },
645 { 0, 0, 0, 0, 1, 0, 0.72 },
646 { 0, 0, 0, 0, 0, 1, 0.07 },
649 dt_gui_presets_add_generic(_("B/W artifacts boost"), self->op, self->version(),
650 &(dt_iop_channelmixer_params_t){ { 0, 0, 0, 1, 0, 0, -0.275 },
651 { 0, 0, 0, 0, 1, 0, -0.275 },
652 { 0, 0, 0, 0, 0, 1, 1.275 },
655 dt_gui_presets_add_generic(_("B/W smooth skin"), self->op, self->version(),
656 &(dt_iop_channelmixer_params_t){ { 0, 0, 0, 1, 0, 0, 1.0 },
657 { 0, 0, 0, 0, 1, 0, 0.325 },
658 { 0, 0, 0, 0, 0, 1, -0.4 },
661 dt_gui_presets_add_generic(_("B/W blue artifacts reduce"), self->op, self->version(),
662 &(dt_iop_channelmixer_params_t){ { 0, 0, 0, 1, 0, 0, 0.4 },
663 { 0, 0, 0, 0, 1, 0, 0.750 },
664 { 0, 0, 0, 0, 0, 1, -0.15 },
667
668 dt_gui_presets_add_generic(_("B/W Ilford Delta 100-400"), self->op, self->version(),
669 &(dt_iop_channelmixer_params_t){ { 0, 0, 0, 1, 0, 0, 0.21 },
670 { 0, 0, 0, 0, 1, 0, 0.42 },
671 { 0, 0, 0, 0, 0, 1, 0.37 },
674
675 dt_gui_presets_add_generic(_("B/W Ilford Delta 3200"), self->op, self->version(),
676 &(dt_iop_channelmixer_params_t){ { 0, 0, 0, 1, 0, 0, 0.31 },
677 { 0, 0, 0, 0, 1, 0, 0.36 },
678 { 0, 0, 0, 0, 0, 1, 0.33 },
681
682 dt_gui_presets_add_generic(_("B/W Ilford FP4"), self->op, self->version(),
683 &(dt_iop_channelmixer_params_t){ { 0, 0, 0, 1, 0, 0, 0.28 },
684 { 0, 0, 0, 0, 1, 0, 0.41 },
685 { 0, 0, 0, 0, 0, 1, 0.31 },
688
689 dt_gui_presets_add_generic(_("B/W Ilford HP5"), self->op, self->version(),
690 &(dt_iop_channelmixer_params_t){ { 0, 0, 0, 1, 0, 0, 0.23 },
691 { 0, 0, 0, 0, 1, 0, 0.37 },
692 { 0, 0, 0, 0, 0, 1, 0.40 },
695
696 dt_gui_presets_add_generic(_("B/W Ilford SFX"), self->op, self->version(),
697 &(dt_iop_channelmixer_params_t){ { 0, 0, 0, 1, 0, 0, 0.36 },
698 { 0, 0, 0, 0, 1, 0, 0.31 },
699 { 0, 0, 0, 0, 0, 1, 0.33 },
702
703 dt_gui_presets_add_generic(_("B/W Kodak T-Max 100"), self->op, self->version(),
704 &(dt_iop_channelmixer_params_t){ { 0, 0, 0, 1, 0, 0, 0.24 },
705 { 0, 0, 0, 0, 1, 0, 0.37 },
706 { 0, 0, 0, 0, 0, 1, 0.39 },
709
710 dt_gui_presets_add_generic(_("B/W Kodak T-max 400"), self->op, self->version(),
711 &(dt_iop_channelmixer_params_t){ { 0, 0, 0, 1, 0, 0, 0.27 },
712 { 0, 0, 0, 0, 1, 0, 0.36 },
713 { 0, 0, 0, 0, 0, 1, 0.37 },
716
717 dt_gui_presets_add_generic(_("B/W Kodak Tri-X 400"), self->op, self->version(),
718 &(dt_iop_channelmixer_params_t){ { 0, 0, 0, 1, 0, 0, 0.25 },
719 { 0, 0, 0, 0, 1, 0, 0.35 },
720 { 0, 0, 0, 0, 0, 1, 0.40 },
723
724
726}
727
728// clang-format off
729// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
730// vim: shiftwidth=2 expandtab tabstop=2 cindent
731// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
732// clang-format on
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
void dt_bauhaus_slider_set_default(GtkWidget *widget, float def)
Definition bauhaus.c:1640
float dt_bauhaus_slider_get(GtkWidget *widget)
Definition bauhaus.c:3483
int dt_bauhaus_combobox_get(GtkWidget *widget)
Definition bauhaus.c:2347
void dt_bauhaus_slider_set(GtkWidget *widget, float pos)
Definition bauhaus.c:3506
void dt_bauhaus_combobox_set(GtkWidget *widget, const int pos)
Definition bauhaus.c:2301
void dt_bauhaus_widget_set_label(GtkWidget *widget, const char *label)
Definition bauhaus.c:1653
GtkWidget * dt_bauhaus_slider_new_with_range(dt_bauhaus_t *bh, dt_gui_module_t *self, float min, float max, float step, float defval, int digits)
Definition bauhaus.c:1780
GtkWidget * dt_bauhaus_combobox_new(dt_bauhaus_t *bh, dt_gui_module_t *self)
Definition bauhaus.c:1842
void dt_bauhaus_combobox_add(GtkWidget *widget, const char *text)
Definition bauhaus.c:2016
@ DEVELOP_BLEND_CS_RGB_DISPLAY
Definition blend.h:59
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)
void init(dt_iop_module_t *module)
const char ** description(struct dt_iop_module_t *self)
int default_group()
static void red_callback(GtkWidget *slider, gpointer user_data)
_channelmixer_algorithm_t
@ CHANNEL_MIXER_VERSION_1
@ CHANNEL_MIXER_VERSION_2
_channelmixer_operation_mode_t
@ OPERATION_MODE_HSL_V1
@ OPERATION_MODE_RGB
@ OPERATION_MODE_GRAY
@ OPERATION_MODE_HSL_V2
static void output_callback(GtkComboBox *combo, gpointer user_data)
static void blue_callback(GtkWidget *slider, gpointer user_data)
static __DT_CLONE_TARGETS__ void process_gray(const dt_dev_pixelpipe_iop_t *piece, const float *const restrict in, float *const restrict out, const dt_iop_roi_t *const roi_out)
void init_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
_channelmixer_output_t
@ CHANNEL_HUE
@ CHANNEL_LIGHTNESS
@ CHANNEL_BLUE
@ CHANNEL_GRAY
@ CHANNEL_SATURATION
@ CHANNEL_SIZE
@ CHANNEL_GREEN
@ CHANNEL_RED
const char * name()
void gui_update(struct dt_iop_module_t *self)
void gui_init(struct dt_iop_module_t *self)
static __DT_CLONE_TARGETS__ void process_hsl_v2(const dt_dev_pixelpipe_iop_t *piece, const float *const restrict in, float *const restrict out, const dt_iop_roi_t *const roi_out)
int default_colorspace(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
int flags()
static __DT_CLONE_TARGETS__ void process_hsl_v1(const dt_dev_pixelpipe_iop_t *piece, const float *const restrict in, float *const restrict out, const dt_iop_roi_t *const roi_out)
void init_presets(dt_iop_module_so_t *self)
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)
void cleanup_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
static void green_callback(GtkWidget *slider, gpointer user_data)
const char * deprecated_msg()
int legacy_params(dt_iop_module_t *self, const void *const old_params, const int old_version, void *new_params, const int new_version)
static __DT_CLONE_TARGETS__ void process_rgb(const dt_dev_pixelpipe_iop_t *piece, const float *const restrict in, float *const restrict out, const dt_iop_roi_t *const roi_out)
static const dt_aligned_pixel_simd_t const dt_adaptation_t const float p
@ IOP_CS_RGB
void rgb2hsl(const dt_aligned_pixel_t rgb, float *h, float *s, float *l)
void hsl2rgb(dt_aligned_pixel_t rgb, float h, float s, float l)
static dt_aligned_pixel_t rgb
const dt_colormatrix_t dt_aligned_pixel_t out
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
#define for_each_channel(_var,...)
Definition darktable.h:662
#define DT_MODULE_INTROSPECTION(MODVER, PARAMSTYPE)
Definition darktable.h:151
#define __DT_CLONE_TARGETS__
Definition darktable.h:367
#define __OMP_PARALLEL_FOR__(...)
Definition darktable.h:258
static const dt_aligned_pixel_simd_t value
Definition darktable.h:577
#define dt_database_start_transaction(db)
Definition database.h:77
#define dt_database_release_transaction(db)
Definition database.h:78
#define dt_dev_add_history_item(dev, module, enable, redraw)
void dt_iop_params_t
Definition dev_history.h:41
@ DT_DEV_PIXELPIPE_DISPLAY_MASK
Definition develop.h:118
#define DT_GUI_BOX_SPACING
Definition gtk.h:109
void dt_gui_presets_add_generic(const char *name, dt_dev_operation_t op, const int32_t version, const void *params, const int32_t params_size, const int32_t enabled, const dt_develop_blend_colorspace_t blend_cst)
#define DT_GUI_MODULE(x)
void dt_iop_default_init(dt_iop_module_t *module)
Definition imageop.c:316
const char ** dt_iop_set_description(dt_iop_module_t *module, const char *main_text, const char *purpose, const char *input, const char *process, const char *output)
Definition imageop.c:3141
@ IOP_FLAGS_INCLUDE_IN_STYLES
Definition imageop.h:166
@ IOP_FLAGS_DEPRECATED
Definition imageop.h:168
@ IOP_FLAGS_SUPPORTS_BLENDING
Definition imageop.h:167
@ IOP_FLAGS_ALLOW_TILING
Definition imageop.h:169
@ IOP_GROUP_COLOR
Definition imageop.h:139
#define IOP_GUI_ALLOC(module)
Definition imageop.h:599
void *const ovoid
float *const restrict const size_t k
float *const restrict const size_t const size_t ch
float dt_aligned_pixel_t[4]
static float clamp_simd(const float x)
struct _GtkWidget GtkWidget
Definition splash.h:29
struct dt_gui_gtk_t * gui
Definition darktable.h:775
const struct dt_database_t * db
Definition darktable.h:779
struct dt_bauhaus_t * bauhaus
Definition darktable.h:778
struct dt_develop_t * develop
Definition darktable.h:770
dt_iop_buffer_dsc_t dsc_in
struct dt_iop_module_t *void * data
int32_t reset
Definition gtk.h:172
unsigned int channels
Definition format.h:54
_channelmixer_operation_mode_t operation_mode
float green[CHANNEL_SIZE]
float red[CHANNEL_SIZE]
_channelmixer_algorithm_t algorithm_version
float blue[CHANNEL_SIZE]
GModule *dt_dev_operation_t op
Definition imageop.h:230
dt_iop_params_t * default_params
Definition imageop.h:307
GtkWidget * widget
Definition imageop.h:337
dt_iop_gui_data_t * gui_data
Definition imageop.h:311
dt_iop_params_t * params
Definition imageop.h:307
Region of interest passed through the pixelpipe.
Definition imageop.h:72