Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
imageio_exr.cc
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2010, 2014 Henrik Andersson.
4 Copyright (C) 2010-2012, 2014 johannes hanika.
5 Copyright (C) 2012 Richard Wonka.
6 Copyright (C) 2012-2016 Tobias Ellinghaus.
7 Copyright (C) 2014, 2016 Roman Lebedev.
8 Copyright (C) 2019 Claude Heiland-Allen.
9 Copyright (C) 2020, 2025 Aurélien PIERRE.
10 Copyright (C) 2020 Hubert Kowalski.
11 Copyright (C) 2020-2021 Pascal Obry.
12 Copyright (C) 2020 Philippe Weyland.
13 Copyright (C) 2022 Martin Bařinka.
14 Copyright (C) 2022 Miloš Komarčević.
15 Copyright (C) 2023, 2025 Alynx Zhou.
16
17 darktable is free software: you can redistribute it and/or modify
18 it under the terms of the GNU General Public License as published by
19 the Free Software Foundation, either version 3 of the License, or
20 (at your option) any later version.
21
22 darktable is distributed in the hope that it will be useful,
23 but WITHOUT ANY WARRANTY; without even the implied warranty of
24 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 GNU General Public License for more details.
26
27 You should have received a copy of the GNU General Public License
28 along with darktable. If not, see <http://www.gnu.org/licenses/>.
29*/
30
31#define __STDC_FORMAT_MACROS
32
33#ifdef HAVE_CONFIG_H
34#include "config.h"
35#endif
36
37#include <assert.h>
38#include <inttypes.h>
39#include <memory>
40#include <stdio.h>
41#include <string.h>
42
43#include <OpenEXR/ImfChannelList.h>
44#include <OpenEXR/ImfFrameBuffer.h>
45#include <OpenEXR/ImfInputFile.h>
46#include <OpenEXR/ImfStandardAttributes.h>
47#include <OpenEXR/ImfTestFile.h>
48#include <OpenEXR/ImfThreading.h>
49#include <OpenEXR/ImfTiledInputFile.h>
50
51#include "glib.h"
52
53#include "common/colorspaces.h"
54#include "common/darktable.h"
55#include "common/exif.h"
56#include "common/imageio.h"
57#include "common/imageio_exr.h"
58#include "control/conf.h"
59#include "develop/develop.h"
60
61#include "common/imageio_exr.hh"
62
64{
65 bool isTiled = false;
66
67 Imf::setGlobalThreadCount(darktable.num_openmp_threads);
68
69 std::unique_ptr<Imf::TiledInputFile> fileTiled;
70 std::unique_ptr<Imf::InputFile> file;
71
72 Imath::Box2i dw;
73 Imf::FrameBuffer frameBuffer;
74 uint32_t xstride, ystride;
75
76
77 /* verify openexr image */
78 if(!Imf::isOpenExrFile((const char *)filename, isTiled)) return DT_IMAGEIO_FILE_CORRUPTED;
79
80 /* open exr file */
81 try
82 {
83 if(isTiled)
84 {
85 std::unique_ptr<Imf::TiledInputFile> temp(new Imf::TiledInputFile(filename));
86 fileTiled = std::move(temp);
87 }
88 else
89 {
90 std::unique_ptr<Imf::InputFile> temp(new Imf::InputFile(filename));
91 file = std::move(temp);
92 }
93 }
94 catch(const std::exception &e)
95 {
97 }
98
99 const Imf::Header &header = isTiled ? fileTiled->header() : file->header();
100
101 /* check that channels available is any of supported RGB(a) */
102 bool hasR = false, hasG = false, hasB = false;
103 for(Imf::ChannelList::ConstIterator i = header.channels().begin(); i != header.channels().end(); ++i)
104 {
105 std::string name(i.name());
106 if(name == "R") hasR = true;
107 if(name == "G") hasG = true;
108 if(name == "B") hasB = true;
109 }
110 if(!(hasR && hasG && hasB))
111 {
112 fprintf(stderr, "[exr_read] Warning, only files with RGB(A) channels are supported.\n");
114 }
115
116 if(!img->exif_inited)
117 {
118 // read back exif data
119 // if another software is able to update these exif data, the former test
120 // should be removed to take the potential changes in account (not done
121 // by normal import image flow)
122 const Imf::BlobAttribute *exif = header.findTypedAttribute<Imf::BlobAttribute>("exif");
123 // we append a jpg-compatible exif00 string, so get rid of that again:
124 if(exif && exif->value().size > 6)
125 dt_exif_read_from_blob(img, ((uint8_t *)(exif->value().data.get())) + 6, exif->value().size - 6);
126 }
127
128 /* Get image width and height from displayWindow */
129 dw = header.displayWindow();
130 img->width = dw.max.x - dw.min.x + 1;
131 img->height = dw.max.y - dw.min.y + 1;
132
133 // Try to allocate image data
134 img->dsc.channels = 4;
135 img->dsc.datatype = TYPE_FLOAT;
136 img->dsc.bpp = 4 * sizeof(float);
137 img->dsc.cst = IOP_CS_RGB;
138 img->dsc.filters = 0u;
139 img->flags &= ~DT_IMAGE_RAW;
140 img->flags &= ~DT_IMAGE_S_RAW;
141 img->flags &= ~DT_IMAGE_LDR;
142 img->flags |= DT_IMAGE_HDR;
143 img->loader = LOADER_EXR;
144
145 if(IS_NULL_PTR(mbuf)) return DT_IMAGEIO_OK;
146
147 float *buf = (float *)dt_mipmap_cache_alloc(mbuf, img);
148 if(!buf)
149 {
150 fprintf(stderr, "[exr_read] could not alloc full buffer for image `%s'\n", img->filename);
153 }
154
155 // FIXME: is this really needed?
156 memset(buf, 0, sizeof(float) * 4 * img->width * img->height);
157
158 /* setup framebuffer */
159 xstride = sizeof(float) * 4;
160 ystride = sizeof(float) * img->width * 4;
161 frameBuffer.insert("R", Imf::Slice(Imf::FLOAT, (char *)(buf + 0), xstride, ystride, 1, 1, 0.0));
162 frameBuffer.insert("G", Imf::Slice(Imf::FLOAT, (char *)(buf + 1), xstride, ystride, 1, 1, 0.0));
163 frameBuffer.insert("B", Imf::Slice(Imf::FLOAT, (char *)(buf + 2), xstride, ystride, 1, 1, 0.0));
164 frameBuffer.insert("A", Imf::Slice(Imf::FLOAT, (char *)(buf + 3), xstride, ystride, 1, 1, 0.0));
165
166 try
167 {
168 if(isTiled)
169 {
170 fileTiled->setFrameBuffer(frameBuffer);
171 fileTiled->readTiles(0, fileTiled->numXTiles() - 1, 0, fileTiled->numYTiles() - 1);
172 }
173 else
174 {
175 /* read pixels from dataWindow */
176 dw = header.dataWindow();
177 file->setFrameBuffer(frameBuffer);
178 file->readPixels(dw.min.y, dw.max.y);
179 }
180 }
181 catch(const std::exception &e)
182 {
183 fprintf(stderr, "[exr_read] error reading pixels from `%s': %s\n", filename, e.what());
185 }
186
187 /* try to get the chromaticities and whitepoint. this will add the default linear rec709 profile when nothing
188 * was embedded and look as if it was embedded in colorin. better than defaulting to something wrong there. */
189 Imf::Chromaticities chromaticities;
190 float whiteLuminance = 1.0;
191
192 if(Imf::hasChromaticities(header))
193 {
194 chromaticities = Imf::chromaticities(header);
195
196 /* adapt chromaticities to D65 expected by colorin */
197 cmsCIExyY red_xy = { chromaticities.red[0], chromaticities.red[1], 1.0 };
198 cmsCIEXYZ srcRed;
199 cmsxyY2XYZ(&srcRed, &red_xy);
200
201 cmsCIExyY green_xy = { chromaticities.green[0], chromaticities.green[1], 1.0 };
202 cmsCIEXYZ srcGreen;
203 cmsxyY2XYZ(&srcGreen, &green_xy);
204
205 cmsCIExyY blue_xy = { chromaticities.blue[0], chromaticities.blue[1], 1.0 };
206 cmsCIEXYZ srcBlue;
207 cmsxyY2XYZ(&srcBlue, &blue_xy);
208
209 const cmsCIExyY srcWhite_xy = { chromaticities.white[0], chromaticities.white[1], 1.0 };
210 cmsCIEXYZ srcWhite;
211 cmsxyY2XYZ(&srcWhite, &srcWhite_xy);
212
213 /* use Imf::Chromaticities definition */
214 const cmsCIExyY d65_xy = {0.3127f, 0.3290f, 1.0};
215 cmsCIEXYZ d65;
216 cmsxyY2XYZ(&d65, &d65_xy);
217
218 cmsCIEXYZ dstRed;
219 cmsAdaptToIlluminant(&dstRed, &srcWhite, &d65, &srcRed);
220
221 cmsCIEXYZ dstGreen;
222 cmsAdaptToIlluminant(&dstGreen, &srcWhite, &d65, &srcGreen);
223
224 cmsCIEXYZ dstBlue;
225 cmsAdaptToIlluminant(&dstBlue, &srcWhite, &d65, &srcBlue);
226
227 cmsXYZ2xyY(&red_xy, &dstRed);
228 chromaticities.red[0] = (float)red_xy.x;
229 chromaticities.red[1] = (float)red_xy.y;
230
231 cmsXYZ2xyY(&green_xy, &dstGreen);
232 chromaticities.green[0] = (float)green_xy.x;
233 chromaticities.green[1] = (float)green_xy.y;
234
235 cmsXYZ2xyY(&blue_xy, &dstBlue);
236 chromaticities.blue[0] = (float)blue_xy.x;
237 chromaticities.blue[1] = (float)blue_xy.y;
238
239 chromaticities.white[0] = 0.3127f;
240 chromaticities.white[1] = 0.3290f;
241 }
242
243 if(Imf::hasWhiteLuminance(header))
244 whiteLuminance = Imf::whiteLuminance(header);
245
246// printf("hasChromaticities: %d\n", Imf::hasChromaticities(header));
247// printf("hasWhiteLuminance: %d\n", Imf::hasWhiteLuminance(header));
248// std::cout << chromaticities.red << std::endl;
249// std::cout << chromaticities.green << std::endl;
250// std::cout << chromaticities.blue << std::endl;
251// std::cout << chromaticities.white << std::endl;
252
253 Imath::M44f m = Imf::XYZtoRGB(chromaticities, whiteLuminance);
254
255 for(int i = 0; i < 3; i++)
256 for(int j = 0; j < 3; j++)
257 {
258 img->d65_color_matrix[3 * i + j] = m[j][i];
259 }
260
261 return DT_IMAGEIO_OK;
262}
263
264// clang-format off
265// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
266// vim: shiftwidth=2 expandtab tabstop=2 cindent
267// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
268// clang-format on
#define m
Definition basecurve.c:278
@ IOP_CS_RGB
static const cmsCIEXYZ d65
char * name
darktable_t darktable
Definition darktable.c:183
#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:293
int dt_exif_read_from_blob(dt_image_t *img, uint8_t *blob, const int size)
Definition exif.cc:1681
@ 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_EXR
Definition image.h:227
dt_imageio_retval_t dt_imageio_open_exr(dt_image_t *img, const char *filename, dt_mipmap_buffer_t *mbuf)
void * dt_mipmap_cache_alloc(dt_mipmap_buffer_t *buf, const dt_image_t *img)
Imf ::TypedAttribute< Imf ::Blob > BlobAttribute
int32_t num_openmp_threads
Definition darktable.h:786
int32_t height
Definition image.h:315
dt_image_loader_t loader
Definition image.h:335
int32_t exif_inited
Definition image.h:283
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
char filename[DT_MAX_FILENAME_LEN]
Definition image.h:304
uint32_t filters
Definition format.h:60
unsigned int channels
Definition format.h:54
dt_iop_buffer_type_t datatype
Definition format.h:56