Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
imageio_pnm.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2018 Tobias Ellinghaus.
4 Copyright (C) 2019 Heiko Bauke.
5 Copyright (C) 2020-2021 Pascal Obry.
6 Copyright (C) 2021 Hubert Kowalski.
7 Copyright (C) 2021 luzpaz.
8 Copyright (C) 2022 Martin Baƙinka.
9 Copyright (C) 2023 Alynx Zhou.
10
11 darktable is free software: you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation, either version 3 of the License, or
14 (at your option) any later version.
15
16 darktable is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with darktable. If not, see <http://www.gnu.org/licenses/>.
23*/
24#ifdef HAVE_CONFIG_H
25#include "config.h"
26#endif
27#include "common/darktable.h"
28#include "common/imageio_pfm.h"
29#include "develop/imageop.h" // for IOP_CS_RGB
30
31#include <assert.h>
32#include <errno.h>
33#include <math.h>
34#include <stdio.h>
35#include <stdlib.h>
36#include <strings.h>
37#include <sys/stat.h>
38#include <sys/types.h>
39#include <time.h>
40#include <unistd.h>
41
42// pbm -- portable bit map. values are either 0 or 1, single channel
43static dt_imageio_retval_t _read_pbm(dt_image_t *img, FILE*f, float *buf)
44{
46
47 int bytes_needed = (img->width + 7) / 8;
48 uint8_t *line = calloc(bytes_needed, sizeof(uint8_t));
49
50 float *buf_iter = buf;
51 for(size_t y = 0; y < img->height; y++)
52 {
53 if(fread(line, sizeof(uint8_t), (size_t)bytes_needed, f) != bytes_needed)
54 {
56 break;
57 }
58 for(size_t x = 0; x < bytes_needed; x++)
59 {
60 uint8_t byte = line[x] ^ 0xff;
61 for(int bit = 0; bit < 8 && x * 8 + bit < img->width; bit++)
62 {
63 float value = ((byte & 0x80) >> 7) * 1.0;
64 buf_iter[0] = buf_iter[1] = buf_iter[2] = value;
65 buf_iter[3] = 0.0;
66 buf_iter += 4;
67 byte <<= 1;
68 }
69 }
70 }
71
72 dt_free(line);
73
74 return result;
75}
76
77// pgm -- portable gray map. values are between 0 and max, single channel
78static dt_imageio_retval_t _read_pgm(dt_image_t *img, FILE*f, float *buf)
79{
81
82 unsigned int max;
83 int ret = fscanf(f, "%u", &max);
84 if(ret != 1 || max > 65535) return DT_IMAGEIO_FILE_CORRUPTED;
85
86 if(max <= 255)
87 {
88 uint8_t *line = calloc(img->width, sizeof(uint8_t));
89
90 float *buf_iter = buf;
91 for(size_t y = 0; y < img->height; y++)
92 {
93 if(fread(line, sizeof(uint8_t), (size_t)img->width, f) != img->width)
94 {
96 break;
97 }
98 for(size_t x = 0; x < img->width; x++)
99 {
100 float value = (float)line[x] / (float)max;
101 buf_iter[0] = buf_iter[1] = buf_iter[2] = value;
102 buf_iter[3] = 0.0;
103 buf_iter += 4;
104 }
105 }
106 dt_free(line);
107 }
108 else
109 {
110 uint16_t *line = calloc(img->width, sizeof(uint16_t));
111
112 float *buf_iter = buf;
113 for(size_t y = 0; y < img->height; y++)
114 {
115 if(fread(line, sizeof(uint16_t), (size_t)img->width, f) != img->width)
116 {
118 break;
119 }
120 for(size_t x = 0; x < img->width; x++)
121 {
122 uint16_t intvalue = line[x];
123 if(G_BYTE_ORDER != G_BIG_ENDIAN)
124 intvalue = GUINT16_SWAP_LE_BE(intvalue);
125 float value = (float)intvalue / (float)max;
126 buf_iter[0] = buf_iter[1] = buf_iter[2] = value;
127 buf_iter[3] = 0.0;
128 buf_iter += 4;
129 }
130 }
131 dt_free(line);
132 }
133
134 return result;
135}
136
137// ppm -- portable pix map. values are between 0 and max, three channels
138static dt_imageio_retval_t _read_ppm(dt_image_t *img, FILE*f, float *buf)
139{
141
142 unsigned int max;
143 int ret = fscanf(f, "%u", &max);
144 if(ret != 1 || max > 65535) return DT_IMAGEIO_FILE_CORRUPTED;
145
146 if(max <= 255)
147 {
148 uint8_t *line = calloc((size_t)3 * img->width, sizeof(uint8_t));
149
150 float *buf_iter = buf;
151 for(size_t y = 0; y < img->height; y++)
152 {
153 if(fread(line, 3 * sizeof(uint8_t), (size_t)img->width, f) != img->width)
154 {
156 break;
157 }
158 for(size_t x = 0; x < img->width; x++)
159 {
160 for(int c = 0; c < 3; c++)
161 {
162 float value = (float)line[x * 3 + c] / (float)max;
163 *buf_iter++ = value;
164 }
165 *buf_iter++ = 0.0;
166 }
167 }
168 dt_free(line);
169 }
170 else
171 {
172 uint16_t *line = calloc((size_t)3 * img->width, sizeof(uint16_t));
173
174 float *buf_iter = buf;
175 for(size_t y = 0; y < img->height; y++)
176 {
177 if(fread(line, 3 * sizeof(uint16_t), (size_t)img->width, f) != img->width)
178 {
180 break;
181 }
182 for(size_t x = 0; x < img->width; x++)
183 {
184 for(int c = 0; c < 3; c++)
185 {
186 uint16_t intvalue = line[x * 3 + c];
187 // PPM files are big endian! http://netpbm.sourceforge.net/doc/ppm.html
188 if(G_BYTE_ORDER != G_BIG_ENDIAN)
189 intvalue = GUINT16_SWAP_LE_BE(intvalue);
190 float value = (float)intvalue / (float)max;
191 *buf_iter++ = value;
192 }
193 *buf_iter++ = 0.0;
194 }
195 }
196 dt_free(line);
197 }
198
199 return result;
200}
201
203{
204 const char *ext = filename + strlen(filename);
205 while(*ext != '.' && ext > filename) ext--;
206 if(strcasecmp(ext, ".pbm") && strcasecmp(ext, ".pgm") && strcasecmp(ext, ".ppm")) return DT_IMAGEIO_FILE_CORRUPTED;
207 FILE *f = g_fopen(filename, "rb");
209 int ret = 0;
211
212 char head[2] = { 'X', 'X' };
213 ret = fscanf(f, "%c%c ", head, head + 1);
214 if(ret != 2 || head[0] != 'P') goto end;
215
216 char width_string[10] = { 0 };
217 char height_string[10] = { 0 };
218 ret = fscanf(f, "%9s %9s ", width_string, height_string);
219 if(ret != 2) goto end;
220
221 errno = 0;
222 img->width = strtol(width_string, NULL, 0);
223 img->height = strtol(height_string, NULL, 0);
224 if(errno != 0 || img->width <= 0 || img->height <= 0) goto end;
225
226 img->dsc.channels = 4;
227 img->dsc.datatype = TYPE_FLOAT;
228 img->dsc.bpp = 4 * sizeof(float);
229 img->dsc.cst = IOP_CS_RGB; // pnm is always RGB
230 img->dsc.filters = 0u;
231 img->flags &= ~DT_IMAGE_RAW;
232 img->flags &= ~DT_IMAGE_S_RAW;
233 img->flags &= ~DT_IMAGE_HDR;
234 img->flags |= DT_IMAGE_LDR;
235 img->loader = LOADER_PNM;
236
237 if(IS_NULL_PTR(mbuf))
238 {
239 result = DT_IMAGEIO_OK;
240 goto end;
241 }
242
243 float *buf = (float *)dt_mipmap_cache_alloc(mbuf, img);
244 if(IS_NULL_PTR(buf))
245 {
246 result = DT_IMAGEIO_CACHE_FULL;
247 goto end;
248 }
249
250 // we don't support ASCII variants or P7 anymaps! thanks to magic numbers those shouldn't reach us anyway.
251 if(head[1] == '4')
252 result = _read_pbm(img, f, buf);
253 else if(head[1] == '5')
254 result = _read_pgm(img, f, buf);
255 else if(head[1] == '6')
256 result = _read_ppm(img, f, buf);
257
258end:
259 fclose(f);
260
261 return result;
262}
263
264// clang-format off
265// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
266// vim: shiftwidth=2 expandtab tabstop=2 cindent
267// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
268// clang-format on
@ IOP_CS_RGB
const dt_aligned_pixel_t f
const float max
#define dt_free(ptr)
Definition darktable.h:456
static const dt_aligned_pixel_simd_t value
Definition darktable.h:577
#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
@ 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_PNM
Definition image.h:232
static dt_imageio_retval_t _read_pgm(dt_image_t *img, FILE *f, float *buf)
Definition imageio_pnm.c:78
dt_imageio_retval_t dt_imageio_open_pnm(dt_image_t *img, const char *filename, dt_mipmap_buffer_t *mbuf)
static dt_imageio_retval_t _read_pbm(dt_image_t *img, FILE *f, float *buf)
Definition imageio_pnm.c:43
static dt_imageio_retval_t _read_ppm(dt_image_t *img, FILE *f, float *buf)
static const float x
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 flags
Definition image.h:319
int32_t width
Definition image.h:315
dt_iop_buffer_dsc_t dsc
Definition image.h:337
uint32_t filters
Definition format.h:60
unsigned int channels
Definition format.h:54
dt_iop_buffer_type_t datatype
Definition format.h:56