Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
colorcontrast.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2010 Bruce Guenter.
4 Copyright (C) 2010-2013 johannes hanika.
5 Copyright (C) 2011-2012 Henrik Andersson.
6 Copyright (C) 2011 Jérémy Rosen.
7 Copyright (C) 2011 Robert Bieber.
8 Copyright (C) 2011 Rostyslav Pidgornyi.
9 Copyright (C) 2011 Sergey Astanin.
10 Copyright (C) 2011-2014, 2016, 2019 Tobias Ellinghaus.
11 Copyright (C) 2012 Richard Wonka.
12 Copyright (C) 2012, 2014 Ulrich Pegelow.
13 Copyright (C) 2013 Simon Spannagel.
14 Copyright (C) 2014-2016 Roman Lebedev.
15 Copyright (C) 2015 Pedro Côrte-Real.
16 Copyright (C) 2017 Heiko Bauke.
17 Copyright (C) 2018, 2020, 2022-2023, 2025-2026 Aurélien PIERRE.
18 Copyright (C) 2018 Edgardo Hoszowski.
19 Copyright (C) 2018 Maurizio Paglia.
20 Copyright (C) 2018-2020, 2022 Pascal Obry.
21 Copyright (C) 2018 rawfiner.
22 Copyright (C) 2019 Andreas Schneider.
23 Copyright (C) 2020 Aldric Renaudin.
24 Copyright (C) 2020 Diederik Ter Rahe.
25 Copyright (C) 2020-2021 Hubert Kowalski.
26 Copyright (C) 2020-2021 Ralf Brown.
27 Copyright (C) 2022 Hanno Schwalm.
28 Copyright (C) 2022 Martin Bařinka.
29 Copyright (C) 2022 Philipp Lutz.
30
31 darktable is free software: you can redistribute it and/or modify
32 it under the terms of the GNU General Public License as published by
33 the Free Software Foundation, either version 3 of the License, or
34 (at your option) any later version.
35
36 darktable is distributed in the hope that it will be useful,
37 but WITHOUT ANY WARRANTY; without even the implied warranty of
38 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
39 GNU General Public License for more details.
40
41 You should have received a copy of the GNU General Public License
42 along with darktable. If not, see <http://www.gnu.org/licenses/>.
43*/
44/* -*- Mode: c; c-basic-offset: 2; -*- */
45
46#ifdef HAVE_CONFIG_H
47#include "config.h"
48#endif
49#include "bauhaus/bauhaus.h"
50#include "common/opencl.h"
51#include "control/control.h"
52#include "develop/imageop.h"
53#include "develop/imageop_gui.h"
54
55#include "gui/gtk.h"
56#include "iop/iop_api.h"
57
58#include <assert.h>
59#include <gtk/gtk.h>
60#include <stdlib.h>
61
63
71
73{
74 float a_steepness; // $MIN: 0.0 $MAX: 5.0 $DEFAULT: 1.0 $DESCRIPTION: "green-magenta contrast"
75 float a_offset;
76 float b_steepness; // $MIN: 0.0 $MAX: 5.0 $DEFAULT: 1.0 $DESCRIPTION: "blue-yellow contrast"
77 float b_offset;
78 int unbound; // $DEFAULT: 1
80
82{
83 // whatever you need to make your gui happy.
84 // stored in self->gui_data
85 GtkBox *vbox;
86 GtkWidget *a_scale; // this is needed by gui_update
89
91{
92 // this is stored in the pixelpipeline after a commit (not the db),
93 // you can do some precomputation and get this data in process().
94 // stored in piece->data
96 float a_offset;
98 float b_offset;
101
102const char *name()
103{
104 return _("color contrast");
105}
106
107const char *aliases()
108{
109 return _("saturation");
110}
111
112const char **description(struct dt_iop_module_t *self)
113{
114 return dt_iop_set_description(self, _("increase saturation and separation between\n"
115 "opposite colors"),
116 _("creative"),
117 _("non-linear, Lab, display-referred"),
118 _("non-linear, Lab"),
119 _("non-linear, Lab, display-referred"));
120}
121
126
128{
129 return IOP_GROUP_COLOR;
130}
131
133{
134 return IOP_CS_LAB;
135}
136
137int legacy_params(dt_iop_module_t *self, const void *const old_params, const int old_version,
138 void *new_params, const int new_version)
139{
140 if(old_version == 1 && new_version == 2)
141 {
142 const dt_iop_colorcontrast_params1_t *old = old_params;
143 dt_iop_colorcontrast_params_t *new = new_params;
144
145 new->a_steepness = old->a_steepness;
146 new->a_offset = old->a_offset;
147 new->b_steepness = old->b_steepness;
148 new->b_offset = old->b_offset;
149 new->unbound = 0;
150 return 0;
151 }
152 return 1;
153}
154
155__OMP_DECLARE_SIMD__(aligned(in,out:64) aligned(slope,offset,low,high))
156static inline void clamped_scaling(float *const restrict out, const float *const restrict in,
157 const dt_aligned_pixel_t slope, const dt_aligned_pixel_t offset,
158 const dt_aligned_pixel_t low, const dt_aligned_pixel_t high)
159{
160 for_each_channel(c,dt_omp_nontemporal(out))
161 out[c] = CLAMPS(in[c] * slope[c] + offset[c], low[c], high[c]);
162}
163
165int process(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const void *const ivoid,
166 void *const ovoid)
167{
168 const dt_iop_roi_t *const roi_out = &piece->roi_out;
169 // this is called for preview and full pipe separately, each with its own pixelpipe piece.
170
171 // get our data struct:
173
174 // how many colors in our buffer?
175
176 const float *const restrict in = DT_IS_ALIGNED((const float *const)ivoid);
177 float *const restrict out = DT_IS_ALIGNED((float *const)ovoid);
178 const size_t npixels = (size_t)roi_out->width * roi_out->height;
179
180 const dt_aligned_pixel_t slope = { 1.0f, d->a_steepness, d->b_steepness, 1.0f };
181 const dt_aligned_pixel_t offset = { 0.0f, d->a_offset, d->b_offset, 0.0f };
182 const dt_aligned_pixel_t lowlimit = { -INFINITY, -128.0f, -128.0f, -INFINITY };
183 const dt_aligned_pixel_t highlimit = { INFINITY, 128.0f, 128.0f, INFINITY };
184
185 if(d->unbound)
186 {
188 for(size_t k = 0; k < (size_t)4 * npixels; k += 4)
189 {
190 for_each_channel(c,dt_omp_nontemporal(out))
191 {
192 out[k + c] = (in[k + c] * slope[c]) + offset[c];
193 }
194 }
195 }
196 else
197 {
199 for(size_t k = 0; k < npixels; k ++)
200 {
201 // the inner per-pixel loop needs to be declared in a separate vectorizable function to convince the
202 // compiler that it doesn't need to check for overlap or misalignment of the buffers for *every* pixel,
203 // which actually makes the code slower than not vectorizing....
204 clamped_scaling(out + 4*k, in + 4*k, slope, offset, lowlimit, highlimit);
205 }
206 }
207
208 return 0;
209}
210
214{
217 d->a_steepness = p->a_steepness;
218 d->a_offset = p->a_offset;
219 d->b_steepness = p->b_steepness;
220 d->b_offset = p->b_offset;
221 d->unbound = p->unbound;
222}
223
229
231{
232 dt_free_align(piece->data);
233 piece->data = NULL;
234}
235
243
245{
247
248 g->a_scale = dt_bauhaus_slider_from_params(self, "a_steepness");
249 gtk_widget_set_tooltip_text(g->a_scale, _("steepness of the a* curve in Lab\nlower values desaturate greens and magenta while higher saturate them"));
250
251 g->b_scale = dt_bauhaus_slider_from_params(self, "b_steepness");
252 gtk_widget_set_tooltip_text(g->b_scale, _("steepness of the b* curve in Lab\nlower values desaturate blues and yellows while higher saturate them"));
253}
254
255// clang-format off
256// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
257// vim: shiftwidth=2 expandtab tabstop=2 cindent
258// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
259// clang-format on
void dt_bauhaus_slider_set(GtkWidget *widget, float pos)
Definition bauhaus.c:3506
static const dt_aligned_pixel_simd_t const dt_adaptation_t const float p
@ IOP_CS_LAB
const char ** description(struct dt_iop_module_t *self)
int default_group()
__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)
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)
void gui_update(dt_iop_module_t *self)
const char * aliases()
void init_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
const char * name()
void gui_init(dt_iop_module_t *self)
int default_colorspace(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
int flags()
void cleanup_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
int legacy_params(dt_iop_module_t *self, const void *const old_params, const int old_version, void *new_params, const int new_version)
const dt_colormatrix_t dt_aligned_pixel_t out
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
#define dt_free_align(ptr)
Definition darktable.h:481
static void * dt_calloc_align(size_t size)
Definition darktable.h:488
#define DT_IS_ALIGNED(x)
Definition darktable.h:371
#define for_each_channel(_var,...)
Definition darktable.h:662
#define DT_MODULE_INTROSPECTION(MODVER, PARAMSTYPE)
Definition darktable.h:151
#define __OMP_DECLARE_SIMD__(...)
Definition darktable.h:263
#define __DT_CLONE_TARGETS__
Definition darktable.h:367
#define __OMP_PARALLEL_FOR__(...)
Definition darktable.h:258
void dt_iop_params_t
Definition dev_history.h:41
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
GtkWidget * dt_bauhaus_slider_from_params(dt_iop_module_t *self, const char *param)
Definition imageop_gui.c:77
void *const ovoid
float *const restrict const size_t k
#define CLAMPS(A, L, H)
Definition math.h:76
float dt_aligned_pixel_t[4]
struct _GtkWidget GtkWidget
Definition splash.h:29
struct dt_iop_module_t *void * data
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