Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
scalepixels.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2014 Pascal de Bruijn.
4 Copyright (C) 2014, 2016 Roman Lebedev.
5 Copyright (C) 2014, 2016, 2019 Tobias Ellinghaus.
6 Copyright (C) 2015 Pedro Côrte-Real.
7 Copyright (C) 2017 Heiko Bauke.
8 Copyright (C) 2018, 2020, 2023, 2025-2026 Aurélien PIERRE.
9 Copyright (C) 2018 Edgardo Hoszowski.
10 Copyright (C) 2018 Maurizio Paglia.
11 Copyright (C) 2018-2020, 2022 Pascal Obry.
12 Copyright (C) 2018 rawfiner.
13 Copyright (C) 2019-2020 Aldric Renaudin.
14 Copyright (C) 2019 Andreas Schneider.
15 Copyright (C) 2020 Diederik Ter Rahe.
16 Copyright (C) 2020 Ralf Brown.
17 Copyright (C) 2022 Martin Bařinka.
18 Copyright (C) 2022 Philipp Lutz.
19
20 darktable is free software: you can redistribute it and/or modify
21 it under the terms of the GNU General Public License as published by
22 the Free Software Foundation, either version 3 of the License, or
23 (at your option) any later version.
24
25 darktable is distributed in the hope that it will be useful,
26 but WITHOUT ANY WARRANTY; without even the implied warranty of
27 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 GNU General Public License for more details.
29
30 You should have received a copy of the GNU General Public License
31 along with darktable. If not, see <http://www.gnu.org/licenses/>.
32*/
33#ifdef HAVE_CONFIG_H
34#include "config.h"
35#endif
36#include "bauhaus/bauhaus.h"
38#include "develop/imageop.h"
39#include "develop/tiling.h"
40
41#include "gui/gtk.h"
42#include "iop/iop_api.h"
43
44#include <gtk/gtk.h>
45#include <stdlib.h>
46
48
50{
51 // Aspect ratio of the pixels, usually 1 but some cameras need scaling
52 // <1 means the image needs to be stretched vertically, (0.5 means 2x)
53 // >1 means the image needs to be stretched horizontally (2 mean 2x)
54 float pixel_aspect_ratio; // $DEFAULT: 1.0f
56
60
66
67const char *name()
68{
69 return C_("modulename", "scale pixels");
70}
71
77
79{
81}
82
84{
85 return IOP_TAG_DISTORT;
86}
87
92
93const char **description(struct dt_iop_module_t *self)
94{
95 return dt_iop_set_description(self,
96 _("internal module to setup technical specificities of raw sensor.\n\n"
97 "you should not touch values here !"),
98 NULL, NULL, NULL, NULL);
99}
100
101static void transform(const dt_dev_pixelpipe_iop_t *const piece, float *p)
102{
104
105 if(d->pixel_aspect_ratio < 1.0f)
106 {
107 p[1] /= d->pixel_aspect_ratio;
108 }
109 else
110 {
111 p[0] *= d->pixel_aspect_ratio;
112 }
113}
114
116 const dt_dev_pixelpipe_iop_t *piece)
117{
118 // Since the scaling is calculated by modify_roi_in use that to get them
119 // This doesn't seem strictly needed but since clipping.c also does it we try
120 // and avoid breaking any assumptions elsewhere in the code
121 dt_dev_pixelpipe_iop_t piece_copy = *piece;
122 dt_iop_roi_t roi_out, roi_in;
123 roi_out.width = piece->buf_in.width;
124 roi_out.height = piece->buf_in.height;
125 self->modify_roi_in(self, pipe, &piece_copy, &roi_out, &roi_in);
126}
127
129 float *points, size_t points_count)
130{
131 precalculate_scale(self, pipe, piece);
133
134 for(size_t i = 0; i < points_count * 2; i += 2)
135 {
136 points[i] /= d->x_scale;
137 points[i+1] /= d->y_scale;
138 }
139
140 return 1;
141}
142
144 float *points, size_t points_count)
145{
146 precalculate_scale(self, pipe, piece);
148
149 for(size_t i = 0; i < points_count * 2; i += 2)
150 {
151 points[i] *= d->x_scale;
152 points[i+1] *= d->y_scale;
153 }
154
155 return 1;
156}
157
158void distort_mask(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, struct dt_dev_pixelpipe_iop_t *piece,
159 const float *const in, float *const out, const dt_iop_roi_t *const roi_in,
160 const dt_iop_roi_t *const roi_out)
161{
162 (void)pipe;
163 // TODO
164 memset(out, 0, sizeof(float) * roi_out->width * roi_out->height);
165 fprintf(stderr, "TODO: implement %s() in %s\n", __FUNCTION__, __FILE__);
166}
167
169 dt_iop_roi_t *roi_out,
170 const dt_iop_roi_t *const roi_in)
171{
172 *roi_out = *roi_in;
173
174 float xy[2] = { roi_out->x, roi_out->y };
175 float wh[2] = { roi_out->width, roi_out->height };
176
177 transform(piece, xy);
178 transform(piece, wh);
179
180 roi_out->x = (int)floorf(xy[0]);
181 roi_out->y = (int)floorf(xy[1]);
182 roi_out->width = (int)ceilf(wh[0]);
183 roi_out->height = (int)ceilf(wh[1]);
184
185 // sanity check.
186 if(roi_out->x < 0) roi_out->x = 0;
187 if(roi_out->y < 0) roi_out->y = 0;
188 if(roi_out->width < 1) roi_out->width = 1;
189 if(roi_out->height < 1) roi_out->height = 1;
190}
191
193 const dt_iop_roi_t *const roi_out,
194 dt_iop_roi_t *roi_in)
195{
196 *roi_in = *roi_out;
197
198 // If possible try to get an image that's strictly larger than what we want to output
199 float hw[2] = {roi_out->height, roi_out->width};
200 transform(piece, hw); // transform() is used reversed here intentionally
201 roi_in->height = hw[0];
202 roi_in->width = hw[1];
203
204 float reduction_ratio = MAX(hw[0] / (piece->buf_in.height * 1.0f), hw[1] / (piece->buf_in.width * 1.0f));
205 if (reduction_ratio > 1.0f)
206 {
207 roi_in->height /= reduction_ratio;
208 roi_in->width /= reduction_ratio;
209 }
210
212 d->x_scale = (roi_in->width * 1.0f) / (roi_out->width * 1.0f);
213 d->y_scale = (roi_in->height * 1.0f) / (roi_out->height * 1.0f);
214
215 roi_in->scale = roi_out->scale * MAX(d->x_scale, d->y_scale);
216 roi_in->x = roi_out->x * d->x_scale;
217 roi_in->y = roi_out->y * d->y_scale;
218}
219
222 const void *const ivoid, void *const ovoid)
223{
224 (void)pipe;
225 const dt_iop_roi_t *const roi_in = &piece->roi_in;
226 const dt_iop_roi_t *const roi_out = &piece->roi_out;
227 const int ch = piece->dsc_in.channels;
228 const int ch_width = ch * roi_in->width;
230 const dt_iop_scalepixels_data_t * const d = piece->data;
232 // (slow) point-by-point transformation.
233 // TODO: optimize with scanlines and linear steps between?
234 for(int j = 0; j < roi_out->height; j++)
235 {
236 float *out = ((float *)ovoid) + (size_t)4 * j * roi_out->width;
237 for(int i = 0; i < roi_out->width; i++, out += 4)
238 {
239 float x = i*d->x_scale;
240 float y = j*d->y_scale;
241
242 dt_interpolation_compute_pixel4c(interpolation, (float *)ivoid, out, x, y, roi_in->width,
243 roi_in->height, ch_width);
244 }
245 }
246 return 0;
247}
248
251{
252 const dt_iop_scalepixels_params_t *p = params;
254
255 d->pixel_aspect_ratio = p->pixel_aspect_ratio;
256 d->x_scale = 1.0f;
257 d->y_scale = 1.0f;
258
259 if(isnan(p->pixel_aspect_ratio) || p->pixel_aspect_ratio <= 0.0f || p->pixel_aspect_ratio == 1.0f)
260 piece->enabled = 0;
261}
262
268
270{
271 dt_free_align(piece->data);
272 piece->data = NULL;
273}
274
276{
278
279 const dt_image_t *const image = &(self->dev->image_storage);
280
282
283 self->default_enabled = (!isnan(d->pixel_aspect_ratio) &&
284 d->pixel_aspect_ratio > 0.0f &&
285 d->pixel_aspect_ratio != 1.0f);
286
287 // FIXME: does not work.
288 self->hide_enable_button = !self->default_enabled;
289
290 if(self->widget)
291 gtk_label_set_text(GTK_LABEL(self->widget), self->default_enabled
292 ? _("automatic pixel scaling")
293 :_("automatic pixel scaling\nonly works for the sensors that need it."));
294}
295
297{
298}
299
301{
302 IOP_GUI_ALLOC(scalepixels);
303
304 self->widget = dt_ui_label_new("");
305 gtk_label_set_line_wrap(GTK_LABEL(self->widget), TRUE);
306
307}
308
309// clang-format off
310// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
311// vim: shiftwidth=2 expandtab tabstop=2 cindent
312// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
313// clang-format on
#define TRUE
Definition ashift_lsd.c:162
static const dt_aligned_pixel_simd_t const dt_adaptation_t const float p
@ IOP_CS_RGB
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_MODULE_INTROSPECTION(MODVER, PARAMSTYPE)
Definition darktable.h:151
#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
static GtkWidget * dt_ui_label_new(const gchar *str)
Definition gtk.h:461
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_ALLOW_TILING
Definition imageop.h:169
@ IOP_FLAGS_UNSAFE_COPY
Definition imageop.h:177
@ IOP_FLAGS_ONE_INSTANCE
Definition imageop.h:172
@ IOP_FLAGS_TILING_FULL_ROI
Definition imageop.h:171
@ IOP_GROUP_TECHNICAL
Definition imageop.h:143
#define IOP_GUI_ALLOC(module)
Definition imageop.h:599
@ IOP_TAG_DISTORT
Definition imageop.h:151
void *const ovoid
const struct dt_interpolation * dt_interpolation_new(enum dt_interpolation_type type)
__DT_CLONE_TARGETS__ void dt_interpolation_compute_pixel4c(const struct dt_interpolation *itor, const float *in, float *out, const float x, const float y, const int width, const int height, const int linestride)
@ DT_INTERPOLATION_USERPREF
static const float x
float *const restrict const size_t const size_t ch
int operation_tags()
Definition scalepixels.c:83
void distort_mask(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, struct dt_dev_pixelpipe_iop_t *piece, const float *const in, float *const out, const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out)
const char ** description(struct dt_iop_module_t *self)
Definition scalepixels.c:93
void modify_roi_out(dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece, dt_iop_roi_t *roi_out, const dt_iop_roi_t *const roi_in)
int default_group()
Definition scalepixels.c:78
void gui_update(dt_iop_module_t *self)
Refresh GUI controls from current params and configuration.
__DT_CLONE_TARGETS__ int process(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 modify_roi_in(dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece, const dt_iop_roi_t *const roi_out, dt_iop_roi_t *roi_in)
const char * name()
Definition scalepixels.c:67
void gui_init(dt_iop_module_t *self)
int distort_backtransform(dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, float *points, size_t points_count)
void reload_defaults(dt_iop_module_t *self)
void cleanup_pipe(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
int default_colorspace(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
Definition scalepixels.c:88
int flags()
Definition scalepixels.c:72
void commit_params(dt_iop_module_t *self, dt_iop_params_t *params, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
static void transform(const dt_dev_pixelpipe_iop_t *const piece, float *p)
void init_pipe(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
int distort_transform(dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, float *points, size_t points_count)
static void precalculate_scale(dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
dt_iop_buffer_dsc_t dsc_in
struct dt_iop_module_t *void * data
dt_image_t image_storage
Definition develop.h:259
float pixel_aspect_ratio
Definition image.h:356
unsigned int channels
Definition format.h:54
int32_t hide_enable_button
Definition imageop.h:262
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
gboolean default_enabled
Definition imageop.h:303
Region of interest passed through the pixelpipe.
Definition imageop.h:72
double scale
Definition imageop.h:74
#define MAX(a, b)
Definition thinplate.c:29