| /*M/////////////////////////////////////////////////////////////////////////////////////// |
| // |
| // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. |
| // |
| // By downloading, copying, installing or using the software you agree to this license. |
| // If you do not agree to this license, do not download, install, |
| // copy or use the software. |
| // |
| // |
| // Intel License Agreement |
| // For Open Source Computer Vision Library |
| // |
| // Copyright (C) 2000, Intel Corporation, all rights reserved. |
| // Third party copyrights are property of their respective owners. |
| // |
| // Redistribution and use in source and binary forms, with or without modification, |
| // are permitted provided that the following conditions are met: |
| // |
| // * Redistribution's of source code must retain the above copyright notice, |
| // this list of conditions and the following disclaimer. |
| // |
| // * Redistribution's in binary form must reproduce the above copyright notice, |
| // this list of conditions and the following disclaimer in the documentation |
| // and/or other materials provided with the distribution. |
| // |
| // * The name of Intel Corporation may not be used to endorse or promote products |
| // derived from this software without specific prior written permission. |
| // |
| // This software is provided by the copyright holders and contributors "as is" and |
| // any express or implied warranties, including, but not limited to, the implied |
| // warranties of merchantability and fitness for a particular purpose are disclaimed. |
| // In no event shall the Intel Corporation or contributors be liable for any direct, |
| // indirect, incidental, special, exemplary, or consequential damages |
| // (including, but not limited to, procurement of substitute goods or services; |
| // loss of use, data, or profits; or business interruption) however caused |
| // and on any theory of liability, whether in contract, strict liability, |
| // or tort (including negligence or otherwise) arising in any way out of |
| // the use of this software, even if advised of the possibility of such damage. |
| // |
| //M*/ |
| |
| #include "_highgui.h" |
| |
| #ifdef HAVE_ILMIMF |
| |
| #include <OpenEXR/ImfHeader.h> |
| #include <OpenEXR/ImfInputFile.h> |
| #include <OpenEXR/ImfOutputFile.h> |
| #include <OpenEXR/ImfChannelList.h> |
| #include <OpenEXR/ImfStandardAttributes.h> |
| #include <OpenEXR/half.h> |
| #include "grfmt_exr.h" |
| |
| #if defined _MSC_VER && _MSC_VER >= 1200 |
| #pragma comment(lib, "Half.lib") |
| #pragma comment(lib, "Iex.lib") |
| #pragma comment(lib, "IlmImf.lib") |
| #pragma comment(lib, "IlmThread.lib") |
| #pragma comment(lib, "Imath.lib") |
| |
| #undef UINT |
| #define UINT ((Imf::PixelType)0) |
| #undef HALF |
| #define HALF ((Imf::PixelType)1) |
| #undef FLOAT |
| #define FLOAT ((Imf::PixelType)2) |
| #undef uint |
| #define uint unsigned |
| |
| #endif |
| |
| // Exr Filter Factory |
| GrFmtExr::GrFmtExr() |
| { |
| m_sign_len = 4; |
| m_signature = "\x76\x2f\x31\x01"; |
| m_description = "OpenEXR Image files (*.exr)"; |
| } |
| |
| |
| GrFmtExr::~GrFmtExr() |
| { |
| } |
| |
| |
| GrFmtReader* GrFmtExr::NewReader( const char* filename ) |
| { |
| return new GrFmtExrReader( filename ); |
| } |
| |
| |
| GrFmtWriter* GrFmtExr::NewWriter( const char* filename ) |
| { |
| return new GrFmtExrWriter( filename ); |
| } |
| |
| |
| /////////////////////// GrFmtExrReader /////////////////// |
| |
| GrFmtExrReader::GrFmtExrReader( const char* filename ) : GrFmtReader( filename ) |
| { |
| m_file = new InputFile( filename ); |
| m_red = m_green = m_blue = 0; |
| } |
| |
| |
| GrFmtExrReader::~GrFmtExrReader() |
| { |
| Close(); |
| } |
| |
| |
| void GrFmtExrReader::Close() |
| { |
| if( m_file ) |
| { |
| delete m_file; |
| m_file = 0; |
| } |
| |
| GrFmtReader::Close(); |
| } |
| |
| bool GrFmtExrReader::ReadHeader() |
| { |
| bool result = false; |
| |
| if( !m_file ) // probably paranoid |
| return false; |
| |
| m_datawindow = m_file->header().dataWindow(); |
| m_width = m_datawindow.max.x - m_datawindow.min.x + 1; |
| m_height = m_datawindow.max.y - m_datawindow.min.y + 1; |
| |
| // the type HALF is converted to 32 bit float |
| // and the other types supported by OpenEXR are 32 bit anyway |
| m_bit_depth = 32; |
| |
| if( hasChromaticities( m_file->header() )) |
| m_chroma = chromaticities( m_file->header() ); |
| |
| const ChannelList &channels = m_file->header().channels(); |
| m_red = channels.findChannel( "R" ); |
| m_green = channels.findChannel( "G" ); |
| m_blue = channels.findChannel( "B" ); |
| if( m_red || m_green || m_blue ) |
| { |
| m_iscolor = true; |
| m_ischroma = false; |
| result = true; |
| } |
| else |
| { |
| m_green = channels.findChannel( "Y" ); |
| if( m_green ) |
| { |
| m_ischroma = true; |
| m_red = channels.findChannel( "RY" ); |
| m_blue = channels.findChannel( "BY" ); |
| m_iscolor = (m_blue || m_red); |
| result = true; |
| } |
| else |
| result = false; |
| } |
| |
| if( result ) |
| { |
| int uintcnt = 0; |
| int chcnt = 0; |
| if( m_red ) |
| { |
| chcnt++; |
| uintcnt += ( m_red->type == UINT ); |
| } |
| if( m_green ) |
| { |
| chcnt++; |
| uintcnt += ( m_green->type == UINT ); |
| } |
| if( m_blue ) |
| { |
| chcnt++; |
| uintcnt += ( m_blue->type == UINT ); |
| } |
| m_type = (chcnt == uintcnt) ? UINT : FLOAT; |
| |
| m_isfloat = (m_type == FLOAT); |
| } |
| |
| if( !result ) |
| Close(); |
| |
| return result; |
| } |
| |
| |
| bool GrFmtExrReader::ReadData( uchar* data, int step, int color ) |
| { |
| bool justcopy = m_native_depth; |
| bool chromatorgb = false; |
| bool rgbtogray = false; |
| bool result = true; |
| FrameBuffer frame; |
| int xsample[3] = {1, 1, 1}; |
| char *buffer; |
| int xstep; |
| int ystep; |
| |
| xstep = m_native_depth ? 4 : 1; |
| |
| if( !m_native_depth || (!color && m_iscolor )) |
| { |
| buffer = (char *)new float[ m_width * 3 ]; |
| ystep = 0; |
| } |
| else |
| { |
| buffer = (char *)data; |
| ystep = step; |
| } |
| |
| if( m_ischroma ) |
| { |
| if( color ) |
| { |
| if( m_iscolor ) |
| { |
| if( m_blue ) |
| { |
| frame.insert( "BY", Slice( m_type, |
| buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep, |
| 12, ystep, m_blue->xSampling, m_blue->ySampling, 0.0 )); |
| xsample[0] = m_blue->ySampling; |
| } |
| if( m_green ) |
| { |
| frame.insert( "Y", Slice( m_type, |
| buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 4, |
| 12, ystep, m_green->xSampling, m_green->ySampling, 0.0 )); |
| xsample[1] = m_green->ySampling; |
| } |
| if( m_red ) |
| { |
| frame.insert( "RY", Slice( m_type, |
| buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 8, |
| 12, ystep, m_red->xSampling, m_red->ySampling, 0.0 )); |
| xsample[2] = m_red->ySampling; |
| } |
| chromatorgb = true; |
| } |
| else |
| { |
| frame.insert( "Y", Slice( m_type, |
| buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep, |
| 12, ystep, m_green->xSampling, m_green->ySampling, 0.0 )); |
| frame.insert( "Y", Slice( m_type, |
| buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 4, |
| 12, ystep, m_green->xSampling, m_green->ySampling, 0.0 )); |
| frame.insert( "Y", Slice( m_type, |
| buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 8, |
| 12, ystep, m_green->xSampling, m_green->ySampling, 0.0 )); |
| xsample[0] = m_green->ySampling; |
| xsample[1] = m_green->ySampling; |
| xsample[2] = m_green->ySampling; |
| } |
| } |
| else |
| { |
| frame.insert( "Y", Slice( m_type, |
| buffer - m_datawindow.min.x * 4 - m_datawindow.min.y * ystep, |
| 4, ystep, m_green->xSampling, m_green->ySampling, 0.0 )); |
| xsample[0] = m_green->ySampling; |
| } |
| } |
| else |
| { |
| if( m_blue ) |
| { |
| frame.insert( "B", Slice( m_type, |
| buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep, |
| 12, ystep, m_blue->xSampling, m_blue->ySampling, 0.0 )); |
| xsample[0] = m_blue->ySampling; |
| } |
| if( m_green ) |
| { |
| frame.insert( "G", Slice( m_type, |
| buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 4, |
| 12, ystep, m_green->xSampling, m_green->ySampling, 0.0 )); |
| xsample[1] = m_green->ySampling; |
| } |
| if( m_red ) |
| { |
| frame.insert( "R", Slice( m_type, |
| buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 8, |
| 12, ystep, m_red->xSampling, m_red->ySampling, 0.0 )); |
| xsample[2] = m_red->ySampling; |
| } |
| if(color == 0) |
| { |
| rgbtogray = true; |
| justcopy = false; |
| } |
| } |
| |
| m_file->setFrameBuffer( frame ); |
| if( justcopy ) |
| { |
| m_file->readPixels( m_datawindow.min.y, m_datawindow.max.y ); |
| |
| if( color ) |
| { |
| if( m_blue && (m_blue->xSampling != 1 || m_blue->ySampling != 1) ) |
| UpSample( data, 3, step / xstep, xsample[0], m_blue->ySampling ); |
| if( m_green && (m_green->xSampling != 1 || m_green->ySampling != 1) ) |
| UpSample( data + xstep, 3, step / xstep, xsample[1], m_green->ySampling ); |
| if( m_red && (m_red->xSampling != 1 || m_red->ySampling != 1) ) |
| UpSample( data + 2 * xstep, 3, step / xstep, xsample[2], m_red->ySampling ); |
| } |
| else if( m_green && (m_green->xSampling != 1 || m_green->ySampling != 1) ) |
| UpSample( data, 1, step / xstep, xsample[0], m_green->ySampling ); |
| } |
| else |
| { |
| uchar *out = data; |
| int x, y; |
| for( y = m_datawindow.min.y; y <= m_datawindow.max.y; y++ ) |
| { |
| m_file->readPixels( y, y ); |
| |
| if( rgbtogray ) |
| { |
| if( xsample[0] != 1 ) |
| UpSampleX( (float *)buffer, 3, xsample[0] ); |
| if( xsample[1] != 1 ) |
| UpSampleX( (float *)buffer + 4, 3, xsample[1] ); |
| if( xsample[2] != 1 ) |
| UpSampleX( (float *)buffer + 8, 3, xsample[2] ); |
| |
| RGBToGray( (float *)buffer, (float *)out ); |
| } |
| else |
| { |
| if( xsample[0] != 1 ) |
| UpSampleX( (float *)buffer, 3, xsample[0] ); |
| if( xsample[1] != 1 ) |
| UpSampleX( (float *)(buffer + 4), 3, xsample[1] ); |
| if( xsample[2] != 1 ) |
| UpSampleX( (float *)(buffer + 8), 3, xsample[2] ); |
| |
| if( chromatorgb ) |
| ChromaToBGR( (float *)buffer, 1, step ); |
| |
| if( m_type == FLOAT ) |
| { |
| float *fi = (float *)buffer; |
| for( x = 0; x < m_width * 3; x++) |
| { |
| int t = cvRound(fi[x]*5); |
| out[x] = CV_CAST_8U(t); |
| } |
| } |
| else |
| { |
| uint *ui = (uint *)buffer; |
| for( x = 0; x < m_width * 3; x++) |
| { |
| uint t = ui[x]; |
| out[x] = CV_CAST_8U(t); |
| } |
| } |
| } |
| |
| out += step; |
| } |
| if( color ) |
| { |
| if( m_blue && (m_blue->xSampling != 1 || m_blue->ySampling != 1) ) |
| UpSampleY( data, 3, step / xstep, m_blue->ySampling ); |
| if( m_green && (m_green->xSampling != 1 || m_green->ySampling != 1) ) |
| UpSampleY( data + xstep, 3, step / xstep, m_green->ySampling ); |
| if( m_red && (m_red->xSampling != 1 || m_red->ySampling != 1) ) |
| UpSampleY( data + 2 * xstep, 3, step / xstep, m_red->ySampling ); |
| } |
| else if( m_green && (m_green->xSampling != 1 || m_green->ySampling != 1) ) |
| UpSampleY( data, 1, step / xstep, m_green->ySampling ); |
| } |
| |
| if( chromatorgb ) |
| ChromaToBGR( (float *)data, m_height, step / xstep ); |
| |
| Close(); |
| |
| return result; |
| } |
| |
| /** |
| // on entry pixel values are stored packed in the upper left corner of the image |
| // this functions expands them by duplication to cover the whole image |
| */ |
| void GrFmtExrReader::UpSample( uchar *data, int xstep, int ystep, int xsample, int ysample ) |
| { |
| for( int y = (m_height - 1) / ysample, yre = m_height - ysample; y >= 0; y--, yre -= ysample ) |
| { |
| for( int x = (m_width - 1) / xsample, xre = m_width - xsample; x >= 0; x--, xre -= xsample ) |
| { |
| for( int i = 0; i < ysample; i++ ) |
| { |
| for( int n = 0; n < xsample; n++ ) |
| { |
| if( !m_native_depth ) |
| data[(yre + i) * ystep + (xre + n) * xstep] = data[y * ystep + x * xstep]; |
| else if( m_type == FLOAT ) |
| ((float *)data)[(yre + i) * ystep + (xre + n) * xstep] = ((float *)data)[y * ystep + x * xstep]; |
| else |
| ((uint *)data)[(yre + i) * ystep + (xre + n) * xstep] = ((uint *)data)[y * ystep + x * xstep]; |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| // on entry pixel values are stored packed in the upper left corner of the image |
| // this functions expands them by duplication to cover the whole image |
| */ |
| void GrFmtExrReader::UpSampleX( float *data, int xstep, int xsample ) |
| { |
| for( int x = (m_width - 1) / xsample, xre = m_width - xsample; x >= 0; x--, xre -= xsample ) |
| { |
| for( int n = 0; n < xsample; n++ ) |
| { |
| if( m_type == FLOAT ) |
| ((float *)data)[(xre + n) * xstep] = ((float *)data)[x * xstep]; |
| else |
| ((uint *)data)[(xre + n) * xstep] = ((uint *)data)[x * xstep]; |
| } |
| } |
| } |
| |
| /** |
| // on entry pixel values are stored packed in the upper left corner of the image |
| // this functions expands them by duplication to cover the whole image |
| */ |
| void GrFmtExrReader::UpSampleY( uchar *data, int xstep, int ystep, int ysample ) |
| { |
| for( int y = m_height - ysample, yre = m_height - ysample; y >= 0; y -= ysample, yre -= ysample ) |
| { |
| for( int x = 0; x < m_width; x++ ) |
| { |
| for( int i = 1; i < ysample; i++ ) |
| { |
| if( !m_native_depth ) |
| data[(yre + i) * ystep + x * xstep] = data[y * ystep + x * xstep]; |
| else if( m_type == FLOAT ) |
| ((float *)data)[(yre + i) * ystep + x * xstep] = ((float *)data)[y * ystep + x * xstep]; |
| else |
| ((uint *)data)[(yre + i) * ystep + x * xstep] = ((uint *)data)[y * ystep + x * xstep]; |
| } |
| } |
| } |
| } |
| |
| /** |
| // algorithm from ImfRgbaYca.cpp |
| */ |
| void GrFmtExrReader::ChromaToBGR( float *data, int numlines, int step ) |
| { |
| int x, y, t; |
| |
| for( y = 0; y < numlines; y++ ) |
| { |
| for( x = 0; x < m_width; x++ ) |
| { |
| double b, Y, r; |
| if( !m_native_depth ) |
| { |
| b = ((uchar *)data)[y * step + x * 3]; |
| Y = ((uchar *)data)[y * step + x * 3 + 1]; |
| r = ((uchar *)data)[y * step + x * 3 + 2]; |
| } |
| else if( m_type == FLOAT ) |
| { |
| b = data[y * step + x * 3]; |
| Y = data[y * step + x * 3 + 1]; |
| r = data[y * step + x * 3 + 2]; |
| } |
| else |
| { |
| b = ((uint *)data)[y * step + x * 3]; |
| Y = ((uint *)data)[y * step + x * 3 + 1]; |
| r = ((uint *)data)[y * step + x * 3 + 2]; |
| } |
| r = (r + 1) * Y; |
| b = (b + 1) * Y; |
| Y = (Y - b * m_chroma.blue[1] - r * m_chroma.red[1]) / m_chroma.green[1]; |
| |
| if( !m_native_depth ) |
| { |
| int t = cvRound(b); |
| ((uchar *)data)[y * step + x * 3] = CV_CAST_8U(t); |
| t = cvRound(Y); |
| ((uchar *)data)[y * step + x * 3 + 1] = CV_CAST_8U(t); |
| t = cvRound(r); |
| ((uchar *)data)[y * step + x * 3 + 2] = CV_CAST_8U(t); |
| } |
| else if( m_type == FLOAT ) |
| { |
| data[y * step + x * 3] = (float)b; |
| data[y * step + x * 3 + 1] = (float)Y; |
| data[y * step + x * 3 + 2] = (float)r; |
| } |
| else |
| { |
| int t = cvRound(b); |
| ((uint *)data)[y * step + x * 3] = (uint)MAX(t,0); |
| t = cvRound(Y); |
| ((uint *)data)[y * step + x * 3 + 1] = (uint)MAX(t,0); |
| t = cvRound(r); |
| ((uint *)data)[y * step + x * 3 + 2] = (uint)MAX(t,0); |
| } |
| } |
| } |
| } |
| |
| |
| /** |
| // convert one row to gray |
| */ |
| void GrFmtExrReader::RGBToGray( float *in, float *out ) |
| { |
| if( m_type == FLOAT ) |
| { |
| if( m_native_depth ) |
| { |
| for( int i = 0, n = 0; i < m_width; i++, n += 3 ) |
| out[i] = in[n] * m_chroma.blue[0] + in[n + 1] * m_chroma.green[0] + in[n + 2] * m_chroma.red[0]; |
| } |
| else |
| { |
| uchar *o = (uchar *)out; |
| for( int i = 0, n = 0; i < m_width; i++, n += 3 ) |
| o[i] = (uchar) (in[n] * m_chroma.blue[0] + in[n + 1] * m_chroma.green[0] + in[n + 2] * m_chroma.red[0]); |
| } |
| } |
| else // UINT |
| { |
| if( m_native_depth ) |
| { |
| uint *ui = (uint *)in; |
| for( int i = 0; i < m_width * 3; i++ ) |
| ui[i] -= 0x80000000; |
| int *si = (int *)in; |
| for( int i = 0, n = 0; i < m_width; i++, n += 3 ) |
| ((int *)out)[i] = int(si[n] * m_chroma.blue[0] + si[n + 1] * m_chroma.green[0] + si[n + 2] * m_chroma.red[0]); |
| } |
| else // how to best convert float to uchar? |
| { |
| uint *ui = (uint *)in; |
| for( int i = 0, n = 0; i < m_width; i++, n += 3 ) |
| ((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)); |
| } |
| } |
| } |
| |
| /////////////////////// GrFmtExrWriter /////////////////// |
| |
| |
| GrFmtExrWriter::GrFmtExrWriter( const char* filename ) : GrFmtWriter( filename ) |
| { |
| } |
| |
| |
| GrFmtExrWriter::~GrFmtExrWriter() |
| { |
| } |
| |
| |
| bool GrFmtExrWriter::IsFormatSupported( int depth ) |
| { |
| return depth == IPL_DEPTH_8U || depth == IPL_DEPTH_8S || |
| depth == IPL_DEPTH_16U || depth == IPL_DEPTH_16S || |
| depth == IPL_DEPTH_32S || depth == IPL_DEPTH_32F; |
| // TODO: do (or should) we support 64f? |
| } |
| |
| |
| // TODO scale appropriately |
| bool GrFmtExrWriter::WriteImage( const uchar* data, int step, |
| int width, int height, int depth, int channels ) |
| { |
| bool result = false; |
| |
| Header header( width, height ); |
| PixelType type; |
| bool issigned = depth < 0; |
| bool isfloat = depth == IPL_DEPTH_32F || depth == IPL_DEPTH_64F; |
| |
| if(depth == IPL_DEPTH_8U || depth == IPL_DEPTH_8S) |
| type = HALF; |
| else if(isfloat) |
| type = FLOAT; |
| else |
| type = UINT; |
| |
| depth &= 255; |
| |
| if( channels == 3 ) |
| { |
| header.channels().insert( "R", Channel( type )); |
| header.channels().insert( "G", Channel( type )); |
| header.channels().insert( "B", Channel( type )); |
| //printf("bunt\n"); |
| } |
| else |
| { |
| header.channels().insert( "Y", Channel( type )); |
| //printf("gray\n"); |
| } |
| |
| OutputFile file( m_filename, header ); |
| |
| FrameBuffer frame; |
| |
| char *buffer; |
| int bufferstep; |
| int size; |
| if( type == FLOAT && depth == 32 ) |
| { |
| buffer = (char *)const_cast<uchar *>(data); |
| bufferstep = step; |
| size = 4; |
| } |
| else if( depth > 16 || type == UINT ) |
| { |
| buffer = (char *)new uint[width * channels]; |
| bufferstep = 0; |
| size = 4; |
| } |
| else |
| { |
| buffer = (char *)new half[width * channels]; |
| bufferstep = 0; |
| size = 2; |
| } |
| |
| //printf("depth %d %s\n", depth, types[type]); |
| |
| if( channels == 3 ) |
| { |
| frame.insert( "B", Slice( type, buffer, size * 3, bufferstep )); |
| frame.insert( "G", Slice( type, buffer + size, size * 3, bufferstep )); |
| frame.insert( "R", Slice( type, buffer + size * 2, size * 3, bufferstep )); |
| } |
| else |
| frame.insert( "Y", Slice( type, buffer, size, bufferstep )); |
| |
| file.setFrameBuffer( frame ); |
| |
| int offset = issigned ? 1 << (depth - 1) : 0; |
| |
| result = true; |
| if( type == FLOAT && depth == 32 ) |
| { |
| try |
| { |
| file.writePixels( height ); |
| } |
| catch(...) |
| { |
| result = false; |
| } |
| } |
| else |
| { |
| // int scale = 1 << (32 - depth); |
| // printf("scale %d\n", scale); |
| for(int line = 0; line < height; line++) |
| { |
| if(type == UINT) |
| { |
| uint *buf = (uint *)buffer; // FIXME 64-bit problems |
| |
| if( depth <= 8 ) |
| { |
| for(int i = 0; i < width * channels; i++) |
| buf[i] = data[i] + offset; |
| } |
| else if( depth <= 16 ) |
| { |
| unsigned short *sd = (unsigned short *)data; |
| for(int i = 0; i < width * channels; i++) |
| buf[i] = sd[i] + offset; |
| } |
| else |
| { |
| int *sd = (int *)data; // FIXME 64-bit problems |
| for(int i = 0; i < width * channels; i++) |
| buf[i] = (uint) sd[i] + offset; |
| } |
| } |
| else |
| { |
| half *buf = (half *)buffer; |
| |
| if( depth <= 8 ) |
| { |
| for(int i = 0; i < width * channels; i++) |
| buf[i] = data[i]; |
| } |
| else if( depth <= 16 ) |
| { |
| unsigned short *sd = (unsigned short *)data; |
| for(int i = 0; i < width * channels; i++) |
| buf[i] = sd[i]; |
| } |
| } |
| try |
| { |
| file.writePixels( 1 ); |
| } |
| catch(...) |
| { |
| result = false; |
| break; |
| } |
| data += step; |
| } |
| delete buffer; |
| } |
| |
| return result; |
| } |
| |
| #endif |
| |
| /* End of file. */ |