Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
apps/ansel-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 "system/macros.h"
27#include "system/mem_alloc.h"
29#include <glib.h>
30#include <glib/gstdio.h>
31#include <inttypes.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35
36float *read_pfm(const char *filename, int *wd, int *ht)
37{
38 FILE *f = g_fopen(filename, "rb");
39
40 if(IS_NULL_PTR(f))
41 {
42 fprintf(stderr, "can't open input file\n");
43 return NULL;
44 }
45
46 char magic[2];
47 char scale_factor_string[64] = { 0 };
48 int width, height, cols, unused = 0;
49 // using fscanf to read floats only really works with LANG=C :(
50 unused = fscanf(f, "%c%c %d %d %63s%*[^\n]", &magic[0], &magic[1], &width, &height, scale_factor_string);
51 if(magic[0] != 'P' || unused != 5 || fgetc(f) != '\n')
52 {
53 fprintf(stderr, "wrong input file format\n");
54 fclose(f);
55 return NULL;
56 }
57 if(magic[1] == 'F')
58 cols = 3;
59 else if(magic[1] == 'f')
60 cols = 1;
61 else
62 {
63 fprintf(stderr, "wrong input file format\n");
64 fclose(f);
65 return NULL;
66 }
67
68 float scale_factor = g_ascii_strtod(scale_factor_string, NULL);
69 int swap_byte_order = (scale_factor >= 0.0) ^ (G_BYTE_ORDER == G_BIG_ENDIAN);
70
71 float *image = (float *)dt_pixelpipe_cache_alloc_align_float_cache((size_t)3 * width * height, 0);
72 if(IS_NULL_PTR(image))
73 {
74 fprintf(stderr, "error allocating memory\n");
75 fclose(f);
76 return NULL;
77 }
78
79 if(cols == 3)
80 {
81 int ret = fread(image, 3 * sizeof(float), (size_t)width * height, f);
82 if(ret != width * height)
83 {
84 fprintf(stderr, "error reading PFM\n");
86 fclose(f);
87 return NULL;
88 }
89 if(swap_byte_order)
90 {
91 for(size_t i = (size_t)width * height; i > 0; i--)
92 for(int c = 0; c < 3; c++)
93 {
94 union {
95 float f;
96 guint32 i;
97 } v;
98 v.f = image[3 * (i - 1) + c];
99 v.i = GUINT32_SWAP_LE_BE(v.i);
100 image[3 * (i - 1) + c] = v.f;
101 }
102 }
103 }
104 else
105 for(size_t j = 0; j < height; j++)
106 for(size_t i = 0; i < width; i++)
107 {
108 union {
109 float f;
110 guint32 i;
111 } v;
112 int ret = fread(&v.f, sizeof(float), 1, f);
113 if(ret != 1)
114 {
115 fprintf(stderr, "error reading PFM\n");
117 fclose(f);
118 return NULL;
119 }
120 if(swap_byte_order) v.i = GUINT32_SWAP_LE_BE(v.i);
121 image[3 * (width * j + i) + 2] = image[3 * (width * j + i) + 1] = image[3 * (width * j + i) + 0] = v.f;
122 }
123 float *line = (float *)calloc(3 * width, sizeof(float));
124 for(size_t j = 0; j < height / 2; j++)
125 {
126 memcpy(line, image + width * j * 3, sizeof(float) * width * 3);
127 memcpy(image + width * j * 3, image + width * (height - 1 - j) * 3, sizeof(float) * width * 3);
128 memcpy(image + width * (height - 1 - j) * 3, line, sizeof(float) * width * 3);
129 }
130 dt_free(line);
131 fclose(f);
132
133 if(wd) *wd = width;
134 if(ht) *ht = height;
135 return image;
136}
137
138void write_pfm(const char *filename, int width, int height, float *data)
139{
140 FILE *f = g_fopen(filename, "wb");
141 if(f)
142 {
143 // INFO: per-line fwrite call seems to perform best. LebedevRI, 18.04.2014
144 (void)fprintf(f, "PF\n%d %d\n-1.0\n", width, height);
145 void *buf_line = dt_pixelpipe_cache_alloc_align_float_cache((size_t)3 * width, 0);
146 if(IS_NULL_PTR(buf_line)) goto error;
147
148 for(int j = 0; j < height; j++)
149 {
150 // NOTE: pfm has rows in reverse order
151 const int row_in = height - 1 - j;
152 const float *in = data + 3 * (size_t)width * row_in;
153 float *out = (float *)buf_line;
154 for(int i = 0; i < width; i++, in += 3, out += 3)
155 {
156 memcpy(out, in, sizeof(float) * 3);
157 }
158 int cnt = fwrite(buf_line, sizeof(float) * 3, width, f);
159 if(cnt != width) break;
160 }
161
162 error:;
164 buf_line = NULL;
165 fclose(f);
166 }
167}
168
169// clang-format off
170// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
171// vim: shiftwidth=2 expandtab tabstop=2 cindent
172// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
173// clang-format on
float * read_pfm(const char *filename, int *wd, int *ht)
void write_pfm(const char *filename, int width, int height, float *data)
static void error(char *msg)
Definition ashift_lsd.c:202
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
const float f
const float v
const dt_colormatrix_t dt_aligned_pixel_t out
#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:65
#define dt_free(ptr)
Definition mem_alloc.h:97
uint32_t width
Definition mipmap_cache.c:0
uint32_t height
Definition mipmap_cache.c:1
#define dt_pixelpipe_cache_alloc_align_float_cache(pixels, id)
#define dt_pixelpipe_cache_free_align(mem)