Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
colisa.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2013-2016 Roman Lebedev.
4 Copyright (C) 2013-2014, 2016, 2019 Tobias Ellinghaus.
5 Copyright (C) 2013-2014, 2016 Ulrich Pegelow.
6 Copyright (C) 2015 Pedro Côrte-Real.
7 Copyright (C) 2016 johannes hanika.
8 Copyright (C) 2017 Heiko Bauke.
9 Copyright (C) 2018, 2020, 2022-2023, 2025-2026 Aurélien PIERRE.
10 Copyright (C) 2018 Edgardo Hoszowski.
11 Copyright (C) 2018 Maurizio Paglia.
12 Copyright (C) 2018, 2020, 2022 Pascal Obry.
13 Copyright (C) 2018 rawfiner.
14 Copyright (C) 2019 Andreas Schneider.
15 Copyright (C) 2020 Aldric Renaudin.
16 Copyright (C) 2020, 2022 Diederik Ter Rahe.
17 Copyright (C) 2020 Ralf Brown.
18 Copyright (C) 2022 Hanno Schwalm.
19 Copyright (C) 2022 Martin Bařinka.
20 Copyright (C) 2022 Philipp Lutz.
21
22 darktable is free software: you can redistribute it and/or modify
23 it under the terms of the GNU General Public License as published by
24 the Free Software Foundation, either version 3 of the License, or
25 (at your option) any later version.
26
27 darktable is distributed in the hope that it will be useful,
28 but WITHOUT ANY WARRANTY; without even the implied warranty of
29 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 GNU General Public License for more details.
31
32 You should have received a copy of the GNU General Public License
33 along with darktable. If not, see <http://www.gnu.org/licenses/>.
34*/
35
36#ifdef HAVE_CONFIG_H
37#include "config.h"
38#endif
39#include "develop/develop.h"
40#include "system/openmp.h"
42#include "system/mem_alloc.h"
44#include "develop/imageop.h"
46#include "develop/imageop_gui.h"
47
48#include "iop/iop_api.h"
49
50#include <assert.h>
51#include <math.h>
52#include <stdlib.h>
53#include <string.h>
54
55#include <gtk/gtk.h>
56#include <inttypes.h>
57
59
61{
62 float contrast; // $MIN: -1.0 $MAX: 1.0 $DEFAULT: 0.0
63 float brightness; // $MIN: -1.0 $MAX: 1.0 $DEFAULT: 0.0
64 float saturation; // $MIN: -1.0 $MAX: 1.0 $DEFAULT: 0.0
66
73
75{
76 float contrast;
79 float ctable[0x10000]; // precomputed look-up table for contrast curve
80 float cunbounded_coeffs[3]; // approximation for extrapolation of contrast curve
81 float ltable[0x10000]; // precomputed look-up table for brightness curve
82 float lunbounded_coeffs[3]; // approximation for extrapolation of brightness curve
84
85const char *name()
86{
87 return _("contrast brightness saturation");
88}
89
90const char **description(struct dt_iop_module_t *self)
91{
92 return dt_iop_set_description(self, _("adjust the look of the image"),
93 _("creative"),
94 _("non-linear, Lab, display-referred"),
95 _("non-linear, Lab"),
96 _("non-linear, Lab, display-referred"));
97}
98
103
105{
106 return IOP_GROUP_EFFECTS;
107}
108
110{
111 return IOP_CS_LAB;
112}
113
116{
117 default_input_format(self, pipe, piece, dsc);
118 dsc->channels = 4;
119 dsc->datatype = TYPE_FLOAT;
120}
121
123int process(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const void *const ivoid,
124 void *const ovoid)
125{
126 (void)self;
127 (void)pipe;
128 const dt_iop_roi_t *const roi_in = &piece->roi_in;
130 float *in = (float *)ivoid;
131 float *out = (float *)ovoid;
132
133 const int width = roi_in->width;
134 const int height = roi_in->height;
135 const int ch = 4;
137 for(size_t k = 0; k < (size_t)width * height; k++)
138 {
139 float L = (in[k * ch + 0] < 100.0f)
140 ? data->ctable[CLAMP((int)(in[k * ch + 0] / 100.0f * 0x10000ul), 0, 0xffff)]
141 : dt_iop_eval_exp(data->cunbounded_coeffs, in[k * ch + 0] / 100.0f);
142 out[k * ch + 0] = (L < 100.0f) ? data->ltable[CLAMP((int)(L / 100.0f * 0x10000ul), 0, 0xffff)]
143 : dt_iop_eval_exp(data->lunbounded_coeffs, L / 100.0f);
144 out[k * ch + 1] = in[k * ch + 1] * data->saturation;
145 out[k * ch + 2] = in[k * ch + 2] * data->saturation;
146 out[k * ch + 3] = in[k * ch + 3];
147 }
148 return 0;
149}
150
151
154{
157
158 d->contrast = p->contrast + 1.0f; // rescale from [-1;+1] to [0;+2] (zero meaning no contrast -> gray plane)
159 d->brightness = p->brightness * 2.0f; // rescale from [-1;+1] to [-2;+2]
160 d->saturation = p->saturation + 1.0f; // rescale from [-1;+1] to [0;+2] (zero meaning no saturation -> b&w)
161
162 // generate precomputed contrast curve
163 if(d->contrast <= 1.0f)
164 {
165// linear curve for d->contrast below 1
167 for(int k = 0; k < 0x10000; k++) d->ctable[k] = d->contrast * (100.0f * k / 0x10000 - 50.0f) + 50.0f;
168 }
169 else
170 {
171 // sigmoidal curve for d->contrast above 1
172 const float boost = 20.0f;
173 const float contrastm1sq = boost * (d->contrast - 1.0f) * (d->contrast - 1.0f);
174 const float contrastscale = sqrtf(1.0f + contrastm1sq);
176 for(int k = 0; k < 0x10000; k++)
177 {
178 float kx2m1 = 2.0f * (float)k / 0x10000 - 1.0f;
179 d->ctable[k] = 50.0f * (contrastscale * kx2m1 / sqrtf(1.0f + contrastm1sq * kx2m1 * kx2m1) + 1.0f);
180 }
181 }
182
183 // now the extrapolation stuff for the contrast curve:
184 const float xc[4] = { 0.7f, 0.8f, 0.9f, 1.0f };
185 const float yc[4] = { d->ctable[CLAMP((int)(xc[0] * 0x10000ul), 0, 0xffff)],
186 d->ctable[CLAMP((int)(xc[1] * 0x10000ul), 0, 0xffff)],
187 d->ctable[CLAMP((int)(xc[2] * 0x10000ul), 0, 0xffff)],
188 d->ctable[CLAMP((int)(xc[3] * 0x10000ul), 0, 0xffff)] };
189 dt_iop_estimate_exp(xc, yc, 4, d->cunbounded_coeffs);
190
191
192 // generate precomputed brightness curve
193 const float gamma = (d->brightness >= 0.0f) ? 1.0f / (1.0f + d->brightness) : (1.0f - d->brightness);
195 for(int k = 0; k < 0x10000; k++)
196 {
197 d->ltable[k] = 100.0f * powf((float)k / 0x10000, gamma);
198 }
199
200 // now the extrapolation stuff for the brightness curve:
201 const float xl[4] = { 0.7f, 0.8f, 0.9f, 1.0f };
202 const float yl[4] = { d->ltable[CLAMP((int)(xl[0] * 0x10000ul), 0, 0xffff)],
203 d->ltable[CLAMP((int)(xl[1] * 0x10000ul), 0, 0xffff)],
204 d->ltable[CLAMP((int)(xl[2] * 0x10000ul), 0, 0xffff)],
205 d->ltable[CLAMP((int)(xl[3] * 0x10000ul), 0, 0xffff)] };
206 dt_iop_estimate_exp(xl, yl, 4, d->lunbounded_coeffs);
207}
208
210{
212 piece->data = (void *)d;
213 piece->data_size = sizeof(dt_iop_colisa_data_t);
214 // Checked AFTER both piece->data and piece->data_size are set, deliberately.
215 // dt_iop_init_pipe() disables the node for us when it sees data_size > 0 with a NULL
216 // data -- returning before data_size is assigned skips that and leaves the node enabled
217 // with no storage. dt_calloc_align() returns NULL on failure and pipe nodes are built
218 // exactly when memory is tightest (Sentry 134134395 faulted in atrous's init_pipe).
219 if(IS_NULL_PTR(piece->data)) return;
220 for(int k = 0; k < 0x10000; k++) d->ctable[k] = d->ltable[k] = 100.0f * k / 0x10000; // identity
221}
222
224{
225 dt_free_align(piece->data);
226 piece->data = NULL;
227}
228
229void gui_init(struct dt_iop_module_t *self)
230{
232
233 g->contrast = dt_bauhaus_slider_from_params(self, N_("contrast"));
234 g->brightness = dt_bauhaus_slider_from_params(self, N_("brightness"));
235 g->saturation = dt_bauhaus_slider_from_params(self, N_("saturation"));
236
237 gtk_widget_set_tooltip_text(g->contrast, _("contrast adjustment"));
238 gtk_widget_set_tooltip_text(g->brightness, _("brightness adjustment"));
239 gtk_widget_set_tooltip_text(g->saturation, _("color saturation adjustment"));
240}
241
242// clang-format off
243// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
244// vim: shiftwidth=2 expandtab tabstop=2 cindent
245// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
246// clang-format on
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
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 colisa.c:152
const char ** description(struct dt_iop_module_t *self)
Definition colisa.c:90
int default_group()
Definition colisa.c:104
__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 colisa.c:123
void init_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition colisa.c:209
const char * name()
Definition colisa.c:85
void gui_init(struct dt_iop_module_t *self)
Definition colisa.c:229
int default_colorspace(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
Definition colisa.c:109
void input_format(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece, dt_iop_buffer_dsc_t *dsc)
Definition colisa.c:114
int flags()
Definition colisa.c:99
void cleanup_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition colisa.c:223
@ IOP_CS_LAB
struct _GtkWidget GtkWidget
GtkWidget, opaque, spelled exactly as GTK spells it.
Definition colorspaces.h:98
const dt_colormatrix_t dt_aligned_pixel_t out
void dt_iop_params_t
Definition dev_history.h:43
void default_input_format(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece, dt_iop_buffer_dsc_t *dsc)
@ TYPE_FLOAT
Definition format.h:56
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
@ IOP_FLAGS_INCLUDE_IN_STYLES
Definition imageop.h:185
@ IOP_FLAGS_DEPRECATED
Definition imageop.h:187
@ IOP_FLAGS_SUPPORTS_BLENDING
Definition imageop.h:186
@ IOP_FLAGS_ALLOW_TILING
Definition imageop.h:188
@ IOP_GROUP_EFFECTS
Definition imageop.h:161
GtkWidget * dt_bauhaus_slider_from_params(dt_iop_module_t *self, const char *param)
#define IOP_GUI_ALLOC(module)
Definition imageop_gui.h:93
void *const ovoid
static void dt_iop_estimate_exp(const float *const x, const float *const y, const int num, float *coeff)
static float dt_iop_eval_exp(const float *const coeff, const float x)
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
uint32_t width
Definition mipmap_cache.c:0
uint32_t height
Definition mipmap_cache.c:1
#define DT_MODULE_INTROSPECTION(MODVER, PARAMSTYPE)
DT_MODULE() for a module whose params struct is introspected.
#define __OMP_PARALLEL_FOR__(...)
Definition openmp.h:95
struct dt_iop_module_t *void * data
unsigned int channels
Definition format.h:83
dt_iop_buffer_type_t datatype
Definition format.h:85
float lunbounded_coeffs[3]
Definition colisa.c:82
float ctable[0x10000]
Definition colisa.c:79
float ltable[0x10000]
Definition colisa.c:81
float cunbounded_coeffs[3]
Definition colisa.c:80
GtkWidget * saturation
Definition colisa.c:71
GtkWidget * contrast
Definition colisa.c:69
GtkWidget * brightness
Definition colisa.c:70
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__