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