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