Final merge of HEAD (bf-blender) into the orange branch.
[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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, 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 #include "IMB_imbuf_types.h"
39 #include "IMB_imbuf.h"
40         
41 #include "IMB_allocimbuf.h"
42 }
43
44 #include <iostream>
45
46 #if defined (_WIN32) && !defined(FREE_WINDOWS)
47 #include <half.h>
48 #include <IlmImf/ImfVersion.h>
49 #include <IlmImf/ImfArray.h>
50 #include <IlmImf/ImfIO.h>
51 #include <IlmImf/ImfChannelList.h>
52 #include <IlmImf/ImfPixelType.h>
53 #include <IlmImf/ImfInputFile.h>
54 #include <IlmImf/ImfOutputFile.h>
55 #include <IlmImf/ImfCompression.h>
56 #include <IlmImf/ImfCompressionAttribute.h>
57 #include <Imath/ImathBox.h>
58 #else
59 #include <OpenEXR/half.h>
60 #include <OpenEXR/ImfVersion.h>
61 #include <OpenEXR/ImathBox.h>
62 #include <OpenEXR/ImfArray.h>
63 #include <OpenEXR/ImfIO.h>
64 #include <OpenEXR/ImfChannelList.h>
65 #include <OpenEXR/ImfPixelType.h>
66 #include <OpenEXR/ImfInputFile.h>
67 #include <OpenEXR/ImfOutputFile.h>
68 #include <OpenEXR/ImfCompression.h>
69 #include <OpenEXR/ImfCompressionAttribute.h>
70 #endif
71
72 using namespace Imf;
73 using namespace Imath;
74
75 class Mem_IStream: public IStream
76 {
77 public:
78         
79         Mem_IStream (unsigned char *exrbuf, int exrsize):
80     IStream("dummy"), _exrpos (0), _exrsize(exrsize)  { _exrbuf = exrbuf; }
81         
82         virtual bool    read (char c[], int n);
83         virtual Int64   tellg ();
84         virtual void    seekg (Int64 pos);
85         virtual void    clear ();
86         //virtual ~Mem_IStream() {}; // unused
87         
88 private:
89                 
90                 Int64 _exrpos;
91         Int64 _exrsize;
92         unsigned char *_exrbuf;
93 };
94
95 bool Mem_IStream::read (char c[], int n)
96 {
97         if (n + _exrpos <= _exrsize)
98     {
99                 memcpy(c, (void *)(&_exrbuf[_exrpos]), n);
100                 _exrpos += n;
101                 return true;
102     }
103         else
104                 return false;
105 }
106
107 Int64 Mem_IStream::tellg ()
108 {
109         return _exrpos;
110 }
111
112 void Mem_IStream::seekg (Int64 pos)
113 {
114         _exrpos = pos;
115 }
116
117 void Mem_IStream::clear () 
118
119 }
120
121 struct _RGBAZ
122 {
123         half r;
124         half g;
125         half b;
126         half a;
127         half z;
128 };
129
130 typedef struct _RGBAZ RGBAZ;
131
132 extern "C"
133 {
134         
135 int imb_is_a_openexr(unsigned char *mem)
136 {
137         return Imf::isImfMagic ((const char *)mem);
138 }
139
140 static void openexr_header_compression(Header *header, int compression)
141 {
142         switch(compression)
143         {
144                 case 0:
145                         header->compression() = NO_COMPRESSION;
146                         break;
147                 case 1:
148                         header->compression() = PXR24_COMPRESSION;
149                         break;
150                 case 2:
151                         header->compression() = ZIP_COMPRESSION;
152                         break;
153                 case 3:
154                         header->compression() = PIZ_COMPRESSION;
155                         break;
156                 case 4:
157                         header->compression() = RLE_COMPRESSION;
158                         break;
159                 default:
160                         header->compression() = NO_COMPRESSION;
161                         break; 
162         }
163 }
164
165 static short imb_save_openexr_half(struct ImBuf *ibuf, char *name, int flags)
166 {
167         
168         int width = ibuf->x;
169         int height = ibuf->y;
170         int write_zbuf = (flags & IB_zbuffloat) && ibuf->zbuf_float != NULL;   // summarize
171         
172         try
173         {
174                 Header header (width, height);
175                 
176                 openexr_header_compression(&header, ibuf->ftype & OPENEXR_COMPRESS);
177                 
178                 header.channels().insert ("R", Channel (HALF));
179                 header.channels().insert ("G", Channel (HALF));
180                 header.channels().insert ("B", Channel (HALF));
181                 header.channels().insert ("A", Channel (HALF));
182                 if (write_zbuf)         // z we do as float always
183                         header.channels().insert ("Z", Channel (FLOAT));
184                 
185                 FrameBuffer frameBuffer;                        
186                 OutputFile *file = new OutputFile(name, header);                        
187                 
188                 /* we store first everything in half array */
189                 RGBAZ *pixels = new RGBAZ[height * width];
190                 RGBAZ *to = pixels;
191                 int xstride= sizeof (RGBAZ);
192                 int ystride= xstride*width;
193                 
194                 /* indicate used buffers */
195                 frameBuffer.insert ("R", Slice (HALF,  (char *) &pixels[0].r, xstride, ystride));       
196                 frameBuffer.insert ("G", Slice (HALF,  (char *) &pixels[0].g, xstride, ystride));
197                 frameBuffer.insert ("B", Slice (HALF,  (char *) &pixels[0].b, xstride, ystride));
198                 frameBuffer.insert ("A", Slice (HALF, (char *) &pixels[0].a, xstride, ystride));
199         
200                 if (write_zbuf)
201                         frameBuffer.insert ("Z", Slice (FLOAT, (char *) ibuf->zbuf_float + 4*(height-1)*width,
202                                                                                         sizeof(float), sizeof(float) * -width));
203                 if(ibuf->rect_float) {
204                         float *from;
205                         
206                         for (int i = ibuf->y-1; i >= 0; i--) 
207                         {
208                                 from= ibuf->rect_float + 4*i*width;
209                                 
210                                 for (int j = ibuf->x; j > 0; j--) 
211                                 {
212                                         to->r = from[0];
213                                         to->g = from[1];
214                                         to->b = from[2];
215                                         to->a = from[3];
216                                         to++; from += 4;
217                                 }
218                         }
219                 }
220                 else {
221                         unsigned char *from;
222                         
223                         for (int i = ibuf->y-1; i >= 0; i--) 
224                         {
225                                 from= (unsigned char *)(ibuf->rect + i*width);
226                                 
227                                 for (int j = ibuf->x; j > 0; j--) 
228                                 {
229                                         to->r = (float)(from[0])/255.0;
230                                         to->g = (float)(from[1])/255.0;
231                                         to->b = (float)(from[2])/255.0;
232                                         to->a = (float)(from[3])/255.0;
233                                         to++; from += 4;
234                                 }
235                         }
236                 }
237                 
238 //              printf("OpenEXR-save: Writing OpenEXR file of height %d.\n", height);
239                 
240                 file->setFrameBuffer (frameBuffer);                               
241                 file->writePixels (height);                                       
242                 delete file;
243         }
244         catch (const std::exception &exc)
245         {      
246                 printf("OpenEXR-save: ERROR: %s\n", exc.what());
247                 if (ibuf) IMB_freeImBuf(ibuf);
248                 
249                 return (0);
250         }
251         
252         return (1);
253 }
254
255 static short imb_save_openexr_float(struct ImBuf *ibuf, char *name, int flags)
256 {
257         
258         int width = ibuf->x;
259         int height = ibuf->y;
260         int write_zbuf = (flags & IB_zbuffloat) && ibuf->zbuf_float != NULL;   // summarize
261
262         try
263         {
264                 Header header (width, height);
265                 
266                 openexr_header_compression(&header, ibuf->ftype & OPENEXR_COMPRESS);
267                 
268                 header.channels().insert ("R", Channel (FLOAT));
269                 header.channels().insert ("G", Channel (FLOAT));
270                 header.channels().insert ("B", Channel (FLOAT));
271                 header.channels().insert ("A", Channel (FLOAT));
272                 if (write_zbuf)
273                         header.channels().insert ("Z", Channel (FLOAT));
274                 
275                 FrameBuffer frameBuffer;                        
276                 OutputFile *file = new OutputFile(name, header);                        
277                 float *first= ibuf->rect_float + 4*(height-1)*width;
278                 int xstride = sizeof(float) * 4;
279                 int ystride = - xstride*width;
280
281                 frameBuffer.insert ("R", Slice (FLOAT,  (char *) first, xstride, ystride));
282                 frameBuffer.insert ("G", Slice (FLOAT,  (char *) (first+1), xstride, ystride));
283                 frameBuffer.insert ("B", Slice (FLOAT,  (char *) (first+2), xstride, ystride));
284                 frameBuffer.insert ("A", Slice (FLOAT,  (char *) (first+3), xstride, ystride));
285
286                 if (write_zbuf)
287                         frameBuffer.insert ("Z", Slice (FLOAT, (char *) ibuf->zbuf_float + 4*(height-1)*width,
288                                                                                         sizeof(float), sizeof(float) * -width));
289                 file->setFrameBuffer (frameBuffer);                               
290                 file->writePixels (height);                                       
291                 delete file;
292         }
293         catch (const std::exception &exc)
294         {      
295                 printf("OpenEXR-save: ERROR: %s\n", exc.what());
296                 if (ibuf) IMB_freeImBuf(ibuf);
297                 
298                 return (0);
299         }
300         
301         return (1);
302         //      printf("OpenEXR-save: Done.\n");
303 }
304
305
306 short imb_save_openexr(struct ImBuf *ibuf, char *name, int flags)
307 {
308         if (flags & IB_mem) 
309         {
310                 printf("OpenEXR-save: Create EXR in memory CURRENTLY NOT SUPPORTED !\n");
311                 imb_addencodedbufferImBuf(ibuf);
312                 ibuf->encodedsize = 0;    
313                 return(0);
314         } 
315         
316         if (ibuf->ftype & OPENEXR_HALF) 
317                 return imb_save_openexr_half(ibuf, name, flags);
318         else {
319                 /* when no float rect, we save as half (16 bits is sufficient) */
320                 if (ibuf->rect_float==NULL)
321                         return imb_save_openexr_half(ibuf, name, flags);
322                 else
323                         return imb_save_openexr_float(ibuf, name, flags);
324         }
325 }
326
327
328 typedef struct RGBA
329 {
330         float r;
331         float g;
332         float b;
333         float a;
334 } RGBA;
335
336
337 static void exr_print_filecontents(InputFile *file)
338 {
339         const ChannelList &channels = file->header().channels();
340         
341         for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i)
342         {
343                 const Channel &channel = i.channel();
344                 printf("OpenEXR-load: Found channel %s of type %d\n", i.name(), channel.type);
345         }
346 }
347
348 static int exr_has_zbuffer(InputFile *file)
349 {
350         const ChannelList &channels = file->header().channels();
351         
352         for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i)
353         {
354                 const Channel &channel = i.channel();
355                 if(strcmp("Z", i.name())==0)
356                         return 1;
357         }
358         return 0;
359 }
360
361
362 struct ImBuf *imb_load_openexr(unsigned char *mem, int size, int flags)
363 {
364         struct ImBuf *ibuf = NULL;
365         InputFile *file = NULL;
366         
367         if (imb_is_a_openexr(mem) == 0) return(NULL);
368         
369         try
370         {
371                 Mem_IStream membuf(mem, size); 
372                 file = new InputFile(membuf);
373                 
374                 Box2i dw = file->header().dataWindow();
375                 int width  = dw.max.x - dw.min.x + 1;
376                 int height = dw.max.y - dw.min.y + 1;
377                 
378                 //printf("OpenEXR-load: image data window %d %d %d %d\n", 
379                 //         dw.min.x, dw.min.y, dw.max.x, dw.max.y);
380
381                 //exr_print_filecontents(file);
382                 
383                 ibuf = IMB_allocImBuf(width, height, 32, 0, 0);
384                 
385                 if (ibuf) 
386                 {
387                         ibuf->ftype = OPENEXR;
388                         
389                         if (!(flags & IB_test))
390                         {
391                                 FrameBuffer frameBuffer;
392                                 float *first;
393                                 int xstride = sizeof(float) * 4;
394                                 int ystride = - xstride*width;
395                                 
396                                 imb_addrectfloatImBuf(ibuf);
397                                 
398                                 /* inverse correct first pixel for datawindow coordinates (- dw.min.y because of y flip) */
399                                 first= ibuf->rect_float - 4*(dw.min.x - dw.min.y*width);
400                                 /* but, since we read y-flipped (negative y stride) we move to last scanline */
401                                 first+= 4*(height-1)*width;
402                                 
403                                 frameBuffer.insert ("R", Slice (FLOAT,  (char *) first, xstride, ystride));
404                                 frameBuffer.insert ("G", Slice (FLOAT,  (char *) (first+1), xstride, ystride));
405                                 frameBuffer.insert ("B", Slice (FLOAT,  (char *) (first+2), xstride, ystride));
406                                                                                                                                                 /* 1.0 is fill value */
407                                 frameBuffer.insert ("A", Slice (FLOAT,  (char *) (first+3), xstride, ystride, 1, 1, 1.0f));
408
409                                 if(exr_has_zbuffer(file)) {
410                                         float *firstz;
411                                         
412                                         addzbuffloatImBuf(ibuf);
413                                         firstz= ibuf->zbuf_float - (dw.min.x - dw.min.y*width);
414                                         firstz+= (height-1)*width;
415                                         frameBuffer.insert ("Z", Slice (FLOAT,  (char *)firstz , sizeof(float), -width*sizeof(float)));
416                                 }
417                                 
418                                 file->setFrameBuffer (frameBuffer);
419                                 file->readPixels (dw.min.y, dw.max.y);
420                                 
421                                 IMB_rect_from_float(ibuf);
422                         }
423                 }
424                 return(ibuf);
425                                 
426         }
427         catch (const std::exception &exc)
428         {
429                 std::cerr << exc.what() << std::endl;
430                 if (ibuf) IMB_freeImBuf(ibuf);
431                 
432                 return (0);
433         }
434         
435 }
436
437
438 } // export "C"