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 "system/macros.h"
54#include "system/openmp.h"
55#include "metadata/exif.h"
56#include "imageio/imageio_exr.h"
57#include "develop/develop.h"
58
60
62{
63 bool isTiled = false;
64
65 Imf::setGlobalThreadCount(dt_get_num_openmp_threads());
66
67 std::unique_ptr<Imf::TiledInputFile> fileTiled;
68 std::unique_ptr<Imf::InputFile> file;
69
70 Imath::Box2i dw;
71 Imf::FrameBuffer frameBuffer;
72 uint32_t xstride, ystride;
73
74
75 /* verify openexr image */
76 if(!Imf::isOpenExrFile((const char *)filename, isTiled)) return DT_IMAGEIO_FILE_CORRUPTED;
77
78 /* open exr file */
79 try
80 {
81 if(isTiled)
82 {
83 std::unique_ptr<Imf::TiledInputFile> temp(new Imf::TiledInputFile(filename));
84 fileTiled = std::move(temp);
85 }
86 else
87 {
88 std::unique_ptr<Imf::InputFile> temp(new Imf::InputFile(filename));
89 file = std::move(temp);
90 }
91 }
92 catch(const std::exception &e)
93 {
95 }
96
97 const Imf::Header &header = isTiled ? fileTiled->header() : file->header();
98
99 /* check that channels available is any of supported RGB(a) */
100 bool hasR = false, hasG = false, hasB = false;
101 for(Imf::ChannelList::ConstIterator i = header.channels().begin(); i != header.channels().end(); ++i)
102 {
103 std::string name(i.name());
104 if(name == "R") hasR = true;
105 if(name == "G") hasG = true;
106 if(name == "B") hasB = true;
107 }
108 if(!(hasR && hasG && hasB))
109 {
110 fprintf(stderr, "[exr_read] Warning, only files with RGB(A) channels are supported.\n");
112 }
113
114 if(!img->exif_inited)
115 {
116 // read back exif data
117 // if another software is able to update these exif data, the former test
118 // should be removed to take the potential changes in account (not done
119 // by normal import image flow)
120 const Imf::BlobAttribute *exif = header.findTypedAttribute<Imf::BlobAttribute>("exif");
121 // we append a jpg-compatible exif00 string, so get rid of that again:
122 if(exif && exif->value().size > 6)
123 dt_exif_read_from_blob(img, ((uint8_t *)(exif->value().data.get())) + 6, exif->value().size - 6);
124 }
125
126 /* Get image width and height from displayWindow */
127 dw = header.displayWindow();
128 img->width = dw.max.x - dw.min.x + 1;
129 img->height = dw.max.y - dw.min.y + 1;
130
131 // Try to allocate image data
132 img->dsc.channels = 4;
133 img->dsc.datatype = TYPE_FLOAT;
134 img->dsc.bpp = 4 * sizeof(float);
135 img->dsc.cst = IOP_CS_RGB;
136 img->dsc.filters = 0u;
137 img->flags &= ~DT_IMAGE_RAW;
138 img->flags &= ~DT_IMAGE_S_RAW;
139 img->flags &= ~DT_IMAGE_LDR;
140 img->flags |= DT_IMAGE_HDR;
141 img->loader = LOADER_EXR;
142
143 if(IS_NULL_PTR(mbuf)) return DT_IMAGEIO_OK;
144
145 float *buf = (float *)dt_mipmap_cache_alloc(mbuf, img);
146 if(!buf)
147 {
148 fprintf(stderr, "[exr_read] could not alloc full buffer for image `%s'\n", img->filename);
151 }
152
153 // FIXME: is this really needed?
154 memset(buf, 0, sizeof(float) * 4 * img->width * img->height);
155
156 /* setup framebuffer */
157 xstride = sizeof(float) * 4;
158 ystride = sizeof(float) * img->width * 4;
159 frameBuffer.insert("R", Imf::Slice(Imf::FLOAT, (char *)(buf + 0), xstride, ystride, 1, 1, 0.0));
160 frameBuffer.insert("G", Imf::Slice(Imf::FLOAT, (char *)(buf + 1), xstride, ystride, 1, 1, 0.0));
161 frameBuffer.insert("B", Imf::Slice(Imf::FLOAT, (char *)(buf + 2), xstride, ystride, 1, 1, 0.0));
162 frameBuffer.insert("A", Imf::Slice(Imf::FLOAT, (char *)(buf + 3), xstride, ystride, 1, 1, 0.0));
163
164 try
165 {
166 if(isTiled)
167 {
168 fileTiled->setFrameBuffer(frameBuffer);
169 fileTiled->readTiles(0, fileTiled->numXTiles() - 1, 0, fileTiled->numYTiles() - 1);
170 }
171 else
172 {
173 /* read pixels from dataWindow */
174 dw = header.dataWindow();
175 file->setFrameBuffer(frameBuffer);
176 file->readPixels(dw.min.y, dw.max.y);
177 }
178 }
179 catch(const std::exception &e)
180 {
181 fprintf(stderr, "[exr_read] error reading pixels from `%s': %s\n", filename, e.what());
183 }
184
185 /* try to get the chromaticities and whitepoint. this will add the default linear rec709 profile when nothing
186 * was embedded and look as if it was embedded in colorin. better than defaulting to something wrong there. */
187 Imf::Chromaticities chromaticities;
188 float whiteLuminance = 1.0;
189
190 if(Imf::hasChromaticities(header))
191 {
192 chromaticities = Imf::chromaticities(header);
193
194 /* adapt chromaticities to D65 expected by colorin */
195 cmsCIExyY red_xy = { chromaticities.red[0], chromaticities.red[1], 1.0 };
196 cmsCIEXYZ srcRed;
197 cmsxyY2XYZ(&srcRed, &red_xy);
198
199 cmsCIExyY green_xy = { chromaticities.green[0], chromaticities.green[1], 1.0 };
200 cmsCIEXYZ srcGreen;
201 cmsxyY2XYZ(&srcGreen, &green_xy);
202
203 cmsCIExyY blue_xy = { chromaticities.blue[0], chromaticities.blue[1], 1.0 };
204 cmsCIEXYZ srcBlue;
205 cmsxyY2XYZ(&srcBlue, &blue_xy);
206
207 const cmsCIExyY srcWhite_xy = { chromaticities.white[0], chromaticities.white[1], 1.0 };
208 cmsCIEXYZ srcWhite;
209 cmsxyY2XYZ(&srcWhite, &srcWhite_xy);
210
211 /* use Imf::Chromaticities definition */
212 const cmsCIExyY d65_xy = {0.3127f, 0.3290f, 1.0};
213 cmsCIEXYZ d65;
214 cmsxyY2XYZ(&d65, &d65_xy);
215
216 cmsCIEXYZ dstRed;
217 cmsAdaptToIlluminant(&dstRed, &srcWhite, &d65, &srcRed);
218
219 cmsCIEXYZ dstGreen;
220 cmsAdaptToIlluminant(&dstGreen, &srcWhite, &d65, &srcGreen);
221
222 cmsCIEXYZ dstBlue;
223 cmsAdaptToIlluminant(&dstBlue, &srcWhite, &d65, &srcBlue);
224
225 cmsXYZ2xyY(&red_xy, &dstRed);
226 chromaticities.red[0] = (float)red_xy.x;
227 chromaticities.red[1] = (float)red_xy.y;
228
229 cmsXYZ2xyY(&green_xy, &dstGreen);
230 chromaticities.green[0] = (float)green_xy.x;
231 chromaticities.green[1] = (float)green_xy.y;
232
233 cmsXYZ2xyY(&blue_xy, &dstBlue);
234 chromaticities.blue[0] = (float)blue_xy.x;
235 chromaticities.blue[1] = (float)blue_xy.y;
236
237 chromaticities.white[0] = 0.3127f;
238 chromaticities.white[1] = 0.3290f;
239 }
240
241 if(Imf::hasWhiteLuminance(header))
242 whiteLuminance = Imf::whiteLuminance(header);
243
244// printf("hasChromaticities: %d\n", Imf::hasChromaticities(header));
245// printf("hasWhiteLuminance: %d\n", Imf::hasWhiteLuminance(header));
246// std::cout << chromaticities.red << std::endl;
247// std::cout << chromaticities.green << std::endl;
248// std::cout << chromaticities.blue << std::endl;
249// std::cout << chromaticities.white << std::endl;
250
251 Imath::M44f m = Imf::XYZtoRGB(chromaticities, whiteLuminance);
252
253 for(int i = 0; i < 3; i++)
254 for(int j = 0; j < 3; j++)
255 {
256 img->d65_color_matrix[3 * i + j] = m[j][i];
257 }
258
259 return DT_IMAGEIO_OK;
260}
261
262// clang-format off
263// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
264// vim: shiftwidth=2 expandtab tabstop=2 cindent
265// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
266// clang-format on
#define m
Definition basecurve.c:283
@ IOP_CS_RGB
static const cmsCIEXYZ d65
int dt_get_num_openmp_threads(void)
Number of OpenMP threads the application decided to use.
Definition darktable.c:518
int dt_exif_read_from_blob(dt_image_t *img, uint8_t *blob, const int size)
Definition exif.cc:1909
What a photograph says about itself: the EXIF, IPTC and XMP tags a camera and a cataloguer write,...
@ 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_EXR
Definition image.h:288
dt_imageio_retval_t dt_imageio_open_exr(dt_image_t *img, const char *filename, dt_mipmap_buffer_t *mbuf)
#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
void * dt_mipmap_cache_alloc(dt_mipmap_buffer_t *buf, const dt_image_t *img)
Imf ::TypedAttribute< Imf ::Blob > BlobAttribute
const char * name
Definition pdf.h:90
int32_t height
Definition image.h:397
dt_image_loader_t loader
Definition image.h:417
int32_t exif_inited
Definition image.h:365
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
char filename[DT_MAX_FILENAME_LEN]
Definition image.h:386
uint32_t filters
Definition format.h:89
unsigned int channels
Definition format.h:83
dt_iop_buffer_type_t datatype
Definition format.h:85