Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
imageio_rgbe.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2009-2011, 2014 johannes hanika.
4 Copyright (C) 2011, 2014, 2016-2017 Tobias Ellinghaus.
5 Copyright (C) 2012 Richard Wonka.
6 Copyright (C) 2013, 2016 Roman Lebedev.
7 Copyright (C) 2014 Ulrich Pegelow.
8 Copyright (C) 2020 Heiko Bauke.
9 Copyright (C) 2020-2021 Pascal Obry.
10 Copyright (C) 2022 Martin Baƙinka.
11 Copyright (C) 2023 Alynx Zhou.
12
13 darktable is free software: you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation, either version 3 of the License, or
16 (at your option) any later version.
17
18 darktable is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with darktable. If not, see <http://www.gnu.org/licenses/>.
25*/
26#ifdef HAVE_CONFIG_H
27#include "common/darktable.h"
28#include "config.h"
29#endif
30#include "common/imageio_rgbe.h"
31#include "develop/imageop.h" // for IOP_CS_RGB
32#include <ctype.h>
33#include <math.h>
34#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37
38
39/* THIS CODE CARRIES NO GUARANTEE OF USABILITY OR FITNESS FOR ANY PURPOSE.
40 * WHILE THE AUTHORS HAVE TRIED TO ENSURE THE PROGRAM WORKS CORRECTLY,
41 * IT IS STRICTLY USE AT YOUR OWN RISK.
42 *
43 * based on code written by Greg Ward */
44
45
46typedef struct
47{
48 int valid; /* indicate which fields are valid */
49 char programtype[16]; /* listed at beginning of file to identify it
50 * after "#?". defaults to "RGBE" */
51 float gamma; /* image has already been gamma corrected with
52 * given gamma. defaults to 1.0 (no correction) */
53 float exposure; /* a value of 1.0 in an image corresponds to
54 * <exposure> watts/steradian/m^2.
55 * defaults to 1.0 */
56 float primaries[8]; /* xy for R, G an B primaries plus white point
57 * defaults to:
58 * 0.640 0.330 0.290 0.600 0.150 0.060 0.333 0.333 */
60
61/* flags indicating which fields in an rgbe_header_info are valid */
62#define RGBE_VALID_PROGRAMTYPE 0x01
63#define RGBE_VALID_GAMMA 0x02
64#define RGBE_VALID_EXPOSURE 0x04
65
66/* return codes for rgbe routines */
67#define RGBE_RETURN_SUCCESS 0
68#define RGBE_RETURN_FAILURE -1
69
70#define RGBE_DATA_RED 0
71#define RGBE_DATA_GREEN 1
72#define RGBE_DATA_BLUE 2
73/* number of floats per pixel */
74#define RGBE_DATA_SIZE 3
75
83
84/* default error routine. change this to change error handling */
85static int rgbe_error(int rgbe_error_code, char *msg)
86{
87 switch(rgbe_error_code)
88 {
89 case rgbe_read_error:
90 perror("RGBE read error");
91 break;
93 perror("RGBE write error");
94 break;
96 fprintf(stderr, "RGBE bad file format: %s\n", msg);
97 break;
98 default:
100 fprintf(stderr, "RGBE error: %s\n", msg);
101 }
102 return RGBE_RETURN_FAILURE;
103}
104
105#if 0
106/* standard conversion from float pixels to rgbe pixels */
107/* note: you can remove the "inline"s if your compiler complains about it */
108static void
109float2rgbe(unsigned char rgbe[4], float red, float green, float blue)
110{
111 float v;
112 int e;
113
114 v = red;
115 if (green > v) v = green;
116 if (blue > v) v = blue;
117 if (v < 1e-32)
118 {
119 rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0;
120 }
121 else
122 {
123 v = frexp(v,&e) * 256.0/v;
124 rgbe[0] = (unsigned char) (red * v);
125 rgbe[1] = (unsigned char) (green * v);
126 rgbe[2] = (unsigned char) (blue * v);
127 rgbe[3] = (unsigned char) (e + 128);
128 }
129}
130#endif
131
132/* standard conversion from rgbe to float pixels */
133/* note: Ward uses ldexp(col+0.5,exp-(128+8)). However we wanted pixels */
134/* in the range [0,1] to map back into the range [0,1]. */
135static void rgbe2float(float *red, float *green, float *blue, unsigned char rgbe[4])
136{
137 if(rgbe[3]) /*nonzero pixel*/
138 {
139 const float f = ldexpf(1.0f, rgbe[3] - (int)(128 + 8));
140 *red = rgbe[0] * f;
141 *green = rgbe[1] * f;
142 *blue = rgbe[2] * f;
143 }
144 else
145 *red = *green = *blue = 0.0f;
146}
147
148#if 0
149/* default minimal header. modify if you want more information in header */
150int RGBE_WriteHeader(FILE *fp, int width, int height, rgbe_header_info *info)
151{
152 char *programtype = "RGBE";
153
154 if (info && (info->valid & RGBE_VALID_PROGRAMTYPE))
155 programtype = info->programtype;
156 if (fprintf(fp,"#?%s\n",programtype) < 0)
157 return rgbe_error(rgbe_write_error,NULL);
158 /* The #? is to identify file type, the programtype is optional. */
159 if (info && (info->valid & RGBE_VALID_GAMMA))
160 {
161 if (fprintf(fp,"GAMMA=%g\n",info->gamma) < 0)
162 return rgbe_error(rgbe_write_error,NULL);
163 }
164 if (info && (info->valid & RGBE_VALID_EXPOSURE))
165 {
166 if (fprintf(fp,"EXPOSURE=%g\n",info->exposure) < 0)
167 return rgbe_error(rgbe_write_error,NULL);
168 }
169 if (fprintf(fp,"FORMAT=32-bit_rle_rgbe\n\n") < 0)
170 return rgbe_error(rgbe_write_error,NULL);
171 if (fprintf(fp, "-Y %d +X %d\n", height, width) < 0)
172 return rgbe_error(rgbe_write_error,NULL);
173 return RGBE_RETURN_SUCCESS;
174}
175#endif
176
177/* minimal header reading. modify if you want to parse more information */
178int RGBE_ReadHeader(FILE *fp, int *width, int *height, rgbe_header_info *info)
179{
180 char buf[128];
181
182 if(info)
183 {
184 info->valid = 0;
185 info->programtype[0] = 0;
186 info->gamma = info->exposure = 1.0;
187 static const float default_primaries[] = { 0.640, 0.330, 0.290, 0.600, 0.150, 0.060, 0.333, 0.333 };
188 memcpy(info->primaries, default_primaries, sizeof(info->primaries));
189 }
190 if(fgets(buf, sizeof(buf) / sizeof(buf[0]), fp) == NULL) return rgbe_error(rgbe_read_error, NULL);
191 if((buf[0] != '#') || (buf[1] != '?'))
192 {
193 /* if you want to require the magic token then uncomment the next line */
194 /*return rgbe_error(rgbe_format_error,"bad initial token"); */
195 }
196 else if(info)
197 {
199 size_t i;
200 for(i = 0; i < sizeof(info->programtype) - 1; i++)
201 {
202 if((buf[i + 2] == 0) || isspace(buf[i + 2])) break;
203 info->programtype[i] = buf[i + 2];
204 }
205 info->programtype[i] = 0;
206 if(fgets(buf, sizeof(buf) / sizeof(buf[0]), fp) == 0) return rgbe_error(rgbe_read_error, NULL);
207 }
208 gboolean format_is_rgbe = FALSE;
209 for(;;)
210 {
211 if((buf[0] == 0) || (buf[0] == '\n'))
212 break;
213 else if(strcmp(buf, "FORMAT=32-bit_rle_rgbe\n") == 0)
214 format_is_rgbe = TRUE;
215 else if(info)
216 {
217 if(g_str_has_prefix(buf, "GAMMA="))
218 {
219 char *startptr = buf + strlen("GAMMA="), *endptr;
220 float tmp = g_ascii_strtod(startptr, &endptr);
221 if(startptr != endptr)
222 {
223 info->gamma = tmp;
224 info->valid |= RGBE_VALID_GAMMA;
225 }
226 }
227 else if(g_str_has_prefix(buf, "EXPOSURE="))
228 {
229 char *startptr = buf + strlen("EXPOSURE="), *endptr;
230 float tmp = g_ascii_strtod(startptr, &endptr);
231 if(startptr != endptr)
232 {
233 info->exposure = tmp;
234 info->valid |= RGBE_VALID_EXPOSURE;
235 }
236 }
237 else if(g_str_has_prefix(buf, "PRIMARIES="))
238 {
239 float tmp[8];
240 gboolean all_ok = TRUE;
241 char *startptr = buf + strlen("PRIMARIES="), *endptr;
242 for(int i = 0; i < 8; i++)
243 {
244 tmp[i] = g_ascii_strtod(startptr, &endptr);
245 if(startptr == endptr)
246 {
247 all_ok = FALSE;
248 break;
249 }
250 startptr = endptr;
251 }
252 if(all_ok) memcpy(info->primaries, tmp, sizeof(info->primaries));
253 }
254 }
255
256 if(fgets(buf, sizeof(buf) / sizeof(buf[0]), fp) == 0) return rgbe_error(rgbe_read_error, NULL);
257 }
258 if(!format_is_rgbe)
259 return rgbe_error(rgbe_format_error, "no FORMAT specifier found or it's not 32-bit_rle_rgbe");
260 while(!strcmp(buf, "\n")) // be nice and accept more than one blank line
261 if(fgets(buf, sizeof(buf) / sizeof(buf[0]), fp) == 0) return rgbe_error(rgbe_read_error, NULL);
262 if(sscanf(buf, "-Y %d +X %d", height, width) < 2)
263 return rgbe_error(rgbe_format_error, "missing image size specifier");
264 return RGBE_RETURN_SUCCESS;
265}
266
267#if 0
268/* simple write routine that does not use run length encoding */
269/* These routines can be made faster by allocating a larger buffer and
270 fread-ing and fwrite-ing the data in larger chunks */
271int RGBE_WritePixels(FILE *fp, float *data, int numpixels)
272{
273 unsigned char rgbe[4];
274
275 while (numpixels-- > 0)
276 {
277 float2rgbe(rgbe,data[RGBE_DATA_RED],
278 data[RGBE_DATA_GREEN],data[RGBE_DATA_BLUE]);
279 data += RGBE_DATA_SIZE;
280 if (fwrite(rgbe, sizeof(rgbe), 1, fp) < 1)
281 return rgbe_error(rgbe_write_error,NULL);
282 }
283 return RGBE_RETURN_SUCCESS;
284}
285#endif
286
287/* simple read routine. will not correctly handle run length encoding */
288int RGBE_ReadPixels(FILE *fp, float *data, int numpixels)
289{
290 unsigned char rgbe[4];
291
292 while(numpixels-- > 0)
293 {
294 if(fread(rgbe, sizeof(rgbe), 1, fp) < 1) return rgbe_error(rgbe_read_error, NULL);
295 rgbe2float(&data[RGBE_DATA_RED], &data[RGBE_DATA_GREEN], &data[RGBE_DATA_BLUE], rgbe);
296 data += RGBE_DATA_SIZE;
297 }
298 return RGBE_RETURN_SUCCESS;
299}
300
301#if 0
302/* The code below is only needed for the run-length encoded files. */
303/* Run length encoding adds considerable complexity but does */
304/* save some space. For each scanline, each channel (r,g,b,e) is */
305/* encoded separately for better compression. */
306
307static int RGBE_WriteBytes_RLE(FILE *fp, unsigned char *data, int numbytes)
308{
309#define MINRUNLENGTH 4
310 int cur, beg_run, run_count, old_run_count, nonrun_count;
311 unsigned char buf[2];
312
313 cur = 0;
314 while(cur < numbytes)
315 {
316 beg_run = cur;
317 /* find next run of length at least 4 if one exists */
318 run_count = old_run_count = 0;
319 while((run_count < MINRUNLENGTH) && (beg_run < numbytes))
320 {
321 beg_run += run_count;
322 old_run_count = run_count;
323 run_count = 1;
324 while((data[beg_run] == data[beg_run + run_count])
325 && (beg_run + run_count < numbytes) && (run_count < 127))
326 run_count++;
327 }
328 /* if data before next big run is a short run then write it as such */
329 if ((old_run_count > 1)&&(old_run_count == beg_run - cur))
330 {
331 buf[0] = 128 + old_run_count; /*write short run*/
332 buf[1] = data[cur];
333 if (fwrite(buf,sizeof(buf[0])*2,1,fp) < 1)
334 return rgbe_error(rgbe_write_error,NULL);
335 cur = beg_run;
336 }
337 /* write out bytes until we reach the start of the next run */
338 while(cur < beg_run)
339 {
340 nonrun_count = beg_run - cur;
341 if (nonrun_count > 128)
342 nonrun_count = 128;
343 buf[0] = nonrun_count;
344 if (fwrite(buf,sizeof(buf[0]),1,fp) < 1)
345 return rgbe_error(rgbe_write_error,NULL);
346 if (fwrite(&data[cur],sizeof(data[0])*nonrun_count,1,fp) < 1)
347 return rgbe_error(rgbe_write_error,NULL);
348 cur += nonrun_count;
349 }
350 /* write out next run if one was found */
351 if (run_count >= MINRUNLENGTH)
352 {
353 buf[0] = 128 + run_count;
354 buf[1] = data[beg_run];
355 if (fwrite(buf,sizeof(buf[0])*2,1,fp) < 1)
356 return rgbe_error(rgbe_write_error,NULL);
357 cur += run_count;
358 }
359 }
360 return RGBE_RETURN_SUCCESS;
361#undef MINRUNLENGTH
362}
363
364int RGBE_WritePixels_RLE(FILE *fp, float *data, int scanline_width,
365 int num_scanlines)
366{
367 unsigned char rgbe[4];
368 unsigned char *buffer;
369 int i, err;
370
371 if ((scanline_width < 8)||(scanline_width > 0x7fff))
372 /* run length encoding is not allowed so write flat*/
373 return RGBE_WritePixels(fp,data,scanline_width*num_scanlines);
374 buffer = (unsigned char *)malloc(sizeof(unsigned char)*4*scanline_width);
375 if (IS_NULL_PTR(buffer))
376 /* no buffer space so write flat */
377 return RGBE_WritePixels(fp,data,scanline_width*num_scanlines);
378 while(num_scanlines-- > 0)
379 {
380 rgbe[0] = 2;
381 rgbe[1] = 2;
382 rgbe[2] = scanline_width >> 8;
383 rgbe[3] = scanline_width & 0xFF;
384 if (fwrite(rgbe, sizeof(rgbe), 1, fp) < 1)
385 {
386 dt_free(buffer);
387 return rgbe_error(rgbe_write_error,NULL);
388 }
389 for(i=0; i<scanline_width; i++)
390 {
391 float2rgbe(rgbe,data[RGBE_DATA_RED],
392 data[RGBE_DATA_GREEN],data[RGBE_DATA_BLUE]);
393 buffer[i] = rgbe[0];
394 buffer[i+scanline_width] = rgbe[1];
395 buffer[i+2*scanline_width] = rgbe[2];
396 buffer[i+3*scanline_width] = rgbe[3];
397 data += RGBE_DATA_SIZE;
398 }
399 /* write out each of the four channels separately run length encoded */
400 /* first red, then green, then blue, then exponent */
401 for(i=0; i<4; i++)
402 {
403 if ((err = RGBE_WriteBytes_RLE(fp,&buffer[i*scanline_width],
404 scanline_width)) != RGBE_RETURN_SUCCESS)
405 {
406 dt_free(buffer);
407 return err;
408 }
409 }
410 }
411 dt_free(buffer);
412 return RGBE_RETURN_SUCCESS;
413}
414#endif
415
416int RGBE_ReadPixels_RLE(FILE *fp, float *data, int scanline_width, int num_scanlines)
417{
418 unsigned char rgbe[4], *scanline_buffer, *ptr_end;
419 int count;
420 unsigned char buf[2];
421
422 if((scanline_width < 8) || (scanline_width > 0x7fff)) /* run length encoding is not allowed so read flat*/
423 return RGBE_ReadPixels(fp, data, scanline_width * num_scanlines);
424 scanline_buffer = NULL;
425 /* read in each successive scanline */
426 while(num_scanlines > 0)
427 {
428 if(fread(rgbe, sizeof(rgbe), 1, fp) < 1)
429 {
430 dt_free(scanline_buffer);
431 return rgbe_error(rgbe_read_error, NULL);
432 }
433 if((rgbe[0] != 2) || (rgbe[1] != 2) || (rgbe[2] & 0x80))
434 {
435 /* this file is not run length encoded */
436 rgbe2float(&data[0], &data[1], &data[2], rgbe);
437 data += RGBE_DATA_SIZE;
438 dt_free(scanline_buffer);
439 return RGBE_ReadPixels(fp, data, scanline_width * num_scanlines - 1);
440 }
441 if((((int)rgbe[2]) << 8 | rgbe[3]) != scanline_width)
442 {
443 dt_free(scanline_buffer);
444 return rgbe_error(rgbe_format_error, "wrong scanline width");
445 }
446 if(IS_NULL_PTR(scanline_buffer))
447 scanline_buffer = (unsigned char *)malloc(sizeof(unsigned char) * 4 * scanline_width);
448 if(IS_NULL_PTR(scanline_buffer)) return rgbe_error(rgbe_memory_error, "unable to allocate buffer space");
449
450 unsigned char *ptr = &scanline_buffer[0];
451 /* read each of the four channels for the scanline into the buffer */
452 for(int i = 0; i < 4; i++)
453 {
454 ptr_end = &scanline_buffer[(i + 1) * scanline_width];
455 while(ptr < ptr_end)
456 {
457 if(fread(buf, sizeof(buf[0]) * 2, 1, fp) < 1)
458 {
459 dt_free(scanline_buffer);
460 return rgbe_error(rgbe_read_error, NULL);
461 }
462 if(buf[0] > 128)
463 {
464 /* a run of the same value */
465 count = buf[0] - 128;
466 if((count == 0) || (count > ptr_end - ptr))
467 {
468 dt_free(scanline_buffer);
469 return rgbe_error(rgbe_format_error, "bad scanline data");
470 }
471 while(count-- > 0) *ptr++ = buf[1];
472 }
473 else
474 {
475 /* a non-run */
476 count = buf[0];
477 if((count == 0) || (count > ptr_end - ptr))
478 {
479 dt_free(scanline_buffer);
480 return rgbe_error(rgbe_format_error, "bad scanline data");
481 }
482 *ptr++ = buf[1];
483 if(--count > 0)
484 {
485 if(fread(ptr, sizeof(*ptr) * count, 1, fp) < 1)
486 {
487 dt_free(scanline_buffer);
488 return rgbe_error(rgbe_read_error, NULL);
489 }
490 ptr += count;
491 }
492 }
493 }
494 }
495 /* now convert data from buffer into floats */
496 for(int i = 0; i < scanline_width; i++)
497 {
498 rgbe[0] = scanline_buffer[i];
499 rgbe[1] = scanline_buffer[i + scanline_width];
500 rgbe[2] = scanline_buffer[i + 2 * scanline_width];
501 rgbe[3] = scanline_buffer[i + 3 * scanline_width];
502 rgbe2float(&data[RGBE_DATA_RED], &data[RGBE_DATA_GREEN], &data[RGBE_DATA_BLUE], rgbe);
503 data += RGBE_DATA_SIZE;
504 }
505 num_scanlines--;
506 }
507 dt_free(scanline_buffer);
508 return RGBE_RETURN_SUCCESS;
509}
510
511#undef RGBE_VALID_PROGRAMTYPE
512#undef RGBE_VALID_GAMMA
513#undef RGBE_VALID_EXPOSURE
514
515#undef RGBE_RETURN_SUCCESS
516#undef RGBE_RETURN_FAILURE
517
518#undef RGBE_DATA_RED
519#undef RGBE_DATA_GREEN
520#undef RGBE_DATA_BLUE
521#undef RGBE_DATA_SIZE
522
523// this function is borrowed from OpenEXR code
525//
526// Copyright (c) 2003, Industrial Light & Magic, a division of Lucas
527// Digital Ltd. LLC
528//
529// All rights reserved.
530//
531// Redistribution and use in source and binary forms, with or without
532// modification, are permitted provided that the following conditions are
533// met:
534// * Redistributions of source code must retain the above copyright
535// notice, this list of conditions and the following disclaimer.
536// * Redistributions in binary form must reproduce the above
537// copyright notice, this list of conditions and the following disclaimer
538// in the documentation and/or other materials provided with the
539// distribution.
540// * Neither the name of Industrial Light & Magic nor the names of
541// its contributors may be used to endorse or promote products derived
542// from this software without specific prior written permission.
543//
544// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
545// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
546// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
547// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
548// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
549// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
550// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
551// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
552// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
553// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
554// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
555//
557static void _xy2matrix(const float r[2], const float g[2], const float b[2],
558 const float w[2], const float Y, float M[4][4])
559{
560 float X = w[0] * Y / w[1];
561 float Z = (1 - w[0] - w[1]) * Y / w[1];
562
563 //
564 // Scale factors for matrix rows
565 //
566 float d = r[0] * (b[1] - g[1]) +
567 b[0] * (g[1] - r[1]) +
568 g[0] * (r[1] - b[1]);
569 float Sr = (X * (b[1] - g[1]) -
570 g[0] * (Y * (b[1] - 1) +
571 b[1] * (X + Z)) +
572 b[0] * (Y * (g[1] - 1) +
573 g[1] * (X + Z))) / d;
574 float Sg = (X * (r[1] - b[1]) +
575 r[0] * (Y * (b[1] - 1) +
576 b[1] * (X + Z)) -
577 b[0] * (Y * (r[1] - 1) +
578 r[1] * (X + Z))) / d;
579 float Sb = (X * (g[1] - r[1]) -
580 r[0] * (Y * (g[1] - 1) +
581 g[1] * (X + Z)) +
582 g[0] * (Y * (r[1] - 1) +
583 r[1] * (X + Z))) / d;
584
585 //
586 // Assemble the matrix
587 //
588 for(int i = 0; i < 4; i++) M[i][3] = M[3][i] = 0.0;
589 M[3][3] = 1.0;
590 M[0][0] = Sr * r[0];
591 M[0][1] = Sr * r[1];
592 M[0][2] = Sr * (1 - r[0] - r[1]);
593 M[1][0] = Sg * g[0];
594 M[1][1] = Sg * g[1];
595 M[1][2] = Sg * (1 - g[0] - g[1]);
596 M[2][0] = Sb * b[0];
597 M[2][1] = Sb * b[1];
598 M[2][2] = Sb * (1 - b[0] - b[1]);
599}
600
602{
603 const char *ext = filename + strlen(filename);
604 while(*ext != '.' && ext > filename) ext--;
605 if(strncmp(ext, ".hdr", 4) && strncmp(ext, ".HDR", 4) && strncmp(ext, ".Hdr", 4))
607 FILE *f = g_fopen(filename, "rb");
609
610 rgbe_header_info info;
611 if(RGBE_ReadHeader(f, &img->width, &img->height, &info)) goto error_corrupt;
612
613 img->dsc.channels = 4;
614 img->dsc.datatype = TYPE_FLOAT;
615 img->dsc.bpp = 4 * sizeof(float);
616 img->dsc.cst = IOP_CS_RGB;
617 img->dsc.filters = 0u;
618 img->flags &= ~DT_IMAGE_LDR;
619 img->flags &= ~DT_IMAGE_RAW;
620 img->flags &= ~DT_IMAGE_S_RAW;
621 img->flags |= DT_IMAGE_HDR;
622 img->loader = LOADER_RGBE;
623
624 if(IS_NULL_PTR(mbuf))
625 {
626 fclose(f);
627 return DT_IMAGEIO_OK;
628 }
629
630 float *buf = (float *)dt_mipmap_cache_alloc(mbuf, img);
631 if(IS_NULL_PTR(buf)) goto error_cache_full;
632 if(RGBE_ReadPixels_RLE(f, buf, img->width, img->height))
633 {
634 goto error_corrupt;
635 }
636 fclose(f);
637 // repair nan/inf etc
638 for(size_t i = (size_t)img->width * img->height; i > 0; i--)
639 for(int c = 0; c < 3; c++) buf[4 * (i - 1) + c] = fmaxf(0.0f, fminf(10000.0, buf[3 * (i - 1) + c]));
640
641 // set the color matrix
642 float m[4][4];
643 _xy2matrix(&info.primaries[0], &info.primaries[2], &info.primaries[4], &info.primaries[6], 1.0, m);
644
645 float mat[3][3];
646
647 for(int i = 0; i < 3; i++)
648 for(int j = 0; j < 3; j++)
649 {
650 mat[i][j] = m[j][i];
651 }
652
653 mat3inv((float *)img->d65_color_matrix, (float *)mat);
654 return DT_IMAGEIO_OK;
655
656error_corrupt:
657 fclose(f);
659error_cache_full:
660 fclose(f);
662}
663
664// clang-format off
665// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
666// vim: shiftwidth=2 expandtab tabstop=2 cindent
667// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
668// clang-format on
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
#define m
Definition basecurve.c:278
int width
Definition bilateral.h:1
int height
Definition bilateral.h:1
@ IOP_CS_RGB
int mat3inv(float *const dst, const float *const src)
const dt_aligned_pixel_t f
static const dt_colormatrix_t M
#define dt_free(ptr)
Definition darktable.h:456
#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_HDR
Definition image.h:113
@ LOADER_RGBE
Definition image.h:228
#define RGBE_DATA_BLUE
#define RGBE_VALID_GAMMA
int RGBE_ReadPixels_RLE(FILE *fp, float *data, int scanline_width, int num_scanlines)
#define RGBE_RETURN_SUCCESS
#define RGBE_DATA_GREEN
static void _xy2matrix(const float r[2], const float g[2], const float b[2], const float w[2], const float Y, float M[4][4])
rgbe_error_codes
@ rgbe_write_error
@ rgbe_memory_error
@ rgbe_format_error
@ rgbe_read_error
int RGBE_ReadHeader(FILE *fp, int *width, int *height, rgbe_header_info *info)
dt_imageio_retval_t dt_imageio_open_rgbe(dt_image_t *img, const char *filename, dt_mipmap_buffer_t *mbuf)
int RGBE_ReadPixels(FILE *fp, float *data, int numpixels)
#define RGBE_DATA_RED
#define RGBE_DATA_SIZE
#define RGBE_VALID_PROGRAMTYPE
static void rgbe2float(float *red, float *green, float *blue, unsigned char rgbe[4])
#define RGBE_RETURN_FAILURE
static int rgbe_error(int rgbe_error_code, char *msg)
#define RGBE_VALID_EXPOSURE
const float v
void * dt_mipmap_cache_alloc(dt_mipmap_buffer_t *buf, const dt_image_t *img)
tuple green
const float r
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
float d65_color_matrix[9]
Definition image.h:339
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
char programtype[16]