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