Cleanup: style
[blender-staging.git] / source / blender / imbuf / intern / openexr / openexr_api.cpp
1 /*
2  * ***** BEGIN GPLLICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * Copyright by Gernot Ziegler <gz@lysator.liu.se>.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): Austin Benesh, Ton Roosendaal (float, half, speedup, cleanup...).
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/imbuf/intern/openexr/openexr_api.cpp
29  *  \ingroup openexr
30  */
31
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <stddef.h>
35 #include <stdexcept>
36 #include <fstream>
37 #include <string>
38 #include <set>
39 #include <errno.h>
40 #include <algorithm>
41 #include <iostream>
42
43 #include <half.h>
44 #include <Iex.h>
45 #include <ImfVersion.h>
46 #include <ImathBox.h>
47 #include <ImfArray.h>
48 #include <ImfIO.h>
49 #include <ImfChannelList.h>
50 #include <ImfPixelType.h>
51 #include <ImfInputFile.h>
52 #include <ImfOutputFile.h>
53 #include <ImfCompression.h>
54 #include <ImfCompressionAttribute.h>
55 #include <ImfStringAttribute.h>
56 #include <ImfStandardAttributes.h>
57
58 /* multiview/multipart */
59 #include <ImfMultiView.h>
60 #include <ImfMultiPartInputFile.h>
61 #include <ImfInputPart.h>
62 #include <ImfOutputPart.h>
63 #include <ImfMultiPartOutputFile.h>
64 #include <ImfTiledOutputPart.h>
65 #include <ImfPartType.h>
66 #include <ImfPartHelper.h>
67
68 #include "DNA_scene_types.h" /* For OpenEXR compression constants */
69
70 #include <openexr_api.h>
71
72 #if defined (WIN32) && !defined(FREE_WINDOWS)
73 #include "utfconv.h"
74 #endif
75
76 extern "C"
77 {
78
79 // The following prevents a linking error in debug mode for MSVC using the libs in CVS
80 #if defined(WITH_OPENEXR) && defined(_WIN32) && defined(DEBUG) && !defined(__MINGW32__)
81 _CRTIMP void __cdecl _invalid_parameter_noinfo(void)
82 {
83 }
84 #endif
85
86 #include "MEM_guardedalloc.h"
87
88 #include "BLI_blenlib.h"
89 #include "BLI_math_color.h"
90 #include "BLI_threads.h"
91
92 #include "BKE_idprop.h"
93 #include "BKE_image.h"
94
95 #include "IMB_imbuf_types.h"
96 #include "IMB_imbuf.h"
97 #include "IMB_allocimbuf.h"
98 #include "IMB_metadata.h"
99
100 #include "openexr_multi.h"
101 }
102
103 extern "C" {
104 #include "IMB_colormanagement.h"
105 #include "IMB_colormanagement_intern.h"
106 }
107
108 using namespace Imf;
109 using namespace Imath;
110
111 extern "C"
112 {
113 /* prototype */
114 static struct ExrPass *imb_exr_get_pass(ListBase *lb, char *passname);
115 static bool exr_has_multiview(MultiPartInputFile& file);
116 static bool exr_has_multipart_file(MultiPartInputFile& file);
117 static bool exr_has_alpha(MultiPartInputFile& file);
118 static bool exr_has_zbuffer(MultiPartInputFile& file);
119 static void exr_printf(const char *__restrict format, ...);
120 static void imb_exr_type_by_channels(ChannelList& channels, StringVector& views,
121                                      bool *r_singlelayer, bool *r_multilayer, bool *r_multiview);
122 }
123
124 /* Memory Input Stream */
125
126 class Mem_IStream : public Imf::IStream
127 {
128 public:
129
130         Mem_IStream(unsigned char *exrbuf, size_t exrsize) :
131                 IStream("dummy"), _exrpos(0), _exrsize(exrsize)
132         {
133                 _exrbuf = exrbuf;
134         }
135
136         virtual bool    read(char c[], int n);
137         virtual Int64   tellg();
138         virtual void    seekg(Int64 pos);
139         virtual void    clear();
140         //virtual ~Mem_IStream() {}; // unused
141
142 private:
143
144         Int64 _exrpos;
145         Int64 _exrsize;
146         unsigned char *_exrbuf;
147 };
148
149 bool Mem_IStream::read(char c[], int n)
150 {
151         if (n + _exrpos <= _exrsize) {
152                 memcpy(c, (void *)(&_exrbuf[_exrpos]), n);
153                 _exrpos += n;
154                 return true;
155         }
156         else
157                 return false;
158 }
159
160 Int64 Mem_IStream::tellg()
161 {
162         return _exrpos;
163 }
164
165 void Mem_IStream::seekg(Int64 pos)
166 {
167         _exrpos = pos;
168 }
169
170 void Mem_IStream::clear()
171 {
172 }
173
174 /* File Input Stream */
175
176 class IFileStream : public Imf::IStream
177 {
178 public:
179         IFileStream(const char *filename)
180         : IStream(filename)
181         {
182                 /* utf-8 file path support on windows */
183 #if defined (WIN32) && !defined(FREE_WINDOWS)
184                 wchar_t *wfilename = alloc_utf16_from_8(filename, 0);
185                 ifs.open(wfilename, std::ios_base::binary);
186                 free(wfilename);
187 #else
188                 ifs.open(filename, std::ios_base::binary);
189 #endif
190
191                 if (!ifs)
192                         Iex::throwErrnoExc();
193         }
194
195         virtual bool read(char c[], int n)
196         {
197                 if (!ifs)
198                         throw Iex::InputExc("Unexpected end of file.");
199
200                 errno = 0;
201                 ifs.read(c, n);
202                 return check_error();
203         }
204
205         virtual Int64 tellg()
206         {
207                 return std::streamoff(ifs.tellg());
208         }
209
210         virtual void seekg(Int64 pos)
211         {
212                 ifs.seekg(pos);
213                 check_error();
214         }
215
216         virtual void clear()
217         {
218                 ifs.clear();
219         }
220
221 private:
222         bool check_error()
223         {
224                 if (!ifs) {
225                         if (errno)
226                                 Iex::throwErrnoExc();
227
228                         return false;
229                 }
230
231                 return true;
232         }
233
234         std::ifstream ifs;
235 };
236
237 /* File Output Stream */
238
239 class OFileStream : public OStream
240 {
241 public:
242         OFileStream(const char *filename)
243         : OStream(filename)
244         {
245                 /* utf-8 file path support on windows */
246 #if defined (WIN32) && !defined(FREE_WINDOWS)
247                 wchar_t *wfilename = alloc_utf16_from_8(filename, 0);
248                 ofs.open(wfilename, std::ios_base::binary);
249                 free(wfilename);
250 #else
251                 ofs.open(filename, std::ios_base::binary);
252 #endif
253
254                 if (!ofs)
255                         Iex::throwErrnoExc();
256         }
257
258         virtual void write(const char c[], int n)
259         {
260                 errno = 0;
261                 ofs.write(c, n);
262                 check_error();
263         }
264
265         virtual Int64 tellp()
266         {
267                 return std::streamoff(ofs.tellp());
268         }
269
270         virtual void seekp(Int64 pos)
271         {
272                 ofs.seekp(pos);
273                 check_error();
274         }
275
276 private:
277         void check_error()
278         {
279                 if (!ofs) {
280                         if (errno)
281                                 Iex::throwErrnoExc();
282
283                         throw Iex::ErrnoExc("File output failed.");
284                 }
285         }
286
287         std::ofstream ofs;
288 };
289
290 struct _RGBAZ {
291         half r;
292         half g;
293         half b;
294         half a;
295         half z;
296 };
297
298 typedef struct _RGBAZ RGBAZ;
299
300 extern "C"
301 {
302
303 /**
304  * Test presence of OpenEXR file.
305  * \param mem pointer to loaded OpenEXR bitstream
306  */
307 int imb_is_a_openexr(const unsigned char *mem)
308 {
309         return Imf::isImfMagic((const char *)mem);
310 }
311
312 static void openexr_header_compression(Header *header, int compression)
313 {
314         switch (compression) {
315                 case R_IMF_EXR_CODEC_NONE:
316                         header->compression() = NO_COMPRESSION;
317                         break;
318                 case R_IMF_EXR_CODEC_PXR24:
319                         header->compression() = PXR24_COMPRESSION;
320                         break;
321                 case R_IMF_EXR_CODEC_ZIP:
322                         header->compression() = ZIP_COMPRESSION;
323                         break;
324                 case R_IMF_EXR_CODEC_PIZ:
325                         header->compression() = PIZ_COMPRESSION;
326                         break;
327                 case R_IMF_EXR_CODEC_RLE:
328                         header->compression() = RLE_COMPRESSION;
329                         break;
330                 case R_IMF_EXR_CODEC_ZIPS:
331                         header->compression() = ZIPS_COMPRESSION;
332                         break;
333                 case R_IMF_EXR_CODEC_B44:
334                         header->compression() = B44_COMPRESSION;
335                         break;
336                 case R_IMF_EXR_CODEC_B44A:
337                         header->compression() = B44A_COMPRESSION;
338                         break;
339 #if OPENEXR_VERSION_MAJOR >= 2 && OPENEXR_VERSION_MINOR >= 2
340                 case R_IMF_EXR_CODEC_DWAA:
341                         header->compression() = DWAA_COMPRESSION;
342                         break;
343                 case R_IMF_EXR_CODEC_DWAB:
344                         header->compression() = DWAB_COMPRESSION;
345                         break;
346 #endif
347                 default:
348                         header->compression() = ZIP_COMPRESSION;
349                         break;
350         }
351 }
352
353 static void openexr_header_metadata(Header *header, struct ImBuf *ibuf)
354 {
355         if (ibuf->metadata) {
356                 IDProperty *prop;
357
358                 for (prop = (IDProperty *)ibuf->metadata->data.group.first; prop; prop = prop->next) {
359                         if (prop->type == IDP_STRING) {
360                                 header->insert(prop->name, StringAttribute(IDP_String(prop)));
361                         }
362                 }
363         }
364
365         if (ibuf->ppm[0] > 0.0)
366                 addXDensity(*header, ibuf->ppm[0] / 39.3700787); /* 1 meter = 39.3700787 inches */
367 }
368
369 static void openexr_header_metadata_callback(void *data, const char *propname, char *prop, int UNUSED(len))
370 {
371         Header *header = (Header *)data;
372         header->insert(propname, StringAttribute(prop));
373 }
374
375
376 static bool imb_save_openexr_half(
377         ImBuf *ibuf, const char *name, const int flags, const int totviews,
378         const char * (*getview)(void *base, int view_id),
379         ImBuf *(*getbuffer)(void *base, const int view_id))
380 {
381         const int channels = ibuf->channels;
382         const bool is_alpha = (channels >= 4) && (ibuf->planes == 32);
383         const bool is_zbuf = (flags & IB_zbuffloat) && ibuf->zbuf_float != NULL; /* summarize */
384         const int width = ibuf->x;
385         const int height = ibuf->y;
386         const bool is_multiview = (flags & IB_multiview) && ibuf->userdata;
387
388         BLI_assert((!is_multiview) || (getview && getbuffer));
389
390         std::vector <string> views;
391         int view_id;
392
393         try
394         {
395                 Header header(width, height);
396
397                 openexr_header_compression(&header, ibuf->foptions.flag & OPENEXR_COMPRESS);
398                 openexr_header_metadata(&header, ibuf);
399
400                 /* create views when possible */
401                 for (view_id = 0; view_id < totviews; view_id ++)
402                         views.push_back(is_multiview ? getview(ibuf->userdata, view_id) : "");
403
404                 if (is_multiview)
405                         addMultiView(header, views);
406
407                 for (view_id = 0; view_id < totviews; view_id ++) {
408                         header.channels().insert(insertViewName("R", views, view_id), Channel(HALF));
409                         header.channels().insert(insertViewName("G", views, view_id), Channel(HALF));
410                         header.channels().insert(insertViewName("B", views, view_id), Channel(HALF));
411                         if (is_alpha)
412                                 header.channels().insert(insertViewName("A", views, view_id), Channel(HALF));
413                         if (is_zbuf)     // z we do as float always
414                                 header.channels().insert(insertViewName("Z", views, view_id), Channel(Imf::FLOAT));
415                 }
416
417                 FrameBuffer frameBuffer;
418
419                 /* manually create ofstream, so we can handle utf-8 filepaths on windows */
420                 OFileStream file_stream(name);
421                 OutputFile file(file_stream, header);
422
423                 /* we store first everything in half array */
424                 std::vector<RGBAZ> pixels(height * width * totviews);
425                 int xstride = sizeof(RGBAZ);
426                 int ystride = xstride * width;
427
428                 for (view_id = 0; view_id < totviews; view_id ++) {
429                         ImBuf *view_ibuf = is_multiview ? getbuffer(ibuf->userdata, view_id) : ibuf;
430                         const size_t offset = view_id * width * height;
431                         RGBAZ *to = &pixels[offset];
432
433                         /* TODO (dfelinto)
434                          * In some cases we get NULL ibufs, it needs investigation, meanwhile prevent crash
435                          * Multiview Render + Image Editor + OpenEXR + Multi-View
436                          */
437                         if (view_ibuf == NULL) {
438                                 throw std::runtime_error(std::string("Missing data to write to ") + name);
439                         }
440
441                         /* indicate used buffers */
442                         frameBuffer.insert(insertViewName("R", views, view_id), Slice(HALF,  (char *) &pixels[offset].r, xstride, ystride));
443                         frameBuffer.insert(insertViewName("G", views, view_id), Slice(HALF,  (char *) &pixels[offset].g, xstride, ystride));
444                         frameBuffer.insert(insertViewName("B", views, view_id), Slice(HALF,  (char *) &pixels[offset].b, xstride, ystride));
445                         if (is_alpha)
446                                 frameBuffer.insert(insertViewName("A", views, view_id), Slice(HALF, (char *) &pixels[offset].a, xstride, ystride));
447                         if (is_zbuf)
448                                 frameBuffer.insert(insertViewName("Z", views, view_id), Slice(Imf::FLOAT, (char *)(view_ibuf->zbuf_float + (height - 1) * width),
449                                                    sizeof(float), sizeof(float) * -width));
450                         if (view_ibuf->rect_float) {
451                                 float *from;
452
453                                 for (int i = view_ibuf->y - 1; i >= 0; i--) {
454                                         from = view_ibuf->rect_float + channels * i * width;
455
456                                         for (int j = view_ibuf->x; j > 0; j--) {
457                                                 to->r = from[0];
458                                                 to->g = (channels >= 2) ? from[1] : from[0];
459                                                 to->b = (channels >= 3) ? from[2] : from[0];
460                                                 to->a = (channels >= 4) ? from[3] : 1.0f;
461                                                 to++; from += channels;
462                                         }
463                                 }
464                         }
465                         else {
466                                 unsigned char *from;
467
468                                 for (int i = view_ibuf->y - 1; i >= 0; i--) {
469                                         from = (unsigned char *)view_ibuf->rect + 4 * i * width;
470
471                                         for (int j = view_ibuf->x; j > 0; j--) {
472                                                 to->r = srgb_to_linearrgb((float)from[0] / 255.0f);
473                                                 to->g = srgb_to_linearrgb((float)from[1] / 255.0f);
474                                                 to->b = srgb_to_linearrgb((float)from[2] / 255.0f);
475                                                 to->a = channels >= 4 ? (float)from[3] / 255.0f : 1.0f;
476                                                 to++; from += 4;
477                                         }
478                                 }
479                         }
480
481                         if (is_multiview)
482                                 IMB_freeImBuf(view_ibuf);
483                 }
484
485                 exr_printf("OpenEXR-save: Writing OpenEXR file of height %d.\n", height);
486
487                 file.setFrameBuffer(frameBuffer);
488                 file.writePixels(height);
489         }
490         catch (const std::exception& exc)
491         {
492                 printf("OpenEXR-save: ERROR: %s\n", exc.what());
493
494                 return false;
495         }
496
497         return true;
498 }
499
500 static bool imb_save_openexr_float(
501         ImBuf *ibuf, const char *name, const int flags, const int totviews,
502         const char * (*getview)(void *base, const int view_id),
503         ImBuf *(*getbuffer)(void *base, const int view_id))
504 {
505         const int channels = ibuf->channels;
506         const bool is_alpha = (channels >= 4) && (ibuf->planes == 32);
507         const bool is_zbuf = (flags & IB_zbuffloat) && ibuf->zbuf_float != NULL; /* summarize */
508         const int width = ibuf->x;
509         const int height = ibuf->y;
510         const bool is_multiview = (flags & IB_multiview) && ibuf->userdata;
511
512         BLI_assert((!is_multiview) || (getview && getbuffer));
513
514         std::vector <string> views;
515         int view_id;
516
517         try
518         {
519                 Header header(width, height);
520
521                 openexr_header_compression(&header, ibuf->foptions.flag & OPENEXR_COMPRESS);
522                 openexr_header_metadata(&header, ibuf);
523
524                 /* create views when possible */
525                 for (view_id = 0; view_id < totviews; view_id ++)
526                         views.push_back(is_multiview ? getview(ibuf->userdata, view_id) : "");
527
528                 if (is_multiview)
529                         addMultiView(header, views);
530
531                 for (view_id = 0; view_id < totviews; view_id ++) {
532                         header.channels().insert(insertViewName("R", views, view_id), Channel(Imf::FLOAT));
533                         header.channels().insert(insertViewName("G", views, view_id), Channel(Imf::FLOAT));
534                         header.channels().insert(insertViewName("B", views, view_id), Channel(Imf::FLOAT));
535                         if (is_alpha)
536                                 header.channels().insert(insertViewName("A", views, view_id), Channel(Imf::FLOAT));
537                         if (is_zbuf)
538                                 header.channels().insert(insertViewName("Z", views, view_id), Channel(Imf::FLOAT));
539                 }
540
541                 FrameBuffer frameBuffer;
542
543                 /* manually create ofstream, so we can handle utf-8 filepaths on windows */
544                 OFileStream file_stream(name);
545                 OutputFile file(file_stream, header);
546
547                 int xstride = sizeof(float) * channels;
548                 int ystride = -xstride * width;
549
550                 for (view_id = 0; view_id < totviews; view_id ++) {
551                         float *rect[4] = {NULL, NULL, NULL, NULL};
552                         ImBuf *view_ibuf = is_multiview ? getbuffer(ibuf->userdata, view_id) : ibuf;
553
554                         /* TODO (dfelinto)
555                          * In some cases we get NULL ibufs, it needs investigation, meanwhile prevent crash
556                          * Multiview Render + Image Editor + OpenEXR + Multi-View
557                          */
558                         if (view_ibuf == NULL) {
559                                 throw std::runtime_error(std::string("Missing data to write to ") + name);
560                         }
561
562                         /* last scanline, stride negative */
563                         rect[0] = view_ibuf->rect_float + channels * (height - 1) * width;
564                         rect[1] = (channels >= 2) ? rect[0] + 1 : rect[0];
565                         rect[2] = (channels >= 3) ? rect[0] + 2 : rect[0];
566                         rect[3] = (channels >= 4) ? rect[0] + 3 : rect[0]; /* red as alpha, is this needed since alpha isn't written? */
567
568                         frameBuffer.insert(insertViewName("R", views, view_id), Slice(Imf::FLOAT,  (char *)rect[0], xstride, ystride));
569                         frameBuffer.insert(insertViewName("G", views, view_id), Slice(Imf::FLOAT,  (char *)rect[1], xstride, ystride));
570                         frameBuffer.insert(insertViewName("B", views, view_id), Slice(Imf::FLOAT,  (char *)rect[2], xstride, ystride));
571                         if (is_alpha)
572                                 frameBuffer.insert(insertViewName("A", views, view_id), Slice(Imf::FLOAT,  (char *)rect[3], xstride, ystride));
573                         if (is_zbuf)
574                                 frameBuffer.insert(insertViewName("Z", views, view_id), Slice(Imf::FLOAT, (char *) (view_ibuf->zbuf_float + (height - 1) * width),
575                                                                   sizeof(float), sizeof(float) * -width));
576
577                         if (is_multiview)
578                                 IMB_freeImBuf(view_ibuf);
579                 }
580                 file.setFrameBuffer(frameBuffer);
581                 file.writePixels(height);
582         }
583         catch (const std::exception& exc)
584         {
585                 printf("OpenEXR-save: ERROR: %s\n", exc.what());
586                 return false;
587         }
588
589         return true;
590 }
591
592 int imb_save_openexr(struct ImBuf *ibuf, const char *name, int flags)
593 {
594         if (flags & IB_mem) {
595                 printf("OpenEXR-save: Create EXR in memory CURRENTLY NOT SUPPORTED !\n");
596                 imb_addencodedbufferImBuf(ibuf);
597                 ibuf->encodedsize = 0;
598                 return(0);
599         }
600
601         if (ibuf->foptions.flag & OPENEXR_HALF)
602                 return (int) imb_save_openexr_half(ibuf, name, flags, 1, NULL, NULL);
603         else {
604                 /* when no float rect, we save as half (16 bits is sufficient) */
605                 if (ibuf->rect_float == NULL)
606                         return (int) imb_save_openexr_half(ibuf, name, flags, 1, NULL, NULL);
607                 else
608                         return (int) imb_save_openexr_float(ibuf, name, flags, 1, NULL, NULL);
609         }
610 }
611
612 static bool imb_save_openexr_multiview(
613         ImBuf *ibuf, const char *name, const int flags, const int totviews,
614         const char *(*getview)(void *base, const int view_id),
615         ImBuf *(*getbuffer)(void *base, const int view_id))
616 {
617         if (flags & IB_mem) {
618                 printf("OpenEXR-save: Create multiview EXR in memory CURRENTLY NOT SUPPORTED !\n");
619                 imb_addencodedbufferImBuf(ibuf);
620                 ibuf->encodedsize = 0;
621                 return false;
622         }
623
624         if (ibuf->foptions.flag & OPENEXR_HALF)
625                 return imb_save_openexr_half(ibuf, name, flags, totviews, getview, getbuffer);
626         else {
627                 /* when no float rect, we save as half (16 bits is sufficient) */
628                 if (ibuf->rect_float == NULL)
629                         return imb_save_openexr_half(ibuf, name, flags, totviews, getview, getbuffer);
630                 else
631                         return imb_save_openexr_float(ibuf, name, flags, totviews, getview, getbuffer);
632         }
633 }
634
635 /* Save single-layer multiview OpenEXR
636  * If we have more multiview formats in the future, the function below could be incorporated
637  * in our ImBuf write functions, meanwhile this is an OpenEXR special case only */
638 bool IMB_exr_multiview_save(
639         ImBuf *ibuf, const char *name, const int flags, const int totviews,
640         const char *(*getview)(void *base, const int view_id),
641         ImBuf *(*getbuffer)(void *base, const int view_id))
642 {
643         return imb_save_openexr_multiview(ibuf, name, flags, totviews, getview, getbuffer);
644 }
645
646 /* ********************* Nicer API, MultiLayer and with Tile file support ************************************ */
647
648 /* naming rules:
649  * - parse name from right to left
650  * - last character is channel ID, 1 char like 'A' 'R' 'G' 'B' 'X' 'Y' 'Z' 'W' 'U' 'V'
651  * - separated with a dot; the Pass name (like "Depth", "Color", "Diffuse" or "Combined")
652  * - separated with a dot: the Layer name (like "Lamp1" or "Walls" or "Characters")
653  */
654
655 static ListBase exrhandles = {NULL, NULL};
656
657 typedef struct ExrHandle {
658         struct ExrHandle *next, *prev;
659         char name[FILE_MAX];
660
661         IStream *ifile_stream;
662         MultiPartInputFile *ifile;
663
664         OFileStream *ofile_stream;
665         MultiPartOutputFile *mpofile;
666         OutputFile *ofile;
667
668         int tilex, tiley;
669         int width, height;
670         int mipmap;
671
672         StringVector *multiView; /* it needs to be a pointer due to Windows release builds of EXR2.0 segfault when opening EXR bug */
673         int parts;
674
675         ListBase channels;  /* flattened out, ExrChannel */
676         ListBase layers;    /* hierarchical, pointing in end to ExrChannel */
677
678         int num_half_channels;  /* used during filr save, allows faster temporary buffers allocation */
679 } ExrHandle;
680
681 /* flattened out channel */
682 typedef struct ExrChannel {
683         struct ExrChannel *next, *prev;
684
685         char name[EXR_TOT_MAXNAME + 1];  /* full name with everything */
686         struct MultiViewChannelName *m;  /* struct to store all multipart channel info */
687         int xstride, ystride;            /* step to next pixel, to next scanline */
688         float *rect;                     /* first pointer to write in */
689         char chan_id;                    /* quick lookup of channel char */
690         int view_id;                     /* quick lookup of channel view */
691         bool use_half_float;             /* when saving use half float for file storage */
692 } ExrChannel;
693
694
695 /* hierarchical; layers -> passes -> channels[] */
696 typedef struct ExrPass {
697         struct ExrPass *next, *prev;
698         char name[EXR_PASS_MAXNAME];
699         int totchan;
700         float *rect;
701         struct ExrChannel *chan[EXR_PASS_MAXCHAN];
702         char chan_id[EXR_PASS_MAXCHAN];
703
704         char internal_name[EXR_PASS_MAXNAME]; /* name with no view */
705         char view[EXR_VIEW_MAXNAME];
706         int view_id;
707 } ExrPass;
708
709 typedef struct ExrLayer {
710         struct ExrLayer *next, *prev;
711         char name[EXR_LAY_MAXNAME + 1];
712         ListBase passes;
713 } ExrLayer;
714
715 /* ********************** */
716
717 void *IMB_exr_get_handle(void)
718 {
719         ExrHandle *data = (ExrHandle *)MEM_callocN(sizeof(ExrHandle), "exr handle");
720         data->multiView = new StringVector();
721
722         BLI_addtail(&exrhandles, data);
723         return data;
724 }
725
726 void *IMB_exr_get_handle_name(const char *name)
727 {
728         ExrHandle *data = (ExrHandle *) BLI_rfindstring(&exrhandles, name, offsetof(ExrHandle, name));
729
730         if (data == NULL) {
731                 data = (ExrHandle *)IMB_exr_get_handle();
732                 BLI_strncpy(data->name, name, strlen(name) + 1);
733         }
734         return data;
735 }
736
737 /* multiview functions */
738 } // extern "C"
739
740 extern "C"
741 {
742
743 void IMB_exr_add_view(void *handle, const char *name)
744 {
745         ExrHandle *data = (ExrHandle *)handle;
746         data->multiView->push_back(name);
747 }
748
749 static int imb_exr_get_multiView_id(StringVector& views, const std::string& name)
750 {
751         int count = 0;
752         for (StringVector::const_iterator i = views.begin(); count < views.size(); ++i) {
753                 if (name == *i)
754                         return count;
755                 else
756                         count ++;
757         }
758
759         /* no views or wrong name */
760         return -1;
761 }
762
763 static void imb_exr_get_views(MultiPartInputFile& file, StringVector& views)
764 {
765         if (exr_has_multipart_file(file) == false) {
766                 if (exr_has_multiview(file)) {
767                         StringVector sv = multiView(file.header(0));
768                         for (StringVector::const_iterator i = sv.begin(); i != sv.end(); ++i)
769                                 views.push_back(*i);
770                 }
771         }
772
773         else {
774                 for (int p = 0; p < file.parts(); p++) {
775                         std::string view = "";
776                         if (file.header(p).hasView())
777                                 view = file.header(p).view();
778
779                         if (imb_exr_get_multiView_id(views, view) == -1)
780                                 views.push_back(view);
781                 }
782         }
783 }
784
785 /* Multilayer Blender files have the view name in all the passes (even the default view one) */
786 static void imb_exr_insert_view_name(char *name_full, const char *passname, const char *viewname)
787 {
788         BLI_assert(!ELEM(name_full, passname, viewname));
789
790         if (viewname == NULL || viewname[0] == '\0') {
791                 BLI_strncpy(name_full, passname, sizeof(((ExrChannel *)NULL)->name));
792                 return;
793         }
794
795         const char delims[] = {'.', '\0'};
796         const char *sep;
797         const char *token;
798         size_t len;
799
800         len = BLI_str_rpartition(passname, delims, &sep, &token);
801
802         if (sep) {
803                 BLI_snprintf(name_full, EXR_PASS_MAXNAME, "%.*s.%s.%s", (int)len, passname, viewname, token);
804         }
805         else {
806                 BLI_snprintf(name_full, EXR_PASS_MAXNAME, "%s.%s", passname, viewname);
807         }
808 }
809
810 /* adds flattened ExrChannels */
811 /* xstride, ystride and rect can be done in set_channel too, for tile writing */
812 /* passname does not include view */
813 void IMB_exr_add_channel(void *handle,
814                          const char *layname, const char *passname, const char *viewname,
815                          int xstride, int ystride, float *rect,
816                          bool use_half_float)
817 {
818         ExrHandle *data = (ExrHandle *)handle;
819         ExrChannel *echan;
820
821         echan = (ExrChannel *)MEM_callocN(sizeof(ExrChannel), "exr channel");
822         echan->m = new MultiViewChannelName ();
823
824         if (layname && layname[0] != '\0') {
825                 echan->m->name = layname;
826                 echan->m->name.append(".");
827                 echan->m->name.append(passname);
828         }
829         else {
830                 echan->m->name.assign(passname);
831         }
832
833         echan->m->internal_name = echan->m->name;
834
835         echan->m->view.assign(viewname ? viewname : "");
836
837         /* quick look up */
838         echan->view_id = std::max(0, imb_exr_get_multiView_id(*data->multiView, echan->m->view));
839
840         /* name has to be unique, thus it's a combination of layer, pass, view, and channel */
841         if (layname && layname[0] != '\0') {
842                 imb_exr_insert_view_name(echan->name, echan->m->name.c_str(), echan->m->view.c_str());
843         }
844         else if (data->multiView->size() > 1) {
845                 std::string raw_name = insertViewName(echan->m->name, *data->multiView, echan->view_id);
846                 BLI_strncpy(echan->name, raw_name.c_str(), sizeof(echan->name));
847         }
848         else {
849                 BLI_strncpy(echan->name, echan->m->name.c_str(), sizeof(echan->name));
850         }
851
852         echan->xstride = xstride;
853         echan->ystride = ystride;
854         echan->rect = rect;
855         echan->use_half_float = use_half_float;
856
857         if (echan->use_half_float) {
858                 data->num_half_channels++;
859         }
860
861         exr_printf("added channel %s\n", echan->name);
862         BLI_addtail(&data->channels, echan);
863 }
864
865 /* used for output files (from RenderResult) (single and multilayer, single and multiview) */
866 int IMB_exr_begin_write(void *handle, const char *filename, int width, int height, int compress, const StampData *stamp)
867 {
868         ExrHandle *data = (ExrHandle *)handle;
869         Header header(width, height);
870         ExrChannel *echan;
871
872         data->width = width;
873         data->height = height;
874
875         bool is_singlelayer, is_multilayer, is_multiview;
876
877         for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
878                 header.channels().insert(echan->name,
879                                          Channel(echan->use_half_float ? Imf::HALF : Imf::FLOAT));
880         }
881
882         openexr_header_compression(&header, compress);
883         BKE_stamp_info_callback(&header, const_cast<StampData *>(stamp), openexr_header_metadata_callback, false);
884         /* header.lineOrder() = DECREASING_Y; this crashes in windows for file read! */
885
886         imb_exr_type_by_channels(header.channels(), *data->multiView, &is_singlelayer, &is_multilayer, &is_multiview);
887
888         if (is_multilayer)
889                 header.insert("BlenderMultiChannel", StringAttribute("Blender V2.55.1 and newer"));
890
891         if (is_multiview)
892                 addMultiView(header, *data->multiView);
893
894         /* avoid crash/abort when we don't have permission to write here */
895         /* manually create ofstream, so we can handle utf-8 filepaths on windows */
896         try {
897                 data->ofile_stream = new OFileStream(filename);
898                 data->ofile = new OutputFile(*(data->ofile_stream), header);
899         }
900         catch (const std::exception& exc) {
901                 std::cerr << "IMB_exr_begin_write: ERROR: " << exc.what() << std::endl;
902
903                 delete data->ofile;
904                 delete data->ofile_stream;
905
906                 data->ofile = NULL;
907                 data->ofile_stream = NULL;
908         }
909
910         return (data->ofile != NULL);
911 }
912
913 /* only used for writing temp. render results (not image files)
914  * (FSA and Save Buffers) */
915 void IMB_exrtile_begin_write(void *handle, const char *filename, int mipmap, int width, int height, int tilex, int tiley)
916 {
917         ExrHandle *data = (ExrHandle *)handle;
918         Header header(width, height);
919         std::vector<Header> headers;
920         ExrChannel *echan;
921
922         data->tilex = tilex;
923         data->tiley = tiley;
924         data->width = width;
925         data->height = height;
926         data->mipmap = mipmap;
927
928         header.setTileDescription(TileDescription(tilex, tiley, (mipmap) ? MIPMAP_LEVELS : ONE_LEVEL));
929         header.compression() = RLE_COMPRESSION;
930         header.setType(TILEDIMAGE);
931
932         header.insert("BlenderMultiChannel", StringAttribute("Blender V2.43"));
933
934         int numparts = data->multiView->size();
935
936         /* copy header from all parts of input to our header array
937          * those temporary files have one part per view */
938         for (int i = 0; i < numparts; i++) {
939                 headers.push_back (header);
940                 headers[headers.size() - 1].setView((*(data->multiView))[i]);
941                 headers[headers.size() - 1].setName((*(data->multiView))[i]);
942         }
943
944         exr_printf("\nIMB_exrtile_begin_write\n");
945         exr_printf("%s %-6s %-22s \"%s\"\n", "p", "view", "name", "internal_name");
946         exr_printf("---------------------------------------------------------------\n");
947
948         /* assign channels  */
949         for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
950                 /* Tiles are expected to be saved with full float currently. */
951                 BLI_assert(echan->use_half_float == 0);
952
953                 echan->m->internal_name = echan->m->name;
954                 echan->m->part_number = echan->view_id;
955
956                 headers[echan->view_id].channels().insert(echan->m->internal_name, Channel(Imf::FLOAT));
957                 exr_printf("%d %-6s %-22s \"%s\"\n", echan->m->part_number, echan->m->view.c_str(), echan->m->name.c_str(), echan->m->internal_name.c_str());
958         }
959
960         /* avoid crash/abort when we don't have permission to write here */
961         /* manually create ofstream, so we can handle utf-8 filepaths on windows */
962         try {
963                 data->ofile_stream = new OFileStream(filename);
964                 data->mpofile = new MultiPartOutputFile(*(data->ofile_stream), &headers[0], headers.size());
965         }
966         catch (const std::exception &) {
967                 delete data->mpofile;
968                 delete data->ofile_stream;
969
970                 data->mpofile = NULL;
971                 data->ofile_stream = NULL;
972         }
973 }
974
975 /* read from file */
976 int IMB_exr_begin_read(void *handle, const char *filename, int *width, int *height)
977 {
978         ExrHandle *data = (ExrHandle *)handle;
979         ExrChannel *echan;
980
981         if (BLI_exists(filename) && BLI_file_size(filename) > 32) {   /* 32 is arbitrary, but zero length files crashes exr */
982                 /* avoid crash/abort when we don't have permission to write here */
983                 try {
984                         data->ifile_stream = new IFileStream(filename);
985                         data->ifile = new MultiPartInputFile(*(data->ifile_stream));
986                 }
987                 catch (const std::exception &) {
988                         delete data->ifile;
989                         delete data->ifile_stream;
990
991                         data->ifile = NULL;
992                         data->ifile_stream = NULL;
993                 }
994
995                 if (data->ifile) {
996                         Box2i dw = data->ifile->header(0).dataWindow();
997                         data->width = *width  = dw.max.x - dw.min.x + 1;
998                         data->height = *height = dw.max.y - dw.min.y + 1;
999
1000                         imb_exr_get_views(*data->ifile, *data->multiView);
1001
1002                         std::vector<MultiViewChannelName> channels;
1003                         GetChannelsInMultiPartFile(*data->ifile, channels);
1004
1005                         for (size_t i = 0; i < channels.size(); i++) {
1006                                 IMB_exr_add_channel(data, NULL, channels[i].name.c_str(), channels[i].view.c_str(), 0, 0, NULL, false);
1007                 
1008                                 echan = (ExrChannel *)data->channels.last;
1009                                 echan->m->name = channels[i].name;
1010                                 echan->m->view = channels[i].view;
1011                                 echan->m->part_number = channels[i].part_number;
1012                                 echan->m->internal_name = channels[i].internal_name;
1013                         }
1014
1015                         return 1;
1016                 }
1017         }
1018         return 0;
1019 }
1020
1021 /* still clumsy name handling, layers/channels can be ordered as list in list later */
1022 /* passname here is the raw channel name without the layer */
1023 void IMB_exr_set_channel(void *handle, const char *layname, const char *passname, int xstride, int ystride, float *rect)
1024 {
1025         ExrHandle *data = (ExrHandle *)handle;
1026         ExrChannel *echan;
1027         char name[EXR_TOT_MAXNAME + 1];
1028
1029         if (layname) {
1030                 char lay[EXR_LAY_MAXNAME + 1], pass[EXR_PASS_MAXNAME + 1];
1031                 BLI_strncpy(lay, layname, EXR_LAY_MAXNAME);
1032                 BLI_strncpy(pass, passname, EXR_PASS_MAXNAME);
1033
1034                 BLI_snprintf(name, sizeof(name), "%s.%s", lay, pass);
1035         }
1036         else
1037                 BLI_strncpy(name, passname, EXR_TOT_MAXNAME - 1);
1038
1039         echan = (ExrChannel *)BLI_findstring(&data->channels, name, offsetof(ExrChannel, name));
1040
1041         if (echan) {
1042                 echan->xstride = xstride;
1043                 echan->ystride = ystride;
1044                 echan->rect = rect;
1045         }
1046         else
1047                 printf("IMB_exr_set_channel error %s\n", name);
1048 }
1049
1050 float  *IMB_exr_channel_rect(void *handle, const char *layname, const char *passname, const char *viewname)
1051 {
1052         ExrHandle *data = (ExrHandle *)handle;
1053         ExrChannel *echan;
1054         char name[EXR_TOT_MAXNAME + 1];
1055
1056         if (layname) {
1057                 char lay[EXR_LAY_MAXNAME + 1], pass[EXR_PASS_MAXNAME + 1];
1058                 BLI_strncpy(lay, layname, EXR_LAY_MAXNAME);
1059                 BLI_strncpy(pass, passname, EXR_PASS_MAXNAME);
1060
1061                 BLI_snprintf(name, sizeof(name), "%s.%s", lay, pass);
1062         }
1063         else
1064                 BLI_strncpy(name, passname, EXR_TOT_MAXNAME - 1);
1065
1066         /* name has to be unique, thus it's a combination of layer, pass, view, and channel */
1067         if (layname && layname[0] != '\0') {
1068                 char temp_buf[EXR_PASS_MAXNAME];
1069                 imb_exr_insert_view_name(temp_buf, name, viewname);
1070                 BLI_strncpy(name, temp_buf, sizeof(name));
1071         }
1072         else if (data->multiView->size() > 1) {
1073                 const int view_id = std::max(0, imb_exr_get_multiView_id(*data->multiView, viewname));
1074                 std::string raw_name = insertViewName(name, *data->multiView, view_id);
1075                 BLI_strncpy(name, raw_name.c_str(), sizeof(name));
1076         }
1077
1078         echan = (ExrChannel *)BLI_findstring(&data->channels, name, offsetof(ExrChannel, name));
1079
1080         if (echan)
1081                 return echan->rect;
1082
1083         return NULL;
1084 }
1085
1086 void IMB_exr_clear_channels(void *handle)
1087 {
1088         ExrHandle *data = (ExrHandle *)handle;
1089         ExrChannel *chan;
1090
1091         for (chan = (ExrChannel *)data->channels.first; chan; chan = chan->next)
1092                 delete chan->m;
1093
1094         BLI_freelistN(&data->channels);
1095 }
1096
1097 void IMB_exr_write_channels(void *handle)
1098 {
1099         ExrHandle *data = (ExrHandle *)handle;
1100         FrameBuffer frameBuffer;
1101         ExrChannel *echan;
1102
1103         if (data->channels.first) {
1104                 const size_t num_pixels = ((size_t)data->width) * data->height;
1105                 half *rect_half = NULL, *current_rect_half;
1106
1107                 /* We allocate teporary storage for half pixels for all the channels at once. */
1108                 if (data->num_half_channels != 0) {
1109                         rect_half = (half *)MEM_mallocN(sizeof(half) * data->num_half_channels * num_pixels, __func__);
1110                         current_rect_half = rect_half;
1111                 }
1112
1113                 for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
1114                         /* Writting starts from last scanline, stride negative. */
1115                         if (echan->use_half_float) {
1116                                 float *rect = echan->rect;
1117                                 half *cur = current_rect_half;
1118                                 for (size_t i = 0; i < num_pixels; ++i, ++cur) {
1119                                         *cur = rect[i * echan->xstride];
1120                                 }
1121                                 half *rect_to_write = current_rect_half + (data->height - 1) * data->width;
1122                                 frameBuffer.insert(echan->name, Slice(Imf::HALF,  (char *)rect_to_write,
1123                                                                       sizeof(half), -data->width * sizeof(half)));
1124                                 current_rect_half += num_pixels;
1125                         }
1126                         else {
1127                                 float *rect = echan->rect + echan->xstride * (data->height - 1) * data->width;
1128                                 frameBuffer.insert(echan->name, Slice(Imf::FLOAT,  (char *)rect,
1129                                                                       echan->xstride * sizeof(float), -echan->ystride * sizeof(float)));
1130                         }
1131                 }
1132
1133                 data->ofile->setFrameBuffer(frameBuffer);
1134                 try {
1135                         data->ofile->writePixels(data->height);
1136                 }
1137                 catch (const std::exception& exc) {
1138                         std::cerr << "OpenEXR-writePixels: ERROR: " << exc.what() << std::endl;
1139                 }
1140                 /* Free temporary buffers. */
1141                 if (rect_half != NULL) {
1142                         MEM_freeN(rect_half);
1143                 }
1144         }
1145         else {
1146                 printf("Error: attempt to save MultiLayer without layers.\n");
1147         }
1148 }
1149
1150 /* temporary function, used for FSA and Save Buffers */
1151 /* called once per tile * view */
1152 void IMB_exrtile_write_channels(void *handle, int partx, int party, int level, const char *viewname)
1153 {
1154         ExrHandle *data = (ExrHandle *)handle;
1155         FrameBuffer frameBuffer;
1156         ExrChannel *echan;
1157         std::string view(viewname);
1158         const int view_id = imb_exr_get_multiView_id(*data->multiView, view);
1159
1160         exr_printf("\nIMB_exrtile_write_channels(view: %s)\n", viewname);
1161         exr_printf("%s %-6s %-22s \"%s\"\n", "p", "view", "name", "internal_name");
1162         exr_printf("---------------------------------------------------------------------\n");
1163
1164         for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
1165
1166                 /* eventually we can make the parts' channels to include
1167                    only the current view TODO */
1168                 if (strcmp(viewname, echan->m->view.c_str()) != 0)
1169                         continue;
1170
1171                 exr_printf("%d %-6s %-22s \"%s\"\n",
1172                            echan->m->part_number,
1173                            echan->m->view.c_str(),
1174                            echan->m->name.c_str(),
1175                            echan->m->internal_name.c_str()
1176                            );
1177
1178                 float *rect = echan->rect - echan->xstride * partx - echan->ystride * party;
1179                 frameBuffer.insert(echan->m->internal_name,
1180                                    Slice(Imf::FLOAT,
1181                                          (char *)rect,
1182                                          echan->xstride * sizeof(float),
1183                                          echan->ystride * sizeof(float)
1184                                         )
1185                                   );
1186         }
1187
1188         TiledOutputPart out (*data->mpofile, view_id);
1189         out.setFrameBuffer(frameBuffer);
1190
1191         try {
1192                 // printf("write tile %d %d\n", partx/data->tilex, party/data->tiley);
1193                 out.writeTile(partx / data->tilex, party / data->tiley, level);
1194         }
1195         catch (const std::exception& exc) {
1196                 std::cerr << "OpenEXR-writeTile: ERROR: " << exc.what() << std::endl;
1197         }
1198 }
1199
1200 /* called only when handle has all views */
1201 void IMB_exrmultiview_write_channels(void *handle, const char *viewname)
1202 {
1203         ExrHandle *data = (ExrHandle *)handle;
1204         const int view_id = viewname ? imb_exr_get_multiView_id(*data->multiView, viewname) : -1;
1205         int numparts = (view_id == -1 ? data->parts : view_id + 1);
1206         std::vector <FrameBuffer> frameBuffers(numparts);
1207         std::vector <OutputPart> outputParts;
1208         ExrChannel *echan;
1209         int i, part;
1210
1211         if (data->channels.first == NULL)
1212                 return;
1213
1214         exr_printf("\nIMB_exrmultiview_write_channels()\n");
1215
1216         for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
1217                 if (view_id != -1 && echan->view_id != view_id)
1218                         continue;
1219
1220                 part = (view_id == -1 ? echan->m->part_number : echan->view_id);
1221
1222                 /* last scanline, stride negative */
1223                 float *rect = echan->rect + echan->xstride * (data->height - 1) * data->width;
1224                 frameBuffers[part].insert(echan->m->internal_name,
1225                                           Slice(Imf::FLOAT,
1226                                                 (char *)rect,
1227                                                 echan->xstride * sizeof(float),
1228                                                 -echan->ystride * sizeof(float))
1229                 );
1230         }
1231
1232         for (i = 0; i < numparts; i++) {
1233                 OutputPart out(*data->mpofile, i);
1234                 out.setFrameBuffer(frameBuffers[i]);
1235                 outputParts.push_back(out);
1236         }
1237
1238         try {
1239                 for (i = 0; i < numparts; i++) {
1240                         if (view_id != -1 && i != view_id)
1241                                 continue;
1242
1243                         outputParts[i].writePixels(data->height);
1244                 }
1245         }
1246         catch (const std::exception& exc) {
1247                 std::cerr << "OpenEXR-write Multi Part: ERROR: " << exc.what() << std::endl;
1248         }
1249 }
1250
1251 void IMB_exr_read_channels(void *handle)
1252 {
1253         ExrHandle *data = (ExrHandle *)handle;
1254         ExrChannel *echan;
1255         int numparts = data->ifile->parts();
1256         std::vector<FrameBuffer> frameBuffers(numparts);
1257         std::vector<InputPart> inputParts;
1258
1259         /* check if exr was saved with previous versions of blender which flipped images */
1260         const StringAttribute *ta = data->ifile->header(0).findTypedAttribute <StringAttribute> ("BlenderMultiChannel");
1261         short flip = (ta && STREQLEN(ta->value().c_str(), "Blender V2.43", 13)); /* 'previous multilayer attribute, flipped */
1262
1263         exr_printf("\nIMB_exr_read_channels\n%s %-6s %-22s \"%s\"\n---------------------------------------------------------------------\n", "p", "view", "name", "internal_name");
1264
1265         for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
1266                 exr_printf("%d %-6s %-22s \"%s\"\n", echan->m->part_number, echan->m->view.c_str(), echan->m->name.c_str(), echan->m->internal_name.c_str());
1267
1268                 if (echan->rect) {
1269                         if (flip)
1270                                 frameBuffers[echan->m->part_number].insert(echan->m->internal_name, Slice(Imf::FLOAT,  (char *)echan->rect,
1271                                                                       echan->xstride * sizeof(float), echan->ystride * sizeof(float)));
1272                         else
1273                                 frameBuffers[echan->m->part_number].insert(echan->m->internal_name, Slice(Imf::FLOAT,  (char *)(echan->rect + echan->xstride * (data->height - 1) * data->width),
1274                                                                       echan->xstride * sizeof(float), -echan->ystride * sizeof(float)));
1275                 }
1276                 else
1277                         printf("warning, channel with no rect set %s\n", echan->m->internal_name.c_str());
1278         }
1279
1280         for (int i = 0; i < numparts; i++) {
1281                 InputPart in (*data->ifile, i);
1282                 in.setFrameBuffer(frameBuffers[i]);
1283                 inputParts.push_back(in);
1284         }
1285
1286         try {
1287                 for (int i = 0; i < numparts; i++) {
1288                         Header header = inputParts[i].header();
1289                         exr_printf("readPixels:readPixels[%d]: min.y: %d, max.y: %d\n", i, header.dataWindow().min.y, header.dataWindow().max.y);
1290                         inputParts[i].readPixels(header.dataWindow().min.y, header.dataWindow().max.y);
1291                         inputParts[i].readPixels(0, data->height - 1);
1292                 }
1293         }
1294         catch (const std::exception& exc) {
1295                 std::cerr << "OpenEXR-readPixels: ERROR: " << exc.what() << std::endl;
1296         }
1297 }
1298
1299 void IMB_exr_multilayer_convert(void *handle, void *base,
1300                                 void * (*addview)(void *base, const char *str),
1301                                 void * (*addlayer)(void *base, const char *str),
1302                                 void (*addpass)(void *base, void *lay, const char *str,
1303                                                 float *rect, int totchan, const char *chan_id,
1304                                                 const char *view))
1305 {
1306         ExrHandle *data = (ExrHandle *)handle;
1307         ExrLayer *lay;
1308         ExrPass *pass;
1309
1310         /* RenderResult needs at least one RenderView */
1311         if (data->multiView->size() == 0) {
1312                 addview(base, "");
1313         }
1314         else {
1315                 /* add views to RenderResult */
1316                 for (StringVector::const_iterator i = data->multiView->begin(); i != data->multiView->end(); ++i) {
1317                         addview(base, (*i).c_str());
1318                 }
1319         }
1320
1321         if (BLI_listbase_is_empty(&data->layers)) {
1322                 printf("cannot convert multilayer, no layers in handle\n");
1323                 return;
1324         }
1325
1326         for (lay = (ExrLayer *)data->layers.first; lay; lay = lay->next) {
1327                 void *laybase = addlayer(base, lay->name);
1328                 if (laybase) {
1329                         for (pass = (ExrPass *)lay->passes.first; pass; pass = pass->next) {
1330                                 addpass(base, laybase, pass->internal_name, pass->rect, pass->totchan, pass->chan_id, pass->view);
1331                                 pass->rect = NULL;
1332                         }
1333                 }
1334         }
1335 }
1336
1337 void IMB_exr_multiview_convert(void *handle, void *base,
1338                                void (*addview)(void *base, const char *str),
1339                                void (*addbuffer)(void *base, const char *str, ImBuf *ibuf, const int frame),
1340                                const int frame)
1341 {
1342         ExrHandle *data = (ExrHandle *)handle;
1343         MultiPartInputFile *file = data->ifile;
1344         ExrLayer *lay;
1345         ExrPass *pass;
1346         ImBuf *ibuf = NULL;
1347         const bool is_alpha = exr_has_alpha(*file);
1348         Box2i dw = file->header(0).dataWindow();
1349         const size_t width  = dw.max.x - dw.min.x + 1;
1350         const size_t height = dw.max.y - dw.min.y + 1;
1351         const bool is_depth = exr_has_zbuffer(*file);
1352         
1353         /* add views to RenderResult */
1354         for (StringVector::const_iterator i = data->multiView->begin(); i != data->multiView->end(); ++i) {
1355                 addview(base, (*i).c_str());
1356         }
1357         
1358         if (BLI_listbase_is_empty(&data->layers)) {
1359                 printf("cannot convert multiviews, no views in handle\n");
1360                 return;
1361         }
1362         
1363         /* there is one float/pass per layer (layer here is a view) */
1364         BLI_assert(BLI_listbase_count_ex(&data->layers, 2) == 1);
1365         lay = (ExrLayer *)data->layers.first;
1366         for (pass = (ExrPass *)lay->passes.first; pass; pass = pass->next) {
1367                 if (STREQ(pass->chan_id, "RGB") || STREQ(pass->chan_id, "RGBA")) {
1368                         ibuf = IMB_allocImBuf(width, height, is_alpha ? 32 : 24, IB_rectfloat);
1369
1370                         if (!ibuf) {
1371                                 printf("error creating multiview buffer\n");
1372                                 return;
1373                         }
1374
1375                         IMB_buffer_float_from_float(
1376                                 ibuf->rect_float, pass->rect, pass->totchan,
1377                                 IB_PROFILE_LINEAR_RGB, IB_PROFILE_LINEAR_RGB, false,
1378                                 ibuf->x, ibuf->y, ibuf->x, ibuf->x);
1379
1380                         if (hasXDensity(file->header(0))) {
1381                                 ibuf->ppm[0] = xDensity(file->header(0)) * 39.3700787f;
1382                                 ibuf->ppm[1] = ibuf->ppm[0] * (double)file->header(0).pixelAspectRatio();
1383                         }
1384
1385                         if (is_depth) {
1386                                 ExrPass *zpass;
1387                                 for (zpass = (ExrPass *)lay->passes.first; zpass; zpass = zpass->next) {
1388                                         if (STREQ(zpass->chan_id, "Z") && STREQ(zpass->view, pass->view)) {
1389                                                 addzbuffloatImBuf(ibuf);
1390                                                 memcpy(ibuf->zbuf_float, zpass->rect, sizeof(float) * ibuf->x * ibuf->y);
1391                                         }
1392                                 }
1393                         }
1394
1395                         addbuffer(base, pass->view, ibuf, frame);
1396                 }
1397         }
1398 }
1399
1400 void IMB_exr_close(void *handle)
1401 {
1402         ExrHandle *data = (ExrHandle *)handle;
1403         ExrLayer *lay;
1404         ExrPass *pass;
1405         ExrChannel *chan;
1406
1407         delete data->ifile;
1408         delete data->ifile_stream;
1409         delete data->ofile;
1410         delete data->mpofile;
1411         delete data->ofile_stream;
1412         delete data->multiView;
1413
1414         data->ifile = NULL;
1415         data->ifile_stream = NULL;
1416         data->ofile = NULL;
1417         data->mpofile = NULL;
1418         data->ofile_stream = NULL;
1419
1420         for (chan = (ExrChannel *)data->channels.first; chan; chan = chan->next) {
1421                 delete chan->m;
1422         }
1423         BLI_freelistN(&data->channels);
1424
1425         for (lay = (ExrLayer *)data->layers.first; lay; lay = lay->next) {
1426                 for (pass = (ExrPass *)lay->passes.first; pass; pass = pass->next)
1427                         if (pass->rect)
1428                                 MEM_freeN(pass->rect);
1429                 BLI_freelistN(&lay->passes);
1430         }
1431         BLI_freelistN(&data->layers);
1432
1433         BLI_remlink(&exrhandles, data);
1434         MEM_freeN(data);
1435 }
1436
1437 /* ********* */
1438
1439 /* get a substring from the end of the name, separated by '.' */
1440 static int imb_exr_split_token(const char *str, const char *end, const char **token)
1441 {
1442         const char delims[] = {'.', '\0'};
1443         const char *sep;
1444
1445         BLI_str_partition_ex(str, end, delims, &sep, token, true);
1446
1447         if (!sep) {
1448                 *token = str;
1449         }
1450
1451         return (int)(end - *token);
1452 }
1453
1454 static int imb_exr_split_channel_name(ExrChannel *echan, char *layname, char *passname)
1455 {
1456         const char *name = echan->m->name.c_str();
1457         const char *end = name + strlen(name);
1458         const char *token;
1459         char tokenbuf[EXR_TOT_MAXNAME];
1460         int len;
1461         
1462         /* some multilayers have the combined buffer with names A B G R saved */
1463         if (name[1] == 0) {
1464                 echan->chan_id = name[0];
1465                 layname[0] = '\0';
1466
1467                 if (ELEM(name[0], 'R', 'G', 'B', 'A'))
1468                         strcpy(passname, "Combined");
1469                 else if (name[0] == 'Z')
1470                         strcpy(passname, "Depth");
1471                 else
1472                         strcpy(passname, name);
1473
1474                 return 1;
1475         }
1476
1477         /* last token is single character channel identifier */
1478         len = imb_exr_split_token(name, end, &token);
1479         if (len == 0) {
1480                 printf("multilayer read: bad channel name: %s\n", name);
1481                 return 0;
1482         }
1483         else if (len == 1) {
1484                 echan->chan_id = token[0];
1485         }
1486         else if (len > 1) {
1487                 bool ok = false;
1488
1489                 if (len == 2) {
1490                         /* some multilayers are using two-letter channels name,
1491                          * like, MX or NZ, which is basically has structure of
1492                          *   <pass_prefix><component>
1493                          *
1494                          * This is a bit silly, but see file from [#35658].
1495                          *
1496                          * Here we do some magic to distinguish such cases.
1497                          */
1498                         if (ELEM(token[1], 'X', 'Y', 'Z') ||
1499                             ELEM(token[1], 'R', 'G', 'B') ||
1500                             ELEM(token[1], 'U', 'V', 'A'))
1501                         {
1502                                 echan->chan_id = token[1];
1503                                 ok = true;
1504                         }
1505                 }
1506
1507                 if (ok == false) {
1508                         BLI_strncpy(tokenbuf, token, std::min(len + 1, EXR_TOT_MAXNAME));
1509                         printf("multilayer read: channel token too long: %s\n", tokenbuf);
1510                         return 0;
1511                 }
1512         }
1513         end -= len + 1; /* +1 to skip '.' separator */
1514
1515         /* second token is pass name */
1516         len = imb_exr_split_token(name, end, &token);
1517         if (len == 0) {
1518                 printf("multilayer read: bad channel name: %s\n", name);
1519                 return 0;
1520         }
1521         BLI_strncpy(passname, token, len + 1);
1522         end -= len + 1; /* +1 to skip '.' separator */
1523
1524         /* all preceding tokens combined as layer name */
1525         if (end > name)
1526                 BLI_strncpy(layname, name, (int)(end - name) + 1);
1527         else
1528                 layname[0] = '\0';
1529
1530         return 1;
1531 }
1532
1533 static ExrLayer *imb_exr_get_layer(ListBase *lb, char *layname)
1534 {
1535         ExrLayer *lay = (ExrLayer *)BLI_findstring(lb, layname, offsetof(ExrLayer, name));
1536
1537         if (lay == NULL) {
1538                 lay = (ExrLayer *)MEM_callocN(sizeof(ExrLayer), "exr layer");
1539                 BLI_addtail(lb, lay);
1540                 BLI_strncpy(lay->name, layname, EXR_LAY_MAXNAME);
1541         }
1542
1543         return lay;
1544 }
1545
1546 static ExrPass *imb_exr_get_pass(ListBase *lb, char *passname)
1547 {
1548         ExrPass *pass = (ExrPass *)BLI_findstring(lb, passname, offsetof(ExrPass, name));
1549
1550         if (pass == NULL) {
1551                 pass = (ExrPass *)MEM_callocN(sizeof(ExrPass), "exr pass");
1552
1553                 if (STREQ(passname, "Combined"))
1554                         BLI_addhead(lb, pass);
1555                 else
1556                         BLI_addtail(lb, pass);
1557         }
1558
1559         BLI_strncpy(pass->name, passname, EXR_LAY_MAXNAME);
1560
1561         return pass;
1562 }
1563
1564 /* creates channels, makes a hierarchy and assigns memory to channels */
1565 static ExrHandle *imb_exr_begin_read_mem(IStream &file_stream, MultiPartInputFile &file, int width, int height)
1566 {
1567         ExrLayer *lay;
1568         ExrPass *pass;
1569         ExrChannel *echan;
1570         ExrHandle *data = (ExrHandle *)IMB_exr_get_handle();
1571         int a;
1572         char layname[EXR_TOT_MAXNAME], passname[EXR_TOT_MAXNAME];
1573
1574         data->ifile_stream = &file_stream;
1575         data->ifile = &file;
1576
1577         data->width = width;
1578         data->height = height;
1579
1580         std::vector<MultiViewChannelName> channels;
1581         GetChannelsInMultiPartFile(*data->ifile, channels);
1582
1583         imb_exr_get_views(*data->ifile, *data->multiView);
1584
1585         for (size_t i = 0; i < channels.size(); i++) {
1586                 IMB_exr_add_channel(data, NULL, channels[i].name.c_str(), channels[i].view.c_str(), 0, 0, NULL, false);
1587
1588                 echan = (ExrChannel *)data->channels.last;
1589                 echan->m->name = channels[i].name;
1590                 echan->m->view = channels[i].view;
1591                 echan->m->part_number = channels[i].part_number;
1592                 echan->m->internal_name = channels[i].internal_name;
1593         }
1594
1595         /* now try to sort out how to assign memory to the channels */
1596         /* first build hierarchical layer list */
1597         for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
1598                 if (imb_exr_split_channel_name(echan, layname, passname)) {
1599
1600                         const char *view = echan->m->view.c_str();
1601                         char internal_name[EXR_PASS_MAXNAME];
1602
1603                         BLI_strncpy(internal_name, passname, EXR_PASS_MAXNAME);
1604
1605                         if (view[0] != '\0') {
1606                                 char tmp_pass[EXR_PASS_MAXNAME];
1607                                 BLI_snprintf(tmp_pass, sizeof(tmp_pass), "%s.%s", passname, view);
1608                                 BLI_strncpy(passname, tmp_pass, sizeof(passname));
1609                         }
1610
1611                         ExrLayer *lay = imb_exr_get_layer(&data->layers, layname);
1612                         ExrPass *pass = imb_exr_get_pass(&lay->passes, passname);
1613
1614                         pass->chan[pass->totchan] = echan;
1615                         pass->totchan++;
1616                         pass->view_id = echan->view_id;
1617                         BLI_strncpy(pass->view, view, sizeof(pass->view));
1618                         BLI_strncpy(pass->internal_name, internal_name, EXR_PASS_MAXNAME);
1619
1620                         if (pass->totchan >= EXR_PASS_MAXCHAN)
1621                                 break;
1622                 }
1623         }
1624         if (echan) {
1625                 printf("error, too many channels in one pass: %s\n", echan->m->name.c_str());
1626                 IMB_exr_close(data);
1627                 return NULL;
1628         }
1629
1630         /* with some heuristics, try to merge the channels in buffers */
1631         for (lay = (ExrLayer *)data->layers.first; lay; lay = lay->next) {
1632                 for (pass = (ExrPass *)lay->passes.first; pass; pass = pass->next) {
1633                         if (pass->totchan) {
1634                                 pass->rect = (float *)MEM_mapallocN(width * height * pass->totchan * sizeof(float), "pass rect");
1635                                 if (pass->totchan == 1) {
1636                                         echan = pass->chan[0];
1637                                         echan->rect = pass->rect;
1638                                         echan->xstride = 1;
1639                                         echan->ystride = width;
1640                                         pass->chan_id[0] = echan->chan_id;
1641                                 }
1642                                 else {
1643                                         char lookup[256];
1644
1645                                         memset(lookup, 0, sizeof(lookup));
1646
1647                                         /* we can have RGB(A), XYZ(W), UVA */
1648                                         if (pass->totchan == 3 || pass->totchan == 4) {
1649                                                 if (pass->chan[0]->chan_id == 'B' || pass->chan[1]->chan_id == 'B' ||  pass->chan[2]->chan_id == 'B') {
1650                                                         lookup[(unsigned int)'R'] = 0;
1651                                                         lookup[(unsigned int)'G'] = 1;
1652                                                         lookup[(unsigned int)'B'] = 2;
1653                                                         lookup[(unsigned int)'A'] = 3;
1654                                                 }
1655                                                 else if (pass->chan[0]->chan_id == 'Y' || pass->chan[1]->chan_id == 'Y' ||  pass->chan[2]->chan_id == 'Y') {
1656                                                         lookup[(unsigned int)'X'] = 0;
1657                                                         lookup[(unsigned int)'Y'] = 1;
1658                                                         lookup[(unsigned int)'Z'] = 2;
1659                                                         lookup[(unsigned int)'W'] = 3;
1660                                                 }
1661                                                 else {
1662                                                         lookup[(unsigned int)'U'] = 0;
1663                                                         lookup[(unsigned int)'V'] = 1;
1664                                                         lookup[(unsigned int)'A'] = 2;
1665                                                 }
1666                                                 for (a = 0; a < pass->totchan; a++) {
1667                                                         echan = pass->chan[a];
1668                                                         echan->rect = pass->rect + lookup[(unsigned int)echan->chan_id];
1669                                                         echan->xstride = pass->totchan;
1670                                                         echan->ystride = width * pass->totchan;
1671                                                         pass->chan_id[(unsigned int)lookup[(unsigned int)echan->chan_id]] = echan->chan_id;
1672                                                 }
1673                                         }
1674                                         else { /* unknown */
1675                                                 for (a = 0; a < pass->totchan; a++) {
1676                                                         echan = pass->chan[a];
1677                                                         echan->rect = pass->rect + a;
1678                                                         echan->xstride = pass->totchan;
1679                                                         echan->ystride = width * pass->totchan;
1680                                                         pass->chan_id[a] = echan->chan_id;
1681                                                 }
1682                                         }
1683                                 }
1684                         }
1685                 }
1686         }
1687
1688         return data;
1689 }
1690
1691
1692 /* ********************************************************* */
1693
1694 /* debug only */
1695 static void exr_printf(const char *fmt, ...)
1696 {
1697 #if 0
1698         char output[1024];
1699         va_list args;
1700         va_start(args, fmt);
1701         std::vsprintf(output, fmt, args);
1702         va_end(args);
1703         printf("%s", output);
1704 #else
1705         (void)fmt;
1706 #endif
1707 }
1708
1709 static void exr_print_filecontents(MultiPartInputFile& file)
1710 {
1711         int numparts = file.parts();
1712         if (numparts == 1 && hasMultiView(file.header(0))) {
1713                 const StringVector views = multiView(file.header(0));
1714                 printf("OpenEXR-load: MultiView file\n");
1715                 printf("OpenEXR-load: Default view: %s\n", defaultViewName(views).c_str());
1716                 for (StringVector::const_iterator i = views.begin(); i != views.end(); ++i) {
1717                         printf("OpenEXR-load: Found view %s\n", (*i).c_str());
1718                 }
1719         }
1720         else if (numparts > 1) {
1721                 printf("OpenEXR-load: MultiPart file\n");
1722                 for (int i = 0; i < numparts; i++) {
1723                         if (file.header(i).hasView())
1724                                 printf("OpenEXR-load: Part %d: view = \"%s\"\n", i, file.header(i).view().c_str());
1725                 }
1726         }
1727
1728         for (int j = 0; j < numparts; j++) {
1729                 const ChannelList& channels = file.header(j).channels();
1730                 for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i) {
1731                         const Channel& channel = i.channel();
1732                         printf("OpenEXR-load: Found channel %s of type %d\n", i.name(), channel.type);
1733                 }
1734         }
1735 }
1736
1737 /* for non-multilayer, map  R G B A channel names to something that's in this file */
1738 static const char *exr_rgba_channelname(MultiPartInputFile& file, const char *chan)
1739 {
1740         const ChannelList& channels = file.header(0).channels();
1741
1742         for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i) {
1743                 /* const Channel &channel = i.channel(); */ /* Not used yet */
1744                 const char *str = i.name();
1745                 int len = strlen(str);
1746                 if (len) {
1747                         if (BLI_strcasecmp(chan, str + len - 1) == 0) {
1748                                 return str;
1749                         }
1750                 }
1751         }
1752         return chan;
1753 }
1754
1755 static bool exr_has_rgb(MultiPartInputFile& file)
1756 {
1757         return file.header(0).channels().findChannel("R") != NULL &&
1758                file.header(0).channels().findChannel("G") != NULL &&
1759                file.header(0).channels().findChannel("B") != NULL;
1760 }
1761
1762 static bool exr_has_luma(MultiPartInputFile& file)
1763 {
1764         /* Y channel is the luma and should always present fir luma space images,
1765          * optionally it could be also channels for chromas called BY and RY.
1766          */
1767         return file.header(0).channels().findChannel("Y") != NULL;
1768 }
1769
1770 static bool exr_has_chroma(MultiPartInputFile& file)
1771 {
1772         return file.header(0).channels().findChannel("BY") != NULL &&
1773                file.header(0).channels().findChannel("RY") != NULL;
1774 }
1775
1776 static bool exr_has_zbuffer(MultiPartInputFile& file)
1777 {
1778         return !(file.header(0).channels().findChannel("Z") == NULL);
1779 }
1780
1781 static bool exr_has_alpha(MultiPartInputFile& file)
1782 {
1783         return !(file.header(0).channels().findChannel("A") == NULL);
1784 }
1785
1786 static bool imb_exr_is_multilayer_file(MultiPartInputFile& file)
1787 {
1788         const StringAttribute *comments = file.header(0).findTypedAttribute<StringAttribute>("BlenderMultiChannel");
1789         const ChannelList& channels = file.header(0).channels();
1790         std::set <std::string> layerNames;
1791
1792         /* will not include empty layer names */
1793         channels.layers(layerNames);
1794
1795         if (comments || layerNames.size() > 1)
1796                 return true;
1797
1798         if (layerNames.size()) {
1799                 /* if layerNames is not empty, it means at least one layer is non-empty,
1800                  * but it also could be layers without names in the file and such case
1801                  * shall be considered a multilayer exr
1802                  *
1803                  * that's what we do here: test whether there're empty layer names together
1804                  * with non-empty ones in the file
1805                  */
1806                 for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); i++) {
1807                         std::string layerName = i.name();
1808                         size_t pos = layerName.rfind ('.');
1809
1810                         if (pos == std::string::npos)
1811                                 return true;
1812                 }
1813         }
1814
1815         return false;
1816 }
1817
1818 static void imb_exr_type_by_channels(ChannelList& channels, StringVector& views,
1819                                      bool *r_singlelayer, bool *r_multilayer, bool *r_multiview)
1820 {
1821         std::set <std::string> layerNames;
1822
1823         *r_singlelayer = true;
1824         *r_multilayer = *r_multiview = false;
1825
1826         /* will not include empty layer names */
1827         channels.layers(layerNames);
1828
1829         if (views.size() && views[0] != "") {
1830                 *r_multiview = true;
1831         }
1832         else {
1833                 *r_singlelayer = false;
1834                 *r_multilayer = true;
1835                 *r_multiview = false;
1836                 return;
1837         }
1838
1839         if (layerNames.size()) {
1840                 /* if layerNames is not empty, it means at least one layer is non-empty,
1841                  * but it also could be layers without names in the file and such case
1842                  * shall be considered a multilayer exr
1843                  *
1844                  * that's what we do here: test whether there're empty layer names together
1845                  * with non-empty ones in the file
1846                  */
1847                 for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); i++)
1848                         for (std::set<string>::iterator i = layerNames.begin(); i != layerNames.end(); i++)
1849                                 /* see if any layername differs from a viewname */
1850                                 if (imb_exr_get_multiView_id(views, *i) == -1) {
1851                                         std::string layerName = *i;
1852                                         size_t pos = layerName.rfind ('.');
1853
1854                                         if (pos == std::string::npos) {
1855                                                 *r_multilayer = true;
1856                                                 *r_singlelayer = false;
1857                                                 return;
1858                                         }
1859                                 }
1860         }
1861         else {
1862                 *r_singlelayer = true;
1863                 *r_multilayer = false;
1864                 *r_multiview = false;
1865         }
1866
1867         BLI_assert(r_singlelayer != r_multilayer);
1868 }
1869
1870 bool IMB_exr_has_singlelayer_multiview(void *handle)
1871 {
1872         ExrHandle *data = (ExrHandle *)handle;
1873         MultiPartInputFile *file = data->ifile;
1874         std::set <std::string> layerNames;
1875         const ChannelList& channels = file->header(0).channels();
1876         const StringAttribute *comments;
1877
1878         if (exr_has_multiview(*file) == false)
1879                 return false;
1880
1881         comments = file->header(0).findTypedAttribute<StringAttribute>("BlenderMultiChannel");
1882
1883         if (comments)
1884                 return false;
1885
1886         /* will not include empty layer names */
1887         channels.layers(layerNames);
1888
1889         /* returns false if any layer differs from views list */
1890         if (layerNames.size())
1891                 for (std::set<string>::iterator i = layerNames.begin(); i != layerNames.end(); i++)
1892                         if (imb_exr_get_multiView_id(*data->multiView, *i) == -1)
1893                                 return false;
1894
1895         return true;
1896 }
1897
1898 bool IMB_exr_has_multilayer(void *handle)
1899 {
1900         ExrHandle *data = (ExrHandle *)handle;
1901         return imb_exr_is_multilayer_file(*data->ifile);
1902 }
1903
1904 static bool exr_has_multiview(MultiPartInputFile& file)
1905 {
1906         return hasMultiView(file.header(0));
1907 }
1908
1909 static bool exr_has_multipart_file(MultiPartInputFile& file)
1910 {
1911         return file.parts() > 1;
1912 }
1913
1914 /* it returns true if the file is multilayer or multiview */
1915 static bool imb_exr_is_multi(MultiPartInputFile& file)
1916 {
1917         /* multipart files are treated as multilayer in blender - even if they are single layer openexr with multiview */
1918         if (exr_has_multipart_file(file))
1919                 return true;
1920
1921         if (exr_has_multiview(file))
1922                 return true;
1923
1924         if (imb_exr_is_multilayer_file(file))
1925                 return true;
1926
1927         return false;
1928 }
1929
1930 struct ImBuf *imb_load_openexr(const unsigned char *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE])
1931 {
1932         struct ImBuf *ibuf = NULL;
1933         Mem_IStream *membuf = NULL;
1934         MultiPartInputFile *file = NULL;
1935
1936         if (imb_is_a_openexr(mem) == 0) return(NULL);
1937
1938         colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_FLOAT);
1939
1940         try
1941         {
1942                 bool is_multi;
1943
1944                 membuf = new Mem_IStream((unsigned char *)mem, size);
1945                 file = new MultiPartInputFile(*membuf);
1946
1947                 Box2i dw = file->header(0).dataWindow();
1948                 const int width  = dw.max.x - dw.min.x + 1;
1949                 const int height = dw.max.y - dw.min.y + 1;
1950
1951                 //printf("OpenEXR-load: image data window %d %d %d %d\n",
1952                 //         dw.min.x, dw.min.y, dw.max.x, dw.max.y);
1953
1954                 if (0) // debug
1955                         exr_print_filecontents(*file);
1956
1957                 is_multi = imb_exr_is_multi(*file);
1958
1959                 /* do not make an ibuf when */
1960                 if (is_multi && !(flags & IB_test) && !(flags & IB_multilayer)) {
1961                         printf("Error: can't process EXR multilayer file\n");
1962                 }
1963                 else {
1964                         const int is_alpha = exr_has_alpha(*file);
1965
1966                         ibuf = IMB_allocImBuf(width, height, is_alpha ? 32 : 24, 0);
1967
1968                         if (hasXDensity(file->header(0))) {
1969                                 ibuf->ppm[0] = xDensity(file->header(0)) * 39.3700787f;
1970                                 ibuf->ppm[1] = ibuf->ppm[0] * (double)file->header(0).pixelAspectRatio();
1971                         }
1972
1973                         ibuf->ftype = IMB_FTYPE_OPENEXR;
1974
1975                         if (!(flags & IB_test)) {
1976
1977                                 if (flags & IB_metadata) {
1978                                         const Header & header = file->header(0);
1979                                         Header::ConstIterator iter;
1980
1981                                         for (iter = header.begin(); iter != header.end(); iter++) {
1982                                                 const StringAttribute *attrib = file->header(0).findTypedAttribute <StringAttribute> (iter.name());
1983
1984                                                 /* not all attributes are string attributes so we might get some NULLs here */
1985                                                 if (attrib) {
1986                                                         IMB_metadata_add_field(ibuf, iter.name(), attrib->value().c_str());
1987                                                         ibuf->flags |= IB_metadata;
1988                                                 }
1989                                         }
1990                                 }
1991
1992                                 if (is_multi && ((flags & IB_thumbnail) == 0)) { /* only enters with IB_multilayer flag set */
1993                                         /* constructs channels for reading, allocates memory in channels */
1994                                         ExrHandle *handle = imb_exr_begin_read_mem(*membuf, *file, width, height);
1995                                         if (handle) {
1996                                                 IMB_exr_read_channels(handle);
1997                                                 ibuf->userdata = handle;         /* potential danger, the caller has to check for this! */
1998                                         }
1999                                 }
2000                                 else {
2001                                         const bool has_rgb = exr_has_rgb(*file);
2002                                         const bool has_luma = exr_has_luma(*file);
2003                                         FrameBuffer frameBuffer;
2004                                         float *first;
2005                                         int xstride = sizeof(float) * 4;
2006                                         int ystride = -xstride * width;
2007
2008                                         imb_addrectfloatImBuf(ibuf);
2009
2010                                         /* inverse correct first pixel for datawindow coordinates (- dw.min.y because of y flip) */
2011                                         first = ibuf->rect_float - 4 * (dw.min.x - dw.min.y * width);
2012                                         /* but, since we read y-flipped (negative y stride) we move to last scanline */
2013                                         first += 4 * (height - 1) * width;
2014
2015                                         if (has_rgb) {
2016                                                 frameBuffer.insert(exr_rgba_channelname(*file, "R"),
2017                                                                    Slice(Imf::FLOAT,  (char *) first, xstride, ystride));
2018                                                 frameBuffer.insert(exr_rgba_channelname(*file, "G"),
2019                                                                    Slice(Imf::FLOAT,  (char *) (first + 1), xstride, ystride));
2020                                                 frameBuffer.insert(exr_rgba_channelname(*file, "B"),
2021                                                                    Slice(Imf::FLOAT,  (char *) (first + 2), xstride, ystride));
2022                                         }
2023                                         else if (has_luma) {
2024                                                 frameBuffer.insert(exr_rgba_channelname(*file, "Y"),
2025                                                                    Slice(Imf::FLOAT,  (char *) first, xstride, ystride));
2026                                                 frameBuffer.insert(exr_rgba_channelname(*file, "BY"),
2027                                                                    Slice(Imf::FLOAT,  (char *) (first + 1), xstride, ystride, 1, 1, 0.5f));
2028                                                 frameBuffer.insert(exr_rgba_channelname(*file, "RY"),
2029                                                                    Slice(Imf::FLOAT,  (char *) (first + 2), xstride, ystride, 1, 1, 0.5f));
2030                                         }
2031
2032                                         /* 1.0 is fill value, this still needs to be assigned even when (is_alpha == 0) */
2033                                         frameBuffer.insert(exr_rgba_channelname(*file, "A"),
2034                                                            Slice(Imf::FLOAT,  (char *) (first + 3), xstride, ystride, 1, 1, 1.0f));
2035
2036                                         if (exr_has_zbuffer(*file)) {
2037                                                 float *firstz;
2038
2039                                                 addzbuffloatImBuf(ibuf);
2040                                                 firstz = ibuf->zbuf_float - (dw.min.x - dw.min.y * width);
2041                                                 firstz += (height - 1) * width;
2042                                                 frameBuffer.insert("Z", Slice(Imf::FLOAT,  (char *)firstz, sizeof(float), -width * sizeof(float)));
2043                                         }
2044
2045                                         InputPart in (*file, 0);
2046                                         in.setFrameBuffer(frameBuffer);
2047                                         in.readPixels(dw.min.y, dw.max.y);
2048
2049                                         // XXX, ImBuf has no nice way to deal with this.
2050                                         // ideally IM_rect would be used when the caller wants a rect BUT
2051                                         // at the moment all functions use IM_rect.
2052                                         // Disabling this is ok because all functions should check if a rect exists and create one on demand.
2053                                         //
2054                                         // Disabling this because the sequencer frees immediate.
2055                                         //
2056                                         // if (flag & IM_rect)
2057                                         //     IMB_rect_from_float(ibuf);
2058
2059                                         if (!has_rgb && has_luma) {
2060                                                 size_t a;
2061                                                 if (exr_has_chroma(*file)) {
2062                                                         for (a = 0; a < (size_t) ibuf->x * ibuf->y; ++a) {
2063                                                                 float *color = ibuf->rect_float + a * 4;
2064                                                                 ycc_to_rgb(color[0] * 255.0f, color[1] * 255.0f, color[2] * 255.0f,
2065                                                                            &color[0], &color[1], &color[2],
2066                                                                            BLI_YCC_ITU_BT709);
2067                                                         }
2068                                                 }
2069                                                 else {
2070                                                         for (a = 0; a < (size_t) ibuf->x * ibuf->y; ++a) {
2071                                                                 float *color = ibuf->rect_float + a * 4;
2072                                                                 color[1] = color[2] = color[0];
2073                                                         }
2074                                                 }
2075                                         }
2076
2077                                         /* file is no longer needed */
2078                                         delete membuf;
2079                                         delete file;
2080                                 }
2081                         }
2082                         else {
2083                                 delete membuf;
2084                                 delete file;
2085                         }
2086
2087                         if (flags & IB_alphamode_detect)
2088                                 ibuf->flags |= IB_alphamode_premul;
2089                 }
2090                 return(ibuf);
2091         }
2092         catch (const std::exception& exc)
2093         {
2094                 std::cerr << exc.what() << std::endl;
2095                 if (ibuf) IMB_freeImBuf(ibuf);
2096                 delete file;
2097                 delete membuf;
2098
2099                 return (0);
2100         }
2101
2102 }
2103
2104 void imb_initopenexr(void)
2105 {
2106         int num_threads = BLI_system_thread_count();
2107
2108         setGlobalThreadCount(num_threads);
2109 }
2110
2111 } // export "C"