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