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