Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
chart/pfm.c
Go to the documentation of this file.
1/*
2 * This file is part of darktable,
3 * Copyright (C) 2016 johannes hanika.
4 * Copyright (C) 2016 PkmX.
5 * Copyright (C) 2016-2017 Tobias Ellinghaus.
6 * Copyright (C) 2017 Peter Budai.
7 * Copyright (C) 2019, 2025-2026 Aurélien PIERRE.
8 * Copyright (C) 2020 Hubert Kowalski.
9 * Copyright (C) 2020 Pascal Obry.
10 * Copyright (C) 2022 Martin Bařinka.
11 *
12 * darktable is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation, either version 3 of the License, or
15 * (at your option) any later version.
16 *
17 * darktable is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with darktable. If not, see <http://www.gnu.org/licenses/>.
24 */
25
26#include "common/darktable.h"
27#include <glib.h>
28#include <inttypes.h>
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
32
33float *read_pfm(const char *filename, int *wd, int *ht)
34{
35 FILE *f = g_fopen(filename, "rb");
36
37 if(IS_NULL_PTR(f))
38 {
39 fprintf(stderr, "can't open input file\n");
40 return NULL;
41 }
42
43 char magic[2];
44 char scale_factor_string[64] = { 0 };
45 int width, height, cols, unused = 0;
46 // using fscanf to read floats only really works with LANG=C :(
47 unused = fscanf(f, "%c%c %d %d %63s%*[^\n]", &magic[0], &magic[1], &width, &height, scale_factor_string);
48 if(magic[0] != 'P' || unused != 5 || fgetc(f) != '\n')
49 {
50 fprintf(stderr, "wrong input file format\n");
51 fclose(f);
52 return NULL;
53 }
54 if(magic[1] == 'F')
55 cols = 3;
56 else if(magic[1] == 'f')
57 cols = 1;
58 else
59 {
60 fprintf(stderr, "wrong input file format\n");
61 fclose(f);
62 return NULL;
63 }
64
65 float scale_factor = g_ascii_strtod(scale_factor_string, NULL);
66 int swap_byte_order = (scale_factor >= 0.0) ^ (G_BYTE_ORDER == G_BIG_ENDIAN);
67
68 float *image = (float *)dt_pixelpipe_cache_alloc_align_float_cache((size_t)3 * width * height, 0);
69 if(IS_NULL_PTR(image))
70 {
71 fprintf(stderr, "error allocating memory\n");
72 fclose(f);
73 return NULL;
74 }
75
76 if(cols == 3)
77 {
78 int ret = fread(image, 3 * sizeof(float), (size_t)width * height, f);
79 if(ret != width * height)
80 {
81 fprintf(stderr, "error reading PFM\n");
83 fclose(f);
84 return NULL;
85 }
86 if(swap_byte_order)
87 {
88 for(size_t i = (size_t)width * height; i > 0; i--)
89 for(int c = 0; c < 3; c++)
90 {
91 union {
92 float f;
93 guint32 i;
94 } v;
95 v.f = image[3 * (i - 1) + c];
96 v.i = GUINT32_SWAP_LE_BE(v.i);
97 image[3 * (i - 1) + c] = v.f;
98 }
99 }
100 }
101 else
102 for(size_t j = 0; j < height; j++)
103 for(size_t i = 0; i < width; i++)
104 {
105 union {
106 float f;
107 guint32 i;
108 } v;
109 int ret = fread(&v.f, sizeof(float), 1, f);
110 if(ret != 1)
111 {
112 fprintf(stderr, "error reading PFM\n");
114 fclose(f);
115 return NULL;
116 }
117 if(swap_byte_order) v.i = GUINT32_SWAP_LE_BE(v.i);
118 image[3 * (width * j + i) + 2] = image[3 * (width * j + i) + 1] = image[3 * (width * j + i) + 0] = v.f;
119 }
120 float *line = (float *)calloc(3 * width, sizeof(float));
121 for(size_t j = 0; j < height / 2; j++)
122 {
123 memcpy(line, image + width * j * 3, sizeof(float) * width * 3);
124 memcpy(image + width * j * 3, image + width * (height - 1 - j) * 3, sizeof(float) * width * 3);
125 memcpy(image + width * (height - 1 - j) * 3, line, sizeof(float) * width * 3);
126 }
127 dt_free(line);
128 fclose(f);
129
130 if(wd) *wd = width;
131 if(ht) *ht = height;
132 return image;
133}
134
135void write_pfm(const char *filename, int width, int height, float *data)
136{
137 FILE *f = g_fopen(filename, "wb");
138 if(f)
139 {
140 // INFO: per-line fwrite call seems to perform best. LebedevRI, 18.04.2014
141 (void)fprintf(f, "PF\n%d %d\n-1.0\n", width, height);
142 void *buf_line = dt_pixelpipe_cache_alloc_align_float_cache((size_t)3 * width, 0);
143 if(IS_NULL_PTR(buf_line)) goto error;
144
145 for(int j = 0; j < height; j++)
146 {
147 // NOTE: pfm has rows in reverse order
148 const int row_in = height - 1 - j;
149 const float *in = data + 3 * (size_t)width * row_in;
150 float *out = (float *)buf_line;
151 for(int i = 0; i < width; i++, in += 3, out += 3)
152 {
153 memcpy(out, in, sizeof(float) * 3);
154 }
155 int cnt = fwrite(buf_line, sizeof(float) * 3, width, f);
156 if(cnt != width) break;
157 }
158
159 error:;
161 buf_line = NULL;
162 fclose(f);
163 }
164}
165
166// clang-format off
167// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
168// vim: shiftwidth=2 expandtab tabstop=2 cindent
169// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
170// clang-format on
static void error(char *msg)
Definition ashift_lsd.c:202
int width
Definition bilateral.h:1
int height
Definition bilateral.h:1
float * read_pfm(const char *filename, int *wd, int *ht)
Definition chart/pfm.c:33
void write_pfm(const char *filename, int width, int height, float *data)
Definition chart/pfm.c:135
const dt_aligned_pixel_t f
const dt_colormatrix_t dt_aligned_pixel_t out
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
#define dt_pixelpipe_cache_alloc_align_float_cache(pixels, id)
Definition darktable.h:447
#define dt_free(ptr)
Definition darktable.h:456
#define dt_pixelpipe_cache_free_align(mem)
Definition darktable.h:453
#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
const float v