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