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 "system/macros.h"
28#include "system/mem_alloc.h"
29#include "develop/imageop.h" // for IOP_CS_RGB
30
31#include <assert.h>
32#include <glib/gstdio.h>
33#include <errno.h>
34#include <stdio.h>
35#include <stdlib.h>
36#include <strings.h>
37#include <time.h>
38
39// pbm -- portable bit map. values are either 0 or 1, single channel
40static dt_imageio_retval_t _read_pbm(dt_image_t *img, FILE*f, float *buf)
41{
43
44 int bytes_needed = (img->width + 7) / 8;
45 uint8_t *line = calloc(bytes_needed, sizeof(uint8_t));
46
47 float *buf_iter = buf;
48 for(size_t y = 0; y < img->height; y++)
49 {
50 if(fread(line, sizeof(uint8_t), (size_t)bytes_needed, f) != bytes_needed)
51 {
53 break;
54 }
55 for(size_t x = 0; x < bytes_needed; x++)
56 {
57 uint8_t byte = line[x] ^ 0xff;
58 for(int bit = 0; bit < 8 && x * 8 + bit < img->width; bit++)
59 {
60 float value = ((byte & 0x80) >> 7) * 1.0;
61 buf_iter[0] = buf_iter[1] = buf_iter[2] = value;
62 buf_iter[3] = 0.0;
63 buf_iter += 4;
64 byte <<= 1;
65 }
66 }
67 }
68
69 dt_free(line);
70
71 return result;
72}
73
74// pgm -- portable gray map. values are between 0 and max, single channel
75static dt_imageio_retval_t _read_pgm(dt_image_t *img, FILE*f, float *buf)
76{
78
79 unsigned int max;
80 int ret = fscanf(f, "%u", &max);
81 if(ret != 1 || max > 65535) return DT_IMAGEIO_FILE_CORRUPTED;
82
83 if(max <= 255)
84 {
85 uint8_t *line = calloc(img->width, sizeof(uint8_t));
86
87 float *buf_iter = buf;
88 for(size_t y = 0; y < img->height; y++)
89 {
90 if(fread(line, sizeof(uint8_t), (size_t)img->width, f) != img->width)
91 {
93 break;
94 }
95 for(size_t x = 0; x < img->width; x++)
96 {
97 float value = (float)line[x] / (float)max;
98 buf_iter[0] = buf_iter[1] = buf_iter[2] = value;
99 buf_iter[3] = 0.0;
100 buf_iter += 4;
101 }
102 }
103 dt_free(line);
104 }
105 else
106 {
107 uint16_t *line = calloc(img->width, sizeof(uint16_t));
108
109 float *buf_iter = buf;
110 for(size_t y = 0; y < img->height; y++)
111 {
112 if(fread(line, sizeof(uint16_t), (size_t)img->width, f) != img->width)
113 {
115 break;
116 }
117 for(size_t x = 0; x < img->width; x++)
118 {
119 uint16_t intvalue = line[x];
120 if(G_BYTE_ORDER != G_BIG_ENDIAN)
121 intvalue = GUINT16_SWAP_LE_BE(intvalue);
122 float value = (float)intvalue / (float)max;
123 buf_iter[0] = buf_iter[1] = buf_iter[2] = value;
124 buf_iter[3] = 0.0;
125 buf_iter += 4;
126 }
127 }
128 dt_free(line);
129 }
130
131 return result;
132}
133
134// ppm -- portable pix map. values are between 0 and max, three channels
135static dt_imageio_retval_t _read_ppm(dt_image_t *img, FILE*f, float *buf)
136{
138
139 unsigned int max;
140 int ret = fscanf(f, "%u", &max);
141 if(ret != 1 || max > 65535) return DT_IMAGEIO_FILE_CORRUPTED;
142
143 if(max <= 255)
144 {
145 uint8_t *line = calloc((size_t)3 * img->width, sizeof(uint8_t));
146
147 float *buf_iter = buf;
148 for(size_t y = 0; y < img->height; y++)
149 {
150 if(fread(line, 3 * sizeof(uint8_t), (size_t)img->width, f) != img->width)
151 {
153 break;
154 }
155 for(size_t x = 0; x < img->width; x++)
156 {
157 for(int c = 0; c < 3; c++)
158 {
159 float value = (float)line[x * 3 + c] / (float)max;
160 *buf_iter++ = value;
161 }
162 *buf_iter++ = 0.0;
163 }
164 }
165 dt_free(line);
166 }
167 else
168 {
169 uint16_t *line = calloc((size_t)3 * img->width, sizeof(uint16_t));
170
171 float *buf_iter = buf;
172 for(size_t y = 0; y < img->height; y++)
173 {
174 if(fread(line, 3 * sizeof(uint16_t), (size_t)img->width, f) != img->width)
175 {
177 break;
178 }
179 for(size_t x = 0; x < img->width; x++)
180 {
181 for(int c = 0; c < 3; c++)
182 {
183 uint16_t intvalue = line[x * 3 + c];
184 // PPM files are big endian! http://netpbm.sourceforge.net/doc/ppm.html
185 if(G_BYTE_ORDER != G_BIG_ENDIAN)
186 intvalue = GUINT16_SWAP_LE_BE(intvalue);
187 float value = (float)intvalue / (float)max;
188 *buf_iter++ = value;
189 }
190 *buf_iter++ = 0.0;
191 }
192 }
193 dt_free(line);
194 }
195
196 return result;
197}
198
200{
201 const char *ext = filename + strlen(filename);
202 while(*ext != '.' && ext > filename) ext--;
203 if(strcasecmp(ext, ".pbm") && strcasecmp(ext, ".pgm") && strcasecmp(ext, ".ppm")) return DT_IMAGEIO_FILE_CORRUPTED;
204 FILE *f = g_fopen(filename, "rb");
206 int ret = 0;
208
209 char head[2] = { 'X', 'X' };
210 ret = fscanf(f, "%c%c ", head, head + 1);
211 if(ret != 2 || head[0] != 'P') goto end;
212
213 char width_string[10] = { 0 };
214 char height_string[10] = { 0 };
215 ret = fscanf(f, "%9s %9s ", width_string, height_string);
216 if(ret != 2) goto end;
217
218 errno = 0;
219 img->width = strtol(width_string, NULL, 0);
220 img->height = strtol(height_string, NULL, 0);
221 if(errno != 0 || img->width <= 0 || img->height <= 0) goto end;
222
223 img->dsc.channels = 4;
224 img->dsc.datatype = TYPE_FLOAT;
225 img->dsc.bpp = 4 * sizeof(float);
226 img->dsc.cst = IOP_CS_RGB; // pnm is always RGB
227 img->dsc.filters = 0u;
228 img->flags &= ~DT_IMAGE_RAW;
229 img->flags &= ~DT_IMAGE_S_RAW;
230 img->flags &= ~DT_IMAGE_HDR;
231 img->flags |= DT_IMAGE_LDR;
232 img->loader = LOADER_PNM;
233
234 if(IS_NULL_PTR(mbuf))
235 {
236 result = DT_IMAGEIO_OK;
237 goto end;
238 }
239
240 float *buf = (float *)dt_mipmap_cache_alloc(mbuf, img);
241 if(IS_NULL_PTR(buf))
242 {
243 result = DT_IMAGEIO_CACHE_FULL;
244 goto end;
245 }
246
247 // we don't support ASCII variants or P7 anymaps! thanks to magic numbers those shouldn't reach us anyway.
248 if(head[1] == '4')
249 result = _read_pbm(img, f, buf);
250 else if(head[1] == '5')
251 result = _read_pgm(img, f, buf);
252 else if(head[1] == '6')
253 result = _read_ppm(img, f, buf);
254
255end:
256 fclose(f);
257
258 return result;
259}
260
261// clang-format off
262// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
263// vim: shiftwidth=2 expandtab tabstop=2 cindent
264// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
265// clang-format on
@ IOP_CS_RGB
static const float x
const float f
const float max
@ TYPE_FLOAT
Definition format.h:56
dt_imageio_retval_t
Definition image.h:91
@ DT_IMAGEIO_OK
Definition image.h:92
@ DT_IMAGEIO_CACHE_FULL
Definition image.h:95
@ DT_IMAGEIO_FILE_CORRUPTED
Definition image.h:94
@ DT_IMAGE_LDR
Definition image.h:122
@ LOADER_PNM
Definition image.h:292
static dt_imageio_retval_t _read_pgm(dt_image_t *img, FILE *f, float *buf)
Definition imageio_pnm.c:75
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:40
static dt_imageio_retval_t _read_ppm(dt_image_t *img, FILE *f, float *buf)
#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(ptr)
g_free() ptr and set it to NULL, skipping both if it is already NULL.
Definition mem_alloc.h:171
void * dt_mipmap_cache_alloc(dt_mipmap_buffer_t *buf, const dt_image_t *img)
static const dt_aligned_pixel_simd_t value
Definition simd.h:144
int32_t height
Definition image.h:397
dt_image_loader_t loader
Definition image.h:417
int32_t flags
Definition image.h:401
int32_t width
Definition image.h:397
dt_iop_buffer_dsc_t dsc
Definition image.h:419
uint32_t filters
Definition format.h:89
unsigned int channels
Definition format.h:83
dt_iop_buffer_type_t datatype
Definition format.h:85