Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
bloom.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2009-2013, 2016 johannes hanika.
4 Copyright (C) 2010-2011 Bruce Guenter.
5 Copyright (C) 2010-2012 Henrik Andersson.
6 Copyright (C) 2010 jan rinze.
7 Copyright (C) 2010 Pascal de Bruijn.
8 Copyright (C) 2011 Antony Dovgal.
9 Copyright (C) 2011 Olivier Tribout.
10 Copyright (C) 2011 Robert Bieber.
11 Copyright (C) 2011-2016, 2019 Tobias Ellinghaus.
12 Copyright (C) 2012 Richard Wonka.
13 Copyright (C) 2012, 2014, 2016-2017 Ulrich Pegelow.
14 Copyright (C) 2013 Simon Spannagel.
15 Copyright (C) 2014-2016 Roman Lebedev.
16 Copyright (C) 2015, 2018, 2020-2022 Pascal Obry.
17 Copyright (C) 2015 Pedro Côrte-Real.
18 Copyright (C) 2017 Heiko Bauke.
19 Copyright (C) 2018, 2020, 2022-2023, 2025-2026 Aurélien PIERRE.
20 Copyright (C) 2018 Edgardo Hoszowski.
21 Copyright (C) 2018 Maurizio Paglia.
22 Copyright (C) 2018 rawfiner.
23 Copyright (C) 2019 Andreas Schneider.
24 Copyright (C) 2020 Aldric Renaudin.
25 Copyright (C) 2020, 2022 Diederik Ter Rahe.
26 Copyright (C) 2020 Hubert Kowalski.
27 Copyright (C) 2020-2021 Ralf Brown.
28 Copyright (C) 2022 Hanno Schwalm.
29 Copyright (C) 2022 Martin Bařinka.
30 Copyright (C) 2022 Philipp Lutz.
31
32 darktable is free software: you can redistribute it and/or modify
33 it under the terms of the GNU General Public License as published by
34 the Free Software Foundation, either version 3 of the License, or
35 (at your option) any later version.
36
37 darktable is distributed in the hope that it will be useful,
38 but WITHOUT ANY WARRANTY; without even the implied warranty of
39 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
40 GNU General Public License for more details.
41
42 You should have received a copy of the GNU General Public License
43 along with darktable. If not, see <http://www.gnu.org/licenses/>.
44*/
45#ifdef HAVE_CONFIG_H
46#include "config.h"
48#endif
49#include "widgets/bauhaus.h"
52#include "pixel/box_filters.h"
53#include "common/imagebuf.h"
54#include "develop/develop.h"
55#include "develop/imageop.h"
56#include "develop/imageop_gui.h"
57#include "develop/tiling.h"
58
59#include "iop/iop_api.h"
60
61#include <assert.h>
62#include <gtk/gtk.h>
63#include <inttypes.h>
64#include <stdlib.h>
65#include <string.h>
66
67#define NUM_BUCKETS 4 /* OpenCL bucket chain size for tmp buffers; minimum 2 */
68
70
72{
73 float size; // $MIN: 0.0 $MAX: 100.0 $DEFAULT: 20.0
74 float threshold; // $MIN: 0.0 $MAX: 100.0 $DEFAULT: 90.0
75 float strength; // $MIN: 0.0 $MAX: 100.0 $DEFAULT: 25.0
77
79{
80 GtkWidget *size, *threshold, *strength; // size,threshold,strength
82
89
90const char *name()
91{
92 return _("bloom");
93}
94
95const char **description(struct dt_iop_module_t *self)
96{
97 return dt_iop_set_description(self, _("apply Orton effect for a dreamy aetherical look"),
98 _("creative"),
99 _("non-linear, Lab, display-referred"),
100 _("non-linear, Lab"),
101 _("non-linear, Lab, display-referred"));
102}
103
104
109
111{
112 return IOP_GROUP_EFFECTS;
113}
114
116{
117 return IOP_CS_LAB;
118}
119
121int process(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const void *const ivoid,
122 void *const ovoid)
123{
124 const dt_iop_roi_t *const roi_in = &piece->roi_in;
125 const dt_iop_roi_t *const roi_out = &piece->roi_out;
126 const dt_iop_bloom_data_t *const data = (dt_iop_bloom_data_t *)piece->data;
127
128 float *restrict blurlightness;
129 if (dt_iop_alloc_image_buffers(self, roi_in, roi_out, 1, &blurlightness, 0))
130 {
131 // out of memory, so just copy image through to output
132 dt_iop_copy_image_roi(ovoid, ivoid, piece->dsc_in.channels, roi_in, roi_out, TRUE);
133 return 1;
134 }
135
136 const float *const restrict in = DT_IS_ALIGNED((float *)ivoid);
137 float *const restrict out = DT_IS_ALIGNED((float *)ovoid);
138 const size_t npixels = (size_t)roi_out->width * roi_out->height;
139
140 /* gather light by threshold */
141 const int rad = 256.0f * (fmin(100.0f, data->size + 1.0f) / 100.0f);
142 const float _r = ceilf(rad * roi_in->scale);
143 const int radius = MIN(256.0f, _r);
144
145 const float scale = 1.0f / exp2f(-1.0f * (fmin(100.0f, data->strength + 1.0f) / 100.0f));
146
147 const float threshold = data->threshold;
148/* get the thresholded lights into buffer */
150 for(size_t k = 0; k < npixels; k++)
151 {
152 const float L = in[4*k] * scale;
153 blurlightness[k] = (L > threshold) ? L : 0.0f;
154 }
155
156 /* horizontal blur into memchannel lightness */
157 const int range = 2 * radius + 1;
158 const int hr = range / 2;
159
160 if(dt_box_mean(blurlightness, roi_out->height, roi_out->width, 1, hr, BOX_ITERATIONS) != 0)
161 {
162 dt_pixelpipe_cache_free_align(blurlightness);
163 return 1;
164 }
165
166/* screen blend lightness with original */
168 for(size_t k = 0; k < npixels; k++)
169 {
170 out[4*k+0] = 100.0f - (((100.0f - in[4*k]) * (100.0f - blurlightness[k])) / 100.0f); // Screen blend
171 out[4*k+1] = in[4*k+1];
172 out[4*k+2] = in[4*k+2];
173 out[4*k+3] = in[4*k+3];
174 }
175 dt_pixelpipe_cache_free_align(blurlightness);
176
177// if(pipe->mask_display & DT_DEV_PIXELPIPE_DISPLAY_MASK)
178// dt_iop_alpha_copy(ivoid, ovoid, roi_out->width, roi_out->height);
179
180 return 0;
181}
182
183void 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)
184{
185 (void)self;
186 (void)pipe;
187 const dt_iop_roi_t *const roi_in = &piece->roi_in;
189
190 const int rad = 256.0f * (fmin(100.0f, d->size + 1.0f) / 100.0f);
191 const float _r = ceilf(rad * roi_in->scale);
192 const int radius = MIN(256.0f, _r);
193
194 tiling->factor = 2.0f + 0.25f + 0.05f; // in + out + blurlightness + slice for dt_box_mean
195 tiling->factor_cl = 2.0f + NUM_BUCKETS * 0.25f; // in + out + NUM_BUCKETS * 0.25 tmp
196 tiling->maxbuf = 1.0f;
197 tiling->overhead = 0;
198 tiling->overlap = 5 * radius; // This is a guess. TODO: check if that's sufficiently large
199 tiling->xalign = 1;
200 tiling->yalign = 1;
201 return;
202}
203
206{
209
210 d->strength = p->strength;
211 d->size = p->size;
212 d->threshold = p->threshold;
213}
214
216{
217 piece->data = dt_calloc_align(sizeof(dt_iop_bloom_data_t));
218 piece->data_size = sizeof(dt_iop_bloom_data_t);
219}
220
222{
223 dt_free_align(piece->data);
224 piece->data = NULL;
225}
226
227void gui_init(struct dt_iop_module_t *self)
228{
230
231 g->size = dt_bauhaus_slider_from_params(self, N_("size"));
233 gtk_widget_set_tooltip_text(g->size, _("the size of bloom"));
234
235 g->threshold = dt_bauhaus_slider_from_params(self, N_("threshold"));
236 dt_bauhaus_slider_set_format(g->threshold, "%");
237 gtk_widget_set_tooltip_text(g->threshold, _("the threshold of light"));
238
239 g->strength = dt_bauhaus_slider_from_params(self, N_("strength"));
240 dt_bauhaus_slider_set_format(g->strength, "%");
241 gtk_widget_set_tooltip_text(g->strength, _("the strength of bloom"));
242}
243
244// clang-format off
245// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
246// vim: shiftwidth=2 expandtab tabstop=2 cindent
247// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
248// clang-format on
#define TRUE
Definition ashift_lsd.c:162
void dt_bauhaus_slider_set_format(GtkWidget *widget, const char *format)
Definition bauhaus.c:3407
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 bloom.c:204
#define NUM_BUCKETS
Definition bloom.c:67
const char ** description(struct dt_iop_module_t *self)
Definition bloom.c:95
int default_group()
Definition bloom.c:110
__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 bloom.c:121
void init_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition bloom.c:215
const char * name()
Definition bloom.c:90
void gui_init(struct dt_iop_module_t *self)
Definition bloom.c:227
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 bloom.c:183
int default_colorspace(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
Definition bloom.c:115
int flags()
Definition bloom.c:105
void cleanup_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition bloom.c:221
int dt_box_mean(float *const buf, const size_t height, const size_t width, const int ch, const int radius, const unsigned iterations)
#define BOX_ITERATIONS
Definition box_filters.h:33
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
@ IOP_CS_LAB
struct _GtkWidget GtkWidget
GtkWidget, opaque, spelled exactly as GTK spells it.
Definition colorspaces.h:98
const float threshold
const dt_colormatrix_t dt_aligned_pixel_t out
void dt_iop_params_t
Definition dev_history.h:43
int dt_iop_alloc_image_buffers(struct dt_iop_module_t *const module, const struct dt_iop_roi_t *const roi_in, const struct dt_iop_roi_t *const roi_out,...)
Definition imagebuf.c:35
void dt_iop_copy_image_roi(float *const __restrict__ out, const float *const __restrict__ in, const size_t ch, const dt_iop_roi_t *const __restrict__ roi_in, const dt_iop_roi_t *const __restrict__ roi_out, const int zero_pad)
Definition imagebuf.c:163
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_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
float *const restrict const size_t k
#define dt_free_align(ptr)
Release memory from dt_alloc_align() and set ptr to NULL.
Definition mem_alloc.h:214
static void * dt_calloc_align(size_t size)
dt_alloc_align() followed by a zero fill.
Definition mem_alloc.h:225
#define DT_IS_ALIGNED(x)
Promise the compiler that x is already cacheline-aligned, and return it.
Definition mem_alloc.h:51
#define DT_MODULE_INTROSPECTION(MODVER, PARAMSTYPE)
DT_MODULE() for a module whose params struct is introspected.
#define __OMP_PARALLEL_FOR__(...)
Definition openmp.h:95
#define dt_pixelpipe_cache_free_align(mem)
dt_iop_buffer_dsc_t dsc_in
struct dt_iop_module_t *void * data
GtkWidget * size
Definition bloom.c:80
GtkWidget * strength
Definition bloom.c:80
GtkWidget * threshold
Definition bloom.c:80
unsigned int channels
Definition format.h:83
Region of interest passed through the pixelpipe.
Definition format.h:49
double scale
Definition format.h:51
int width
Definition format.h:50
int height
Definition format.h:50
#define __DT_CLONE_TARGETS__
#define MIN(a, b)
Definition thinplate.c:32