style cleanup: braces/indentation
[blender-staging.git] / source / blender / imbuf / intern / openexr / openexr_api.cpp
1 /*
2  * ***** BEGIN GPLLICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * Copyright by Gernot Ziegler <gz@lysator.liu.se>.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): Austin Benesh, Ton Roosendaal (float, half, speedup, cleanup...).
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/imbuf/intern/openexr/openexr_api.cpp
29  *  \ingroup openexr
30  */
31
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <stddef.h>
35 #include <fstream>
36 #include <string>
37 #include <set>
38 #include <errno.h>
39
40 #include <openexr_api.h>
41
42 #if defined (WIN32) && !defined(FREE_WINDOWS)
43 #include "utfconv.h"
44 #endif
45
46 extern "C"
47 {
48
49 // The following prevents a linking error in debug mode for MSVC using the libs in CVS
50 #if defined(WITH_OPENEXR) && defined(_WIN32) && defined(_DEBUG) && !defined(__MINGW32__) && !defined(__CYGWIN__)
51 _CRTIMP void __cdecl _invalid_parameter_noinfo(void)
52 {
53 }
54 #endif
55
56 #include "MEM_guardedalloc.h"
57
58 #include "BLI_blenlib.h"
59 #include "BLI_math_color.h"
60 #include "BLI_threads.h"
61
62 #include "IMB_imbuf_types.h"
63 #include "IMB_imbuf.h"
64 #include "IMB_allocimbuf.h"
65 #include "IMB_metadata.h"
66
67 #include "IMB_colormanagement.h"
68 #include "IMB_colormanagement_intern.h"
69
70 #include "openexr_multi.h"
71 }
72
73 #include <iostream>
74
75 #include <half.h>
76 #include <Iex.h>
77 #include <ImfVersion.h>
78 #include <ImathBox.h>
79 #include <ImfArray.h>
80 #include <ImfIO.h>
81 #include <ImfChannelList.h>
82 #include <ImfPixelType.h>
83 #include <ImfInputFile.h>
84 #include <ImfOutputFile.h>
85 #include <ImfCompression.h>
86 #include <ImfCompressionAttribute.h>
87 #include <ImfStringAttribute.h>
88 #include <ImfStandardAttributes.h>
89
90 using namespace Imf;
91 using namespace Imath;
92
93 /* Memory Input Stream */
94
95 class Mem_IStream : public Imf::IStream
96 {
97 public:
98
99         Mem_IStream (unsigned char *exrbuf, size_t exrsize) :
100                 IStream("dummy"), _exrpos(0), _exrsize(exrsize)
101         {
102                 _exrbuf = exrbuf;
103         }
104
105         virtual bool    read(char c[], int n);
106         virtual Int64   tellg();
107         virtual void    seekg(Int64 pos);
108         virtual void    clear();
109         //virtual ~Mem_IStream() {}; // unused
110
111 private:
112
113         Int64 _exrpos;
114         Int64 _exrsize;
115         unsigned char *_exrbuf;
116 };
117
118 bool Mem_IStream::read(char c[], int n)
119 {
120         if (n + _exrpos <= _exrsize) {
121                 memcpy(c, (void *)(&_exrbuf[_exrpos]), n);
122                 _exrpos += n;
123                 return true;
124         }
125         else
126                 return false;
127 }
128
129 Int64 Mem_IStream::tellg()
130 {
131         return _exrpos;
132 }
133
134 void Mem_IStream::seekg(Int64 pos)
135 {
136         _exrpos = pos;
137 }
138
139 void Mem_IStream::clear()
140 {
141 }
142
143 /* File Input Stream */
144
145 class IFileStream : public Imf::IStream
146 {
147 public:
148         IFileStream(const char *filename)
149         : IStream(filename)
150         {
151                 /* utf-8 file path support on windows */
152 #if defined (WIN32) && !defined(FREE_WINDOWS)
153                 wchar_t *wfilename = alloc_utf16_from_8(filename, 0);
154                 ifs.open(wfilename, std::ios_base::binary);
155                 free(wfilename);
156 #else
157                 ifs.open(filename, std::ios_base::binary);
158 #endif
159
160                 if (!ifs)
161                         Iex::throwErrnoExc();
162         }
163
164         virtual bool read(char c[], int n)
165         {
166                 if (!ifs)
167                         throw Iex::InputExc("Unexpected end of file.");
168
169                 errno = 0;
170                 ifs.read(c, n);
171                 return check_error();
172         }
173
174         virtual Int64 tellg()
175         {
176                 return std::streamoff(ifs.tellg());
177         }
178
179         virtual void seekg(Int64 pos)
180         {
181                 ifs.seekg(pos);
182                 check_error();
183         }
184
185         virtual void clear()
186         {
187                 ifs.clear();
188         }
189
190 private:
191         bool check_error()
192         {
193                 if (!ifs) {
194                         if (errno)
195                                 Iex::throwErrnoExc();
196
197                         return false;
198                 }
199
200                 return true;
201         }
202
203         std::ifstream ifs;
204 };
205
206 /* File Output Stream */
207
208 class OFileStream : public OStream
209 {
210 public:
211         OFileStream(const char *filename)
212         : OStream(filename)
213         {
214                 /* utf-8 file path support on windows */
215 #if defined (WIN32) && !defined(FREE_WINDOWS)
216                 wchar_t *wfilename = alloc_utf16_from_8(filename, 0);
217                 ofs.open(wfilename, std::ios_base::binary);
218                 free(wfilename);
219 #else
220                 ofs.open(filename, std::ios_base::binary);
221 #endif
222
223                 if (!ofs)
224                         Iex::throwErrnoExc();
225         }
226
227         virtual void write(const char c[], int n)
228         {
229                 errno = 0;
230                 ofs.write(c, n);
231                 check_error();
232         }
233
234         virtual Int64 tellp()
235         {
236                 return std::streamoff(ofs.tellp());
237         }
238
239         virtual void seekp(Int64 pos)
240         {
241                 ofs.seekp(pos);
242                 check_error();
243         }
244
245 private:
246         void check_error()
247         {
248                 if (!ofs) {
249                         if (errno)
250                                 Iex::throwErrnoExc();
251
252                         throw Iex::ErrnoExc("File output failed.");
253                 }
254         }
255
256         std::ofstream ofs;
257 };
258
259 struct _RGBAZ {
260         half r;
261         half g;
262         half b;
263         half a;
264         half z;
265 };
266
267 typedef struct _RGBAZ RGBAZ;
268
269 extern "C"
270 {
271
272 int imb_is_a_openexr(unsigned char *mem)
273 {
274         return Imf::isImfMagic((const char *)mem);
275 }
276
277 static void openexr_header_compression(Header *header, int compression)
278 {
279         switch (compression) {
280                 case 0:
281                         header->compression() = NO_COMPRESSION;
282                         break;
283                 case 1:
284                         header->compression() = PXR24_COMPRESSION;
285                         break;
286                 case 2:
287                         header->compression() = ZIP_COMPRESSION;
288                         break;
289                 case 3:
290                         header->compression() = PIZ_COMPRESSION;
291                         break;
292                 case 4:
293                         header->compression() = RLE_COMPRESSION;
294                         break;
295                 default:
296                         header->compression() = ZIP_COMPRESSION;
297                         break;
298         }
299 }
300
301 static void openexr_header_metadata(Header *header, struct ImBuf *ibuf)
302 {
303         ImMetaData *info;
304
305         for (info = ibuf->metadata; info; info = info->next)
306                 header->insert(info->key, StringAttribute(info->value));
307
308         if (ibuf->ppm[0] > 0.0)
309                 addXDensity(*header, ibuf->ppm[0] / 39.3700787); /* 1 meter = 39.3700787 inches */
310 }
311
312 static int imb_save_openexr_half(struct ImBuf *ibuf, const char *name, int flags)
313 {
314         const int channels = ibuf->channels;
315         const int is_alpha = (channels >= 4) && (ibuf->planes == 32);
316         const int is_zbuf = (flags & IB_zbuffloat) && ibuf->zbuf_float != NULL; /* summarize */
317         const int width = ibuf->x;
318         const int height = ibuf->y;
319
320         try
321         {
322                 Header header(width, height);
323
324                 openexr_header_compression(&header, ibuf->ftype & OPENEXR_COMPRESS);
325                 openexr_header_metadata(&header, ibuf);
326
327                 header.channels().insert("R", Channel(HALF));
328                 header.channels().insert("G", Channel(HALF));
329                 header.channels().insert("B", Channel(HALF));
330                 if (is_alpha)
331                         header.channels().insert("A", Channel(HALF));
332                 if (is_zbuf)     // z we do as float always
333                         header.channels().insert("Z", Channel(Imf::FLOAT));
334
335                 FrameBuffer frameBuffer;
336
337                 /* manually create ofstream, so we can handle utf-8 filepaths on windows */
338                 OFileStream file_stream(name);
339                 OutputFile file(file_stream, header);
340
341                 /* we store first everything in half array */
342                 RGBAZ *pixels = new RGBAZ[height * width];
343                 RGBAZ *to = pixels;
344                 int xstride = sizeof(RGBAZ);
345                 int ystride = xstride * width;
346
347                 /* indicate used buffers */
348                 frameBuffer.insert("R", Slice(HALF,  (char *) &pixels[0].r, xstride, ystride));
349                 frameBuffer.insert("G", Slice(HALF,  (char *) &pixels[0].g, xstride, ystride));
350                 frameBuffer.insert("B", Slice(HALF,  (char *) &pixels[0].b, xstride, ystride));
351                 if (is_alpha)
352                         frameBuffer.insert("A", Slice(HALF, (char *) &pixels[0].a, xstride, ystride));
353                 if (is_zbuf)
354                         frameBuffer.insert("Z", Slice(Imf::FLOAT, (char *)(ibuf->zbuf_float + (height - 1) * width),
355                                                       sizeof(float), sizeof(float) * -width));
356                 if (ibuf->rect_float) {
357                         float *from;
358
359                         for (int i = ibuf->y - 1; i >= 0; i--) {
360                                 from = ibuf->rect_float + channels * i * width;
361
362                                 for (int j = ibuf->x; j > 0; j--) {
363                                         to->r = from[0];
364                                         to->g = (channels >= 2) ? from[1] : from[0];
365                                         to->b = (channels >= 3) ? from[2] : from[0];
366                                         to->a = (channels >= 4) ? from[3] : 1.0f;
367                                         to++; from += channels;
368                                 }
369                         }
370                 }
371                 else {
372                         unsigned char *from;
373
374                         for (int i = ibuf->y - 1; i >= 0; i--) {
375                                 from = (unsigned char *)ibuf->rect + 4 * i * width;
376
377                                 for (int j = ibuf->x; j > 0; j--) {
378                                         to->r = srgb_to_linearrgb((float)from[0] / 255.0f);
379                                         to->g = srgb_to_linearrgb((float)from[1] / 255.0f);
380                                         to->b = srgb_to_linearrgb((float)from[2] / 255.0f);
381                                         to->a = channels >= 4 ? (float)from[3] / 255.0f : 1.0f;
382                                         to++; from += 4;
383                                 }
384                         }
385                 }
386
387 //              printf("OpenEXR-save: Writing OpenEXR file of height %d.\n", height);
388
389                 file.setFrameBuffer(frameBuffer);
390                 file.writePixels(height);
391
392                 delete[] pixels;
393         }
394         catch (const std::exception &exc)
395         {
396                 printf("OpenEXR-save: ERROR: %s\n", exc.what());
397
398                 return (0);
399         }
400
401         return (1);
402 }
403
404 static int imb_save_openexr_float(struct ImBuf *ibuf, const char *name, int flags)
405 {
406         const int channels = ibuf->channels;
407         const int is_alpha = (channels >= 4) && (ibuf->planes == 32);
408         const int is_zbuf = (flags & IB_zbuffloat) && ibuf->zbuf_float != NULL; /* summarize */
409         const int width = ibuf->x;
410         const int height = ibuf->y;
411
412         try
413         {
414                 Header header(width, height);
415
416                 openexr_header_compression(&header, ibuf->ftype & OPENEXR_COMPRESS);
417                 openexr_header_metadata(&header, ibuf);
418
419                 header.channels().insert("R", Channel(Imf::FLOAT));
420                 header.channels().insert("G", Channel(Imf::FLOAT));
421                 header.channels().insert("B", Channel(Imf::FLOAT));
422                 if (is_alpha)
423                         header.channels().insert("A", Channel(Imf::FLOAT));
424                 if (is_zbuf)
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                 OFileStream file_stream(name);
431                 OutputFile file(file_stream, header);
432
433                 int xstride = sizeof(float) * channels;
434                 int ystride = -xstride * width;
435                 float *rect[4] = {NULL, NULL, NULL, NULL};
436
437                 /* last scanline, stride negative */
438                 rect[0] = ibuf->rect_float + channels * (height - 1) * width;
439                 rect[1] = (channels >= 2) ? rect[0] + 1 : rect[0];
440                 rect[2] = (channels >= 3) ? rect[0] + 2 : rect[0];
441                 rect[3] = (channels >= 4) ? rect[0] + 3 : rect[0]; /* red as alpha, is this needed since alpha isn't written? */
442
443                 frameBuffer.insert("R", Slice(Imf::FLOAT,  (char *)rect[0], xstride, ystride));
444                 frameBuffer.insert("G", Slice(Imf::FLOAT,  (char *)rect[1], xstride, ystride));
445                 frameBuffer.insert("B", Slice(Imf::FLOAT,  (char *)rect[2], xstride, ystride));
446                 if (is_alpha)
447                         frameBuffer.insert("A", Slice(Imf::FLOAT,  (char *)rect[3], xstride, ystride));
448                 if (is_zbuf)
449                         frameBuffer.insert("Z", Slice(Imf::FLOAT, (char *) (ibuf->zbuf_float + (height - 1) * width),
450                                                       sizeof(float), sizeof(float) * -width));
451                 file.setFrameBuffer(frameBuffer);
452                 file.writePixels(height);
453         }
454         catch (const std::exception &exc)
455         {
456                 printf("OpenEXR-save: ERROR: %s\n", exc.what());
457
458                 return (0);
459         }
460
461         return (1);
462         //      printf("OpenEXR-save: Done.\n");
463 }
464
465
466 int imb_save_openexr(struct ImBuf *ibuf, const char *name, int flags)
467 {
468         if (flags & IB_mem) {
469                 printf("OpenEXR-save: Create EXR in memory CURRENTLY NOT SUPPORTED !\n");
470                 imb_addencodedbufferImBuf(ibuf);
471                 ibuf->encodedsize = 0;
472                 return(0);
473         }
474
475         if (ibuf->ftype & OPENEXR_HALF)
476                 return imb_save_openexr_half(ibuf, name, flags);
477         else {
478                 /* when no float rect, we save as half (16 bits is sufficient) */
479                 if (ibuf->rect_float == NULL)
480                         return imb_save_openexr_half(ibuf, name, flags);
481                 else
482                         return imb_save_openexr_float(ibuf, name, flags);
483         }
484 }
485
486 /* ********************* Nicer API, MultiLayer and with Tile file support ************************************ */
487
488 /* naming rules:
489  * - parse name from right to left
490  * - last character is channel ID, 1 char like 'A' 'R' 'G' 'B' 'X' 'Y' 'Z' 'W' 'U' 'V'
491  * - separated with a dot; the Pass name (like "Depth", "Color", "Diffuse" or "Combined")
492  * - separated with a dot: the Layer name (like "Lamp1" or "Walls" or "Characters")
493  */
494
495 static ListBase exrhandles = {NULL, NULL};
496
497 typedef struct ExrHandle {
498         struct ExrHandle *next, *prev;
499
500         IFileStream *ifile_stream;
501         InputFile *ifile;
502
503         OFileStream *ofile_stream;
504         TiledOutputFile *tofile;
505         OutputFile *ofile;
506
507         int tilex, tiley;
508         int width, height;
509         int mipmap;
510
511         ListBase channels;  /* flattened out, ExrChannel */
512         ListBase layers;    /* hierarchical, pointing in end to ExrChannel */
513 } ExrHandle;
514
515 /* flattened out channel */
516 typedef struct ExrChannel {
517         struct ExrChannel *next, *prev;
518
519         char name[EXR_TOT_MAXNAME + 1];  /* full name of layer+pass */
520         int xstride, ystride;            /* step to next pixel, to next scanline */
521         float *rect;                     /* first pointer to write in */
522         char chan_id;                    /* quick lookup of channel char */
523 } ExrChannel;
524
525
526 /* hierarchical; layers -> passes -> channels[] */
527 typedef struct ExrPass {
528         struct ExrPass *next, *prev;
529         char name[EXR_PASS_MAXNAME];
530         int totchan;
531         float *rect;
532         struct ExrChannel *chan[EXR_PASS_MAXCHAN];
533         char chan_id[EXR_PASS_MAXCHAN];
534 } ExrPass;
535
536 typedef struct ExrLayer {
537         struct ExrLayer *next, *prev;
538         char name[EXR_LAY_MAXNAME + 1];
539         ListBase passes;
540 } ExrLayer;
541
542 /* ********************** */
543
544 void *IMB_exr_get_handle(void)
545 {
546         ExrHandle *data = (ExrHandle *)MEM_callocN(sizeof(ExrHandle), "exr handle");
547         BLI_addtail(&exrhandles, data);
548         return data;
549 }
550
551 /* adds flattened ExrChannels */
552 /* xstride, ystride and rect can be done in set_channel too, for tile writing */
553 void IMB_exr_add_channel(void *handle, const char *layname, const char *passname, int xstride, int ystride, float *rect)
554 {
555         ExrHandle *data = (ExrHandle *)handle;
556         ExrChannel *echan;
557
558         echan = (ExrChannel *)MEM_callocN(sizeof(ExrChannel), "exr tile channel");
559
560         if (layname) {
561                 char lay[EXR_LAY_MAXNAME + 1], pass[EXR_PASS_MAXNAME + 1];
562                 BLI_strncpy(lay, layname, EXR_LAY_MAXNAME);
563                 BLI_strncpy(pass, passname, EXR_PASS_MAXNAME);
564
565                 BLI_snprintf(echan->name, sizeof(echan->name), "%s.%s", lay, pass);
566         }
567         else {
568                 BLI_strncpy(echan->name, passname, EXR_TOT_MAXNAME - 1);
569         }
570
571         echan->xstride = xstride;
572         echan->ystride = ystride;
573         echan->rect = rect;
574
575         // printf("added channel %s\n", echan->name);
576         BLI_addtail(&data->channels, echan);
577 }
578
579 /* only used for writing temp. render results (not image files) */
580 int IMB_exr_begin_write(void *handle, const char *filename, int width, int height, int compress)
581 {
582         ExrHandle *data = (ExrHandle *)handle;
583         Header header(width, height);
584         ExrChannel *echan;
585
586         data->width = width;
587         data->height = height;
588
589         for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next)
590                 header.channels().insert(echan->name, Channel(Imf::FLOAT));
591
592         openexr_header_compression(&header, compress);
593         // openexr_header_metadata(&header, ibuf); // no imbuf. cant write
594         /* header.lineOrder() = DECREASING_Y; this crashes in windows for file read! */
595
596         header.insert("BlenderMultiChannel", StringAttribute("Blender V2.55.1 and newer"));
597
598         /* avoid crash/abort when we don't have permission to write here */
599         /* manually create ofstream, so we can handle utf-8 filepaths on windows */
600         try {
601                 data->ofile_stream = new OFileStream(filename);
602                 data->ofile = new OutputFile(*(data->ofile_stream), header);
603         }
604         catch (const std::exception &exc) {
605                 std::cerr << "IMB_exr_begin_write: ERROR: " << exc.what() << std::endl;
606
607                 delete data->ofile;
608                 delete data->ofile_stream;
609
610                 data->ofile = NULL;
611                 data->ofile_stream = NULL;
612         }
613
614         return (data->ofile != NULL);
615 }
616
617 void IMB_exrtile_begin_write(void *handle, const char *filename, int mipmap, int width, int height, int tilex, int tiley)
618 {
619         ExrHandle *data = (ExrHandle *)handle;
620         Header header(width, height);
621         ExrChannel *echan;
622
623         data->tilex = tilex;
624         data->tiley = tiley;
625         data->width = width;
626         data->height = height;
627         data->mipmap = mipmap;
628
629         for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next)
630                 header.channels().insert(echan->name, Channel(Imf::FLOAT));
631
632         header.setTileDescription(TileDescription(tilex, tiley, (mipmap) ? MIPMAP_LEVELS : ONE_LEVEL));
633         header.lineOrder() = RANDOM_Y;
634         header.compression() = RLE_COMPRESSION;
635
636         header.insert("BlenderMultiChannel", StringAttribute("Blender V2.43"));
637
638         /* avoid crash/abort when we don't have permission to write here */
639         /* manually create ofstream, so we can handle utf-8 filepaths on windows */
640         try {
641                 data->ofile_stream = new OFileStream(filename);
642                 data->tofile = new TiledOutputFile(*(data->ofile_stream), header);
643         }
644         catch (const std::exception &) {
645                 delete data->tofile;
646                 delete data->ofile_stream;
647
648                 data->tofile = NULL;
649                 data->ofile_stream = NULL;
650         }
651 }
652
653 /* read from file */
654 int IMB_exr_begin_read(void *handle, const char *filename, int *width, int *height)
655 {
656         ExrHandle *data = (ExrHandle *)handle;
657
658         if (BLI_exists(filename) && BLI_file_size(filename) > 32) {   /* 32 is arbitrary, but zero length files crashes exr */
659                 /* avoid crash/abort when we don't have permission to write here */
660                 try {
661                         data->ifile_stream = new IFileStream(filename);
662                         data->ifile = new InputFile(*(data->ifile_stream));
663                 }
664                 catch (const std::exception &) {
665                         delete data->ifile;
666                         delete data->ifile_stream;
667
668                         data->ifile = NULL;
669                         data->ifile_stream = NULL;
670                 }
671
672                 if (data->ifile) {
673                         Box2i dw = data->ifile->header().dataWindow();
674                         data->width = *width  = dw.max.x - dw.min.x + 1;
675                         data->height = *height = dw.max.y - dw.min.y + 1;
676
677                         const ChannelList &channels = data->ifile->header().channels();
678
679                         for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i)
680                                 IMB_exr_add_channel(data, NULL, i.name(), 0, 0, NULL);
681
682                         return 1;
683                 }
684         }
685         return 0;
686 }
687
688 /* still clumsy name handling, layers/channels can be ordered as list in list later */
689 void IMB_exr_set_channel(void *handle, const char *layname, const char *passname, int xstride, int ystride, float *rect)
690 {
691         ExrHandle *data = (ExrHandle *)handle;
692         ExrChannel *echan;
693         char name[EXR_TOT_MAXNAME + 1];
694
695         if (layname) {
696                 char lay[EXR_LAY_MAXNAME + 1], pass[EXR_PASS_MAXNAME + 1];
697                 BLI_strncpy(lay, layname, EXR_LAY_MAXNAME);
698                 BLI_strncpy(pass, passname, EXR_PASS_MAXNAME);
699
700                 BLI_snprintf(name, sizeof(name), "%s.%s", lay, pass);
701         }
702         else
703                 BLI_strncpy(name, passname, EXR_TOT_MAXNAME - 1);
704
705         echan = (ExrChannel *)BLI_findstring(&data->channels, name, offsetof(ExrChannel, name));
706
707         if (echan) {
708                 echan->xstride = xstride;
709                 echan->ystride = ystride;
710                 echan->rect = rect;
711         }
712         else
713                 printf("IMB_exrtile_set_channel error %s\n", name);
714 }
715
716 void IMB_exrtile_clear_channels(void *handle)
717 {
718         ExrHandle *data = (ExrHandle *)handle;
719         BLI_freelistN(&data->channels);
720 }
721
722 void IMB_exrtile_write_channels(void *handle, int partx, int party, int level)
723 {
724         ExrHandle *data = (ExrHandle *)handle;
725         FrameBuffer frameBuffer;
726         ExrChannel *echan;
727
728         for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
729                 float *rect = echan->rect - echan->xstride * partx - echan->ystride * party;
730
731                 frameBuffer.insert(echan->name, Slice(Imf::FLOAT,  (char *)rect,
732                                                       echan->xstride * sizeof(float), echan->ystride * sizeof(float)));
733         }
734
735         data->tofile->setFrameBuffer(frameBuffer);
736
737         try {
738                 // printf("write tile %d %d\n", partx/data->tilex, party/data->tiley);
739                 data->tofile->writeTile(partx / data->tilex, party / data->tiley, level);
740         }
741         catch (const std::exception &exc) {
742                 std::cerr << "OpenEXR-writeTile: ERROR: " << exc.what() << std::endl;
743         }
744 }
745
746 void IMB_exr_write_channels(void *handle)
747 {
748         ExrHandle *data = (ExrHandle *)handle;
749         FrameBuffer frameBuffer;
750         ExrChannel *echan;
751
752         if (data->channels.first) {
753                 for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
754                         /* last scanline, stride negative */
755                         float *rect = echan->rect + echan->xstride * (data->height - 1) * data->width;
756
757                         frameBuffer.insert(echan->name, Slice(Imf::FLOAT,  (char *)rect,
758                                                               echan->xstride * sizeof(float), -echan->ystride * sizeof(float)));
759                 }
760
761                 data->ofile->setFrameBuffer(frameBuffer);
762                 try {
763                         data->ofile->writePixels(data->height);
764                 }
765                 catch (const std::exception &exc) {
766                         std::cerr << "OpenEXR-writePixels: ERROR: " << exc.what() << std::endl;
767                 }
768         }
769         else {
770                 printf("Error: attempt to save MultiLayer without layers.\n");
771         }
772 }
773
774 void IMB_exr_read_channels(void *handle)
775 {
776         ExrHandle *data = (ExrHandle *)handle;
777         FrameBuffer frameBuffer;
778         ExrChannel *echan;
779
780         /* check if exr was saved with previous versions of blender which flipped images */
781         const StringAttribute *ta = data->ifile->header().findTypedAttribute <StringAttribute> ("BlenderMultiChannel");
782         short flip = (ta && strncmp(ta->value().c_str(), "Blender V2.43", 13) == 0); /* 'previous multilayer attribute, flipped */
783
784         for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
785
786                 if (echan->rect) {
787                         if (flip)
788                                 frameBuffer.insert(echan->name, Slice(Imf::FLOAT,  (char *)echan->rect,
789                                                                       echan->xstride * sizeof(float), echan->ystride * sizeof(float)));
790                         else
791                                 frameBuffer.insert(echan->name, Slice(Imf::FLOAT,  (char *)(echan->rect + echan->xstride * (data->height - 1) * data->width),
792                                                                       echan->xstride * sizeof(float), -echan->ystride * sizeof(float)));
793                 }
794                 else
795                         printf("warning, channel with no rect set %s\n", echan->name);
796         }
797
798         data->ifile->setFrameBuffer(frameBuffer);
799
800         try {
801                 data->ifile->readPixels(0, data->height - 1);
802         }
803         catch (const std::exception &exc) {
804                 std::cerr << "OpenEXR-readPixels: ERROR: " << exc.what() << std::endl;
805         }
806 }
807
808 void IMB_exr_multilayer_convert(void *handle, void *base,
809                                 void * (*addlayer)(void *base, const char *str),
810                                 void (*addpass)(void *base, void *lay, const char *str,
811                                                 float *rect, int totchan, const char *chan_id))
812 {
813         ExrHandle *data = (ExrHandle *)handle;
814         ExrLayer *lay;
815         ExrPass *pass;
816
817         if (data->layers.first == NULL) {
818                 printf("cannot convert multilayer, no layers in handle\n");
819                 return;
820         }
821
822         for (lay = (ExrLayer *)data->layers.first; lay; lay = lay->next) {
823                 void *laybase = addlayer(base, lay->name);
824                 if (laybase) {
825                         for (pass = (ExrPass *)lay->passes.first; pass; pass = pass->next) {
826                                 addpass(base, laybase, pass->name, pass->rect, pass->totchan, pass->chan_id);
827                                 pass->rect = NULL;
828                         }
829                 }
830         }
831 }
832
833
834 void IMB_exr_close(void *handle)
835 {
836         ExrHandle *data = (ExrHandle *)handle;
837         ExrLayer *lay;
838         ExrPass *pass;
839
840         delete data->ifile;
841         delete data->ifile_stream;
842         delete data->ofile;
843         delete data->tofile;
844         delete data->ofile_stream;
845
846         data->ifile = NULL;
847         data->ifile_stream = NULL;
848         data->ofile = NULL;
849         data->tofile = NULL;
850         data->ofile_stream = NULL;
851
852         BLI_freelistN(&data->channels);
853
854         for (lay = (ExrLayer *)data->layers.first; lay; lay = lay->next) {
855                 for (pass = (ExrPass *)lay->passes.first; pass; pass = pass->next)
856                         if (pass->rect)
857                                 MEM_freeN(pass->rect);
858                 BLI_freelistN(&lay->passes);
859         }
860         BLI_freelistN(&data->layers);
861
862         BLI_remlink(&exrhandles, data);
863         MEM_freeN(data);
864 }
865
866 /* ********* */
867
868 /* get a substring from the end of the name, separated by '.' */
869 static int imb_exr_split_token(const char *str, const char *end, const char **token)
870 {
871         ptrdiff_t maxlen = end - str;
872         int len = 0;
873         while (len < maxlen && *(end - len - 1) != '.') {
874                 len++;
875         }
876
877         *token = end - len;
878         return len;
879 }
880
881 static int imb_exr_split_channel_name(ExrChannel *echan, char *layname, char *passname)
882 {
883         const char *name = echan->name;
884         const char *end = name + strlen(name);
885         const char *token;
886         char tokenbuf[EXR_TOT_MAXNAME];
887         int len;
888         
889         /* some multilayers have the combined buffer with names A B G R saved */
890         if (name[1] == 0) {
891                 echan->chan_id = name[0];
892                 layname[0] = '\0';
893                 strcpy(passname, "Combined");
894                 return 1;
895         }
896
897         /* last token is single character channel identifier */
898         len = imb_exr_split_token(name, end, &token);
899         if (len == 0) {
900                 printf("multilayer read: bad channel name: %s\n", name);
901                 return 0;
902         }
903         else if (len == 1) {
904                 echan->chan_id = token[0];
905         }
906         else if (len > 1) {
907                 bool ok = false;
908
909                 if (len == 2) {
910                         /* some multilayers are using two-letter channels name,
911                          * like, MX or NZ, which is basically has structure of
912                          *   <pass_prefix><component>
913                          *
914                          * This is a bit silly, but see file from [#35658].
915                          *
916                          * Here we do some magic to distinguish such cases.
917                          */
918                         if (ELEM3(token[1], 'X', 'Y', 'Z') ||
919                             ELEM3(token[1], 'R', 'G', 'B') ||
920                             ELEM3(token[1], 'U', 'V', 'A'))
921                         {
922                                 echan->chan_id = token[1];
923                                 ok = true;
924                         }
925                 }
926
927                 if (ok == false) {
928                         BLI_strncpy(tokenbuf, token, std::min(len + 1, EXR_TOT_MAXNAME));
929                         printf("multilayer read: channel token too long: %s\n", tokenbuf);
930                         return 0;
931                 }
932         }
933         end -= len + 1; /* +1 to skip '.' separator */
934
935         /* second token is pass name */
936         len = imb_exr_split_token(name, end, &token);
937         if (len == 0) {
938                 printf("multilayer read: bad channel name: %s\n", name);
939                 return 0;
940         }
941         BLI_strncpy(passname, token, len + 1);
942         end -= len + 1; /* +1 to skip '.' separator */
943
944         /* all preceding tokens combined as layer name */
945         if (end > name)
946                 BLI_strncpy(layname, name, (int)(end - name) + 1);
947         else
948                 layname[0] = '\0';
949
950         return 1;
951 }
952
953 static ExrLayer *imb_exr_get_layer(ListBase *lb, char *layname)
954 {
955         ExrLayer *lay = (ExrLayer *)BLI_findstring(lb, layname, offsetof(ExrLayer, name));
956
957         if (lay == NULL) {
958                 lay = (ExrLayer *)MEM_callocN(sizeof(ExrLayer), "exr layer");
959                 BLI_addtail(lb, lay);
960                 BLI_strncpy(lay->name, layname, EXR_LAY_MAXNAME);
961         }
962
963         return lay;
964 }
965
966 static ExrPass *imb_exr_get_pass(ListBase *lb, char *passname)
967 {
968         ExrPass *pass = (ExrPass *)BLI_findstring(lb, passname, offsetof(ExrPass, name));
969
970         if (pass == NULL) {
971                 pass = (ExrPass *)MEM_callocN(sizeof(ExrPass), "exr pass");
972
973                 if (strcmp(passname, "Combined") == 0)
974                         BLI_addhead(lb, pass);
975                 else
976                         BLI_addtail(lb, pass);
977         }
978
979         BLI_strncpy(pass->name, passname, EXR_LAY_MAXNAME);
980
981         return pass;
982 }
983
984 /* creates channels, makes a hierarchy and assigns memory to channels */
985 static ExrHandle *imb_exr_begin_read_mem(InputFile *file, int width, int height)
986 {
987         ExrLayer *lay;
988         ExrPass *pass;
989         ExrChannel *echan;
990         ExrHandle *data = (ExrHandle *)IMB_exr_get_handle();
991         int a;
992         char layname[EXR_TOT_MAXNAME], passname[EXR_TOT_MAXNAME];
993
994         data->ifile = file;
995         data->width = width;
996         data->height = height;
997
998         const ChannelList &channels = data->ifile->header().channels();
999
1000         for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i)
1001                 IMB_exr_add_channel(data, NULL, i.name(), 0, 0, NULL);
1002
1003         /* now try to sort out how to assign memory to the channels */
1004         /* first build hierarchical layer list */
1005         for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
1006                 if (imb_exr_split_channel_name(echan, layname, passname) ) {
1007                         ExrLayer *lay = imb_exr_get_layer(&data->layers, layname);
1008                         ExrPass *pass = imb_exr_get_pass(&lay->passes, passname);
1009
1010                         pass->chan[pass->totchan] = echan;
1011                         pass->totchan++;
1012                         if (pass->totchan >= EXR_PASS_MAXCHAN)
1013                                 break;
1014                 }
1015         }
1016         if (echan) {
1017                 printf("error, too many channels in one pass: %s\n", echan->name);
1018                 IMB_exr_close(data);
1019                 return NULL;
1020         }
1021
1022         /* with some heuristics, try to merge the channels in buffers */
1023         for (lay = (ExrLayer *)data->layers.first; lay; lay = lay->next) {
1024                 for (pass = (ExrPass *)lay->passes.first; pass; pass = pass->next) {
1025                         if (pass->totchan) {
1026                                 pass->rect = (float *)MEM_mapallocN(width * height * pass->totchan * sizeof(float), "pass rect");
1027                                 if (pass->totchan == 1) {
1028                                         echan = pass->chan[0];
1029                                         echan->rect = pass->rect;
1030                                         echan->xstride = 1;
1031                                         echan->ystride = width;
1032                                         pass->chan_id[0] = echan->chan_id;
1033                                 }
1034                                 else {
1035                                         char lookup[256];
1036
1037                                         memset(lookup, 0, sizeof(lookup));
1038
1039                                         /* we can have RGB(A), XYZ(W), UVA */
1040                                         if (pass->totchan == 3 || pass->totchan == 4) {
1041                                                 if (pass->chan[0]->chan_id == 'B' || pass->chan[1]->chan_id == 'B' ||  pass->chan[2]->chan_id == 'B') {
1042                                                         lookup[(unsigned int)'R'] = 0;
1043                                                         lookup[(unsigned int)'G'] = 1;
1044                                                         lookup[(unsigned int)'B'] = 2;
1045                                                         lookup[(unsigned int)'A'] = 3;
1046                                                 }
1047                                                 else if (pass->chan[0]->chan_id == 'Y' || pass->chan[1]->chan_id == 'Y' ||  pass->chan[2]->chan_id == 'Y') {
1048                                                         lookup[(unsigned int)'X'] = 0;
1049                                                         lookup[(unsigned int)'Y'] = 1;
1050                                                         lookup[(unsigned int)'Z'] = 2;
1051                                                         lookup[(unsigned int)'W'] = 3;
1052                                                 }
1053                                                 else {
1054                                                         lookup[(unsigned int)'U'] = 0;
1055                                                         lookup[(unsigned int)'V'] = 1;
1056                                                         lookup[(unsigned int)'A'] = 2;
1057                                                 }
1058                                                 for (a = 0; a < pass->totchan; a++) {
1059                                                         echan = pass->chan[a];
1060                                                         echan->rect = pass->rect + lookup[(unsigned int)echan->chan_id];
1061                                                         echan->xstride = pass->totchan;
1062                                                         echan->ystride = width * pass->totchan;
1063                                                         pass->chan_id[(unsigned int)lookup[(unsigned int)echan->chan_id]] = echan->chan_id;
1064                                                 }
1065                                         }
1066                                         else { /* unknown */
1067                                                 for (a = 0; a < pass->totchan; a++) {
1068                                                         echan = pass->chan[a];
1069                                                         echan->rect = pass->rect + a;
1070                                                         echan->xstride = pass->totchan;
1071                                                         echan->ystride = width * pass->totchan;
1072                                                         pass->chan_id[a] = echan->chan_id;
1073                                                 }
1074                                         }
1075                                 }
1076                         }
1077                 }
1078         }
1079
1080         return data;
1081 }
1082
1083
1084 /* ********************************************************* */
1085
1086 /* debug only */
1087 static void exr_print_filecontents(InputFile *file)
1088 {
1089         const ChannelList &channels = file->header().channels();
1090
1091         for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i) {
1092                 const Channel &channel = i.channel();
1093                 printf("OpenEXR-load: Found channel %s of type %d\n", i.name(), channel.type);
1094         }
1095 }
1096
1097 /* for non-multilayer, map  R G B A channel names to something that's in this file */
1098 static const char *exr_rgba_channelname(InputFile *file, const char *chan)
1099 {
1100         const ChannelList &channels = file->header().channels();
1101
1102         for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i) {
1103                 /* const Channel &channel = i.channel(); */ /* Not used yet */
1104                 const char *str = i.name();
1105                 int len = strlen(str);
1106                 if (len) {
1107                         if (BLI_strcasecmp(chan, str + len - 1) == 0) {
1108                                 return str;
1109                         }
1110                 }
1111         }
1112         return chan;
1113 }
1114
1115 static int exr_has_zbuffer(InputFile *file)
1116 {
1117         return !(file->header().channels().findChannel("Z") == NULL);
1118 }
1119
1120 static int exr_has_alpha(InputFile *file)
1121 {
1122         return !(file->header().channels().findChannel("A") == NULL);
1123 }
1124
1125 static int exr_is_multilayer(InputFile *file)
1126 {
1127         const StringAttribute *comments = file->header().findTypedAttribute<StringAttribute>("BlenderMultiChannel");
1128         const ChannelList &channels = file->header().channels();
1129         std::set <std::string> layerNames;
1130
1131         /* will not include empty layer names */
1132         channels.layers(layerNames);
1133
1134         if (comments || layerNames.size() > 1)
1135                 return 1;
1136
1137         if (layerNames.size()) {
1138                 /* if layerNames is not empty, it means at least one layer is non-empty,
1139                  * but it also could be layers without names in the file and such case
1140                  * shall be considered a multilayer exr
1141                  *
1142                  * that's what we do here: test whether there're empty layer names together
1143                  * with non-empty ones in the file
1144                  */
1145                 for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); i++) {
1146                         std::string layerName = i.name();
1147                         size_t pos = layerName.rfind ('.');
1148
1149                         if (pos == std::string::npos)
1150                                 return 1;
1151                 }
1152         }
1153
1154         return 0;
1155 }
1156
1157 struct ImBuf *imb_load_openexr(unsigned char *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE])
1158 {
1159         struct ImBuf *ibuf = NULL;
1160         InputFile *file = NULL;
1161
1162         if (imb_is_a_openexr(mem) == 0) return(NULL);
1163
1164         colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_FLOAT);
1165
1166         try
1167         {
1168                 Mem_IStream *membuf = new Mem_IStream(mem, size);
1169                 int is_multi;
1170                 file = new InputFile(*membuf);
1171
1172                 Box2i dw = file->header().dataWindow();
1173                 const int width  = dw.max.x - dw.min.x + 1;
1174                 const int height = dw.max.y - dw.min.y + 1;
1175
1176                 //printf("OpenEXR-load: image data window %d %d %d %d\n",
1177                 //         dw.min.x, dw.min.y, dw.max.x, dw.max.y);
1178
1179                 if (0) // debug
1180                         exr_print_filecontents(file);
1181
1182                 is_multi = exr_is_multilayer(file);
1183
1184                 /* do not make an ibuf when */
1185                 if (is_multi && !(flags & IB_test) && !(flags & IB_multilayer)) {
1186                         printf("Error: can't process EXR multilayer file\n");
1187                 }
1188                 else {
1189                         const int is_alpha = exr_has_alpha(file);
1190
1191                         ibuf = IMB_allocImBuf(width, height, is_alpha ? 32 : 24, 0);
1192
1193                         if (hasXDensity(file->header())) {
1194                                 ibuf->ppm[0] = xDensity(file->header()) * 39.3700787f;
1195                                 ibuf->ppm[1] = ibuf->ppm[0] * (double)file->header().pixelAspectRatio();
1196                         }
1197
1198                         ibuf->ftype = OPENEXR;
1199
1200                         if (!(flags & IB_test)) {
1201                                 if (is_multi) { /* only enters with IB_multilayer flag set */
1202                                         /* constructs channels for reading, allocates memory in channels */
1203                                         ExrHandle *handle = imb_exr_begin_read_mem(file, width, height);
1204                                         if (handle) {
1205                                                 IMB_exr_read_channels(handle);
1206                                                 ibuf->userdata = handle;         /* potential danger, the caller has to check for this! */
1207                                         }
1208                                 }
1209                                 else {
1210                                         FrameBuffer frameBuffer;
1211                                         float *first;
1212                                         int xstride = sizeof(float) * 4;
1213                                         int ystride = -xstride * width;
1214
1215                                         imb_addrectfloatImBuf(ibuf);
1216
1217                                         /* inverse correct first pixel for datawindow coordinates (- dw.min.y because of y flip) */
1218                                         first = ibuf->rect_float - 4 * (dw.min.x - dw.min.y * width);
1219                                         /* but, since we read y-flipped (negative y stride) we move to last scanline */
1220                                         first += 4 * (height - 1) * width;
1221
1222                                         frameBuffer.insert(exr_rgba_channelname(file, "R"),
1223                                                            Slice(Imf::FLOAT,  (char *) first, xstride, ystride));
1224                                         frameBuffer.insert(exr_rgba_channelname(file, "G"),
1225                                                            Slice(Imf::FLOAT,  (char *) (first + 1), xstride, ystride));
1226                                         frameBuffer.insert(exr_rgba_channelname(file, "B"),
1227                                                            Slice(Imf::FLOAT,  (char *) (first + 2), xstride, ystride));
1228
1229                                         /* 1.0 is fill value, this still needs to be assigned even when (is_alpha == 0) */
1230                                         frameBuffer.insert(exr_rgba_channelname(file, "A"),
1231                                                            Slice(Imf::FLOAT,  (char *) (first + 3), xstride, ystride, 1, 1, 1.0f));
1232
1233                                         if (exr_has_zbuffer(file)) {
1234                                                 float *firstz;
1235
1236                                                 addzbuffloatImBuf(ibuf);
1237                                                 firstz = ibuf->zbuf_float - (dw.min.x - dw.min.y * width);
1238                                                 firstz += (height - 1) * width;
1239                                                 frameBuffer.insert("Z", Slice(Imf::FLOAT,  (char *)firstz, sizeof(float), -width * sizeof(float)));
1240                                         }
1241
1242                                         file->setFrameBuffer(frameBuffer);
1243                                         file->readPixels(dw.min.y, dw.max.y);
1244
1245                                         // XXX, ImBuf has no nice way to deal with this.
1246                                         // ideally IM_rect would be used when the caller wants a rect BUT
1247                                         // at the moment all functions use IM_rect.
1248                                         // Disabling this is ok because all functions should check if a rect exists and create one on demand.
1249                                         //
1250                                         // Disabling this because the sequencer frees immediate.
1251                                         //
1252                                         // if (flag & IM_rect)
1253                                         //     IMB_rect_from_float(ibuf);
1254
1255                                         /* file is no longer needed */
1256                                         delete file;
1257                                 }
1258                         }
1259
1260                         if (flags & IB_alphamode_detect)
1261                                 ibuf->flags |= IB_alphamode_premul;
1262                 }
1263                 return(ibuf);
1264         }
1265         catch (const std::exception &exc)
1266         {
1267                 std::cerr << exc.what() << std::endl;
1268                 if (ibuf) IMB_freeImBuf(ibuf);
1269                 delete file;
1270
1271                 return (0);
1272         }
1273
1274 }
1275
1276 void imb_initopenexr(void)
1277 {
1278         int num_threads = BLI_system_thread_count();
1279
1280         setGlobalThreadCount(num_threads);
1281 }
1282
1283 } // export "C"