Skip to content

Commit a1cf4a9

Browse files
authored
Raster Mask: PNG support and image folder (#20170)
1 parent 0c0b8bf commit a1cf4a9

File tree

1 file changed

+93
-11
lines changed

1 file changed

+93
-11
lines changed

src/iop/rasterfile.c

Lines changed: 93 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "config.h"
2121
#endif
2222
#include <math.h>
23+
#include <stdint.h>
2324
#include <stdlib.h>
2425
#include <stdio.h>
2526
#include <string.h>
@@ -33,6 +34,7 @@
3334
#include "common/interpolation.h"
3435
#include "common/fast_guided_filter.h"
3536
#include "common/pfm.h"
37+
#include "imageio/imageio_png.h"
3638
#include "gui/accelerators.h"
3739
#include "gui/gtk.h"
3840

@@ -96,7 +98,7 @@ const char *aliases()
9698
const char **description(dt_iop_module_t *self)
9799
{
98100
return dt_iop_set_description(self,
99-
_("read PFM files recorded for use as raster masks"),
101+
_("read PFM/PNG files recorded for use as raster masks"),
100102
_("corrective or creative"),
101103
_("linear, raw, scene-referred"),
102104
_("linear, raw"),
@@ -159,6 +161,87 @@ static float *_read_rasterfile(char *filename,
159161
*sheight = 0;
160162
if(!filename || filename[0] == 0) return NULL;
161163

164+
const char *extension = g_strrstr(filename, ".");
165+
const gboolean is_png = extension && !g_ascii_strcasecmp(extension, ".png");
166+
167+
if(is_png)
168+
{
169+
dt_imageio_png_t png;
170+
if(!dt_imageio_png_read_header(filename, &png))
171+
{
172+
dt_print(DT_DEBUG_ALWAYS, "failed to read PNG header from '%s'", filename ? filename : "???");
173+
dt_control_log(_("can't read raster mask file '%s'"), filename ? filename : "???");
174+
return NULL;
175+
}
176+
177+
const size_t rowbytes = png_get_rowbytes(png.png_ptr, png.info_ptr);
178+
uint8_t *buf = dt_alloc_aligned((size_t)png.height * rowbytes);
179+
if(!buf)
180+
{
181+
fclose(png.f);
182+
png_destroy_read_struct(&png.png_ptr, &png.info_ptr, NULL);
183+
dt_print(DT_DEBUG_ALWAYS, "can't read raster mask file '%s'", filename ? filename : "???");
184+
dt_control_log(_("can't read raster mask file '%s'"), filename ? filename : "???");
185+
return NULL;
186+
}
187+
188+
if(!dt_imageio_png_read_image(&png, buf))
189+
{
190+
dt_free_align(buf);
191+
dt_print(DT_DEBUG_ALWAYS, "can't read raster mask file '%s'", filename ? filename : "???");
192+
dt_control_log(_("can't read raster mask file '%s'"), filename ? filename : "???");
193+
return NULL;
194+
}
195+
196+
const int width = png.width;
197+
const int height = png.height;
198+
float *mask = dt_iop_image_alloc(width, height, 1);
199+
if(!mask)
200+
{
201+
dt_free_align(buf);
202+
dt_print(DT_DEBUG_ALWAYS, "can't read raster mask file '%s'", filename ? filename : "???");
203+
dt_control_log(_("can't read raster mask file '%s'"), filename ? filename : "???");
204+
return NULL;
205+
}
206+
207+
if(png.bit_depth < 16)
208+
{
209+
const float normalizer = 1.0f / 255.0f;
210+
DT_OMP_FOR()
211+
for(size_t k = 0; k < (size_t)width * height; k++)
212+
{
213+
const size_t base = 3 * k;
214+
float val = 0.0f;
215+
if(mode & DT_RASTERFILE_MODE_RED) val = MAX(val, buf[base] * normalizer);
216+
if(mode & DT_RASTERFILE_MODE_GREEN) val = MAX(val, buf[base + 1] * normalizer);
217+
if(mode & DT_RASTERFILE_MODE_BLUE) val = MAX(val, buf[base + 2] * normalizer);
218+
mask[k] = CLIP(val);
219+
}
220+
}
221+
else
222+
{
223+
const float normalizer = 1.0f / 65535.0f;
224+
DT_OMP_FOR()
225+
for(size_t k = 0; k < (size_t)width * height; k++)
226+
{
227+
const size_t base = 6 * k;
228+
const float red = (buf[base] * 256.0f + buf[base + 1]) * normalizer;
229+
const float green = (buf[base + 2] * 256.0f + buf[base + 3]) * normalizer;
230+
const float blue = (buf[base + 4] * 256.0f + buf[base + 5]) * normalizer;
231+
float val = 0.0f;
232+
if(mode & DT_RASTERFILE_MODE_RED) val = MAX(val, red);
233+
if(mode & DT_RASTERFILE_MODE_GREEN) val = MAX(val, green);
234+
if(mode & DT_RASTERFILE_MODE_BLUE) val = MAX(val, blue);
235+
mask[k] = CLIP(val);
236+
}
237+
}
238+
239+
dt_free_align(buf);
240+
*swidth = width;
241+
*sheight = height;
242+
return mask;
243+
}
244+
162245
int width, height, channels, error = 0;
163246
float *image = dt_read_pfm(filename, &error, &width, &height, &channels, 3);
164247
float *mask = dt_iop_image_alloc(width, height, 1);
@@ -191,14 +274,11 @@ static float *_read_rasterfile(char *filename,
191274
static int _check_extension(const struct dirent *namestruct)
192275
{
193276
const char *filename = namestruct->d_name;
194-
int res = 0;
195-
if(!filename || !filename[0]) return res;
196-
char *p = g_strrstr(filename, ".");
197-
if(!p) return res;
198-
char *fext = g_ascii_strdown(g_strdup(p), -1);
199-
if(!g_strcmp0(fext, ".pfm")) res = 1;
200-
g_free(fext);
201-
return res;
277+
if(!filename || !filename[0]) return 0;
278+
const char *p = g_strrstr(filename, ".");
279+
return p
280+
&& (!g_ascii_strcasecmp(p, ".pfm")
281+
|| !g_ascii_strcasecmp(p, ".png"));
202282
}
203283

204284
static void _update_filepath(dt_iop_module_t *self)
@@ -263,9 +343,11 @@ static void _fbutton_clicked(GtkWidget *widget, dt_iop_module_t *self)
263343
gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(filechooser), FALSE);
264344
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(filechooser), mfolder);
265345
GtkFileFilter *filter = GTK_FILE_FILTER(gtk_file_filter_new());
266-
// only pfm files yet supported
346+
// only pfm/png files yet supported
267347
gtk_file_filter_add_pattern(filter, "*.pfm");
268348
gtk_file_filter_add_pattern(filter, "*.PFM");
349+
gtk_file_filter_add_pattern(filter, "*.png");
350+
gtk_file_filter_add_pattern(filter, "*.PNG");
269351
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(filechooser), filter);
270352
gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(filechooser), filter);
271353

@@ -592,7 +674,7 @@ void gui_init(dt_iop_module_t *self)
592674

593675
g->fbutton = dtgtk_button_new(dtgtk_cairo_paint_directory, CPF_NONE, NULL);
594676
gtk_widget_set_name(g->fbutton, "non-flat");
595-
gtk_widget_set_tooltip_text(g->fbutton, _("select the PFM file recorded as a raster mask,\n"
677+
gtk_widget_set_tooltip_text(g->fbutton, _("select the PFM/PNG file recorded as a raster mask,\n"
596678
"CAUTION: path must be set in preferences/processing before choosing"));
597679
g_signal_connect(G_OBJECT(g->fbutton), "clicked", G_CALLBACK(_fbutton_clicked), self);
598680

0 commit comments

Comments
 (0)