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 "develop/imageop_gui.h"
37#include "widgets/bauhaus.h"
40#include "pixel/interpolation.h"
42#include "develop/imageop.h"
43#include "develop/tiling.h"
44
45#include "iop/iop_api.h"
46
47#include <gtk/gtk.h>
48#include <stdlib.h>
49#include "widgets/label.h"
50
52
54{
55 // Aspect ratio of the pixels, usually 1 but some cameras need scaling
56 // <1 means the image needs to be stretched vertically, (0.5 means 2x)
57 // >1 means the image needs to be stretched horizontally (2 mean 2x)
58 float pixel_aspect_ratio; // $DEFAULT: 1.0f
60
64
70
71const char *name()
72{
73 return C_("modulename", "scale pixels");
74}
75
81
83{
85}
86
88{
89 return IOP_TAG_DISTORT;
90}
91
96
97const char **description(struct dt_iop_module_t *self)
98{
99 return dt_iop_set_description(self,
100 _("internal module to setup technical specificities of raw sensor.\n\n"
101 "you should not touch values here !"),
102 NULL, NULL, NULL, NULL);
103}
104
105static void transform(const dt_dev_pixelpipe_iop_t *const piece, float *p)
106{
108
109 if(d->pixel_aspect_ratio < 1.0f)
110 {
111 p[1] /= d->pixel_aspect_ratio;
112 }
113 else
114 {
115 p[0] *= d->pixel_aspect_ratio;
116 }
117}
118
136static void _scalepixels_scales(const float pixel_aspect_ratio, float *x_scale, float *y_scale)
137{
138 if(pixel_aspect_ratio < 1.0f)
139 {
140 *x_scale = 1.0f;
141 *y_scale = pixel_aspect_ratio;
142 }
143 else
144 {
145 *x_scale = 1.0f / pixel_aspect_ratio;
146 *y_scale = 1.0f;
147 }
148}
149
151 const dt_dev_pixelpipe_iop_t *piece)
152{
153 /* Writes into the piece, as it always has: process() reads these two fields, and the distort
154 * callbacks below deliberately reset them to the full-frame values before using them. */
156 _scalepixels_scales(d->pixel_aspect_ratio, &d->x_scale, &d->y_scale);
157}
158
160 float *points, size_t points_count)
161{
162 precalculate_scale(self, pipe, piece);
164
165 for(size_t i = 0; i < points_count * 2; i += 2)
166 {
167 points[i] /= d->x_scale;
168 points[i+1] /= d->y_scale;
169 }
170
171 return 1;
172}
173
175 float *points, size_t points_count)
176{
177 precalculate_scale(self, pipe, piece);
179
180 for(size_t i = 0; i < points_count * 2; i += 2)
181 {
182 points[i] *= d->x_scale;
183 points[i+1] *= d->y_scale;
184 }
185
186 return 1;
187}
188
189void distort_mask(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, struct dt_dev_pixelpipe_iop_t *piece,
190 const float *const in, float *const out, const dt_iop_roi_t *const roi_in,
191 const dt_iop_roi_t *const roi_out)
192{
193 (void)pipe;
194 // TODO
195 memset(out, 0, sizeof(float) * roi_out->width * roi_out->height);
196 fprintf(stderr, "TODO: implement %s() in %s\n", __FUNCTION__, __FILE__);
197}
198
200 dt_iop_roi_t *roi_out,
201 const dt_iop_roi_t *const roi_in)
202{
203 *roi_out = *roi_in;
204
205 float xy[2] = { roi_out->x, roi_out->y };
206 float wh[2] = { roi_out->width, roi_out->height };
207
208 transform(piece, xy);
209 transform(piece, wh);
210
211 roi_out->x = (int)floorf(xy[0]);
212 roi_out->y = (int)floorf(xy[1]);
213 roi_out->width = (int)ceilf(wh[0]);
214 roi_out->height = (int)ceilf(wh[1]);
215
216 // sanity check.
217 if(roi_out->x < 0) roi_out->x = 0;
218 if(roi_out->y < 0) roi_out->y = 0;
219 if(roi_out->width < 1) roi_out->width = 1;
220 if(roi_out->height < 1) roi_out->height = 1;
221}
222
224 const dt_iop_roi_t *const roi_out,
225 dt_iop_roi_t *roi_in)
226{
227 *roi_in = *roi_out;
228
229 // If possible try to get an image that's strictly larger than what we want to output
230 float hw[2] = {roi_out->height, roi_out->width};
231 transform(piece, hw); // transform() is used reversed here intentionally
232 roi_in->height = hw[0];
233 roi_in->width = hw[1];
234
235 float reduction_ratio = MAX(hw[0] / (piece->buf_in.height * 1.0f), hw[1] / (piece->buf_in.width * 1.0f));
236 if (reduction_ratio > 1.0f)
237 {
238 roi_in->height /= reduction_ratio;
239 roi_in->width /= reduction_ratio;
240 }
241
243 d->x_scale = (roi_in->width * 1.0f) / (roi_out->width * 1.0f);
244 d->y_scale = (roi_in->height * 1.0f) / (roi_out->height * 1.0f);
245
246 roi_in->scale = roi_out->scale * MAX(d->x_scale, d->y_scale);
247 roi_in->x = roi_out->x * d->x_scale;
248 roi_in->y = roi_out->y * d->y_scale;
249}
250
253 const void *const ivoid, void *const ovoid)
254{
255 (void)pipe;
256 const dt_iop_roi_t *const roi_in = &piece->roi_in;
257 const dt_iop_roi_t *const roi_out = &piece->roi_out;
258 const int ch = piece->dsc_in.channels;
259 const int ch_width = ch * roi_in->width;
261 const dt_iop_scalepixels_data_t * const d = piece->data;
263 // (slow) point-by-point transformation.
264 // TODO: optimize with scanlines and linear steps between?
265 for(int j = 0; j < roi_out->height; j++)
266 {
267 float *out = ((float *)ovoid) + (size_t)4 * j * roi_out->width;
268 for(int i = 0; i < roi_out->width; i++, out += 4)
269 {
270 float x = i*d->x_scale;
271 float y = j*d->y_scale;
272
273 dt_interpolation_compute_pixel4c(interpolation, (float *)ivoid, out, x, y, roi_in->width,
274 roi_in->height, ch_width);
275 }
276 }
277 return 0;
278}
279
282{
283 const dt_iop_scalepixels_params_t *p = params;
285
286 d->pixel_aspect_ratio = p->pixel_aspect_ratio;
287 d->x_scale = 1.0f;
288 d->y_scale = 1.0f;
289
290 if(isnan(p->pixel_aspect_ratio) || p->pixel_aspect_ratio <= 0.0f || p->pixel_aspect_ratio == 1.0f)
291 piece->enabled = 0;
292}
293
294/* --- the geometry service's view of this module (develop/geometry/geometry.h) --------- */
295
300
301static void _scalepixels_geometry_map_size(const void *data, const dt_iop_roi_t *const in, dt_iop_roi_t *out)
302{
304 *out = *in;
305
306 /* modify_roi_out() runs the aspect transform on the origin and on the size; expressed through
307 * the scales, that is a division, since transform() maps input to output and the scales are
308 * the input-over-output ratio. */
309 out->x = (int)floorf(in->x / g->x_scale);
310 out->y = (int)floorf(in->y / g->y_scale);
311 out->width = (int)ceilf(in->width / g->x_scale);
312 out->height = (int)ceilf(in->height / g->y_scale);
313
314 // sanity check.
315 if(out->x < 0) out->x = 0;
316 if(out->y < 0) out->y = 0;
317 if(out->width < 1) out->width = 1;
318 if(out->height < 1) out->height = 1;
319}
320
321static int _scalepixels_geometry_transform(const void *data, const dt_geometry_record_t *const record,
322 dt_geometry_chain_t *chain, float *points, size_t points_count)
323{
325 for(size_t i = 0; i < points_count * 2; i += 2)
326 {
327 points[i] /= g->x_scale;
328 points[i + 1] /= g->y_scale;
329 }
330 return 1;
331}
332
333static int _scalepixels_geometry_backtransform(const void *data, const dt_geometry_record_t *const record,
334 dt_geometry_chain_t *chain, float *points,
335 size_t points_count)
336{
338 for(size_t i = 0; i < points_count * 2; i += 2)
339 {
340 points[i] *= g->x_scale;
341 points[i + 1] *= g->y_scale;
342 }
343 return 1;
344}
345
351
352gboolean geometry_record(dt_iop_module_t *self, const void *params, dt_geometry_record_t *record)
353{
354 const dt_iop_scalepixels_params_t *const p = (const dt_iop_scalepixels_params_t *)params;
355
356 /* The same disabling condition commit_params() applies: a ratio of one, or a nonsensical one,
357 * means this module does nothing. Published as identity. */
358 if(isnan(p->pixel_aspect_ratio) || p->pixel_aspect_ratio <= 0.0f || p->pixel_aspect_ratio == 1.0f)
359 return TRUE;
360
363 if(IS_NULL_PTR(data)) return FALSE;
364 _scalepixels_scales(p->pixel_aspect_ratio, &data->x_scale, &data->y_scale);
365
366 record->data = data;
367 record->free_data = dt_free_gpointer;
369 return TRUE;
370}
371
377
379{
380 dt_free_align(piece->data);
381 piece->data = NULL;
382}
383
385{
387
388 const dt_image_t *const image = &(self->dev->image_storage);
389
391
392 self->default_enabled = (!isnan(d->pixel_aspect_ratio) &&
393 d->pixel_aspect_ratio > 0.0f &&
394 d->pixel_aspect_ratio != 1.0f);
395
396 // FIXME: does not work.
397 self->hide_enable_button = !self->default_enabled;
398 // Label text reflects the per-image default; applied in gui_update() (GUI thread, widget exists).
399}
400
402{
403 gtk_label_set_text(GTK_LABEL(self->gui->widget), self->default_enabled
404 ? _("automatic pixel scaling")
405 : _("automatic pixel scaling\nonly works for the sensors that need it."));
406}
407
409{
410 IOP_GUI_ALLOC(scalepixels);
411
412 self->gui->widget = dt_ui_label_new("");
413 gtk_label_set_line_wrap(GTK_LABEL(self->gui->widget), TRUE);
414
415}
416
417// clang-format off
418// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
419// vim: shiftwidth=2 expandtab tabstop=2 cindent
420// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
421// clang-format on
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
@ IOP_CS_RGB
static const float x
const dt_colormatrix_t dt_aligned_pixel_t out
void dt_iop_params_t
Definition dev_history.h:43
Where things are on the image, answered without a pipeline.
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_ALLOW_TILING
Definition imageop.h:188
@ IOP_FLAGS_UNSAFE_COPY
Definition imageop.h:196
@ IOP_FLAGS_ONE_INSTANCE
Definition imageop.h:191
@ IOP_FLAGS_TILING_FULL_ROI
Definition imageop.h:190
@ IOP_GROUP_TECHNICAL
Definition imageop.h:162
@ IOP_TAG_DISTORT
Definition imageop.h:170
#define IOP_GUI_ALLOC(module)
Definition imageop_gui.h:93
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
GtkWidget * dt_ui_label_new(const gchar *str)
Definition label.c:125
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
static void dt_free_gpointer(gpointer ptr)
g_free() one pointer, with the signature GDestroyNotify wants.
Definition mem_alloc.h:184
#define DT_MODULE_INTROSPECTION(MODVER, PARAMSTYPE)
DT_MODULE() for a module whose params struct is introspected.
#define __OMP_PARALLEL_FOR__(...)
Definition openmp.h:95
int operation_tags()
Definition scalepixels.c:87
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:97
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:82
static void _scalepixels_scales(const float pixel_aspect_ratio, float *x_scale, float *y_scale)
The axis scales this module applies, from its one parameter. THE constructor.
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)
static int _scalepixels_geometry_backtransform(const void *data, const dt_geometry_record_t *const record, dt_geometry_chain_t *chain, float *points, size_t points_count)
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)
static const dt_geometry_vtable_t _scalepixels_geometry_vtable
const char * name()
Definition scalepixels.c:71
gboolean geometry_record(dt_iop_module_t *self, const void *params, dt_geometry_record_t *record)
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)
static void _scalepixels_geometry_map_size(const void *data, const dt_iop_roi_t *const in, dt_iop_roi_t *out)
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:92
int flags()
Definition scalepixels.c:76
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 int _scalepixels_geometry_transform(const void *data, const dt_geometry_record_t *const record, dt_geometry_chain_t *chain, 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:225
One module instance's contribution, as data.
Definition geometry.h:99
const dt_geometry_vtable_t * vtable
Definition geometry.h:110
void(* free_data)(void *data)
Definition geometry.h:112
A module's geometry, evaluated. Pure functions of the record's own data.
Definition geometry.h:75
void(* map_size)(const void *data, const dt_iop_roi_t *const in, dt_iop_roi_t *out)
Full-resolution input rect -> output rect. Mirrors modify_roi_out() at scale 1.
Definition geometry.h:77
float pixel_aspect_ratio
Definition image.h:443
unsigned int channels
Definition format.h:83
GtkWidget * widget
Definition imageop_gui.h:47
int32_t hide_enable_button
Definition imageop.h:270
dt_iop_params_t * default_params
Definition imageop.h:333
struct dt_iop_module_gui_t * gui
Definition imageop.h:346
struct dt_develop_t * dev
Definition imageop.h:311
gboolean default_enabled
Definition imageop.h:318
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 MAX(a, b)
Definition thinplate.c:29