Skip to content

Commit 2d920b3

Browse files
authored
Merge pull request #18405 from victoryforce/pnm-loader-tweaks
[imageio] PNM loader tweaks and maintenance
2 parents ecbef72 + 4afda7d commit 2d920b3

File tree

2 files changed

+39
-19
lines changed

2 files changed

+39
-19
lines changed

src/imageio/imageio.c

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
This file is part of darktable,
3-
Copyright (C) 2009-2024 darktable developers.
3+
Copyright (C) 2009-2025 darktable developers.
44
55
darktable is free software: you can redistribute it and/or modify
66
it under the terms of the GNU General Public License as published by
@@ -1635,9 +1635,6 @@ dt_imageio_retval_t dt_imageio_open(dt_image_t *img,
16351635
if(!_image_handled(ret))
16361636
ret = dt_imageio_open_jpeg(img, filename, buf);
16371637

1638-
if(!_image_handled(ret))
1639-
ret = dt_imageio_open_pnm(img, filename, buf);
1640-
16411638
// final fallback that tries to open file via GraphicsMagick or ImageMagick
16421639
if(!_image_handled(ret))
16431640
ret = dt_imageio_open_exotic(img, filename, buf);

src/imageio/imageio_pnm.c

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,8 @@ static dt_imageio_retval_t _read_pgm(dt_image_t *img, FILE*f, float *buf)
7777
dt_imageio_retval_t result = DT_IMAGEIO_OK;
7878

7979
unsigned int max;
80-
// We expect at most a 5-digit number (65535) + a newline + '\0', so 7 characters.
80+
// We expect at most a 5-digit number (65535) + a newline + '\0',
81+
// so 7 characters.
8182
char maxvalue_string[7];
8283
if(fgets(maxvalue_string,7,f))
8384
max = atoi(maxvalue_string);
@@ -122,6 +123,9 @@ static dt_imageio_retval_t _read_pgm(dt_image_t *img, FILE*f, float *buf)
122123
for(size_t x = 0; x < img->width; x++)
123124
{
124125
uint16_t intvalue = line[x];
126+
// PGM files are big endian, the most significant byte is first
127+
// in the case where the value must be represented by two bytes.
128+
// See http://netpbm.sourceforge.net/doc/pgm.html
125129
if(G_BYTE_ORDER != G_BIG_ENDIAN)
126130
intvalue = GUINT16_SWAP_LE_BE(intvalue);
127131
float value = (float)intvalue / (float)max;
@@ -142,7 +146,8 @@ static dt_imageio_retval_t _read_ppm(dt_image_t *img, FILE*f, float *buf)
142146
dt_imageio_retval_t result = DT_IMAGEIO_OK;
143147

144148
unsigned int max;
145-
// We expect at most a 5-digit number (65535) + a newline + '\0', so 7 characters.
149+
// We expect at most a 5-digit number (65535) + a newline + '\0',
150+
// so 7 characters.
146151
char maxvalue_string[7];
147152
if(fgets(maxvalue_string,7,f))
148153
max = atoi(maxvalue_string);
@@ -191,7 +196,9 @@ static dt_imageio_retval_t _read_ppm(dt_image_t *img, FILE*f, float *buf)
191196
for(int c = 0; c < 3; c++)
192197
{
193198
uint16_t intvalue = line[x * 3 + c];
194-
// PPM files are big endian! http://netpbm.sourceforge.net/doc/ppm.html
199+
// PPM files are big endian, the most significant byte is first
200+
// in the case where the value must be represented by two bytes.
201+
// See http://netpbm.sourceforge.net/doc/ppm.html
195202
if(G_BYTE_ORDER != G_BIG_ENDIAN)
196203
intvalue = GUINT16_SWAP_LE_BE(intvalue);
197204
float value = (float)intvalue / (float)max;
@@ -206,50 +213,60 @@ static dt_imageio_retval_t _read_ppm(dt_image_t *img, FILE*f, float *buf)
206213
return result;
207214
}
208215

209-
dt_imageio_retval_t dt_imageio_open_pnm(dt_image_t *img, const char *filename, dt_mipmap_buffer_t *mbuf)
216+
dt_imageio_retval_t dt_imageio_open_pnm(dt_image_t *img,
217+
const char *filename,
218+
dt_mipmap_buffer_t *mbuf)
210219
{
211-
const char *ext = filename + strlen(filename);
212-
while(*ext != '.' && ext > filename) ext--;
213-
if(strcasecmp(ext, ".pbm") && strcasecmp(ext, ".pgm") && strcasecmp(ext, ".pnm") && strcasecmp(ext, ".ppm"))
214-
return DT_IMAGEIO_UNSUPPORTED_FORMAT;
215220
FILE *f = g_fopen(filename, "rb");
216221
if(!f) return DT_IMAGEIO_FILE_NOT_FOUND;
217222
int ret = 0;
218223
dt_imageio_retval_t result = DT_IMAGEIO_LOAD_FAILED;
219224

220225
char head[2] = { 'X', 'X' };
221226
ret = fscanf(f, "%c%c ", head, head + 1);
222-
if(ret != 2 || head[0] != 'P') goto end;
227+
if(ret != 2 || head[0] != 'P')
228+
{
229+
fclose(f);
230+
return DT_IMAGEIO_LOAD_FAILED;
231+
}
223232

224233
char width_string[10] = { 0 };
225234
char height_string[10] = { 0 };
226235
ret = fscanf(f, "%9s %9s ", width_string, height_string);
227-
if(ret != 2) goto end;
236+
if(ret != 2)
237+
{
238+
fclose(f);
239+
return DT_IMAGEIO_FILE_CORRUPTED;
240+
}
228241

229242
errno = 0;
230243
img->width = strtol(width_string, NULL, 0);
231244
img->height = strtol(height_string, NULL, 0);
232-
if(errno != 0 || img->width <= 0 || img->height <= 0) goto end;
245+
if(errno != 0 || img->width <= 0 || img->height <= 0)
246+
{
247+
fclose(f);
248+
return DT_IMAGEIO_FILE_CORRUPTED;
249+
}
233250

234251
img->buf_dsc.channels = 4;
235252
img->buf_dsc.datatype = TYPE_FLOAT;
236253

237254
float *buf = (float *)dt_mipmap_cache_alloc(mbuf, img);
238255
if(!buf)
239256
{
240-
result = DT_IMAGEIO_CACHE_FULL;
241-
goto end;
257+
fclose(f);
258+
return DT_IMAGEIO_CACHE_FULL;
242259
}
243260

244-
// we don't support ASCII variants or P7 anymaps! thanks to magic numbers those shouldn't reach us anyway.
261+
// We don't support ASCII variants or P7 anymaps!
262+
// Thanks to magic numbers those shouldn't reach us anyway.
245263
if(head[1] == '4')
246264
result = _read_pbm(img, f, buf);
247265
else if(head[1] == '5')
248266
result = _read_pgm(img, f, buf);
249267
else if(head[1] == '6')
250268
result = _read_ppm(img, f, buf);
251269

252-
end:
253270
fclose(f);
254271

255272
if(result == DT_IMAGEIO_OK)
@@ -259,6 +276,12 @@ dt_imageio_retval_t dt_imageio_open_pnm(dt_image_t *img, const char *filename, d
259276
img->flags &= ~DT_IMAGE_RAW;
260277
img->flags &= ~DT_IMAGE_S_RAW;
261278
img->flags &= ~DT_IMAGE_HDR;
279+
280+
// The most common and generally assumed interpretation of the
281+
// image data in PNM seems to be that the values ​​are non-linear.
282+
// This is why we set the so called 'LDR' flag, which essentially,
283+
// in the absence of metadata, signals darktable the need to treat
284+
// the image data as non-linear.
262285
img->flags |= DT_IMAGE_LDR;
263286
img->loader = LOADER_PNM;
264287
}

0 commit comments

Comments
 (0)