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