Added writing of compressed tiffs using libtiff library (patch #1080, thanks to Piete...
authorIlya Lysenkov <no@email>
Thu, 2 Jun 2011 09:06:00 +0000 (09:06 +0000)
committerIlya Lysenkov <no@email>
Thu, 2 Jun 2011 09:06:00 +0000 (09:06 +0000)
modules/highgui/src/grfmt_tiff.cpp
modules/highgui/src/grfmt_tiff.hpp

index 1839a6e..be9c5e1 100644 (file)
@@ -321,8 +321,135 @@ void  TiffEncoder::writeTag( WLByteStream& strm, TiffTag tag,
     strm.putDWord( value );
 }
 
+#ifdef HAVE_TIFF
+bool  TiffEncoder::writeLibTiff( const Mat& img, const vector<int>& /*params*/)
+{
+    int channels = img.channels();
+    int width = img.cols, height = img.rows;
+    int depth = img.depth();
+
+    int bitsPerChannel = -1;
+    switch (depth)
+    {
+        case CV_8U:
+        {
+            bitsPerChannel = 8;
+            break;
+        }
+        case CV_16U:
+        {
+            bitsPerChannel = 16;
+            break;
+        }
+        default:
+        {
+            return false;
+        }   
+    }
+    
+    const int bitsPerByte = 8;
+    size_t fileStep = (width * channels * bitsPerChannel) / bitsPerByte;
+    int rowsPerStrip = (1 << 13)/fileStep;
+
+    if( rowsPerStrip < 1 )
+        rowsPerStrip = 1;
+
+    if( rowsPerStrip > height )
+        rowsPerStrip = height;
+
+
+    // 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 = TIFFOpen(m_filename.c_str(), "w");
+    if (!pTiffHandle)
+    {
+        return false;
+    }
+    
+    // defaults for now, maybe base them on params in the future
+    int   compression  = COMPRESSION_LZW;
+    int   predictor    = PREDICTOR_HORIZONTAL;
+
+    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)
+      || !TIFFSetField(pTiffHandle, TIFFTAG_PREDICTOR, predictor)
+       )
+    {
+        TIFFClose(pTiffHandle);
+        return false;
+    }
+
+    // row buffer, because TIFFWriteScanline modifies the original data!
+    size_t scanlineSize = TIFFScanlineSize(pTiffHandle);
+    AutoBuffer<uchar,1024> _buffer(scanlineSize+32);
+    uchar* buffer = _buffer;
+    if (!buffer)
+    {
+        TIFFClose(pTiffHandle);
+        return false;
+    }
+
+    for (int y = 0; y < height; ++y)
+    {
+        switch(channels)
+        {
+            case 1:
+            {
+                memcpy(buffer, img.data + img.step * y, scanlineSize);
+                break;
+            }
+
+            case 3:
+            {
+                if (depth == CV_8U)
+                    icvCvt_BGR2RGB_8u_C3R( img.data + img.step*y, 0, buffer, 0, cvSize(width,1) );
+                else
+                    icvCvt_BGR2RGB_16u_C3R( (const ushort*)(img.data + img.step*y), 0, (ushort*)buffer, 0, cvSize(width,1) );
+                break;
+            }
+
+            case 4:
+            {
+                if (depth == CV_8U)
+                    icvCvt_BGRA2RGBA_8u_C4R( img.data + img.step*y, 0, buffer, 0, cvSize(width,1) );
+                else
+                    icvCvt_BGRA2RGBA_16u_C4R( (const ushort*)(img.data + img.step*y), 0, (ushort*)buffer, 0, cvSize(width,1) );
+            }
+
+            default:
+            {
+                TIFFClose(pTiffHandle);
+                return false;
+            }
+        }
+
+        int writeResult = TIFFWriteScanline(pTiffHandle, buffer, y, 0);
+        if (writeResult != 1)
+        {
+            TIFFClose(pTiffHandle);
+            return false;
+        }
+    }
+    
+    TIFFClose(pTiffHandle);
+    return true;
+}
 
-bool  TiffEncoder::write( const Mat& img, const vector<int>& )
+#endif
+
+#ifdef HAVE_TIFF
+bool  TiffEncoder::write( const Mat& img, const vector<int>& params)
+#else
+bool  TiffEncoder::write( const Mat& img, const vector<int>& /*params*/)
+#endif
 {
     int channels = img.channels();
     int width = img.cols, height = img.rows;
@@ -341,8 +468,15 @@ bool  TiffEncoder::write( const Mat& img, const vector<int>& )
         if( !strm.open(*m_buf) )
             return false;
     }
-    else if( !strm.open(m_filename) )
-        return false;
+    else 
+    {
+#ifdef HAVE_TIFF
+      return writeLibTiff(img, params);
+#else
+      if( !strm.open(m_filename) )
+          return false;
+#endif
+    }
 
     int rowsPerStrip = (1 << 13)/fileStep;
 
@@ -388,15 +522,22 @@ bool  TiffEncoder::write( const Mat& img, const vector<int>& )
         for( ; y < limit; y++ )
         {
             if( channels == 3 )
+            {
                 if (depth == CV_8U)
                     icvCvt_BGR2RGB_8u_C3R( img.data + img.step*y, 0, buffer, 0, cvSize(width,1) );
                 else
                     icvCvt_BGR2RGB_16u_C3R( (const ushort*)(img.data + img.step*y), 0, (ushort*)buffer, 0, cvSize(width,1) );
-            else if( channels == 4 )
+            }
+            else
+            {
+              if( channels == 4 )
+              {
                 if (depth == CV_8U)
                     icvCvt_BGRA2RGBA_8u_C4R( img.data + img.step*y, 0, buffer, 0, cvSize(width,1) );
                 else
                     icvCvt_BGRA2RGBA_16u_C4R( (const ushort*)(img.data + img.step*y), 0, (ushort*)buffer, 0, cvSize(width,1) );
+              }
+            }
 
             strm.putBytes( channels > 1 ? buffer : img.data + img.step*y, fileStep );
         }
index 037739a..8318548 100644 (file)
@@ -127,6 +127,8 @@ protected:
     void  writeTag( WLByteStream& strm, TiffTag tag,
                     TiffFieldType fieldType,
                     int count, int value );
+
+    bool writeLibTiff( const Mat& img, const vector<int>& params );
 };
 
 }