Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
imageio_png.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2009-2010, 2014 johannes hanika.
4 Copyright (C) 2010 Christian Himpel.
5 Copyright (C) 2012, 2014 Ulrich Pegelow.
6 Copyright (C) 2013-2016 Roman Lebedev.
7 Copyright (C) 2013-2014, 2016-2017 Tobias Ellinghaus.
8 Copyright (C) 2019, 2026 Aurélien PIERRE.
9 Copyright (C) 2019 Philippe Weyland.
10 Copyright (C) 2020 Hubert Kowalski.
11 Copyright (C) 2020-2021 Pascal Obry.
12 Copyright (C) 2021 Miloš Komarčević.
13 Copyright (C) 2022 Martin Bařinka.
14 Copyright (C) 2023-2024 Alynx Zhou.
15
16 darktable is free software: you can redistribute it and/or modify
17 it under the terms of the GNU General Public License as published by
18 the Free Software Foundation, either version 3 of the License, or
19 (at your option) any later version.
20
21 darktable is distributed in the hope that it will be useful,
22 but WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 GNU General Public License for more details.
25
26 You should have received a copy of the GNU General Public License
27 along with darktable. If not, see <http://www.gnu.org/licenses/>.
28*/
29#include <assert.h>
30#include <inttypes.h>
31#include <memory.h>
32#include <png.h>
33#include <stdio.h>
34#include <strings.h>
35
36#include "common/colorspaces.h"
37#include "common/darktable.h"
38#include "imageio_png.h"
39#include "common/exif.h"
40#include "control/conf.h"
41#include "develop/develop.h"
42#include "imageio.h"
43#include "imageio_tiff.h"
44
45int read_header(const char *filename, dt_imageio_png_t *png)
46{
47 png->f = g_fopen(filename, "rb");
48
49 if(IS_NULL_PTR(png->f)) return 1;
50
51#define NUM_BYTES_CHECK (8)
52
53 png_byte dat[NUM_BYTES_CHECK];
54
55 size_t cnt = fread(dat, 1, NUM_BYTES_CHECK, png->f);
56
57 if(cnt != NUM_BYTES_CHECK || png_sig_cmp(dat, (png_size_t)0, NUM_BYTES_CHECK))
58 {
59 fclose(png->f);
60 return 1;
61 }
62
63 png->png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
64
65 if(IS_NULL_PTR(png->png_ptr))
66 {
67 fclose(png->f);
68 return 1;
69 }
70
71 png->info_ptr = png_create_info_struct(png->png_ptr);
72 if(IS_NULL_PTR(png->info_ptr))
73 {
74 fclose(png->f);
75 png_destroy_read_struct(&png->png_ptr, NULL, NULL);
76 return 1;
77 }
78
79 if(setjmp(png_jmpbuf(png->png_ptr)))
80 {
81 fclose(png->f);
82 png_destroy_read_struct(&png->png_ptr, &png->info_ptr, NULL);
83 return 1;
84 }
85
86 png_init_io(png->png_ptr, png->f);
87
88 // we checked some bytes
89 png_set_sig_bytes(png->png_ptr, NUM_BYTES_CHECK);
90
91 // image info
92 png_read_info(png->png_ptr, png->info_ptr);
93
94 png->bit_depth = png_get_bit_depth(png->png_ptr, png->info_ptr);
95 png->color_type = png_get_color_type(png->png_ptr, png->info_ptr);
96
97 // image input transformations
98
99 // palette => rgb
100 if(png->color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png->png_ptr);
101
102 // 1, 2, 4 bit => 8 bit
103 if(png->color_type == PNG_COLOR_TYPE_GRAY && png->bit_depth < 8)
104 {
105 png_set_expand_gray_1_2_4_to_8(png->png_ptr);
106 png->bit_depth = 8;
107 }
108
109 // strip alpha channel
110 if(png->color_type & PNG_COLOR_MASK_ALPHA) png_set_strip_alpha(png->png_ptr);
111
112 // grayscale => rgb
113 if(png->color_type == PNG_COLOR_TYPE_GRAY || png->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
114 png_set_gray_to_rgb(png->png_ptr);
115
116 // reflect changes
117 png_read_update_info(png->png_ptr, png->info_ptr);
118
119 // png->bytespp = 3*bit_depth/8;
120 png->width = png_get_image_width(png->png_ptr, png->info_ptr);
121 png->height = png_get_image_height(png->png_ptr, png->info_ptr);
122
123#undef NUM_BYTES_CHECK
124
125 return 0;
126}
127
128
130{
131 if(setjmp(png_jmpbuf(png->png_ptr)))
132 {
133 fclose(png->f);
134 png_destroy_read_struct(&png->png_ptr, &png->info_ptr, NULL);
135 return 1;
136 }
137
138 png_bytep *row_pointers = malloc(sizeof(png_bytep) * png->height);
139
140 png_bytep row_pointer = (png_bytep)out;
141 const size_t rowbytes = png_get_rowbytes(png->png_ptr, png->info_ptr);
142
143 for(int y = 0; y < png->height; y++)
144 {
145 row_pointers[y] = row_pointer + (size_t)y * rowbytes;
146 }
147
148 png_read_image(png->png_ptr, row_pointers);
149
150 png_read_end(png->png_ptr, png->info_ptr);
151 png_destroy_read_struct(&png->png_ptr, &png->info_ptr, NULL);
152
153 dt_free(row_pointers);
154 fclose(png->f);
155 return 0;
156}
157
158
159
161{
162 const char *ext = filename + strlen(filename);
163 while(*ext != '.' && ext > filename) ext--;
164 if(strncmp(ext, ".png", 4) && strncmp(ext, ".PNG", 4)) return DT_IMAGEIO_FILE_CORRUPTED;
165 if(!img->exif_inited) (void)dt_exif_read(img, filename);
166
167 dt_imageio_png_t image;
168 uint8_t *buf = NULL;
169 uint32_t width, height;
170 uint16_t bpp;
171
172
173 if(read_header(filename, &image) != 0) return DT_IMAGEIO_FILE_CORRUPTED;
174
175 width = img->width = image.width;
176 height = img->height = image.height;
177 bpp = image.bit_depth;
178
179 img->dsc.channels = 4;
180 img->dsc.datatype = TYPE_FLOAT;
181 img->dsc.bpp = 4 * sizeof(float);
182 img->dsc.cst = IOP_CS_RGB; // png is always RGB
183 img->dsc.filters = 0u;
184 img->flags &= ~DT_IMAGE_RAW;
185 img->flags &= ~DT_IMAGE_S_RAW;
186 img->flags &= ~DT_IMAGE_HDR;
187 img->flags |= DT_IMAGE_LDR;
188 img->loader = LOADER_PNG;
189
190 if(IS_NULL_PTR(mbuf))
191 {
192 png_destroy_read_struct(&image.png_ptr, &image.info_ptr, NULL);
193 fclose(image.f);
194 return DT_IMAGEIO_OK;
195 }
196
197 float *mipbuf = (float *)dt_mipmap_cache_alloc(mbuf, img);
198 if(IS_NULL_PTR(mipbuf))
199 {
200 fclose(image.f);
201 png_destroy_read_struct(&image.png_ptr, &image.info_ptr, NULL);
202 fprintf(stderr, "[png_open] could not alloc full buffer for image `%s'\n", img->filename);
204 }
205
207 (size_t)image.height * png_get_rowbytes(image.png_ptr, image.info_ptr),
208 0);
209
210 if(IS_NULL_PTR(buf))
211 {
212 fclose(image.f);
213 png_destroy_read_struct(&image.png_ptr, &image.info_ptr, NULL);
214 fprintf(stderr, "[png_open] could not alloc intermediate buffer for image `%s'\n", img->filename);
216 }
217
218 if(read_image(&image, (void *)buf) != 0)
219 {
221 fprintf(stderr, "[png_open] could not read image `%s'\n", img->filename);
223 }
224
225 for(size_t j = 0; j < height; j++)
226 {
227 if(bpp < 16)
228 for(size_t i = 0; i < width; i++)
229 for(int k = 0; k < 3; k++)
230 mipbuf[4 * (j * width + i) + k] = buf[3 * (j * width + i) + k] * (1.0f / 255.0f);
231 else
232 for(size_t i = 0; i < width; i++)
233 for(int k = 0; k < 3; k++)
234 mipbuf[4 * (j * width + i) + k] = (256.0f * buf[2 * (3 * (j * width + i) + k)]
235 + buf[2 * (3 * (j * width + i) + k) + 1]) * (1.0f / 65535.0f);
236 }
237
239
240 return DT_IMAGEIO_OK;
241}
242
243int dt_imageio_png_read_profile(const char *filename, uint8_t **out)
244{
245 dt_imageio_png_t image;
246 png_charp name;
247 int compression_type;
248 png_uint_32 proflen;
249
250#if PNG_LIBPNG_VER >= 10500 /* 1.5.0 */
251 png_bytep profile;
252#else
253 png_charp profile;
254#endif
255
256 if(!(filename && *filename && out)) return 0;
257
258 if(read_header(filename, &image) != 0) return DT_IMAGEIO_FILE_CORRUPTED;
259
260#ifdef PNG_iCCP_SUPPORTED
261 if(png_get_valid(image.png_ptr, image.info_ptr, PNG_INFO_iCCP) != 0
262 && png_get_iCCP(image.png_ptr, image.info_ptr, &name, &compression_type, &profile, &proflen) != 0)
263 {
264 *out = (uint8_t *)g_malloc(proflen);
265 memcpy(*out, profile, proflen);
266 }
267 else
268#endif
269 proflen = 0;
270
271 png_destroy_read_struct(&image.png_ptr, &image.info_ptr, NULL);
272 fclose(image.f);
273
274 return proflen;
275}
276
277// clang-format off
278// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
279// vim: shiftwidth=2 expandtab tabstop=2 cindent
280// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
281// clang-format on
int width
Definition bilateral.h:1
int height
Definition bilateral.h:1
@ 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))
char * name
#define dt_pixelpipe_cache_alloc_align_cache(size, id)
Definition darktable.h:433
#define dt_free(ptr)
Definition darktable.h:456
#define dt_pixelpipe_cache_free_align(mem)
Definition darktable.h:453
#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 darktable.h:281
int dt_exif_read(dt_image_t *img, const char *path)
Definition exif.cc:1753
@ TYPE_FLOAT
Definition format.h:46
dt_imageio_retval_t
Definition image.h:78
@ DT_IMAGEIO_OK
Definition image.h:79
@ DT_IMAGEIO_CACHE_FULL
Definition image.h:82
@ DT_IMAGEIO_FILE_CORRUPTED
Definition image.h:81
@ DT_IMAGE_LDR
Definition image.h:109
@ LOADER_PNG
Definition image.h:224
int bpp
int read_image(dt_imageio_png_t *png, void *out)
#define NUM_BYTES_CHECK
int read_header(const char *filename, dt_imageio_png_t *png)
Definition imageio_png.c:45
int dt_imageio_png_read_profile(const char *filename, uint8_t **out)
dt_imageio_retval_t dt_imageio_open_png(dt_image_t *img, const char *filename, dt_mipmap_buffer_t *mbuf)
float *const restrict const size_t k
void * dt_mipmap_cache_alloc(dt_mipmap_buffer_t *buf, const dt_image_t *img)
int32_t height
Definition image.h:315
dt_image_loader_t loader
Definition image.h:335
int32_t exif_inited
Definition image.h:283
int32_t flags
Definition image.h:319
int32_t width
Definition image.h:315
dt_iop_buffer_dsc_t dsc
Definition image.h:337
char filename[DT_MAX_FILENAME_LEN]
Definition image.h:304
png_infop info_ptr
Definition imageio_png.h:41
png_structp png_ptr
Definition imageio_png.h:40
uint32_t filters
Definition format.h:60
unsigned int channels
Definition format.h:54
dt_iop_buffer_type_t datatype
Definition format.h:56