• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*M///////////////////////////////////////////////////////////////////////////////////////
2 //
3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4 //
5 //  By downloading, copying, installing or using the software you agree to this license.
6 //  If you do not agree to this license, do not download, install,
7 //  copy or use the software.
8 //
9 //
10 //                           License Agreement
11 //                For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
14 // Copyright (C) 2009, Willow Garage Inc., all rights reserved.
15 // Third party copyrights are property of their respective owners.
16 //
17 // Redistribution and use in source and binary forms, with or without modification,
18 // are permitted provided that the following conditions are met:
19 //
20 //   * Redistribution's of source code must retain the above copyright notice,
21 //     this list of conditions and the following disclaimer.
22 //
23 //   * Redistribution's in binary form must reproduce the above copyright notice,
24 //     this list of conditions and the following disclaimer in the documentation
25 //     and/or other materials provided with the distribution.
26 //
27 //   * The name of the copyright holders may not be used to endorse or promote products
28 //     derived from this software without specific prior written permission.
29 //
30 // This software is provided by the copyright holders and contributors "as is" and
31 // any express or implied warranties, including, but not limited to, the implied
32 // warranties of merchantability and fitness for a particular purpose are disclaimed.
33 // In no event shall the Intel Corporation or contributors be liable for any direct,
34 // indirect, incidental, special, exemplary, or consequential damages
35 // (including, but not limited to, procurement of substitute goods or services;
36 // loss of use, data, or profits; or business interruption) however caused
37 // and on any theory of liability, whether in contract, strict liability,
38 // or tort (including negligence or otherwise) arising in any way out of
39 // the use of this software, even if advised of the possibility of such damage.
40 //
41 //M*/
42 
43 #include "precomp.hpp"
44 
45 #ifdef HAVE_OPENEXR
46 
47 #if defined _MSC_VER && _MSC_VER >= 1200
48 #  pragma warning( disable: 4100 4244 4267 )
49 #endif
50 
51 #if defined __GNUC__ && defined __APPLE__
52 #  pragma GCC diagnostic ignored "-Wshadow"
53 #endif
54 
55 #include <ImfHeader.h>
56 #include <ImfInputFile.h>
57 #include <ImfOutputFile.h>
58 #include <ImfChannelList.h>
59 #include <ImfStandardAttributes.h>
60 #include <half.h>
61 #include "grfmt_exr.hpp"
62 
63 #if defined _WIN32
64 
65 #undef UINT
66 #define UINT ((Imf::PixelType)0)
67 #undef HALF
68 #define HALF ((Imf::PixelType)1)
69 #undef FLOAT
70 #define FLOAT ((Imf::PixelType)2)
71 
72 #endif
73 
74 namespace cv
75 {
76 
77 /////////////////////// ExrDecoder ///////////////////
78 
ExrDecoder()79 ExrDecoder::ExrDecoder()
80 {
81     m_signature = "\x76\x2f\x31\x01";
82     m_file = 0;
83     m_red = m_green = m_blue = 0;
84 }
85 
86 
~ExrDecoder()87 ExrDecoder::~ExrDecoder()
88 {
89     close();
90 }
91 
92 
close()93 void  ExrDecoder::close()
94 {
95     if( m_file )
96     {
97         delete m_file;
98         m_file = 0;
99     }
100 }
101 
102 
type() const103 int  ExrDecoder::type() const
104 {
105     return CV_MAKETYPE((m_isfloat ? CV_32F : CV_32S), m_iscolor ? 3 : 1);
106 }
107 
108 
readHeader()109 bool  ExrDecoder::readHeader()
110 {
111     bool result = false;
112 
113     m_file = new InputFile( m_filename.c_str() );
114 
115     if( !m_file ) // probably paranoid
116         return false;
117 
118     m_datawindow = m_file->header().dataWindow();
119     m_width = m_datawindow.max.x - m_datawindow.min.x + 1;
120     m_height = m_datawindow.max.y - m_datawindow.min.y + 1;
121 
122     // the type HALF is converted to 32 bit float
123     // and the other types supported by OpenEXR are 32 bit anyway
124     m_bit_depth = 32;
125 
126     if( hasChromaticities( m_file->header() ))
127         m_chroma = chromaticities( m_file->header() );
128 
129     const ChannelList &channels = m_file->header().channels();
130     m_red = channels.findChannel( "R" );
131     m_green = channels.findChannel( "G" );
132     m_blue = channels.findChannel( "B" );
133     if( m_red || m_green || m_blue )
134     {
135         m_iscolor = true;
136         m_ischroma = false;
137         result = true;
138     }
139     else
140     {
141         m_green = channels.findChannel( "Y" );
142         if( m_green )
143         {
144             m_ischroma = true;
145             m_red = channels.findChannel( "RY" );
146             m_blue = channels.findChannel( "BY" );
147             m_iscolor = (m_blue || m_red);
148             result = true;
149         }
150         else
151             result = false;
152     }
153 
154     if( result )
155     {
156         int uintcnt = 0;
157         int chcnt = 0;
158         if( m_red )
159         {
160             chcnt++;
161             uintcnt += ( m_red->type == UINT );
162         }
163         if( m_green )
164         {
165             chcnt++;
166             uintcnt += ( m_green->type == UINT );
167         }
168         if( m_blue )
169         {
170             chcnt++;
171             uintcnt += ( m_blue->type == UINT );
172         }
173         m_type = (chcnt == uintcnt) ? UINT : FLOAT;
174 
175         m_isfloat = (m_type == FLOAT);
176     }
177 
178     if( !result )
179         close();
180 
181     return result;
182 }
183 
184 
readData(Mat & img)185 bool  ExrDecoder::readData( Mat& img )
186 {
187     m_native_depth = CV_MAT_DEPTH(type()) == img.depth();
188     bool color = img.channels() > 1;
189 
190     uchar* data = img.ptr();
191     int step = img.step;
192     bool justcopy = m_native_depth;
193     bool chromatorgb = false;
194     bool rgbtogray = false;
195     bool result = true;
196     FrameBuffer frame;
197     int xsample[3] = {1, 1, 1};
198     char *buffer;
199     int xstep;
200     int ystep;
201 
202     xstep = m_native_depth ? 4 : 1;
203 
204     if( !m_native_depth || (!color && m_iscolor ))
205     {
206         buffer = (char *)new float[ m_width * 3 ];
207         ystep = 0;
208     }
209     else
210     {
211         buffer = (char *)data;
212         ystep = step;
213     }
214 
215     if( m_ischroma )
216     {
217         if( color )
218         {
219             if( m_iscolor )
220             {
221                 if( m_blue )
222                 {
223                     frame.insert( "BY", Slice( m_type,
224                                     buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep,
225                                     12, ystep, m_blue->xSampling, m_blue->ySampling, 0.0 ));
226                     xsample[0] = m_blue->ySampling;
227                 }
228                 if( m_green )
229                 {
230                     frame.insert( "Y", Slice( m_type,
231                                     buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 4,
232                                     12, ystep, m_green->xSampling, m_green->ySampling, 0.0 ));
233                     xsample[1] = m_green->ySampling;
234                 }
235                 if( m_red )
236                 {
237                     frame.insert( "RY", Slice( m_type,
238                                     buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 8,
239                                     12, ystep, m_red->xSampling, m_red->ySampling, 0.0 ));
240                     xsample[2] = m_red->ySampling;
241                 }
242                 chromatorgb = true;
243             }
244             else
245             {
246                 frame.insert( "Y", Slice( m_type,
247                               buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep,
248                               12, ystep, m_green->xSampling, m_green->ySampling, 0.0 ));
249                 frame.insert( "Y", Slice( m_type,
250                               buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 4,
251                               12, ystep, m_green->xSampling, m_green->ySampling, 0.0 ));
252                 frame.insert( "Y", Slice( m_type,
253                               buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 8,
254                               12, ystep, m_green->xSampling, m_green->ySampling, 0.0 ));
255                 xsample[0] = m_green->ySampling;
256                 xsample[1] = m_green->ySampling;
257                 xsample[2] = m_green->ySampling;
258             }
259         }
260         else
261         {
262             frame.insert( "Y", Slice( m_type,
263                             buffer - m_datawindow.min.x * 4 - m_datawindow.min.y * ystep,
264                             4, ystep, m_green->xSampling, m_green->ySampling, 0.0 ));
265             xsample[0] = m_green->ySampling;
266         }
267     }
268     else
269     {
270         if( m_blue )
271         {
272             frame.insert( "B", Slice( m_type,
273                             buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep,
274                             12, ystep, m_blue->xSampling, m_blue->ySampling, 0.0 ));
275             xsample[0] = m_blue->ySampling;
276         }
277         if( m_green )
278         {
279             frame.insert( "G", Slice( m_type,
280                             buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 4,
281                             12, ystep, m_green->xSampling, m_green->ySampling, 0.0 ));
282             xsample[1] = m_green->ySampling;
283         }
284         if( m_red )
285         {
286             frame.insert( "R", Slice( m_type,
287                             buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 8,
288                             12, ystep, m_red->xSampling, m_red->ySampling, 0.0 ));
289             xsample[2] = m_red->ySampling;
290         }
291         if(color == 0)
292         {
293             rgbtogray = true;
294             justcopy = false;
295         }
296     }
297 
298     m_file->setFrameBuffer( frame );
299     if( justcopy )
300     {
301         m_file->readPixels( m_datawindow.min.y, m_datawindow.max.y );
302 
303         if( color )
304         {
305             if( m_blue && (m_blue->xSampling != 1 || m_blue->ySampling != 1) )
306                 UpSample( data, 3, step / xstep, xsample[0], m_blue->ySampling );
307             if( m_green && (m_green->xSampling != 1 || m_green->ySampling != 1) )
308                 UpSample( data + xstep, 3, step / xstep, xsample[1], m_green->ySampling );
309             if( m_red && (m_red->xSampling != 1 || m_red->ySampling != 1) )
310                 UpSample( data + 2 * xstep, 3, step / xstep, xsample[2], m_red->ySampling );
311         }
312         else if( m_green && (m_green->xSampling != 1 || m_green->ySampling != 1) )
313             UpSample( data, 1, step / xstep, xsample[0], m_green->ySampling );
314     }
315     else
316     {
317         uchar *out = data;
318         int x, y;
319         for( y = m_datawindow.min.y; y <= m_datawindow.max.y; y++ )
320         {
321             m_file->readPixels( y, y );
322 
323             if( rgbtogray )
324             {
325                 if( xsample[0] != 1 )
326                     UpSampleX( (float *)buffer, 3, xsample[0] );
327                 if( xsample[1] != 1 )
328                     UpSampleX( (float *)buffer + 4, 3, xsample[1] );
329                 if( xsample[2] != 1 )
330                     UpSampleX( (float *)buffer + 8, 3, xsample[2] );
331 
332                 RGBToGray( (float *)buffer, (float *)out );
333             }
334             else
335             {
336                 if( xsample[0] != 1 )
337                     UpSampleX( (float *)buffer, 3, xsample[0] );
338                 if( xsample[1] != 1 )
339                     UpSampleX( (float *)(buffer + 4), 3, xsample[1] );
340                 if( xsample[2] != 1 )
341                     UpSampleX( (float *)(buffer + 8), 3, xsample[2] );
342 
343                 if( chromatorgb )
344                     ChromaToBGR( (float *)buffer, 1, step );
345 
346                 if( m_type == FLOAT )
347                 {
348                     float *fi = (float *)buffer;
349                     for( x = 0; x < m_width * 3; x++)
350                     {
351                         out[x] = cv::saturate_cast<uchar>(fi[x]*5);
352                     }
353                 }
354                 else
355                 {
356                     unsigned *ui = (unsigned *)buffer;
357                     for( x = 0; x < m_width * 3; x++)
358                     {
359                         out[x] = cv::saturate_cast<uchar>(ui[x]);
360                     }
361                 }
362             }
363 
364             out += step;
365         }
366         if( color )
367         {
368             if( m_blue && (m_blue->xSampling != 1 || m_blue->ySampling != 1) )
369                 UpSampleY( data, 3, step / xstep, m_blue->ySampling );
370             if( m_green && (m_green->xSampling != 1 || m_green->ySampling != 1) )
371                 UpSampleY( data + xstep, 3, step / xstep, m_green->ySampling );
372             if( m_red && (m_red->xSampling != 1 || m_red->ySampling != 1) )
373                 UpSampleY( data + 2 * xstep, 3, step / xstep, m_red->ySampling );
374         }
375         else if( m_green && (m_green->xSampling != 1 || m_green->ySampling != 1) )
376             UpSampleY( data, 1, step / xstep, m_green->ySampling );
377     }
378 
379     if( chromatorgb )
380         ChromaToBGR( (float *)data, m_height, step / xstep );
381 
382     close();
383 
384     return result;
385 }
386 
387 /**
388 // on entry pixel values are stored packed in the upper left corner of the image
389 // this functions expands them by duplication to cover the whole image
390  */
UpSample(uchar * data,int xstep,int ystep,int xsample,int ysample)391 void  ExrDecoder::UpSample( uchar *data, int xstep, int ystep, int xsample, int ysample )
392 {
393     for( int y = (m_height - 1) / ysample, yre = m_height - ysample; y >= 0; y--, yre -= ysample )
394     {
395         for( int x = (m_width - 1) / xsample, xre = m_width - xsample; x >= 0; x--, xre -= xsample )
396         {
397             for( int i = 0; i < ysample; i++ )
398             {
399                 for( int n = 0; n < xsample; n++ )
400                 {
401                     if( !m_native_depth )
402                         data[(yre + i) * ystep + (xre + n) * xstep] = data[y * ystep + x * xstep];
403                     else if( m_type == FLOAT )
404                         ((float *)data)[(yre + i) * ystep + (xre + n) * xstep] = ((float *)data)[y * ystep + x * xstep];
405                     else
406                         ((unsigned *)data)[(yre + i) * ystep + (xre + n) * xstep] = ((unsigned *)data)[y * ystep + x * xstep];
407                 }
408             }
409         }
410     }
411 }
412 
413 /**
414 // on entry pixel values are stored packed in the upper left corner of the image
415 // this functions expands them by duplication to cover the whole image
416  */
UpSampleX(float * data,int xstep,int xsample)417 void  ExrDecoder::UpSampleX( float *data, int xstep, int xsample )
418 {
419     for( int x = (m_width - 1) / xsample, xre = m_width - xsample; x >= 0; x--, xre -= xsample )
420     {
421         for( int n = 0; n < xsample; n++ )
422         {
423             if( m_type == FLOAT )
424                 ((float *)data)[(xre + n) * xstep] = ((float *)data)[x * xstep];
425             else
426                 ((unsigned *)data)[(xre + n) * xstep] = ((unsigned *)data)[x * xstep];
427         }
428     }
429 }
430 
431 /**
432 // on entry pixel values are stored packed in the upper left corner of the image
433 // this functions expands them by duplication to cover the whole image
434  */
UpSampleY(uchar * data,int xstep,int ystep,int ysample)435 void  ExrDecoder::UpSampleY( uchar *data, int xstep, int ystep, int ysample )
436 {
437     for( int y = m_height - ysample, yre = m_height - ysample; y >= 0; y -= ysample, yre -= ysample )
438     {
439         for( int x = 0; x < m_width; x++ )
440         {
441             for( int i = 1; i < ysample; i++ )
442             {
443                 if( !m_native_depth )
444                     data[(yre + i) * ystep + x * xstep] = data[y * ystep + x * xstep];
445                 else if( m_type == FLOAT )
446                     ((float *)data)[(yre + i) * ystep + x * xstep] = ((float *)data)[y * ystep + x * xstep];
447                 else
448                     ((unsigned *)data)[(yre + i) * ystep + x * xstep] = ((unsigned *)data)[y * ystep + x * xstep];
449             }
450         }
451     }
452 }
453 
454 /**
455 // algorithm from ImfRgbaYca.cpp
456  */
ChromaToBGR(float * data,int numlines,int step)457 void  ExrDecoder::ChromaToBGR( float *data, int numlines, int step )
458 {
459     for( int y = 0; y < numlines; y++ )
460     {
461         for( int x = 0; x < m_width; x++ )
462         {
463             double b, Y, r;
464             if( !m_native_depth )
465             {
466                 b = ((uchar *)data)[y * step + x * 3];
467                 Y = ((uchar *)data)[y * step + x * 3 + 1];
468                 r = ((uchar *)data)[y * step + x * 3 + 2];
469             }
470             else if( m_type == FLOAT )
471             {
472                 b = data[y * step + x * 3];
473                 Y = data[y * step + x * 3 + 1];
474                 r = data[y * step + x * 3 + 2];
475             }
476             else
477             {
478                 b = ((unsigned *)data)[y * step + x * 3];
479                 Y = ((unsigned *)data)[y * step + x * 3 + 1];
480                 r = ((unsigned *)data)[y * step + x * 3 + 2];
481             }
482             r = (r + 1) * Y;
483             b = (b + 1) * Y;
484             Y = (Y - b * m_chroma.blue[1] - r * m_chroma.red[1]) / m_chroma.green[1];
485 
486             if( !m_native_depth )
487             {
488                 ((uchar *)data)[y * step + x * 3 + 0] = cv::saturate_cast<uchar>(b);
489                 ((uchar *)data)[y * step + x * 3 + 1] = cv::saturate_cast<uchar>(Y);
490                 ((uchar *)data)[y * step + x * 3 + 2] = cv::saturate_cast<uchar>(r);
491             }
492             else if( m_type == FLOAT )
493             {
494                 data[y * step + x * 3] = (float)b;
495                 data[y * step + x * 3 + 1] = (float)Y;
496                 data[y * step + x * 3 + 2] = (float)r;
497             }
498             else
499             {
500                 int t = cvRound(b);
501                 ((unsigned *)data)[y * step + x * 3 + 0] = (unsigned)MAX(t, 0);
502                 t = cvRound(Y);
503                 ((unsigned *)data)[y * step + x * 3 + 1] = (unsigned)MAX(t, 0);
504                 t = cvRound(r);
505                 ((unsigned *)data)[y * step + x * 3 + 2] = (unsigned)MAX(t, 0);
506             }
507         }
508     }
509 }
510 
511 
512 /**
513 // convert one row to gray
514 */
RGBToGray(float * in,float * out)515 void  ExrDecoder::RGBToGray( float *in, float *out )
516 {
517     if( m_type == FLOAT )
518     {
519         if( m_native_depth )
520         {
521             for( int i = 0, n = 0; i < m_width; i++, n += 3 )
522                 out[i] = in[n] * m_chroma.blue[0] + in[n + 1] * m_chroma.green[0] + in[n + 2] * m_chroma.red[0];
523         }
524         else
525         {
526             uchar *o = (uchar *)out;
527             for( int i = 0, n = 0; i < m_width; i++, n += 3 )
528                 o[i] = (uchar) (in[n] * m_chroma.blue[0] + in[n + 1] * m_chroma.green[0] + in[n + 2] * m_chroma.red[0]);
529         }
530     }
531     else // UINT
532     {
533         if( m_native_depth )
534         {
535             unsigned *ui = (unsigned *)in;
536             for( int i = 0; i < m_width * 3; i++ )
537                 ui[i] -= 0x80000000;
538             int *si = (int *)in;
539             for( int i = 0, n = 0; i < m_width; i++, n += 3 )
540                 ((int *)out)[i] = int(si[n] * m_chroma.blue[0] + si[n + 1] * m_chroma.green[0] + si[n + 2] * m_chroma.red[0]);
541         }
542         else // how to best convert float to uchar?
543         {
544             unsigned *ui = (unsigned *)in;
545             for( int i = 0, n = 0; i < m_width; i++, n += 3 )
546                 ((uchar *)out)[i] = uchar((ui[n] * m_chroma.blue[0] + ui[n + 1] * m_chroma.green[0] + ui[n + 2] * m_chroma.red[0]) * (256.0 / 4294967296.0));
547         }
548     }
549 }
550 
551 
newDecoder() const552 ImageDecoder ExrDecoder::newDecoder() const
553 {
554     return makePtr<ExrDecoder>();
555 }
556 
557 /////////////////////// ExrEncoder ///////////////////
558 
559 
ExrEncoder()560 ExrEncoder::ExrEncoder()
561 {
562     m_description = "OpenEXR Image files (*.exr)";
563 }
564 
565 
~ExrEncoder()566 ExrEncoder::~ExrEncoder()
567 {
568 }
569 
570 
isFormatSupported(int depth) const571 bool  ExrEncoder::isFormatSupported( int depth ) const
572 {
573     return CV_MAT_DEPTH(depth) >= CV_8U && CV_MAT_DEPTH(depth) < CV_64F;
574 }
575 
576 
577 // TODO scale appropriately
write(const Mat & img,const std::vector<int> &)578 bool  ExrEncoder::write( const Mat& img, const std::vector<int>& )
579 {
580     int width = img.cols, height = img.rows;
581     int depth = img.depth(), channels = img.channels();
582     bool result = false;
583     bool issigned = depth == CV_8S || depth == CV_16S || depth == CV_32S;
584     bool isfloat = depth == CV_32F || depth == CV_64F;
585     depth = CV_ELEM_SIZE1(depth)*8;
586     const int step = img.step;
587 
588     Header header( width, height );
589     Imf::PixelType type;
590 
591     if(depth == 8)
592         type = HALF;
593     else if(isfloat)
594         type = FLOAT;
595     else
596         type = UINT;
597 
598     if( channels == 3 )
599     {
600         header.channels().insert( "R", Channel( type ));
601         header.channels().insert( "G", Channel( type ));
602         header.channels().insert( "B", Channel( type ));
603         //printf("bunt\n");
604     }
605     else
606     {
607         header.channels().insert( "Y", Channel( type ));
608         //printf("gray\n");
609     }
610 
611     OutputFile file( m_filename.c_str(), header );
612 
613     FrameBuffer frame;
614 
615     char *buffer;
616     int bufferstep;
617     int size;
618     if( type == FLOAT && depth == 32 )
619     {
620         buffer = (char *)const_cast<uchar *>(img.ptr());
621         bufferstep = step;
622         size = 4;
623     }
624     else if( depth > 16 || type == UINT )
625     {
626         buffer = (char *)new unsigned[width * channels];
627         bufferstep = 0;
628         size = 4;
629     }
630     else
631     {
632         buffer = (char *)new half[width * channels];
633         bufferstep = 0;
634         size = 2;
635     }
636 
637     //printf("depth %d %s\n", depth, types[type]);
638 
639     if( channels == 3 )
640     {
641         frame.insert( "B", Slice( type, buffer, size * 3, bufferstep ));
642         frame.insert( "G", Slice( type, buffer + size, size * 3, bufferstep ));
643         frame.insert( "R", Slice( type, buffer + size * 2, size * 3, bufferstep ));
644     }
645     else
646         frame.insert( "Y", Slice( type, buffer, size, bufferstep ));
647 
648     file.setFrameBuffer( frame );
649 
650     int offset = issigned ? 1 << (depth - 1) : 0;
651 
652     result = true;
653     if( type == FLOAT && depth == 32 )
654     {
655         try
656         {
657             file.writePixels( height );
658         }
659         catch(...)
660         {
661             result = false;
662         }
663     }
664     else
665     {
666     //    int scale = 1 << (32 - depth);
667     //    printf("scale %d\n", scale);
668         for(int line = 0; line < height; line++)
669         {
670             if(type == UINT)
671             {
672                 unsigned *buf = (unsigned*)buffer; // FIXME 64-bit problems
673 
674                 if( depth <= 8 )
675                 {
676                     const uchar* sd = img.ptr(line);
677                     for(int i = 0; i < width * channels; i++)
678                         buf[i] = sd[i] + offset;
679                 }
680                 else if( depth <= 16 )
681                 {
682                     const unsigned short *sd = img.ptr<unsigned short>(line);
683                     for(int i = 0; i < width * channels; i++)
684                         buf[i] = sd[i] + offset;
685                 }
686                 else
687                 {
688                     const int *sd = img.ptr<int>(line); // FIXME 64-bit problems
689                     for(int i = 0; i < width * channels; i++)
690                         buf[i] = (unsigned) sd[i] + offset;
691                 }
692             }
693             else
694             {
695                 half *buf = (half *)buffer;
696 
697                 if( depth <= 8 )
698                 {
699                     const uchar* sd = img.ptr(line);
700                     for(int i = 0; i < width * channels; i++)
701                         buf[i] = sd[i];
702                 }
703                 else if( depth <= 16 )
704                 {
705                     const unsigned short *sd = img.ptr<unsigned short>(line);
706                     for(int i = 0; i < width * channels; i++)
707                         buf[i] = sd[i];
708                 }
709             }
710             try
711             {
712                 file.writePixels( 1 );
713             }
714             catch(...)
715             {
716                 result = false;
717                 break;
718             }
719         }
720         delete[] buffer;
721     }
722 
723     return result;
724 }
725 
726 
newEncoder() const727 ImageEncoder ExrEncoder::newEncoder() const
728 {
729     return makePtr<ExrEncoder>();
730 }
731 
732 }
733 
734 #endif
735 
736 /* End of file. */
737