fb38e1e01c8026144af58f780f387809eef7ed33
[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   /** It needs to be a pointer due to Windows release builds of EXR2.0
622    * segfault when opening EXR bug. */
623   StringVector *multiView;
624
625   int parts;
626
627   ListBase channels; /* flattened out, ExrChannel */
628   ListBase layers;   /* hierarchical, pointing in end to ExrChannel */
629
630   int num_half_channels; /* used during filr save, allows faster temporary buffers allocation */
631 } ExrHandle;
632
633 /* flattened out channel */
634 typedef struct ExrChannel {
635   struct ExrChannel *next, *prev;
636
637   char name[EXR_TOT_MAXNAME + 1]; /* full name with everything */
638   struct MultiViewChannelName *m; /* struct to store all multipart channel info */
639   int xstride, ystride;           /* step to next pixel, to next scanline */
640   float *rect;                    /* first pointer to write in */
641   char chan_id;                   /* quick lookup of channel char */
642   int view_id;                    /* quick lookup of channel view */
643   bool use_half_float;            /* when saving use half float for file storage */
644 } ExrChannel;
645
646 /* hierarchical; layers -> passes -> channels[] */
647 typedef struct ExrPass {
648   struct ExrPass *next, *prev;
649   char name[EXR_PASS_MAXNAME];
650   int totchan;
651   float *rect;
652   struct ExrChannel *chan[EXR_PASS_MAXCHAN];
653   char chan_id[EXR_PASS_MAXCHAN];
654
655   char internal_name[EXR_PASS_MAXNAME]; /* name with no view */
656   char view[EXR_VIEW_MAXNAME];
657   int view_id;
658 } ExrPass;
659
660 typedef struct ExrLayer {
661   struct ExrLayer *next, *prev;
662   char name[EXR_LAY_MAXNAME + 1];
663   ListBase passes;
664 } ExrLayer;
665
666 /* ********************** */
667
668 void *IMB_exr_get_handle(void)
669 {
670   ExrHandle *data = (ExrHandle *)MEM_callocN(sizeof(ExrHandle), "exr handle");
671   data->multiView = new StringVector();
672
673   BLI_addtail(&exrhandles, data);
674   return data;
675 }
676
677 void *IMB_exr_get_handle_name(const char *name)
678 {
679   ExrHandle *data = (ExrHandle *)BLI_rfindstring(&exrhandles, name, offsetof(ExrHandle, name));
680
681   if (data == NULL) {
682     data = (ExrHandle *)IMB_exr_get_handle();
683     BLI_strncpy(data->name, name, strlen(name) + 1);
684   }
685   return data;
686 }
687
688 /* multiview functions */
689 }  // extern "C"
690
691 extern "C" {
692
693 void IMB_exr_add_view(void *handle, const char *name)
694 {
695   ExrHandle *data = (ExrHandle *)handle;
696   data->multiView->push_back(name);
697 }
698
699 static int imb_exr_get_multiView_id(StringVector &views, const std::string &name)
700 {
701   int count = 0;
702   for (StringVector::const_iterator i = views.begin(); count < views.size(); ++i) {
703     if (name == *i)
704       return count;
705     else
706       count++;
707   }
708
709   /* no views or wrong name */
710   return -1;
711 }
712
713 static void imb_exr_get_views(MultiPartInputFile &file, StringVector &views)
714 {
715   if (exr_has_multipart_file(file) == false) {
716     if (exr_has_multiview(file)) {
717       StringVector sv = multiView(file.header(0));
718       for (StringVector::const_iterator i = sv.begin(); i != sv.end(); ++i)
719         views.push_back(*i);
720     }
721   }
722
723   else {
724     for (int p = 0; p < file.parts(); p++) {
725       std::string view = "";
726       if (file.header(p).hasView())
727         view = file.header(p).view();
728
729       if (imb_exr_get_multiView_id(views, view) == -1)
730         views.push_back(view);
731     }
732   }
733 }
734
735 /* Multilayer Blender files have the view name in all the passes (even the default view one) */
736 static void imb_exr_insert_view_name(char *name_full, const char *passname, const char *viewname)
737 {
738   BLI_assert(!ELEM(name_full, passname, viewname));
739
740   if (viewname == NULL || viewname[0] == '\0') {
741     BLI_strncpy(name_full, passname, sizeof(((ExrChannel *)NULL)->name));
742     return;
743   }
744
745   const char delims[] = {'.', '\0'};
746   const char *sep;
747   const char *token;
748   size_t len;
749
750   len = BLI_str_rpartition(passname, delims, &sep, &token);
751
752   if (sep) {
753     BLI_snprintf(name_full, EXR_PASS_MAXNAME, "%.*s.%s.%s", (int)len, passname, viewname, token);
754   }
755   else {
756     BLI_snprintf(name_full, EXR_PASS_MAXNAME, "%s.%s", passname, viewname);
757   }
758 }
759
760 /* adds flattened ExrChannels */
761 /* xstride, ystride and rect can be done in set_channel too, for tile writing */
762 /* passname does not include view */
763 void IMB_exr_add_channel(void *handle,
764                          const char *layname,
765                          const char *passname,
766                          const char *viewname,
767                          int xstride,
768                          int ystride,
769                          float *rect,
770                          bool use_half_float)
771 {
772   ExrHandle *data = (ExrHandle *)handle;
773   ExrChannel *echan;
774
775   echan = (ExrChannel *)MEM_callocN(sizeof(ExrChannel), "exr channel");
776   echan->m = new MultiViewChannelName();
777
778   if (layname && layname[0] != '\0') {
779     echan->m->name = layname;
780     echan->m->name.append(".");
781     echan->m->name.append(passname);
782   }
783   else {
784     echan->m->name.assign(passname);
785   }
786
787   echan->m->internal_name = echan->m->name;
788
789   echan->m->view.assign(viewname ? viewname : "");
790
791   /* quick look up */
792   echan->view_id = std::max(0, imb_exr_get_multiView_id(*data->multiView, echan->m->view));
793
794   /* name has to be unique, thus it's a combination of layer, pass, view, and channel */
795   if (layname && layname[0] != '\0') {
796     imb_exr_insert_view_name(echan->name, echan->m->name.c_str(), echan->m->view.c_str());
797   }
798   else if (data->multiView->size() >= 1) {
799     std::string raw_name = insertViewName(echan->m->name, *data->multiView, echan->view_id);
800     BLI_strncpy(echan->name, raw_name.c_str(), sizeof(echan->name));
801   }
802   else {
803     BLI_strncpy(echan->name, echan->m->name.c_str(), sizeof(echan->name));
804   }
805
806   echan->xstride = xstride;
807   echan->ystride = ystride;
808   echan->rect = rect;
809   echan->use_half_float = use_half_float;
810
811   if (echan->use_half_float) {
812     data->num_half_channels++;
813   }
814
815   exr_printf("added channel %s\n", echan->name);
816   BLI_addtail(&data->channels, echan);
817 }
818
819 /* used for output files (from RenderResult) (single and multilayer, single and multiview) */
820 int IMB_exr_begin_write(void *handle,
821                         const char *filename,
822                         int width,
823                         int height,
824                         int compress,
825                         const StampData *stamp)
826 {
827   ExrHandle *data = (ExrHandle *)handle;
828   Header header(width, height);
829   ExrChannel *echan;
830
831   data->width = width;
832   data->height = height;
833
834   bool is_singlelayer, is_multilayer, is_multiview;
835
836   for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
837     header.channels().insert(echan->name, Channel(echan->use_half_float ? Imf::HALF : Imf::FLOAT));
838   }
839
840   openexr_header_compression(&header, compress);
841   BKE_stamp_info_callback(
842       &header, const_cast<StampData *>(stamp), openexr_header_metadata_callback, false);
843   /* header.lineOrder() = DECREASING_Y; this crashes in windows for file read! */
844
845   imb_exr_type_by_channels(
846       header.channels(), *data->multiView, &is_singlelayer, &is_multilayer, &is_multiview);
847
848   if (is_multilayer)
849     header.insert("BlenderMultiChannel", StringAttribute("Blender V2.55.1 and newer"));
850
851   if (is_multiview)
852     addMultiView(header, *data->multiView);
853
854   /* avoid crash/abort when we don't have permission to write here */
855   /* manually create ofstream, so we can handle utf-8 filepaths on windows */
856   try {
857     data->ofile_stream = new OFileStream(filename);
858     data->ofile = new OutputFile(*(data->ofile_stream), header);
859   }
860   catch (const std::exception &exc) {
861     std::cerr << "IMB_exr_begin_write: ERROR: " << exc.what() << std::endl;
862
863     delete data->ofile;
864     delete data->ofile_stream;
865
866     data->ofile = NULL;
867     data->ofile_stream = NULL;
868   }
869
870   return (data->ofile != NULL);
871 }
872
873 /* only used for writing temp. render results (not image files)
874  * (FSA and Save Buffers) */
875 void IMB_exrtile_begin_write(
876     void *handle, const char *filename, int mipmap, int width, int height, int tilex, int tiley)
877 {
878   ExrHandle *data = (ExrHandle *)handle;
879   Header header(width, height);
880   std::vector<Header> headers;
881   ExrChannel *echan;
882
883   data->tilex = tilex;
884   data->tiley = tiley;
885   data->width = width;
886   data->height = height;
887   data->mipmap = mipmap;
888
889   header.setTileDescription(TileDescription(tilex, tiley, (mipmap) ? MIPMAP_LEVELS : ONE_LEVEL));
890   header.compression() = RLE_COMPRESSION;
891   header.setType(TILEDIMAGE);
892
893   header.insert("BlenderMultiChannel", StringAttribute("Blender V2.43"));
894
895   int numparts = data->multiView->size();
896
897   /* copy header from all parts of input to our header array
898    * those temporary files have one part per view */
899   for (int i = 0; i < numparts; i++) {
900     headers.push_back(header);
901     headers[headers.size() - 1].setView((*(data->multiView))[i]);
902     headers[headers.size() - 1].setName((*(data->multiView))[i]);
903   }
904
905   exr_printf("\nIMB_exrtile_begin_write\n");
906   exr_printf("%s %-6s %-22s \"%s\"\n", "p", "view", "name", "internal_name");
907   exr_printf("---------------------------------------------------------------\n");
908
909   /* assign channels  */
910   for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
911     /* Tiles are expected to be saved with full float currently. */
912     BLI_assert(echan->use_half_float == 0);
913
914     echan->m->internal_name = echan->m->name;
915     echan->m->part_number = echan->view_id;
916
917     headers[echan->view_id].channels().insert(echan->m->internal_name, Channel(Imf::FLOAT));
918     exr_printf("%d %-6s %-22s \"%s\"\n",
919                echan->m->part_number,
920                echan->m->view.c_str(),
921                echan->m->name.c_str(),
922                echan->m->internal_name.c_str());
923   }
924
925   /* avoid crash/abort when we don't have permission to write here */
926   /* manually create ofstream, so we can handle utf-8 filepaths on windows */
927   try {
928     data->ofile_stream = new OFileStream(filename);
929     data->mpofile = new MultiPartOutputFile(*(data->ofile_stream), &headers[0], headers.size());
930   }
931   catch (const std::exception &) {
932     delete data->mpofile;
933     delete data->ofile_stream;
934
935     data->mpofile = NULL;
936     data->ofile_stream = NULL;
937   }
938 }
939
940 /* read from file */
941 int IMB_exr_begin_read(void *handle, const char *filename, int *width, int *height)
942 {
943   ExrHandle *data = (ExrHandle *)handle;
944   ExrChannel *echan;
945
946   if (BLI_exists(filename) &&
947       BLI_file_size(filename) > 32) { /* 32 is arbitrary, but zero length files crashes exr */
948     /* avoid crash/abort when we don't have permission to write here */
949     try {
950       data->ifile_stream = new IFileStream(filename);
951       data->ifile = new MultiPartInputFile(*(data->ifile_stream));
952     }
953     catch (const std::exception &) {
954       delete data->ifile;
955       delete data->ifile_stream;
956
957       data->ifile = NULL;
958       data->ifile_stream = NULL;
959     }
960
961     if (data->ifile) {
962       Box2i dw = data->ifile->header(0).dataWindow();
963       data->width = *width = dw.max.x - dw.min.x + 1;
964       data->height = *height = dw.max.y - dw.min.y + 1;
965
966       imb_exr_get_views(*data->ifile, *data->multiView);
967
968       std::vector<MultiViewChannelName> channels;
969       GetChannelsInMultiPartFile(*data->ifile, channels);
970
971       for (size_t i = 0; i < channels.size(); i++) {
972         IMB_exr_add_channel(
973             data, NULL, channels[i].name.c_str(), channels[i].view.c_str(), 0, 0, NULL, false);
974
975         echan = (ExrChannel *)data->channels.last;
976         echan->m->name = channels[i].name;
977         echan->m->view = channels[i].view;
978         echan->m->part_number = channels[i].part_number;
979         echan->m->internal_name = channels[i].internal_name;
980       }
981
982       return 1;
983     }
984   }
985   return 0;
986 }
987
988 /* still clumsy name handling, layers/channels can be ordered as list in list later */
989 /* passname here is the raw channel name without the layer */
990 void IMB_exr_set_channel(
991     void *handle, const char *layname, const char *passname, int xstride, int ystride, float *rect)
992 {
993   ExrHandle *data = (ExrHandle *)handle;
994   ExrChannel *echan;
995   char name[EXR_TOT_MAXNAME + 1];
996
997   if (layname && layname[0] != '\0') {
998     char lay[EXR_LAY_MAXNAME + 1], pass[EXR_PASS_MAXNAME + 1];
999     BLI_strncpy(lay, layname, EXR_LAY_MAXNAME);
1000     BLI_strncpy(pass, passname, EXR_PASS_MAXNAME);
1001
1002     BLI_snprintf(name, sizeof(name), "%s.%s", lay, pass);
1003   }
1004   else {
1005     BLI_strncpy(name, passname, EXR_TOT_MAXNAME - 1);
1006   }
1007
1008   echan = (ExrChannel *)BLI_findstring(&data->channels, name, offsetof(ExrChannel, name));
1009
1010   if (echan) {
1011     echan->xstride = xstride;
1012     echan->ystride = ystride;
1013     echan->rect = rect;
1014   }
1015   else {
1016     printf("IMB_exr_set_channel error %s\n", name);
1017   }
1018 }
1019
1020 float *IMB_exr_channel_rect(void *handle,
1021                             const char *layname,
1022                             const char *passname,
1023                             const char *viewname)
1024 {
1025   ExrHandle *data = (ExrHandle *)handle;
1026   ExrChannel *echan;
1027   char name[EXR_TOT_MAXNAME + 1];
1028
1029   if (layname) {
1030     char lay[EXR_LAY_MAXNAME + 1], pass[EXR_PASS_MAXNAME + 1];
1031     BLI_strncpy(lay, layname, EXR_LAY_MAXNAME);
1032     BLI_strncpy(pass, passname, EXR_PASS_MAXNAME);
1033
1034     BLI_snprintf(name, sizeof(name), "%s.%s", lay, pass);
1035   }
1036   else
1037     BLI_strncpy(name, passname, EXR_TOT_MAXNAME - 1);
1038
1039   /* name has to be unique, thus it's a combination of layer, pass, view, and channel */
1040   if (layname && layname[0] != '\0') {
1041     char temp_buf[EXR_PASS_MAXNAME];
1042     imb_exr_insert_view_name(temp_buf, name, viewname);
1043     BLI_strncpy(name, temp_buf, sizeof(name));
1044   }
1045   else if (data->multiView->size() >= 1) {
1046     const int view_id = std::max(0, imb_exr_get_multiView_id(*data->multiView, viewname));
1047     std::string raw_name = insertViewName(name, *data->multiView, view_id);
1048     BLI_strncpy(name, raw_name.c_str(), sizeof(name));
1049   }
1050
1051   echan = (ExrChannel *)BLI_findstring(&data->channels, name, offsetof(ExrChannel, name));
1052
1053   if (echan)
1054     return echan->rect;
1055
1056   return NULL;
1057 }
1058
1059 void IMB_exr_clear_channels(void *handle)
1060 {
1061   ExrHandle *data = (ExrHandle *)handle;
1062   ExrChannel *chan;
1063
1064   for (chan = (ExrChannel *)data->channels.first; chan; chan = chan->next)
1065     delete chan->m;
1066
1067   BLI_freelistN(&data->channels);
1068 }
1069
1070 void IMB_exr_write_channels(void *handle)
1071 {
1072   ExrHandle *data = (ExrHandle *)handle;
1073   FrameBuffer frameBuffer;
1074   ExrChannel *echan;
1075
1076   if (data->channels.first) {
1077     const size_t num_pixels = ((size_t)data->width) * data->height;
1078     half *rect_half = NULL, *current_rect_half = NULL;
1079
1080     /* We allocate teporary storage for half pixels for all the channels at once. */
1081     if (data->num_half_channels != 0) {
1082       rect_half = (half *)MEM_mallocN(sizeof(half) * data->num_half_channels * num_pixels,
1083                                       __func__);
1084       current_rect_half = rect_half;
1085     }
1086
1087     for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
1088       /* Writing starts from last scanline, stride negative. */
1089       if (echan->use_half_float) {
1090         float *rect = echan->rect;
1091         half *cur = current_rect_half;
1092         for (size_t i = 0; i < num_pixels; ++i, ++cur) {
1093           *cur = rect[i * echan->xstride];
1094         }
1095         half *rect_to_write = current_rect_half + (data->height - 1L) * data->width;
1096         frameBuffer.insert(
1097             echan->name,
1098             Slice(Imf::HALF, (char *)rect_to_write, sizeof(half), -data->width * sizeof(half)));
1099         current_rect_half += num_pixels;
1100       }
1101       else {
1102         float *rect = echan->rect + echan->xstride * (data->height - 1L) * data->width;
1103         frameBuffer.insert(echan->name,
1104                            Slice(Imf::FLOAT,
1105                                  (char *)rect,
1106                                  echan->xstride * sizeof(float),
1107                                  -echan->ystride * sizeof(float)));
1108       }
1109     }
1110
1111     data->ofile->setFrameBuffer(frameBuffer);
1112     try {
1113       data->ofile->writePixels(data->height);
1114     }
1115     catch (const std::exception &exc) {
1116       std::cerr << "OpenEXR-writePixels: ERROR: " << exc.what() << std::endl;
1117     }
1118     /* Free temporary buffers. */
1119     if (rect_half != NULL) {
1120       MEM_freeN(rect_half);
1121     }
1122   }
1123   else {
1124     printf("Error: attempt to save MultiLayer without layers.\n");
1125   }
1126 }
1127
1128 /* temporary function, used for FSA and Save Buffers */
1129 /* called once per tile * view */
1130 void IMB_exrtile_write_channels(
1131     void *handle, int partx, int party, int level, const char *viewname, bool empty)
1132 {
1133   /* Can write empty channels for incomplete renders. */
1134   ExrHandle *data = (ExrHandle *)handle;
1135   FrameBuffer frameBuffer;
1136   std::string view(viewname);
1137   const int view_id = imb_exr_get_multiView_id(*data->multiView, view);
1138
1139   exr_printf("\nIMB_exrtile_write_channels(view: %s)\n", viewname);
1140   exr_printf("%s %-6s %-22s \"%s\"\n", "p", "view", "name", "internal_name");
1141   exr_printf("---------------------------------------------------------------------\n");
1142
1143   if (!empty) {
1144     ExrChannel *echan;
1145
1146     for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
1147
1148       /* eventually we can make the parts' channels to include
1149        * only the current view TODO */
1150       if (strcmp(viewname, echan->m->view.c_str()) != 0)
1151         continue;
1152
1153       exr_printf("%d %-6s %-22s \"%s\"\n",
1154                  echan->m->part_number,
1155                  echan->m->view.c_str(),
1156                  echan->m->name.c_str(),
1157                  echan->m->internal_name.c_str());
1158
1159       float *rect = echan->rect - echan->xstride * partx - echan->ystride * party;
1160       frameBuffer.insert(echan->m->internal_name,
1161                          Slice(Imf::FLOAT,
1162                                (char *)rect,
1163                                echan->xstride * sizeof(float),
1164                                echan->ystride * sizeof(float)));
1165     }
1166   }
1167
1168   TiledOutputPart out(*data->mpofile, view_id);
1169   out.setFrameBuffer(frameBuffer);
1170
1171   try {
1172     // printf("write tile %d %d\n", partx/data->tilex, party/data->tiley);
1173     out.writeTile(partx / data->tilex, party / data->tiley, level);
1174   }
1175   catch (const std::exception &exc) {
1176     std::cerr << "OpenEXR-writeTile: ERROR: " << exc.what() << std::endl;
1177   }
1178 }
1179
1180 void IMB_exr_read_channels(void *handle)
1181 {
1182   ExrHandle *data = (ExrHandle *)handle;
1183   int numparts = data->ifile->parts();
1184
1185   /* check if exr was saved with previous versions of blender which flipped images */
1186   const StringAttribute *ta = data->ifile->header(0).findTypedAttribute<StringAttribute>(
1187       "BlenderMultiChannel");
1188   short flip = (ta && STREQLEN(ta->value().c_str(),
1189                                "Blender V2.43",
1190                                13)); /* 'previous multilayer attribute, flipped */
1191
1192   exr_printf(
1193       "\nIMB_exr_read_channels\n%s %-6s %-22s "
1194       "\"%s\"\n---------------------------------------------------------------------\n",
1195       "p",
1196       "view",
1197       "name",
1198       "internal_name");
1199
1200   for (int i = 0; i < numparts; i++) {
1201     /* Read part header. */
1202     InputPart in(*data->ifile, i);
1203     Header header = in.header();
1204     Box2i dw = header.dataWindow();
1205
1206     /* Insert all matching channel into framebuffer. */
1207     FrameBuffer frameBuffer;
1208     ExrChannel *echan;
1209
1210     for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
1211       if (echan->m->part_number != i) {
1212         continue;
1213       }
1214
1215       exr_printf("%d %-6s %-22s \"%s\"\n",
1216                  echan->m->part_number,
1217                  echan->m->view.c_str(),
1218                  echan->m->name.c_str(),
1219                  echan->m->internal_name.c_str());
1220
1221       if (echan->rect) {
1222         float *rect = echan->rect;
1223         size_t xstride = echan->xstride * sizeof(float);
1224         size_t ystride = echan->ystride * sizeof(float);
1225
1226         if (!flip) {
1227           /* inverse correct first pixel for datawindow coordinates */
1228           rect -= echan->xstride * (dw.min.x - dw.min.y * data->width);
1229           /* move to last scanline to flip to Blender convention */
1230           rect += echan->xstride * (data->height - 1) * data->width;
1231           ystride = -ystride;
1232         }
1233         else {
1234           /* inverse correct first pixel for datawindow coordinates */
1235           rect -= echan->xstride * (dw.min.x + dw.min.y * data->width);
1236         }
1237
1238         frameBuffer.insert(echan->m->internal_name,
1239                            Slice(Imf::FLOAT, (char *)rect, xstride, ystride));
1240       }
1241       else
1242         printf("warning, channel with no rect set %s\n", echan->m->internal_name.c_str());
1243     }
1244
1245     /* Read pixels. */
1246     try {
1247       in.setFrameBuffer(frameBuffer);
1248       exr_printf("readPixels:readPixels[%d]: min.y: %d, max.y: %d\n", i, dw.min.y, dw.max.y);
1249       in.readPixels(dw.min.y, dw.max.y);
1250     }
1251     catch (const std::exception &exc) {
1252       std::cerr << "OpenEXR-readPixels: ERROR: " << exc.what() << std::endl;
1253       break;
1254     }
1255   }
1256 }
1257
1258 void IMB_exr_multilayer_convert(void *handle,
1259                                 void *base,
1260                                 void *(*addview)(void *base, const char *str),
1261                                 void *(*addlayer)(void *base, const char *str),
1262                                 void (*addpass)(void *base,
1263                                                 void *lay,
1264                                                 const char *str,
1265                                                 float *rect,
1266                                                 int totchan,
1267                                                 const char *chan_id,
1268                                                 const char *view))
1269 {
1270   ExrHandle *data = (ExrHandle *)handle;
1271   ExrLayer *lay;
1272   ExrPass *pass;
1273
1274   /* RenderResult needs at least one RenderView */
1275   if (data->multiView->size() == 0) {
1276     addview(base, "");
1277   }
1278   else {
1279     /* add views to RenderResult */
1280     for (StringVector::const_iterator i = data->multiView->begin(); i != data->multiView->end();
1281          ++i) {
1282       addview(base, (*i).c_str());
1283     }
1284   }
1285
1286   if (BLI_listbase_is_empty(&data->layers)) {
1287     printf("cannot convert multilayer, no layers in handle\n");
1288     return;
1289   }
1290
1291   for (lay = (ExrLayer *)data->layers.first; lay; lay = lay->next) {
1292     void *laybase = addlayer(base, lay->name);
1293     if (laybase) {
1294       for (pass = (ExrPass *)lay->passes.first; pass; pass = pass->next) {
1295         addpass(base,
1296                 laybase,
1297                 pass->internal_name,
1298                 pass->rect,
1299                 pass->totchan,
1300                 pass->chan_id,
1301                 pass->view);
1302         pass->rect = NULL;
1303       }
1304     }
1305   }
1306 }
1307
1308 void IMB_exr_close(void *handle)
1309 {
1310   ExrHandle *data = (ExrHandle *)handle;
1311   ExrLayer *lay;
1312   ExrPass *pass;
1313   ExrChannel *chan;
1314
1315   delete data->ifile;
1316   delete data->ifile_stream;
1317   delete data->ofile;
1318   delete data->mpofile;
1319   delete data->ofile_stream;
1320   delete data->multiView;
1321
1322   data->ifile = NULL;
1323   data->ifile_stream = NULL;
1324   data->ofile = NULL;
1325   data->mpofile = NULL;
1326   data->ofile_stream = NULL;
1327
1328   for (chan = (ExrChannel *)data->channels.first; chan; chan = chan->next) {
1329     delete chan->m;
1330   }
1331   BLI_freelistN(&data->channels);
1332
1333   for (lay = (ExrLayer *)data->layers.first; lay; lay = lay->next) {
1334     for (pass = (ExrPass *)lay->passes.first; pass; pass = pass->next)
1335       if (pass->rect)
1336         MEM_freeN(pass->rect);
1337     BLI_freelistN(&lay->passes);
1338   }
1339   BLI_freelistN(&data->layers);
1340
1341   BLI_remlink(&exrhandles, data);
1342   MEM_freeN(data);
1343 }
1344
1345 /* ********* */
1346
1347 /* get a substring from the end of the name, separated by '.' */
1348 static int imb_exr_split_token(const char *str, const char *end, const char **token)
1349 {
1350   const char delims[] = {'.', '\0'};
1351   const char *sep;
1352
1353   BLI_str_partition_ex(str, end, delims, &sep, token, true);
1354
1355   if (!sep) {
1356     *token = str;
1357   }
1358
1359   return (int)(end - *token);
1360 }
1361
1362 static int imb_exr_split_channel_name(ExrChannel *echan, char *layname, char *passname)
1363 {
1364   const char *name = echan->m->name.c_str();
1365   const char *end = name + strlen(name);
1366   const char *token;
1367   char tokenbuf[EXR_TOT_MAXNAME];
1368   int len;
1369
1370   /* some multilayers have the combined buffer with names A B G R saved */
1371   if (name[1] == 0) {
1372     echan->chan_id = name[0];
1373     layname[0] = '\0';
1374
1375     if (ELEM(name[0], 'R', 'G', 'B', 'A'))
1376       strcpy(passname, "Combined");
1377     else if (name[0] == 'Z')
1378       strcpy(passname, "Depth");
1379     else
1380       strcpy(passname, name);
1381
1382     return 1;
1383   }
1384
1385   /* last token is channel identifier */
1386   len = imb_exr_split_token(name, end, &token);
1387   if (len == 0) {
1388     printf("multilayer read: bad channel name: %s\n", name);
1389     return 0;
1390   }
1391   else if (len == 1) {
1392     echan->chan_id = token[0];
1393   }
1394   else if (len > 1) {
1395     bool ok = false;
1396
1397     if (len == 2) {
1398       /* some multilayers are using two-letter channels name,
1399        * like, MX or NZ, which is basically has structure of
1400        *   <pass_prefix><component>
1401        *
1402        * This is a bit silly, but see file from [#35658].
1403        *
1404        * Here we do some magic to distinguish such cases.
1405        */
1406       if (ELEM(token[1], 'X', 'Y', 'Z') || ELEM(token[1], 'R', 'G', 'B') ||
1407           ELEM(token[1], 'U', 'V', 'A')) {
1408         echan->chan_id = token[1];
1409         ok = true;
1410       }
1411     }
1412     else if (BLI_strcaseeq(token, "red")) {
1413       echan->chan_id = 'R';
1414       ok = true;
1415     }
1416     else if (BLI_strcaseeq(token, "green")) {
1417       echan->chan_id = 'G';
1418       ok = true;
1419     }
1420     else if (BLI_strcaseeq(token, "blue")) {
1421       echan->chan_id = 'B';
1422       ok = true;
1423     }
1424     else if (BLI_strcaseeq(token, "alpha")) {
1425       echan->chan_id = 'A';
1426       ok = true;
1427     }
1428     else if (BLI_strcaseeq(token, "depth")) {
1429       echan->chan_id = 'Z';
1430       ok = true;
1431     }
1432
1433     if (ok == false) {
1434       BLI_strncpy(tokenbuf, token, std::min(len + 1, EXR_TOT_MAXNAME));
1435       printf("multilayer read: unknown channel token: %s\n", tokenbuf);
1436       return 0;
1437     }
1438   }
1439   end -= len + 1; /* +1 to skip '.' separator */
1440
1441   /* second token is pass name */
1442   len = imb_exr_split_token(name, end, &token);
1443   if (len == 0) {
1444     printf("multilayer read: bad channel name: %s\n", name);
1445     return 0;
1446   }
1447   BLI_strncpy(passname, token, len + 1);
1448   end -= len + 1; /* +1 to skip '.' separator */
1449
1450   /* all preceding tokens combined as layer name */
1451   if (end > name)
1452     BLI_strncpy(layname, name, (int)(end - name) + 1);
1453   else
1454     layname[0] = '\0';
1455
1456   return 1;
1457 }
1458
1459 static ExrLayer *imb_exr_get_layer(ListBase *lb, char *layname)
1460 {
1461   ExrLayer *lay = (ExrLayer *)BLI_findstring(lb, layname, offsetof(ExrLayer, name));
1462
1463   if (lay == NULL) {
1464     lay = (ExrLayer *)MEM_callocN(sizeof(ExrLayer), "exr layer");
1465     BLI_addtail(lb, lay);
1466     BLI_strncpy(lay->name, layname, EXR_LAY_MAXNAME);
1467   }
1468
1469   return lay;
1470 }
1471
1472 static ExrPass *imb_exr_get_pass(ListBase *lb, char *passname)
1473 {
1474   ExrPass *pass = (ExrPass *)BLI_findstring(lb, passname, offsetof(ExrPass, name));
1475
1476   if (pass == NULL) {
1477     pass = (ExrPass *)MEM_callocN(sizeof(ExrPass), "exr pass");
1478
1479     if (STREQ(passname, "Combined"))
1480       BLI_addhead(lb, pass);
1481     else
1482       BLI_addtail(lb, pass);
1483   }
1484
1485   BLI_strncpy(pass->name, passname, EXR_LAY_MAXNAME);
1486
1487   return pass;
1488 }
1489
1490 /* creates channels, makes a hierarchy and assigns memory to channels */
1491 static ExrHandle *imb_exr_begin_read_mem(IStream &file_stream,
1492                                          MultiPartInputFile &file,
1493                                          int width,
1494                                          int height)
1495 {
1496   ExrLayer *lay;
1497   ExrPass *pass;
1498   ExrChannel *echan;
1499   ExrHandle *data = (ExrHandle *)IMB_exr_get_handle();
1500   int a;
1501   char layname[EXR_TOT_MAXNAME], passname[EXR_TOT_MAXNAME];
1502
1503   data->ifile_stream = &file_stream;
1504   data->ifile = &file;
1505
1506   data->width = width;
1507   data->height = height;
1508
1509   std::vector<MultiViewChannelName> channels;
1510   GetChannelsInMultiPartFile(*data->ifile, channels);
1511
1512   imb_exr_get_views(*data->ifile, *data->multiView);
1513
1514   for (size_t i = 0; i < channels.size(); i++) {
1515     IMB_exr_add_channel(
1516         data, NULL, channels[i].name.c_str(), channels[i].view.c_str(), 0, 0, NULL, false);
1517
1518     echan = (ExrChannel *)data->channels.last;
1519     echan->m->name = channels[i].name;
1520     echan->m->view = channels[i].view;
1521     echan->m->part_number = channels[i].part_number;
1522     echan->m->internal_name = channels[i].internal_name;
1523   }
1524
1525   /* now try to sort out how to assign memory to the channels */
1526   /* first build hierarchical layer list */
1527   for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
1528     if (imb_exr_split_channel_name(echan, layname, passname)) {
1529
1530       const char *view = echan->m->view.c_str();
1531       char internal_name[EXR_PASS_MAXNAME];
1532
1533       BLI_strncpy(internal_name, passname, EXR_PASS_MAXNAME);
1534
1535       if (view[0] != '\0') {
1536         char tmp_pass[EXR_PASS_MAXNAME];
1537         BLI_snprintf(tmp_pass, sizeof(tmp_pass), "%s.%s", passname, view);
1538         BLI_strncpy(passname, tmp_pass, sizeof(passname));
1539       }
1540
1541       ExrLayer *lay = imb_exr_get_layer(&data->layers, layname);
1542       ExrPass *pass = imb_exr_get_pass(&lay->passes, passname);
1543
1544       pass->chan[pass->totchan] = echan;
1545       pass->totchan++;
1546       pass->view_id = echan->view_id;
1547       BLI_strncpy(pass->view, view, sizeof(pass->view));
1548       BLI_strncpy(pass->internal_name, internal_name, EXR_PASS_MAXNAME);
1549
1550       if (pass->totchan >= EXR_PASS_MAXCHAN)
1551         break;
1552     }
1553   }
1554   if (echan) {
1555     printf("error, too many channels in one pass: %s\n", echan->m->name.c_str());
1556     IMB_exr_close(data);
1557     return NULL;
1558   }
1559
1560   /* with some heuristics, try to merge the channels in buffers */
1561   for (lay = (ExrLayer *)data->layers.first; lay; lay = lay->next) {
1562     for (pass = (ExrPass *)lay->passes.first; pass; pass = pass->next) {
1563       if (pass->totchan) {
1564         pass->rect = (float *)MEM_mapallocN(width * height * pass->totchan * sizeof(float),
1565                                             "pass rect");
1566         if (pass->totchan == 1) {
1567           echan = pass->chan[0];
1568           echan->rect = pass->rect;
1569           echan->xstride = 1;
1570           echan->ystride = width;
1571           pass->chan_id[0] = echan->chan_id;
1572         }
1573         else {
1574           char lookup[256];
1575
1576           memset(lookup, 0, sizeof(lookup));
1577
1578           /* we can have RGB(A), XYZ(W), UVA */
1579           if (pass->totchan == 3 || pass->totchan == 4) {
1580             if (pass->chan[0]->chan_id == 'B' || pass->chan[1]->chan_id == 'B' ||
1581                 pass->chan[2]->chan_id == 'B') {
1582               lookup[(unsigned int)'R'] = 0;
1583               lookup[(unsigned int)'G'] = 1;
1584               lookup[(unsigned int)'B'] = 2;
1585               lookup[(unsigned int)'A'] = 3;
1586             }
1587             else if (pass->chan[0]->chan_id == 'Y' || pass->chan[1]->chan_id == 'Y' ||
1588                      pass->chan[2]->chan_id == 'Y') {
1589               lookup[(unsigned int)'X'] = 0;
1590               lookup[(unsigned int)'Y'] = 1;
1591               lookup[(unsigned int)'Z'] = 2;
1592               lookup[(unsigned int)'W'] = 3;
1593             }
1594             else {
1595               lookup[(unsigned int)'U'] = 0;
1596               lookup[(unsigned int)'V'] = 1;
1597               lookup[(unsigned int)'A'] = 2;
1598             }
1599             for (a = 0; a < pass->totchan; a++) {
1600               echan = pass->chan[a];
1601               echan->rect = pass->rect + lookup[(unsigned int)echan->chan_id];
1602               echan->xstride = pass->totchan;
1603               echan->ystride = width * pass->totchan;
1604               pass->chan_id[(unsigned int)lookup[(unsigned int)echan->chan_id]] = echan->chan_id;
1605             }
1606           }
1607           else { /* unknown */
1608             for (a = 0; a < pass->totchan; a++) {
1609               echan = pass->chan[a];
1610               echan->rect = pass->rect + a;
1611               echan->xstride = pass->totchan;
1612               echan->ystride = width * pass->totchan;
1613               pass->chan_id[a] = echan->chan_id;
1614             }
1615           }
1616         }
1617       }
1618     }
1619   }
1620
1621   return data;
1622 }
1623
1624 /* ********************************************************* */
1625
1626 /* debug only */
1627 static void exr_printf(const char *fmt, ...)
1628 {
1629 #if 0
1630   char output[1024];
1631   va_list args;
1632   va_start(args, fmt);
1633   std::vsprintf(output, fmt, args);
1634   va_end(args);
1635   printf("%s", output);
1636 #else
1637   (void)fmt;
1638 #endif
1639 }
1640
1641 static void exr_print_filecontents(MultiPartInputFile &file)
1642 {
1643   int numparts = file.parts();
1644   if (numparts == 1 && hasMultiView(file.header(0))) {
1645     const StringVector views = multiView(file.header(0));
1646     printf("OpenEXR-load: MultiView file\n");
1647     printf("OpenEXR-load: Default view: %s\n", defaultViewName(views).c_str());
1648     for (StringVector::const_iterator i = views.begin(); i != views.end(); ++i) {
1649       printf("OpenEXR-load: Found view %s\n", (*i).c_str());
1650     }
1651   }
1652   else if (numparts > 1) {
1653     printf("OpenEXR-load: MultiPart file\n");
1654     for (int i = 0; i < numparts; i++) {
1655       if (file.header(i).hasView())
1656         printf("OpenEXR-load: Part %d: view = \"%s\"\n", i, file.header(i).view().c_str());
1657     }
1658   }
1659
1660   for (int j = 0; j < numparts; j++) {
1661     const ChannelList &channels = file.header(j).channels();
1662     for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i) {
1663       const Channel &channel = i.channel();
1664       printf("OpenEXR-load: Found channel %s of type %d\n", i.name(), channel.type);
1665     }
1666   }
1667 }
1668
1669 /* for non-multilayer, map  R G B A channel names to something that's in this file */
1670 static const char *exr_rgba_channelname(MultiPartInputFile &file, const char *chan)
1671 {
1672   const ChannelList &channels = file.header(0).channels();
1673
1674   for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i) {
1675     /* const Channel &channel = i.channel(); */ /* Not used yet */
1676     const char *str = i.name();
1677     int len = strlen(str);
1678     if (len) {
1679       if (BLI_strcasecmp(chan, str + len - 1) == 0) {
1680         return str;
1681       }
1682     }
1683   }
1684   return chan;
1685 }
1686
1687 static bool exr_has_rgb(MultiPartInputFile &file)
1688 {
1689   return file.header(0).channels().findChannel("R") != NULL &&
1690          file.header(0).channels().findChannel("G") != NULL &&
1691          file.header(0).channels().findChannel("B") != NULL;
1692 }
1693
1694 static bool exr_has_luma(MultiPartInputFile &file)
1695 {
1696   /* Y channel is the luma and should always present fir luma space images,
1697    * optionally it could be also channels for chromas called BY and RY.
1698    */
1699   return file.header(0).channels().findChannel("Y") != NULL;
1700 }
1701
1702 static bool exr_has_chroma(MultiPartInputFile &file)
1703 {
1704   return file.header(0).channels().findChannel("BY") != NULL &&
1705          file.header(0).channels().findChannel("RY") != NULL;
1706 }
1707
1708 static bool exr_has_zbuffer(MultiPartInputFile &file)
1709 {
1710   return !(file.header(0).channels().findChannel("Z") == NULL);
1711 }
1712
1713 static bool exr_has_alpha(MultiPartInputFile &file)
1714 {
1715   return !(file.header(0).channels().findChannel("A") == NULL);
1716 }
1717
1718 static bool imb_exr_is_multilayer_file(MultiPartInputFile &file)
1719 {
1720   const ChannelList &channels = file.header(0).channels();
1721   std::set<std::string> layerNames;
1722
1723   /* will not include empty layer names */
1724   channels.layers(layerNames);
1725
1726   if (layerNames.size() > 1)
1727     return true;
1728
1729   if (layerNames.size()) {
1730     /* if layerNames is not empty, it means at least one layer is non-empty,
1731      * but it also could be layers without names in the file and such case
1732      * shall be considered a multilayer exr
1733      *
1734      * that's what we do here: test whether there're empty layer names together
1735      * with non-empty ones in the file
1736      */
1737     for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); i++) {
1738       std::string layerName = i.name();
1739       size_t pos = layerName.rfind('.');
1740
1741       if (pos == std::string::npos)
1742         return true;
1743     }
1744   }
1745
1746   return false;
1747 }
1748
1749 static void imb_exr_type_by_channels(ChannelList &channels,
1750                                      StringVector &views,
1751                                      bool *r_singlelayer,
1752                                      bool *r_multilayer,
1753                                      bool *r_multiview)
1754 {
1755   std::set<std::string> layerNames;
1756
1757   *r_singlelayer = true;
1758   *r_multilayer = *r_multiview = false;
1759
1760   /* will not include empty layer names */
1761   channels.layers(layerNames);
1762
1763   if (views.size() && views[0] != "") {
1764     *r_multiview = true;
1765   }
1766   else {
1767     *r_singlelayer = false;
1768     *r_multilayer = (layerNames.size() > 1);
1769     *r_multiview = false;
1770     return;
1771   }
1772
1773   if (layerNames.size()) {
1774     /* if layerNames is not empty, it means at least one layer is non-empty,
1775      * but it also could be layers without names in the file and such case
1776      * shall be considered a multilayer exr
1777      *
1778      * that's what we do here: test whether there're empty layer names together
1779      * with non-empty ones in the file
1780      */
1781     for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); i++)
1782       for (std::set<string>::iterator i = layerNames.begin(); i != layerNames.end(); i++)
1783         /* see if any layername differs from a viewname */
1784         if (imb_exr_get_multiView_id(views, *i) == -1) {
1785           std::string layerName = *i;
1786           size_t pos = layerName.rfind('.');
1787
1788           if (pos == std::string::npos) {
1789             *r_multilayer = true;
1790             *r_singlelayer = false;
1791             return;
1792           }
1793         }
1794   }
1795   else {
1796     *r_singlelayer = true;
1797     *r_multilayer = false;
1798   }
1799
1800   BLI_assert(r_singlelayer != r_multilayer);
1801 }
1802
1803 static bool exr_has_multiview(MultiPartInputFile &file)
1804 {
1805   for (int p = 0; p < file.parts(); p++) {
1806     if (hasMultiView(file.header(p))) {
1807       return true;
1808     }
1809   }
1810
1811   return false;
1812 }
1813
1814 static bool exr_has_multipart_file(MultiPartInputFile &file)
1815 {
1816   return file.parts() > 1;
1817 }
1818
1819 /* it returns true if the file is multilayer or multiview */
1820 static bool imb_exr_is_multi(MultiPartInputFile &file)
1821 {
1822   /* Multipart files are treated as multilayer in blender -
1823    * even if they are single layer openexr with multiview. */
1824   if (exr_has_multipart_file(file))
1825     return true;
1826
1827   if (exr_has_multiview(file))
1828     return true;
1829
1830   if (imb_exr_is_multilayer_file(file))
1831     return true;
1832
1833   return false;
1834 }
1835
1836 bool IMB_exr_has_multilayer(void *handle)
1837 {
1838   ExrHandle *data = (ExrHandle *)handle;
1839   return imb_exr_is_multi(*data->ifile);
1840 }
1841
1842 struct ImBuf *imb_load_openexr(const unsigned char *mem,
1843                                size_t size,
1844                                int flags,
1845                                char colorspace[IM_MAX_SPACE])
1846 {
1847   struct ImBuf *ibuf = NULL;
1848   IMemStream *membuf = NULL;
1849   MultiPartInputFile *file = NULL;
1850
1851   if (imb_is_a_openexr(mem) == 0)
1852     return (NULL);
1853
1854   colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_FLOAT);
1855
1856   try {
1857     bool is_multi;
1858
1859     membuf = new IMemStream((unsigned char *)mem, size);
1860     file = new MultiPartInputFile(*membuf);
1861
1862     Box2i dw = file->header(0).dataWindow();
1863     const int width = dw.max.x - dw.min.x + 1;
1864     const int height = dw.max.y - dw.min.y + 1;
1865
1866     //printf("OpenEXR-load: image data window %d %d %d %d\n",
1867     //     dw.min.x, dw.min.y, dw.max.x, dw.max.y);
1868
1869     if (0)  // debug
1870       exr_print_filecontents(*file);
1871
1872     is_multi = imb_exr_is_multi(*file);
1873
1874     /* do not make an ibuf when */
1875     if (is_multi && !(flags & IB_test) && !(flags & IB_multilayer)) {
1876       printf("Error: can't process EXR multilayer file\n");
1877     }
1878     else {
1879       const int is_alpha = exr_has_alpha(*file);
1880
1881       ibuf = IMB_allocImBuf(width, height, is_alpha ? 32 : 24, 0);
1882
1883       if (hasXDensity(file->header(0))) {
1884         ibuf->ppm[0] = xDensity(file->header(0)) * 39.3700787f;
1885         ibuf->ppm[1] = ibuf->ppm[0] * (double)file->header(0).pixelAspectRatio();
1886       }
1887
1888       ibuf->ftype = IMB_FTYPE_OPENEXR;
1889
1890       if (!(flags & IB_test)) {
1891
1892         if (flags & IB_metadata) {
1893           const Header &header = file->header(0);
1894           Header::ConstIterator iter;
1895
1896           IMB_metadata_ensure(&ibuf->metadata);
1897           for (iter = header.begin(); iter != header.end(); iter++) {
1898             const StringAttribute *attrib = file->header(0).findTypedAttribute<StringAttribute>(
1899                 iter.name());
1900
1901             /* not all attributes are string attributes so we might get some NULLs here */
1902             if (attrib) {
1903               IMB_metadata_set_field(ibuf->metadata, iter.name(), attrib->value().c_str());
1904               ibuf->flags |= IB_metadata;
1905             }
1906           }
1907         }
1908
1909         if (is_multi &&
1910             ((flags & IB_thumbnail) == 0)) { /* only enters with IB_multilayer flag set */
1911           /* constructs channels for reading, allocates memory in channels */
1912           ExrHandle *handle = imb_exr_begin_read_mem(*membuf, *file, width, height);
1913           if (handle) {
1914             IMB_exr_read_channels(handle);
1915             ibuf->userdata = handle; /* potential danger, the caller has to check for this! */
1916           }
1917         }
1918         else {
1919           const bool has_rgb = exr_has_rgb(*file);
1920           const bool has_luma = exr_has_luma(*file);
1921           FrameBuffer frameBuffer;
1922           float *first;
1923           int xstride = sizeof(float) * 4;
1924           int ystride = -xstride * width;
1925
1926           imb_addrectfloatImBuf(ibuf);
1927
1928           /* Inverse correct first pixel for datawindow
1929            * coordinates (- dw.min.y because of y flip). */
1930           first = ibuf->rect_float - 4 * (dw.min.x - dw.min.y * width);
1931           /* but, since we read y-flipped (negative y stride) we move to last scanline */
1932           first += 4 * (height - 1) * width;
1933
1934           if (has_rgb) {
1935             frameBuffer.insert(exr_rgba_channelname(*file, "R"),
1936                                Slice(Imf::FLOAT, (char *)first, xstride, ystride));
1937             frameBuffer.insert(exr_rgba_channelname(*file, "G"),
1938                                Slice(Imf::FLOAT, (char *)(first + 1), xstride, ystride));
1939             frameBuffer.insert(exr_rgba_channelname(*file, "B"),
1940                                Slice(Imf::FLOAT, (char *)(first + 2), xstride, ystride));
1941           }
1942           else if (has_luma) {
1943             frameBuffer.insert(exr_rgba_channelname(*file, "Y"),
1944                                Slice(Imf::FLOAT, (char *)first, xstride, ystride));
1945             frameBuffer.insert(
1946                 exr_rgba_channelname(*file, "BY"),
1947                 Slice(Imf::FLOAT, (char *)(first + 1), xstride, ystride, 1, 1, 0.5f));
1948             frameBuffer.insert(
1949                 exr_rgba_channelname(*file, "RY"),
1950                 Slice(Imf::FLOAT, (char *)(first + 2), xstride, ystride, 1, 1, 0.5f));
1951           }
1952
1953           /* 1.0 is fill value, this still needs to be assigned even when (is_alpha == 0) */
1954           frameBuffer.insert(exr_rgba_channelname(*file, "A"),
1955                              Slice(Imf::FLOAT, (char *)(first + 3), xstride, ystride, 1, 1, 1.0f));
1956
1957           if (exr_has_zbuffer(*file)) {
1958             float *firstz;
1959
1960             addzbuffloatImBuf(ibuf);
1961             firstz = ibuf->zbuf_float - (dw.min.x - dw.min.y * width);
1962             firstz += (height - 1) * width;
1963             frameBuffer.insert(
1964                 "Z", Slice(Imf::FLOAT, (char *)firstz, sizeof(float), -width * sizeof(float)));
1965           }
1966
1967           InputPart in(*file, 0);
1968           in.setFrameBuffer(frameBuffer);
1969           in.readPixels(dw.min.y, dw.max.y);
1970
1971           // XXX, ImBuf has no nice way to deal with this.
1972           // ideally IM_rect would be used when the caller wants a rect BUT
1973           // at the moment all functions use IM_rect.
1974           // Disabling this is ok because all functions should check
1975           // if a rect exists and create one on demand.
1976           //
1977           // Disabling this because the sequencer frees immediate.
1978           //
1979           // if (flag & IM_rect)
1980           //     IMB_rect_from_float(ibuf);
1981
1982           if (!has_rgb && has_luma) {
1983             size_t a;
1984             if (exr_has_chroma(*file)) {
1985               for (a = 0; a < (size_t)ibuf->x * ibuf->y; ++a) {
1986                 float *color = ibuf->rect_float + a * 4;
1987                 ycc_to_rgb(color[0] * 255.0f,
1988                            color[1] * 255.0f,
1989                            color[2] * 255.0f,
1990                            &color[0],
1991                            &color[1],
1992                            &color[2],
1993                            BLI_YCC_ITU_BT709);
1994               }
1995             }
1996             else {
1997               for (a = 0; a < (size_t)ibuf->x * ibuf->y; ++a) {
1998                 float *color = ibuf->rect_float + a * 4;
1999                 color[1] = color[2] = color[0];
2000               }
2001             }
2002           }
2003
2004           /* file is no longer needed */
2005           delete membuf;
2006           delete file;
2007         }
2008       }
2009       else {
2010         delete membuf;
2011         delete file;
2012       }
2013
2014       if (flags & IB_alphamode_detect)
2015         ibuf->flags |= IB_alphamode_premul;
2016     }
2017     return (ibuf);
2018   }
2019   catch (const std::exception &exc) {
2020     std::cerr << exc.what() << std::endl;
2021     if (ibuf)
2022       IMB_freeImBuf(ibuf);
2023     delete file;
2024     delete membuf;
2025
2026     return (0);
2027   }
2028 }
2029
2030 void imb_initopenexr(void)
2031 {
2032   int num_threads = BLI_system_thread_count();
2033
2034   setGlobalThreadCount(num_threads);
2035 }
2036
2037 void imb_exitopenexr(void)
2038 {
2039   /* Tells OpenEXR to free thread pool, also ensures there is no running
2040    * tasks.
2041    */
2042   setGlobalThreadCount(0);
2043 }
2044
2045 }  // export "C"