imgcodecs(tiff): sanitize tiff decoder
authorAlexander Alekhin <alexander.a.alekhin@gmail.com>
Thu, 4 Apr 2019 00:35:08 +0000 (00:35 +0000)
committerAlexander Alekhin <alexander.alekhin@intel.com>
Thu, 4 Apr 2019 11:16:53 +0000 (14:16 +0300)
- more checks
- drop separate branches for 32FC1/32FC3(read) handling
- added for 32F/64F non-compressed
- added tests for 32FC3 (RAW + hdr SGILOG compression)
- added test 64FC1
- dump tiff errors on stderr

modules/imgcodecs/src/grfmt_tiff.cpp
modules/imgcodecs/src/grfmt_tiff.hpp
modules/imgcodecs/src/utils.cpp
modules/imgcodecs/src/utils.hpp
modules/imgcodecs/test/test_tiff.cpp

index 7fa0256..b1f3d81 100644 (file)
@@ -48,6 +48,8 @@
 #include "precomp.hpp"
 
 #ifdef HAVE_TIFF
+#include <opencv2/core/utils/logger.hpp>
+
 #include "grfmt_tiff.hpp"
 #include <limits>
 
@@ -61,23 +63,58 @@ using namespace tiff_dummy_namespace;
 namespace cv
 {
 
+#define CV_TIFF_CHECK_CALL(call) \
+    if (0 == (call)) { \
+        CV_LOG_WARNING(NULL, "OpenCV TIFF(line " << __LINE__ << "): failed " #call); \
+        CV_Error(Error::StsError, "OpenCV TIFF: failed " #call); \
+    }
+
+#define CV_TIFF_CHECK_CALL_INFO(call) \
+    if (0 == (call)) { \
+        CV_LOG_INFO(NULL, "OpenCV TIFF(line " << __LINE__ << "): failed optional call: " #call ", ignoring"); \
+    }
+
+#define CV_TIFF_CHECK_CALL_DEBUG(call) \
+    if (0 == (call)) { \
+        CV_LOG_DEBUG(NULL, "OpenCV TIFF(line " << __LINE__ << "): failed optional call: " #call ", ignoring"); \
+    }
+
+static void cv_tiffCloseHandle(void* handle)
+{
+    TIFFClose((TIFF*)handle);
+}
+
+static void cv_tiffErrorHandler(const char* module, const char* fmt, va_list ap)
+{
+    if (cv::utils::logging::getLogLevel() < cv::utils::logging::LOG_LEVEL_DEBUG)
+        return;
+    // TODO cv::vformat() with va_list parameter
+    fprintf(stderr, "OpenCV TIFF: ");
+    if (module != NULL)
+        fprintf(stderr, "%s: ", module);
+    fprintf(stderr, "Warning, ");
+    vfprintf(stderr, fmt, ap);
+    fprintf(stderr, ".\n");
+}
+
+static bool cv_tiffSetErrorHandler_()
+{
+    TIFFSetErrorHandler(cv_tiffErrorHandler);
+    TIFFSetWarningHandler(cv_tiffErrorHandler);
+    return true;
+}
+
+static bool cv_tiffSetErrorHandler()
+{
+    static bool v = cv_tiffSetErrorHandler_();
+    return v;
+}
 
 static const char fmtSignTiffII[] = "II\x2a\x00";
 static const char fmtSignTiffMM[] = "MM\x00\x2a";
 
-static int grfmt_tiff_err_handler_init = 0;
-static void GrFmtSilentTIFFErrorHandler( const char*, const char*, va_list ) {}
-
 TiffDecoder::TiffDecoder()
 {
-    m_tif = 0;
-    if( !grfmt_tiff_err_handler_init )
-    {
-        grfmt_tiff_err_handler_init = 1;
-
-        TIFFSetErrorHandler( GrFmtSilentTIFFErrorHandler );
-        TIFFSetWarningHandler( GrFmtSilentTIFFErrorHandler );
-    }
     m_hdr = false;
     m_buf_supported = true;
     m_buf_pos = 0;
@@ -86,12 +123,7 @@ TiffDecoder::TiffDecoder()
 
 void TiffDecoder::close()
 {
-    if( m_tif )
-    {
-        TIFF* tif = (TIFF*)m_tif;
-        TIFFClose( tif );
-        m_tif = 0;
-    }
+    m_tif.release();
 }
 
 TiffDecoder::~TiffDecoder()
@@ -113,11 +145,13 @@ bool TiffDecoder::checkSignature( const String& signature ) const
 
 int TiffDecoder::normalizeChannelsNumber(int channels) const
 {
+    CV_Assert(channels <= 4);
     return channels > 4 ? 4 : channels;
 }
 
 ImageDecoder TiffDecoder::newDecoder() const
 {
+    cv_tiffSetErrorHandler();
     return makePtr<TiffDecoder>();
 }
 
@@ -201,8 +235,8 @@ bool TiffDecoder::readHeader()
 {
     bool result = false;
 
-    TIFF* tif = static_cast<TIFF*>(m_tif);
-    if (!m_tif)
+    TIFF* tif = static_cast<TIFF*>(m_tif.get());
+    if (!tif)
     {
         // TIFFOpen() mode flags are different to fopen().  A 'b' in mode "rb" has no effect when reading.
         // http://www.remotesensing.org/libtiff/man/TIFFOpen.3tiff.html
@@ -221,25 +255,30 @@ bool TiffDecoder::readHeader()
         {
             tif = TIFFOpen(m_filename.c_str(), "r");
         }
+        if (tif)
+            m_tif.reset(tif, cv_tiffCloseHandle);
+        else
+            m_tif.release();
     }
 
-    if( tif )
+    if (tif)
     {
         uint32 wdth = 0, hght = 0;
         uint16 photometric = 0;
-        m_tif = tif;
 
-        if( TIFFGetField( tif, TIFFTAG_IMAGEWIDTH, &wdth ) &&
-            TIFFGetField( tif, TIFFTAG_IMAGELENGTH, &hght ) &&
-            TIFFGetField( tif, TIFFTAG_PHOTOMETRIC, &photometric ))
+        CV_TIFF_CHECK_CALL(TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &wdth));
+        CV_TIFF_CHECK_CALL(TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &hght));
+        CV_TIFF_CHECK_CALL(TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &photometric));
+
         {
-            uint16 bpp=8, ncn = photometric > 1 ? 3 : 1;
-            TIFFGetField( tif, TIFFTAG_BITSPERSAMPLE, &bpp );
-            TIFFGetField( tif, TIFFTAG_SAMPLESPERPIXEL, &ncn );
+            bool isGrayScale = photometric == PHOTOMETRIC_MINISWHITE || photometric == PHOTOMETRIC_MINISBLACK;
+            uint16 bpp = 8, ncn = isGrayScale ? 1 : 3;
+            CV_TIFF_CHECK_CALL(TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bpp));
+            CV_TIFF_CHECK_CALL_DEBUG(TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &ncn));
 
             m_width = wdth;
             m_height = hght;
-            if((bpp == 32 && ncn == 3) || photometric == PHOTOMETRIC_LOGLUV)
+            if (ncn == 3 && photometric == PHOTOMETRIC_LOGLUV)
             {
                 m_type = CV_32FC3;
                 m_hdr = true;
@@ -256,23 +295,23 @@ bool TiffDecoder::readHeader()
             switch(bpp)
             {
                 case 1:
-                    m_type = CV_MAKETYPE(CV_8U, photometric > 1 ? wanted_channels : 1);
+                    m_type = CV_MAKETYPE(CV_8U, !isGrayScale ? wanted_channels : 1);
                     result = true;
                     break;
                 case 8:
-                    m_type = CV_MAKETYPE(CV_8U, photometric > 1 ? wanted_channels : 1);
+                    m_type = CV_MAKETYPE(CV_8U, !isGrayScale ? wanted_channels : 1);
                     result = true;
                     break;
                 case 16:
-                    m_type = CV_MAKETYPE(CV_16U, photometric > 1 ? wanted_channels : 1);
+                    m_type = CV_MAKETYPE(CV_16U, !isGrayScale ? wanted_channels : 1);
                     result = true;
                     break;
                 case 32:
-                    m_type = CV_MAKETYPE(CV_32F, photometric > 1 ? 3 : 1);
+                    m_type = CV_MAKETYPE(CV_32F, wanted_channels);
                     result = true;
                     break;
                 case 64:
-                    m_type = CV_MAKETYPE(CV_64F, photometric > 1 ? 3 : 1);
+                    m_type = CV_MAKETYPE(CV_64F, wanted_channels);
                     result = true;
                     break;
             default:
@@ -290,206 +329,210 @@ bool TiffDecoder::readHeader()
 bool TiffDecoder::nextPage()
 {
     // Prepare the next page, if any.
-    return m_tif &&
-           TIFFReadDirectory(static_cast<TIFF*>(m_tif)) &&
+    return !m_tif.empty() &&
+           TIFFReadDirectory(static_cast<TIFF*>(m_tif.get())) &&
            readHeader();
 }
 
 bool  TiffDecoder::readData( Mat& img )
 {
-    if(m_hdr && img.type() == CV_32FC3)
-    {
-        return readData_32FC3(img);
-    }
-    if(img.type() == CV_32FC1)
+    int type_ = img.type();
+    int depth = CV_MAT_DEPTH(type_);
+
+    CV_Assert(!m_tif.empty());
+    TIFF* tif = (TIFF*)m_tif.get();
+
+    uint16 photometric = (uint16)-1;
+    CV_TIFF_CHECK_CALL(TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &photometric));
+
+    if (m_hdr && depth >= CV_32F)
     {
-        return readData_32FC1(img);
+        CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_SGILOGDATAFMT, SGILOGDATAFMT_FLOAT));
     }
-    bool result = false;
+
     bool color = img.channels() > 1;
 
-    if( img.depth() != CV_8U && img.depth() != CV_16U && img.depth() != CV_32F && img.depth() != CV_64F )
-        return false;
+    CV_CheckType(type_, depth == CV_8U || depth == CV_16U || depth == CV_32F || depth == CV_64F, "");
 
-    if( m_tif && m_width && m_height )
+    if (m_width && m_height)
     {
-        TIFF* tif = (TIFF*)m_tif;
-        uint32 tile_width0 = m_width, tile_height0 = 0;
-        int x, y, i;
-        int is_tiled = TIFFIsTiled(tif);
-        uint16 photometric;
-        TIFFGetField( tif, TIFFTAG_PHOTOMETRIC, &photometric );
-        uint16 bpp = 8, ncn = photometric > 1 ? 3 : 1;
-        TIFFGetField( tif, TIFFTAG_BITSPERSAMPLE, &bpp );
-        TIFFGetField( tif, TIFFTAG_SAMPLESPERPIXEL, &ncn );
+        int is_tiled = TIFFIsTiled(tif) != 0;
+        bool isGrayScale = photometric == PHOTOMETRIC_MINISWHITE || photometric == PHOTOMETRIC_MINISBLACK;
+        uint16 bpp = 8, ncn = isGrayScale ? 1 : 3;
+        CV_TIFF_CHECK_CALL(TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bpp));
+        CV_TIFF_CHECK_CALL_DEBUG(TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &ncn));
         uint16 img_orientation = ORIENTATION_TOPLEFT;
-        TIFFGetField( tif, TIFFTAG_ORIENTATION, &img_orientation);
+        CV_TIFF_CHECK_CALL_DEBUG(TIFFGetField(tif, TIFFTAG_ORIENTATION, &img_orientation));
         bool vert_flip = (img_orientation == ORIENTATION_BOTRIGHT) || (img_orientation == ORIENTATION_RIGHTBOT) ||
                          (img_orientation == ORIENTATION_BOTLEFT) || (img_orientation == ORIENTATION_LEFTBOT);
         const int bitsPerByte = 8;
         int dst_bpp = (int)(img.elemSize1() * bitsPerByte);
         int wanted_channels = normalizeChannelsNumber(img.channels());
 
-        if(dst_bpp == 8)
+        if (dst_bpp == 8)
         {
             char errmsg[1024];
-            if(!TIFFRGBAImageOK( tif, errmsg ))
+            if (!TIFFRGBAImageOK(tif, errmsg))
             {
+                CV_LOG_WARNING(NULL, "OpenCV TIFF: TIFFRGBAImageOK: " << errmsg);
                 close();
                 return false;
             }
         }
 
-        if( (!is_tiled) ||
-            (is_tiled &&
-            TIFFGetField( tif, TIFFTAG_TILEWIDTH, &tile_width0 ) &&
-            TIFFGetField( tif, TIFFTAG_TILELENGTH, &tile_height0 )))
+        uint32 tile_width0 = m_width, tile_height0 = 0;
+
+        if (is_tiled)
+        {
+            CV_TIFF_CHECK_CALL(TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tile_width0));
+            CV_TIFF_CHECK_CALL(TIFFGetField(tif, TIFFTAG_TILELENGTH, &tile_height0));
+        }
+        else
         {
-            if(!is_tiled)
-                TIFFGetField( tif, TIFFTAG_ROWSPERSTRIP, &tile_height0 );
+            // optional
+            CV_TIFF_CHECK_CALL_DEBUG(TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &tile_height0));
+        }
 
-            if( tile_width0 <= 0 )
+        {
+            if (tile_width0 == 0)
                 tile_width0 = m_width;
 
-            if( tile_height0 <= 0 ||
-               (!is_tiled && tile_height0 == std::numeric_limits<uint32>::max()) )
+            if (tile_height0 == 0 ||
+                    (!is_tiled && tile_height0 == std::numeric_limits<uint32>::max()) )
                 tile_height0 = m_height;
 
-            if(dst_bpp == 8) {
+            if (dst_bpp == 8)
+            {
                 // we will use TIFFReadRGBA* functions, so allocate temporary buffer for 32bit RGBA
                 bpp = 8;
                 ncn = 4;
             }
-            const size_t buffer_size = (bpp/bitsPerByte) * ncn * tile_height0 * tile_width0;
-            AutoBuffer<uchar> _buffer( buffer_size );
+            else if (dst_bpp == 32 || dst_bpp == 64)
+            {
+                CV_Assert(ncn == img.channels());
+                CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP));
+            }
+            const size_t buffer_size = (bpp / bitsPerByte) * ncn * tile_height0 * tile_width0;
+            AutoBuffer<uchar> _buffer(buffer_size);
             uchar* buffer = _buffer.data();
             ushort* buffer16 = (ushort*)buffer;
-            float* buffer32 = (float*)buffer;
-            double* buffer64 = (double*)buffer;
             int tileidx = 0;
 
-            for( y = 0; y < m_height; y += tile_height0 )
+            for (int y = 0; y < m_height; y += (int)tile_height0)
             {
-                int tile_height = tile_height0;
-
-                if( y + tile_height > m_height )
-                    tile_height = m_height - y;
+                int tile_height = std::min((int)tile_height0, m_height - y);
 
-                uchar* data = img.ptr(vert_flip ? m_height - y - tile_height : y);
+                const int img_y = vert_flip ? m_height - y - tile_height : y;
 
-                for( x = 0; x < m_width; x += tile_width0, tileidx++ )
+                for(int x = 0; x < m_width; x += (int)tile_width0, tileidx++)
                 {
-                    int tile_width = tile_width0, ok;
+                    int tile_width = std::min((int)tile_width0, m_width - x);
 
-                    if( x + tile_width > m_width )
-                        tile_width = m_width - x;
-
-                    switch(dst_bpp)
+                    switch (dst_bpp)
                     {
                         case 8:
                         {
-                            uchar * bstart = buffer;
-                            if( !is_tiled )
-                                ok = TIFFReadRGBAStrip( tif, y, (uint32*)buffer );
-                            else
+                            uchar* bstart = buffer;
+                            if (!is_tiled)
                             {
-                                ok = TIFFReadRGBATile( tif, x, y, (uint32*)buffer );
-                                //Tiles fill the buffer from the bottom up
-                                bstart += (tile_height0 - tile_height) * tile_width0 * 4;
+                                CV_TIFF_CHECK_CALL(TIFFReadRGBAStrip(tif, y, (uint32*)buffer));
                             }
-                            if( !ok )
+                            else
                             {
-                                close();
-                                return false;
+                                CV_TIFF_CHECK_CALL(TIFFReadRGBATile(tif, x, y, (uint32*)buffer));
+                                // Tiles fill the buffer from the bottom up
+                                bstart += (tile_height0 - tile_height) * tile_width0 * 4;
                             }
 
-                            for( i = 0; i < tile_height; i++ )
-                                if( color )
+                            for (int i = 0; i < tile_height; i++)
+                            {
+                                if (color)
                                 {
                                     if (wanted_channels == 4)
                                     {
-                                        icvCvt_BGRA2RGBA_8u_C4R( bstart + i*tile_width0*4, 0,
-                                                             data + x*4 + img.step*(tile_height - i - 1), 0,
-                                                             cvSize(tile_width,1) );
+                                        icvCvt_BGRA2RGBA_8u_C4R(bstart + i*tile_width0*4, 0,
+                                                img.ptr(img_y + tile_height - i - 1, x), 0,
+                                                Size(tile_width, 1) );
                                     }
                                     else
                                     {
-                                        icvCvt_BGRA2BGR_8u_C4C3R( bstart + i*tile_width0*4, 0,
-                                                             data + x*3 + img.step*(tile_height - i - 1), 0,
-                                                             cvSize(tile_width,1), 2 );
+                                        icvCvt_BGRA2BGR_8u_C4C3R(bstart + i*tile_width0*4, 0,
+                                                img.ptr(img_y + tile_height - i - 1, x), 0,
+                                                Size(tile_width, 1), 2);
                                     }
                                 }
                                 else
+                                {
                                     icvCvt_BGRA2Gray_8u_C4C1R( bstart + i*tile_width0*4, 0,
-                                                              data + x + img.step*(tile_height - i - 1), 0,
-                                                              cvSize(tile_width,1), 2 );
+                                            img.ptr(img_y + tile_height - i - 1, x), 0,
+                                            Size(tile_width, 1), 2);
+                                }
+                            }
                             break;
                         }
 
                         case 16:
                         {
-                            if( !is_tiled )
-                                ok = (int)TIFFReadEncodedStrip( tif, tileidx, (uint32*)buffer, buffer_size ) >= 0;
+                            if (!is_tiled)
+                            {
+                                CV_TIFF_CHECK_CALL((int)TIFFReadEncodedStrip(tif, tileidx, (uint32*)buffer, buffer_size) >= 0);
+                            }
                             else
-                                ok = (int)TIFFReadEncodedTile( tif, tileidx, (uint32*)buffer, buffer_size ) >= 0;
-
-                            if( !ok )
                             {
-                                close();
-                                return false;
+                                CV_TIFF_CHECK_CALL((int)TIFFReadEncodedTile(tif, tileidx, (uint32*)buffer, buffer_size) >= 0);
                             }
 
-                            for( i = 0; i < tile_height; i++ )
+                            for (int i = 0; i < tile_height; i++)
                             {
-                                if( color )
+                                if (color)
                                 {
-                                    if( ncn == 1 )
+                                    if (ncn == 1)
                                     {
                                         icvCvt_Gray2BGR_16u_C1C3R(buffer16 + i*tile_width0*ncn, 0,
-                                                                  (ushort*)(data + img.step*i) + x*3, 0,
-                                                                  cvSize(tile_width,1) );
+                                                img.ptr<ushort>(img_y + i, x), 0,
+                                                Size(tile_width, 1));
                                     }
-                                    else if( ncn == 3 )
+                                    else if (ncn == 3)
                                     {
                                         icvCvt_RGB2BGR_16u_C3R(buffer16 + i*tile_width0*ncn, 0,
-                                                               (ushort*)(data + img.step*i) + x*3, 0,
-                                                               cvSize(tile_width,1) );
+                                                img.ptr<ushort>(img_y + i, x), 0,
+                                                Size(tile_width, 1));
                                     }
                                     else if (ncn == 4)
                                     {
                                         if (wanted_channels == 4)
                                         {
                                             icvCvt_BGRA2RGBA_16u_C4R(buffer16 + i*tile_width0*ncn, 0,
-                                                (ushort*)(data + img.step*i) + x * 4, 0,
-                                                cvSize(tile_width, 1));
+                                                img.ptr<ushort>(img_y + i, x), 0,
+                                                Size(tile_width, 1));
                                         }
                                         else
                                         {
                                             icvCvt_BGRA2BGR_16u_C4C3R(buffer16 + i*tile_width0*ncn, 0,
-                                                (ushort*)(data + img.step*i) + x * 3, 0,
-                                                cvSize(tile_width, 1), 2);
+                                                img.ptr<ushort>(img_y + i, x), 0,
+                                                Size(tile_width, 1), 2);
                                         }
                                     }
                                     else
                                     {
                                         icvCvt_BGRA2BGR_16u_C4C3R(buffer16 + i*tile_width0*ncn, 0,
-                                                               (ushort*)(data + img.step*i) + x*3, 0,
-                                                               cvSize(tile_width,1), 2 );
+                                                img.ptr<ushort>(img_y + i, x), 0,
+                                                Size(tile_width, 1), 2);
                                     }
                                 }
                                 else
                                 {
                                     if( ncn == 1 )
                                     {
-                                        memcpy((ushort*)(data + img.step*i)+x,
+                                        memcpy(img.ptr<ushort>(img_y + i, x),
                                                buffer16 + i*tile_width0*ncn,
-                                               tile_width*sizeof(buffer16[0]));
+                                               tile_width*sizeof(ushort));
                                     }
                                     else
                                     {
                                         icvCvt_BGRA2Gray_16u_CnC1R(buffer16 + i*tile_width0*ncn, 0,
-                                                               (ushort*)(data + img.step*i) + x, 0,
-                                                               cvSize(tile_width,1), ncn, 2 );
+                                                img.ptr<ushort>(img_y + i, x), 0,
+                                                Size(tile_width, 1), ncn, 2);
                                     }
                                 }
                             }
@@ -500,120 +543,43 @@ bool  TiffDecoder::readData( Mat& img )
                         case 64:
                         {
                             if( !is_tiled )
-                                ok = (int)TIFFReadEncodedStrip( tif, tileidx, buffer, buffer_size ) >= 0;
-                            else
-                                ok = (int)TIFFReadEncodedTile( tif, tileidx, buffer, buffer_size ) >= 0;
-
-                            if( !ok || ncn != 1 )
                             {
-                                close();
-                                return false;
+                                CV_TIFF_CHECK_CALL((int)TIFFReadEncodedStrip(tif, tileidx, buffer, buffer_size) >= 0);
                             }
-
-                            for( i = 0; i < tile_height; i++ )
+                            else
                             {
-                                if(dst_bpp == 32)
-                                {
-                                    memcpy((float*)(data + img.step*i)+x,
-                                           buffer32 + i*tile_width0*ncn,
-                                           tile_width*sizeof(buffer32[0]));
-                                }
-                                else
-                                {
-                                    memcpy((double*)(data + img.step*i)+x,
-                                         buffer64 + i*tile_width0*ncn,
-                                         tile_width*sizeof(buffer64[0]));
-                                }
+                                CV_TIFF_CHECK_CALL((int)TIFFReadEncodedTile(tif, tileidx, buffer, buffer_size) >= 0);
                             }
 
+                            Mat m_tile(Size(tile_width0, tile_height0), CV_MAKETYPE((dst_bpp == 32) ? CV_32F : CV_64F, ncn), buffer);
+                            Rect roi_tile(0, 0, tile_width, tile_height);
+                            Rect roi_img(x, img_y, tile_width, tile_height);
+                            if (!m_hdr && ncn == 3)
+                                cvtColor(m_tile(roi_tile), img(roi_img), COLOR_RGB2BGR);
+                            else if (!m_hdr && ncn == 4)
+                                cvtColor(m_tile(roi_tile), img(roi_img), COLOR_RGBA2BGRA);
+                            else
+                                m_tile(roi_tile).copyTo(img(roi_img));
                             break;
                         }
                         default:
                         {
-                            close();
-                            return false;
+                            CV_Assert(0 && "OpenCV TIFF: unsupported depth");
                         }
-                    }
-                }
-            }
-
-            result = true;
+                    }  // switch (dst_bpp)
+                }  // for x
+            }  // for y
         }
     }
 
-    return result;
-}
-
-bool TiffDecoder::readData_32FC3(Mat& img)
-{
-    int rows_per_strip = 0, photometric = 0;
-    if(!m_tif)
-    {
-        return false;
-    }
-    TIFF *tif = static_cast<TIFF*>(m_tif);
-    TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rows_per_strip);
-    TIFFGetField( tif, TIFFTAG_PHOTOMETRIC, &photometric );
-    TIFFSetField(tif, TIFFTAG_SGILOGDATAFMT, SGILOGDATAFMT_FLOAT);
-    int size = 3 * m_width * m_height * sizeof (float);
-    tstrip_t strip_size = 3 * m_width * rows_per_strip;
-    float *ptr = img.ptr<float>();
-    for (tstrip_t i = 0; i < TIFFNumberOfStrips(tif); i++, ptr += strip_size)
-    {
-        TIFFReadEncodedStrip(tif, i, ptr, size);
-        size -= strip_size * sizeof(float);
-    }
-    close();
-    if(photometric == PHOTOMETRIC_LOGLUV)
+    if (m_hdr && depth >= CV_32F)
     {
+        CV_Assert(photometric == PHOTOMETRIC_LOGLUV);
         cvtColor(img, img, COLOR_XYZ2BGR);
     }
-    else
-    {
-        cvtColor(img, img, COLOR_RGB2BGR);
-    }
     return true;
 }
 
-bool TiffDecoder::readData_32FC1(Mat& img)
-{
-    if(!m_tif)
-    {
-        return false;
-    }
-    TIFF *tif = static_cast<TIFF*>(m_tif);
-
-    uint32 img_width, img_height;
-    TIFFGetField(tif,TIFFTAG_IMAGEWIDTH, &img_width);
-    TIFFGetField(tif,TIFFTAG_IMAGELENGTH, &img_height);
-    if(img.size() != Size(img_width,img_height))
-    {
-        close();
-        return false;
-    }
-    tsize_t scanlength = TIFFScanlineSize(tif);
-    tdata_t buf = _TIFFmalloc(scanlength);
-    float* data;
-    bool result = true;
-    for (uint32 row = 0; row < img_height; row++)
-    {
-        if (TIFFReadScanline(tif, buf, row) != 1)
-        {
-            result = false;
-            break;
-        }
-        data=(float*)buf;
-        for (uint32 i=0; i<img_width; i++)
-        {
-            img.at<float>(row,i) = data[i];
-        }
-    }
-    _TIFFfree(buf);
-    close();
-
-    return result;
-}
-
 //////////////////////////////////////////////////////////////////////////////////////////
 
 TiffEncoder::TiffEncoder()
@@ -633,7 +599,7 @@ ImageEncoder TiffEncoder::newEncoder() const
 
 bool TiffEncoder::isFormatSupported( int depth ) const
 {
-    return depth == CV_8U || depth == CV_16U || depth == CV_32F;
+    return depth == CV_8U || depth == CV_16U || depth == CV_32F || depth == CV_64F;
 }
 
 void  TiffEncoder::writeTag( WLByteStream& strm, TiffTag tag,
@@ -656,6 +622,8 @@ public:
 
     TIFF* open ()
     {
+        // do NOT put "wb" as the mode, because the b means "big endian" mode, not "binary" mode.
+        // http://www.remotesensing.org/libtiff/man/TIFFOpen.3tiff.html
         return TIFFClientOpen( "", "w", reinterpret_cast<thandle_t>(this), &TiffEncoderBufHelper::read,
                                &TiffEncoderBufHelper::write, &TiffEncoderBufHelper::seek,
                                &TiffEncoderBufHelper::close, &TiffEncoderBufHelper::size,
@@ -721,35 +689,39 @@ private:
     toff_t m_buf_pos;
 };
 
-static void readParam(const std::vector<int>& params, int key, int& value)
+static bool readParam(const std::vector<int>& params, int key, int& value)
 {
-    for(size_t i = 0; i + 1 < params.size(); i += 2)
-        if(params[i] == key)
+    for (size_t i = 0; i + 1 < params.size(); i += 2)
+    {
+        if (params[i] == key)
         {
-            value = params[i+1];
-            break;
+            value = params[i + 1];
+            return true;
         }
+    }
+    return false;
 }
 
 bool TiffEncoder::writeLibTiff( const std::vector<Mat>& img_vec, const std::vector<int>& params)
 {
     // do NOT put "wb" as the mode, because the b means "big endian" mode, not "binary" mode.
     // http://www.remotesensing.org/libtiff/man/TIFFOpen.3tiff.html
-    TIFF* pTiffHandle;
+    TIFF* tif = NULL;
 
     TiffEncoderBufHelper buf_helper(m_buf);
     if ( m_buf )
     {
-        pTiffHandle = buf_helper.open();
+        tif = buf_helper.open();
     }
     else
     {
-        pTiffHandle = TIFFOpen(m_filename.c_str(), "w");
+        tif = TIFFOpen(m_filename.c_str(), "w");
     }
-    if (!pTiffHandle)
+    if (!tif)
     {
         return false;
     }
+    cv::Ptr<void> tif_cleanup(tif, cv_tiffCloseHandle);
 
     //Settings that matter to all images
     int compression = COMPRESSION_LZW;
@@ -768,7 +740,29 @@ bool TiffEncoder::writeLibTiff( const std::vector<Mat>& img_vec, const std::vect
         const Mat& img = img_vec[page];
         int channels = img.channels();
         int width = img.cols, height = img.rows;
-        int depth = img.depth();
+        int type = img.type();
+        int depth = CV_MAT_DEPTH(type);
+        CV_CheckType(type, depth == CV_8U || depth == CV_16U || depth == CV_32F || depth == CV_64F, "");
+        CV_CheckType(type, channels >= 1 && channels <= 4, "");
+
+        CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width));
+        CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height));
+
+        if (img_vec.size() > 1)
+        {
+            CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_SUBFILETYPE, FILETYPE_PAGE));
+            CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_PAGENUMBER, page, img_vec.size()));
+        }
+
+        int compression_param = -1;  // OPENCV_FUTURE
+        if (type == CV_32FC3 && (!readParam(params, IMWRITE_TIFF_COMPRESSION, compression_param) || compression_param == COMPRESSION_SGILOG))
+        {
+            if (!write_32FC3_SGILOG(img, tif))
+                return false;
+            continue;
+        }
+
+        int page_compression = compression;
 
         int bitsPerChannel = -1;
         switch (depth)
@@ -783,9 +777,20 @@ bool TiffEncoder::writeLibTiff( const std::vector<Mat>& img_vec, const std::vect
                 bitsPerChannel = 16;
                 break;
             }
+            case CV_32F:
+            {
+                bitsPerChannel = 32;
+                page_compression = COMPRESSION_NONE;
+                break;
+            }
+            case CV_64F:
+            {
+                bitsPerChannel = 64;
+                page_compression = COMPRESSION_NONE;
+                break;
+            }
             default:
             {
-                TIFFClose(pTiffHandle);
                 return false;
             }
         }
@@ -795,57 +800,42 @@ bool TiffEncoder::writeLibTiff( const std::vector<Mat>& img_vec, const std::vect
 
         int rowsPerStrip = (int)((1 << 13) / fileStep);
         readParam(params, TIFFTAG_ROWSPERSTRIP, rowsPerStrip);
+        rowsPerStrip = std::max(1, std::min(height, rowsPerStrip));
+
+        int colorspace = channels > 1 ? PHOTOMETRIC_RGB : PHOTOMETRIC_MINISBLACK;
+
+        CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bitsPerChannel));
+        CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_COMPRESSION, page_compression));
+        CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, colorspace));
+        CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, channels));
+        CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG));
+        CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, rowsPerStrip));
 
-        if (rowsPerStrip < 1)
-            rowsPerStrip = 1;
-
-        if (rowsPerStrip > height)
-            rowsPerStrip = height;
-
-        int   colorspace = channels > 1 ? PHOTOMETRIC_RGB : PHOTOMETRIC_MINISBLACK;
-
-        if (!TIFFSetField(pTiffHandle, TIFFTAG_IMAGEWIDTH, width)
-            || !TIFFSetField(pTiffHandle, TIFFTAG_IMAGELENGTH, height)
-            || !TIFFSetField(pTiffHandle, TIFFTAG_BITSPERSAMPLE, bitsPerChannel)
-            || !TIFFSetField(pTiffHandle, TIFFTAG_COMPRESSION, compression)
-            || !TIFFSetField(pTiffHandle, TIFFTAG_PHOTOMETRIC, colorspace)
-            || !TIFFSetField(pTiffHandle, TIFFTAG_SAMPLESPERPIXEL, channels)
-            || !TIFFSetField(pTiffHandle, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG)
-            || !TIFFSetField(pTiffHandle, TIFFTAG_ROWSPERSTRIP, rowsPerStrip)
-            || (img_vec.size() > 1 && (
-               !TIFFSetField(pTiffHandle, TIFFTAG_SUBFILETYPE, FILETYPE_PAGE)
-            || !TIFFSetField(pTiffHandle, TIFFTAG_PAGENUMBER, page, img_vec.size() )))
-            )
+        CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, depth >= CV_32F ? SAMPLEFORMAT_IEEEFP : SAMPLEFORMAT_UINT));
+
+        if (page_compression != COMPRESSION_NONE)
         {
-            TIFFClose(pTiffHandle);
-            return false;
+            CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_PREDICTOR, predictor));
         }
 
-        if (compression != COMPRESSION_NONE && !TIFFSetField(pTiffHandle, TIFFTAG_PREDICTOR, predictor))
+        if (resUnit >= RESUNIT_NONE && resUnit <= RESUNIT_CENTIMETER)
         {
-            TIFFClose(pTiffHandle);
-            return false;
+            CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, resUnit));
         }
-
-        if (((resUnit >= RESUNIT_NONE && resUnit <= RESUNIT_CENTIMETER) && !TIFFSetField(pTiffHandle, TIFFTAG_RESOLUTIONUNIT, resUnit))
-            || (dpiX >= 0 && !TIFFSetField(pTiffHandle, TIFFTAG_XRESOLUTION, (float)dpiX))
-            || (dpiY >= 0 && !TIFFSetField(pTiffHandle, TIFFTAG_YRESOLUTION, (float)dpiY))
-            )
+        if (dpiX >= 0)
         {
-            TIFFClose(pTiffHandle);
-            return false;
+            CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_XRESOLUTION, (float)dpiX));
+        }
+        if (dpiY >= 0)
+        {
+            CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_YRESOLUTION, (float)dpiY));
         }
-
 
         // row buffer, because TIFFWriteScanline modifies the original data!
-        size_t scanlineSize = TIFFScanlineSize(pTiffHandle);
+        size_t scanlineSize = TIFFScanlineSize(tif);
         AutoBuffer<uchar> _buffer(scanlineSize + 32);
-        uchar* buffer = _buffer.data();
-        if (!buffer)
-        {
-            TIFFClose(pTiffHandle);
-            return false;
-        }
+        uchar* buffer = _buffer.data(); CV_DbgAssert(buffer);
+        Mat m_buffer(Size(width, 1), CV_MAKETYPE(depth, channels), buffer, (size_t)scanlineSize);
 
         for (int y = 0; y < height; ++y)
         {
@@ -859,122 +849,54 @@ bool TiffEncoder::writeLibTiff( const std::vector<Mat>& img_vec, const std::vect
 
                 case 3:
                 {
-                    if (depth == CV_8U)
-                        icvCvt_BGR2RGB_8u_C3R( img.ptr(y), 0, buffer, 0, cvSize(width, 1));
-                    else
-                        icvCvt_BGR2RGB_16u_C3R( img.ptr<ushort>(y), 0, (ushort*)buffer, 0, cvSize(width, 1));
+                    cvtColor(img(Rect(0, y, width, 1)), (const Mat&)m_buffer, COLOR_BGR2RGB);
                     break;
                 }
 
                 case 4:
                 {
-                    if (depth == CV_8U)
-                        icvCvt_BGRA2RGBA_8u_C4R( img.ptr(y), 0, buffer, 0, cvSize(width, 1));
-                    else
-                        icvCvt_BGRA2RGBA_16u_C4R( img.ptr<ushort>(y), 0, (ushort*)buffer, 0, cvSize(width, 1));
+                    cvtColor(img(Rect(0, y, width, 1)), (const Mat&)m_buffer, COLOR_BGRA2RGBA);
                     break;
                 }
 
                 default:
                 {
-                    TIFFClose(pTiffHandle);
-                    return false;
+                    CV_Assert(0);
                 }
             }
 
-            int writeResult = TIFFWriteScanline(pTiffHandle, buffer, y, 0);
-            if (writeResult != 1)
-            {
-                TIFFClose(pTiffHandle);
-                return false;
-            }
+            CV_TIFF_CHECK_CALL(TIFFWriteScanline(tif, buffer, y, 0) == 1);
         }
 
-        TIFFWriteDirectory(pTiffHandle);
-
+        CV_TIFF_CHECK_CALL(TIFFWriteDirectory(tif));
     }
 
-    TIFFClose(pTiffHandle);
     return true;
 }
 
-bool TiffEncoder::write_32FC3(const Mat& _img)
+bool TiffEncoder::write_32FC3_SGILOG(const Mat& _img, void* tif_)
 {
+    TIFF* tif = (TIFF*)tif_;
+    CV_Assert(tif);
+
     Mat img;
     cvtColor(_img, img, COLOR_BGR2XYZ);
 
-    TIFF* tif;
-
-    TiffEncoderBufHelper buf_helper(m_buf);
-    if ( m_buf )
-    {
-        tif = buf_helper.open();
-    }
-    else
-    {
-        tif = TIFFOpen(m_filename.c_str(), "w");
-    }
-
-    if (!tif)
-    {
-        return false;
-    }
-    TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, img.cols);
-    TIFFSetField(tif, TIFFTAG_IMAGELENGTH, img.rows);
-    TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3);
-    TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_SGILOG);
-    TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_LOGLUV);
-    TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
-    TIFFSetField(tif, TIFFTAG_SGILOGDATAFMT, SGILOGDATAFMT_FLOAT);
-    TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, 1);
-    int strip_size = 3 * img.cols;
-    float *ptr = const_cast<float*>(img.ptr<float>());
-    for (int i = 0; i < img.rows; i++, ptr += strip_size)
-    {
-        TIFFWriteEncodedStrip(tif, i, ptr, strip_size * sizeof(float));
-    }
-    TIFFClose(tif);
-    return true;
-}
-
-bool TiffEncoder::write_32FC1(const Mat& _img)
-{
-
-    TIFF* tif;
-
-    TiffEncoderBufHelper buf_helper(m_buf);
-    if ( m_buf )
-    {
-        tif = buf_helper.open();
-    }
-    else
-    {
-        tif = TIFFOpen(m_filename.c_str(), "w");
-    }
-
-    if (!tif)
-    {
-        return false;
-    }
-
-    TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, _img.cols);
-    TIFFSetField(tif, TIFFTAG_IMAGELENGTH, _img.rows);
-    TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1);
-    TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 32);
-    TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
-    TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP);
-    TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
-    for (uint32 row = 0; row < (uint32)_img.rows; row++)
-    {
-        if (TIFFWriteScanline(tif, (tdata_t)_img.ptr<float>(row), row, 1) != 1)
-        {
-            TIFFClose(tif);
-            return false;
-        }
-    }
-    TIFFWriteDirectory(tif);
-    TIFFClose(tif);
-
+    //done by caller: CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, img.cols));
+    //done by caller: CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_IMAGELENGTH, img.rows));
+    CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3));
+    CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 32));
+    CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_SGILOG));
+    CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_LOGLUV));
+    CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG));
+    CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_SGILOGDATAFMT, SGILOGDATAFMT_FLOAT));
+    CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, 1));
+    const int strip_size = 3 * img.cols;
+    for (int i = 0; i < img.rows; i++)
+    {
+        CV_TIFF_CHECK_CALL(TIFFWriteEncodedStrip(tif, i, (tdata_t)img.ptr<float>(i), strip_size * sizeof(float)) != (tsize_t)-1);
+    }
+    CV_TIFF_CHECK_CALL(TIFFWriteDirectory(tif));
     return true;
 }
 
@@ -985,18 +907,10 @@ bool TiffEncoder::writemulti(const std::vector<Mat>& img_vec, const std::vector<
 
 bool  TiffEncoder::write( const Mat& img, const std::vector<int>& params)
 {
-    int depth = img.depth();
-
-    if(img.type() == CV_32FC3)
-    {
-        return write_32FC3(img);
-    }
-    if(img.type() == CV_32FC1)
-    {
-        return write_32FC1(img);
-    }
+    int type = img.type();
+    int depth = CV_MAT_DEPTH(type);
 
-    CV_Assert(depth == CV_8U || depth == CV_16U);
+    CV_CheckType(type, depth == CV_8U || depth == CV_16U || depth == CV_32F || depth == CV_64F, "");
 
     std::vector<Mat> img_vec;
     img_vec.push_back(img);
index cd1b55e..ee5bcb7 100644 (file)
@@ -106,10 +106,8 @@ public:
     ImageDecoder newDecoder() const CV_OVERRIDE;
 
 protected:
-    void* m_tif;
+    cv::Ptr<void> m_tif;
     int normalizeChannelsNumber(int channels) const;
-    bool readData_32FC3(Mat& img);
-    bool readData_32FC1(Mat& img);
     bool m_hdr;
     size_t m_buf_pos;
 
@@ -139,8 +137,7 @@ protected:
                     int count, int value );
 
     bool writeLibTiff( const std::vector<Mat>& img_vec, const std::vector<int>& params );
-    bool write_32FC3( const Mat& img );
-    bool write_32FC1( const Mat& img );
+    bool write_32FC3_SGILOG(const Mat& img, void* tif);
 
 private:
     TiffEncoder(const TiffEncoder &); // copy disabled
index 6aeb631..14cce83 100644 (file)
@@ -42,6 +42,8 @@
 #include "precomp.hpp"
 #include "utils.hpp"
 
+namespace cv {
+
 int validateToInt(size_t sz)
 {
     int valueInt = (int)sz;
@@ -56,7 +58,7 @@ int validateToInt(size_t sz)
 
 void icvCvt_BGR2Gray_8u_C3C1R( const uchar* rgb, int rgb_step,
                                uchar* gray, int gray_step,
-                               CvSize size, int _swap_rb )
+                               Size size, int _swap_rb )
 {
     int i;
     int swap_rb = _swap_rb ? 2 : 0;
@@ -75,7 +77,7 @@ void icvCvt_BGR2Gray_8u_C3C1R( const uchar* rgb, int rgb_step,
 
 void icvCvt_BGRA2Gray_16u_CnC1R( const ushort* rgb, int rgb_step,
                                 ushort* gray, int gray_step,
-                                CvSize size, int ncn, int _swap_rb )
+                                Size size, int ncn, int _swap_rb )
 {
     int i;
     int swap_rb = _swap_rb ? 2 : 0;
@@ -94,7 +96,7 @@ void icvCvt_BGRA2Gray_16u_CnC1R( const ushort* rgb, int rgb_step,
 
 void icvCvt_BGRA2Gray_8u_C4C1R( const uchar* rgba, int rgba_step,
                                 uchar* gray, int gray_step,
-                                CvSize size, int _swap_rb )
+                                Size size, int _swap_rb )
 {
     int i;
     int swap_rb = _swap_rb ? 2 : 0;
@@ -112,7 +114,7 @@ void icvCvt_BGRA2Gray_8u_C4C1R( const uchar* rgba, int rgba_step,
 
 
 void icvCvt_Gray2BGR_8u_C1C3R( const uchar* gray, int gray_step,
-                               uchar* bgr, int bgr_step, CvSize size )
+                               uchar* bgr, int bgr_step, Size size )
 {
     int i;
     for( ; size.height--; gray += gray_step )
@@ -127,7 +129,7 @@ void icvCvt_Gray2BGR_8u_C1C3R( const uchar* gray, int gray_step,
 
 
 void icvCvt_Gray2BGR_16u_C1C3R( const ushort* gray, int gray_step,
-                              ushort* bgr, int bgr_step, CvSize size )
+                              ushort* bgr, int bgr_step, Size size )
 {
     int i;
     for( ; size.height--; gray += gray_step/sizeof(gray[0]) )
@@ -143,7 +145,7 @@ void icvCvt_Gray2BGR_16u_C1C3R( const ushort* gray, int gray_step,
 
 void icvCvt_BGRA2BGR_8u_C4C3R( const uchar* bgra, int bgra_step,
                                uchar* bgr, int bgr_step,
-                               CvSize size, int _swap_rb )
+                               Size size, int _swap_rb )
 {
     int i;
     int swap_rb = _swap_rb ? 2 : 0;
@@ -163,7 +165,7 @@ void icvCvt_BGRA2BGR_8u_C4C3R( const uchar* bgra, int bgra_step,
 
 void icvCvt_BGRA2BGR_16u_C4C3R( const ushort* bgra, int bgra_step,
                               ushort* bgr, int bgr_step,
-                              CvSize size, int _swap_rb )
+                              Size size, int _swap_rb )
 {
     int i;
     int swap_rb = _swap_rb ? 2 : 0;
@@ -182,7 +184,7 @@ void icvCvt_BGRA2BGR_16u_C4C3R( const ushort* bgra, int bgra_step,
 
 
 void icvCvt_BGRA2RGBA_8u_C4R( const uchar* bgra, int bgra_step,
-                              uchar* rgba, int rgba_step, CvSize size )
+                              uchar* rgba, int rgba_step, Size size )
 {
     int i;
     for( ; size.height--; )
@@ -200,7 +202,7 @@ void icvCvt_BGRA2RGBA_8u_C4R( const uchar* bgra, int bgra_step,
 }
 
 void icvCvt_BGRA2RGBA_16u_C4R( const ushort* bgra, int bgra_step,
-                               ushort* rgba, int rgba_step, CvSize size )
+                               ushort* rgba, int rgba_step, Size size )
 {
  int i;
  for( ; size.height--; )
@@ -220,7 +222,7 @@ void icvCvt_BGRA2RGBA_16u_C4R( const ushort* bgra, int bgra_step,
 
 
 void icvCvt_BGR2RGB_8u_C3R( const uchar* bgr, int bgr_step,
-                            uchar* rgb, int rgb_step, CvSize size )
+                            uchar* rgb, int rgb_step, Size size )
 {
     int i;
     for( ; size.height--; )
@@ -237,7 +239,7 @@ void icvCvt_BGR2RGB_8u_C3R( const uchar* bgr, int bgr_step,
 
 
 void icvCvt_BGR2RGB_16u_C3R( const ushort* bgr, int bgr_step,
-                             ushort* rgb, int rgb_step, CvSize size )
+                             ushort* rgb, int rgb_step, Size size )
 {
     int i;
     for( ; size.height--; )
@@ -256,7 +258,7 @@ void icvCvt_BGR2RGB_16u_C3R( const ushort* bgr, int bgr_step,
 typedef unsigned short ushort;
 
 void icvCvt_BGR5552Gray_8u_C2C1R( const uchar* bgr555, int bgr555_step,
-                                  uchar* gray, int gray_step, CvSize size )
+                                  uchar* gray, int gray_step, Size size )
 {
     int i;
     for( ; size.height--; gray += gray_step, bgr555 += bgr555_step )
@@ -273,7 +275,7 @@ void icvCvt_BGR5552Gray_8u_C2C1R( const uchar* bgr555, int bgr555_step,
 
 
 void icvCvt_BGR5652Gray_8u_C2C1R( const uchar* bgr565, int bgr565_step,
-                                  uchar* gray, int gray_step, CvSize size )
+                                  uchar* gray, int gray_step, Size size )
 {
     int i;
     for( ; size.height--; gray += gray_step, bgr565 += bgr565_step )
@@ -290,7 +292,7 @@ void icvCvt_BGR5652Gray_8u_C2C1R( const uchar* bgr565, int bgr565_step,
 
 
 void icvCvt_BGR5552BGR_8u_C2C3R( const uchar* bgr555, int bgr555_step,
-                                 uchar* bgr, int bgr_step, CvSize size )
+                                 uchar* bgr, int bgr_step, Size size )
 {
     int i;
     for( ; size.height--; bgr555 += bgr555_step )
@@ -308,7 +310,7 @@ void icvCvt_BGR5552BGR_8u_C2C3R( const uchar* bgr555, int bgr555_step,
 
 
 void icvCvt_BGR5652BGR_8u_C2C3R( const uchar* bgr565, int bgr565_step,
-                                 uchar* bgr, int bgr_step, CvSize size )
+                                 uchar* bgr, int bgr_step, Size size )
 {
     int i;
     for( ; size.height--; bgr565 += bgr565_step )
@@ -326,7 +328,7 @@ void icvCvt_BGR5652BGR_8u_C2C3R( const uchar* bgr565, int bgr565_step,
 
 
 void icvCvt_CMYK2BGR_8u_C4C3R( const uchar* cmyk, int cmyk_step,
-                               uchar* bgr, int bgr_step, CvSize size )
+                               uchar* bgr, int bgr_step, Size size )
 {
     int i;
     for( ; size.height--; )
@@ -346,7 +348,7 @@ void icvCvt_CMYK2BGR_8u_C4C3R( const uchar* cmyk, int cmyk_step,
 
 
 void icvCvt_CMYK2Gray_8u_C4C1R( const uchar* cmyk, int cmyk_step,
-                                uchar* gray, int gray_step, CvSize size )
+                                uchar* gray, int gray_step, Size size )
 {
     int i;
     for( ; size.height--; )
@@ -371,7 +373,7 @@ void CvtPaletteToGray( const PaletteEntry* palette, uchar* grayPalette, int entr
     int i;
     for( i = 0; i < entries; i++ )
     {
-        icvCvt_BGR2Gray_8u_C3C1R( (uchar*)(palette + i), 0, grayPalette + i, 0, cvSize(1,1) );
+        icvCvt_BGR2Gray_8u_C3C1R( (uchar*)(palette + i), 0, grayPalette + i, 0, Size(1,1) );
     }
 }
 
@@ -598,6 +600,9 @@ uchar* FillGrayRow1( uchar* data, uchar* indices, int len, uchar* palette )
     return data;
 }
 
+}  // namespace
+
+using namespace cv;
 
 CV_IMPL void
 cvConvertImage( const CvArr* srcarr, CvArr* dstarr, int flags )
@@ -652,7 +657,7 @@ cvConvertImage( const CvArr* srcarr, CvArr* dstarr, int flags )
         uchar *s = src->data.ptr, *d = dst->data.ptr;
         int s_step = src->step, d_step = dst->step;
         int code = src_cn*10 + dst_cn;
-        CvSize size = {src->cols, src->rows};
+        Size size(src->cols, src->rows);
 
         if( CV_IS_MAT_CONT(src->type & dst->type) )
         {
index 6e0ec95..43eb907 100644 (file)
@@ -42,6 +42,8 @@
 #ifndef _UTILS_H_
 #define _UTILS_H_
 
+namespace cv {
+
 int validateToInt(size_t step);
 
 template <typename _Tp> static inline
@@ -68,53 +70,53 @@ struct PaletteEntry
 
 void icvCvt_BGR2Gray_8u_C3C1R( const uchar* bgr, int bgr_step,
                                uchar* gray, int gray_step,
-                               CvSize size, int swap_rb=0 );
+                               Size size, int swap_rb=0 );
 void icvCvt_BGRA2Gray_8u_C4C1R( const uchar* bgra, int bgra_step,
                                 uchar* gray, int gray_step,
-                                CvSize size, int swap_rb=0 );
+                                Size size, int swap_rb=0 );
 void icvCvt_BGRA2Gray_16u_CnC1R( const ushort* bgra, int bgra_step,
                                ushort* gray, int gray_step,
-                               CvSize size, int ncn, int swap_rb=0 );
+                               Size size, int ncn, int swap_rb=0 );
 
 void icvCvt_Gray2BGR_8u_C1C3R( const uchar* gray, int gray_step,
-                               uchar* bgr, int bgr_step, CvSize size );
+                               uchar* bgr, int bgr_step, Size size );
 void icvCvt_Gray2BGR_16u_C1C3R( const ushort* gray, int gray_step,
-                               ushort* bgr, int bgr_step, CvSize size );
+                               ushort* bgr, int bgr_step, Size size );
 
 void icvCvt_BGRA2BGR_8u_C4C3R( const uchar* bgra, int bgra_step,
                                uchar* bgr, int bgr_step,
-                               CvSize size, int swap_rb=0 );
+                               Size size, int swap_rb=0 );
 void icvCvt_BGRA2BGR_16u_C4C3R( const ushort* bgra, int bgra_step,
                                ushort* bgr, int bgr_step,
-                               CvSize size, int _swap_rb );
+                               Size size, int _swap_rb );
 
 void icvCvt_BGR2RGB_8u_C3R( const uchar* bgr, int bgr_step,
-                            uchar* rgb, int rgb_step, CvSize size );
+                            uchar* rgb, int rgb_step, Size size );
 #define icvCvt_RGB2BGR_8u_C3R icvCvt_BGR2RGB_8u_C3R
 void icvCvt_BGR2RGB_16u_C3R( const ushort* bgr, int bgr_step,
-                             ushort* rgb, int rgb_step, CvSize size );
+                             ushort* rgb, int rgb_step, Size size );
 #define icvCvt_RGB2BGR_16u_C3R icvCvt_BGR2RGB_16u_C3R
 
 void icvCvt_BGRA2RGBA_8u_C4R( const uchar* bgra, int bgra_step,
-                              uchar* rgba, int rgba_step, CvSize size );
+                              uchar* rgba, int rgba_step, Size size );
 #define icvCvt_RGBA2BGRA_8u_C4R icvCvt_BGRA2RGBA_8u_C4R
 
 void icvCvt_BGRA2RGBA_16u_C4R( const ushort* bgra, int bgra_step,
-                               ushort* rgba, int rgba_step, CvSize size );
+                               ushort* rgba, int rgba_step, Size size );
 #define icvCvt_RGBA2BGRA_16u_C4R icvCvt_BGRA2RGBA_16u_C4R
 
 void icvCvt_BGR5552Gray_8u_C2C1R( const uchar* bgr555, int bgr555_step,
-                                  uchar* gray, int gray_step, CvSize size );
+                                  uchar* gray, int gray_step, Size size );
 void icvCvt_BGR5652Gray_8u_C2C1R( const uchar* bgr565, int bgr565_step,
-                                  uchar* gray, int gray_step, CvSize size );
+                                  uchar* gray, int gray_step, Size size );
 void icvCvt_BGR5552BGR_8u_C2C3R( const uchar* bgr555, int bgr555_step,
-                                 uchar* bgr, int bgr_step, CvSize size );
+                                 uchar* bgr, int bgr_step, Size size );
 void icvCvt_BGR5652BGR_8u_C2C3R( const uchar* bgr565, int bgr565_step,
-                                 uchar* bgr, int bgr_step, CvSize size );
+                                 uchar* bgr, int bgr_step, Size size );
 void icvCvt_CMYK2BGR_8u_C4C3R( const uchar* cmyk, int cmyk_step,
-                               uchar* bgr, int bgr_step, CvSize size );
+                               uchar* bgr, int bgr_step, Size size );
 void icvCvt_CMYK2Gray_8u_C4C1R( const uchar* ycck, int ycck_step,
-                                uchar* gray, int gray_step, CvSize size );
+                                uchar* gray, int gray_step, Size size );
 
 void  FillGrayPalette( PaletteEntry* palette, int bpp, bool negative = false );
 bool  IsColorPalette( PaletteEntry* palette, int bpp );
@@ -136,4 +138,6 @@ CV_INLINE bool  isBigEndian( void )
     return (((const int*)"\0\x1\x2\x3\x4\x5\x6\x7")[0] & 255) != 0;
 }
 
+}  // namespace
+
 #endif/*_UTILS_H_*/
index 76a2cd4..add15ff 100644 (file)
@@ -158,12 +158,68 @@ TEST(Imgcodecs_Tiff, readWrite_32FC1)
 
     ASSERT_TRUE(cv::imwrite(filenameOutput, img));
     const Mat img2 = cv::imread(filenameOutput, IMREAD_UNCHANGED);
-    ASSERT_EQ(img2.type(),img.type());
-    ASSERT_EQ(img2.size(),img.size());
-    EXPECT_GE(1e-3, cvtest::norm(img, img2, NORM_INF | NORM_RELATIVE));
+    ASSERT_EQ(img2.type(), img.type());
+    ASSERT_EQ(img2.size(), img.size());
+    EXPECT_LE(cvtest::norm(img, img2, NORM_INF | NORM_RELATIVE), 1e-3);
     EXPECT_EQ(0, remove(filenameOutput.c_str()));
 }
 
+TEST(Imgcodecs_Tiff, readWrite_64FC1)
+{
+    const string root = cvtest::TS::ptr()->get_data_path();
+    const string filenameInput = root + "readwrite/test64FC1.tiff";
+    const string filenameOutput = cv::tempfile(".tiff");
+    const Mat img = cv::imread(filenameInput, IMREAD_UNCHANGED);
+    ASSERT_FALSE(img.empty());
+    ASSERT_EQ(CV_64FC1, img.type());
+
+    ASSERT_TRUE(cv::imwrite(filenameOutput, img));
+    const Mat img2 = cv::imread(filenameOutput, IMREAD_UNCHANGED);
+    ASSERT_EQ(img2.type(), img.type());
+    ASSERT_EQ(img2.size(), img.size());
+    EXPECT_LE(cvtest::norm(img, img2, NORM_INF | NORM_RELATIVE), 1e-3);
+    EXPECT_EQ(0, remove(filenameOutput.c_str()));
+}
+
+TEST(Imgcodecs_Tiff, readWrite_32FC3_SGILOG)
+{
+    const string root = cvtest::TS::ptr()->get_data_path();
+    const string filenameInput = root + "readwrite/test32FC3_sgilog.tiff";
+    const string filenameOutput = cv::tempfile(".tiff");
+    const Mat img = cv::imread(filenameInput, IMREAD_UNCHANGED);
+    ASSERT_FALSE(img.empty());
+    ASSERT_EQ(CV_32FC3, img.type());
+
+    ASSERT_TRUE(cv::imwrite(filenameOutput, img));
+    const Mat img2 = cv::imread(filenameOutput, IMREAD_UNCHANGED);
+    ASSERT_EQ(img2.type(), img.type());
+    ASSERT_EQ(img2.size(), img.size());
+    EXPECT_LE(cvtest::norm(img, img2, NORM_INF | NORM_RELATIVE), 0.01);
+    EXPECT_EQ(0, remove(filenameOutput.c_str()));
+}
+
+TEST(Imgcodecs_Tiff, readWrite_32FC3_RAW)
+{
+    const string root = cvtest::TS::ptr()->get_data_path();
+    const string filenameInput = root + "readwrite/test32FC3_raw.tiff";
+    const string filenameOutput = cv::tempfile(".tiff");
+    const Mat img = cv::imread(filenameInput, IMREAD_UNCHANGED);
+    ASSERT_FALSE(img.empty());
+    ASSERT_EQ(CV_32FC3, img.type());
+
+    std::vector<int> params;
+    params.push_back(IMWRITE_TIFF_COMPRESSION);
+    params.push_back(1/*COMPRESSION_NONE*/);
+
+    ASSERT_TRUE(cv::imwrite(filenameOutput, img, params));
+    const Mat img2 = cv::imread(filenameOutput, IMREAD_UNCHANGED);
+    ASSERT_EQ(img2.type(), img.type());
+    ASSERT_EQ(img2.size(), img.size());
+    EXPECT_LE(cvtest::norm(img, img2, NORM_INF | NORM_RELATIVE), 1e-3);
+    EXPECT_EQ(0, remove(filenameOutput.c_str()));
+}
+
+
 //==================================================================================================
 
 typedef testing::TestWithParam<int> Imgcodecs_Tiff_Modes;