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