|
20 | 20 | #include "config.h" |
21 | 21 | #endif |
22 | 22 | #include <math.h> |
| 23 | +#include <stdint.h> |
23 | 24 | #include <stdlib.h> |
24 | 25 | #include <stdio.h> |
25 | 26 | #include <string.h> |
|
33 | 34 | #include "common/interpolation.h" |
34 | 35 | #include "common/fast_guided_filter.h" |
35 | 36 | #include "common/pfm.h" |
| 37 | +#include "imageio/imageio_png.h" |
36 | 38 | #include "gui/accelerators.h" |
37 | 39 | #include "gui/gtk.h" |
38 | 40 |
|
@@ -96,7 +98,7 @@ const char *aliases() |
96 | 98 | const char **description(dt_iop_module_t *self) |
97 | 99 | { |
98 | 100 | 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"), |
100 | 102 | _("corrective or creative"), |
101 | 103 | _("linear, raw, scene-referred"), |
102 | 104 | _("linear, raw"), |
@@ -159,6 +161,87 @@ static float *_read_rasterfile(char *filename, |
159 | 161 | *sheight = 0; |
160 | 162 | if(!filename || filename[0] == 0) return NULL; |
161 | 163 |
|
| 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 | + |
162 | 245 | int width, height, channels, error = 0; |
163 | 246 | float *image = dt_read_pfm(filename, &error, &width, &height, &channels, 3); |
164 | 247 | float *mask = dt_iop_image_alloc(width, height, 1); |
@@ -191,14 +274,11 @@ static float *_read_rasterfile(char *filename, |
191 | 274 | static int _check_extension(const struct dirent *namestruct) |
192 | 275 | { |
193 | 276 | 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")); |
202 | 282 | } |
203 | 283 |
|
204 | 284 | static void _update_filepath(dt_iop_module_t *self) |
@@ -263,9 +343,11 @@ static void _fbutton_clicked(GtkWidget *widget, dt_iop_module_t *self) |
263 | 343 | gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(filechooser), FALSE); |
264 | 344 | gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(filechooser), mfolder); |
265 | 345 | GtkFileFilter *filter = GTK_FILE_FILTER(gtk_file_filter_new()); |
266 | | - // only pfm files yet supported |
| 346 | + // only pfm/png files yet supported |
267 | 347 | gtk_file_filter_add_pattern(filter, "*.pfm"); |
268 | 348 | gtk_file_filter_add_pattern(filter, "*.PFM"); |
| 349 | + gtk_file_filter_add_pattern(filter, "*.png"); |
| 350 | + gtk_file_filter_add_pattern(filter, "*.PNG"); |
269 | 351 | gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(filechooser), filter); |
270 | 352 | gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(filechooser), filter); |
271 | 353 |
|
@@ -592,7 +674,7 @@ void gui_init(dt_iop_module_t *self) |
592 | 674 |
|
593 | 675 | g->fbutton = dtgtk_button_new(dtgtk_cairo_paint_directory, CPF_NONE, NULL); |
594 | 676 | 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" |
596 | 678 | "CAUTION: path must be set in preferences/processing before choosing")); |
597 | 679 | g_signal_connect(G_OBJECT(g->fbutton), "clicked", G_CALLBACK(_fbutton_clicked), self); |
598 | 680 |
|
|
0 commit comments