Home | History | Annotate | Download | only in src
      1 /*M///////////////////////////////////////////////////////////////////////////////////////
      2 //
      3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
      4 //
      5 //  By downloading, copying, installing or using the software you agree to this license.
      6 //  If you do not agree to this license, do not download, install,
      7 //  copy or use the software.
      8 //
      9 //
     10 //                           License Agreement
     11 //                For Open Source Computer Vision Library
     12 //
     13 // Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
     14 // Copyright (C) 2009, Willow Garage Inc., all rights reserved.
     15 // Third party copyrights are property of their respective owners.
     16 //
     17 // Redistribution and use in source and binary forms, with or without modification,
     18 // are permitted provided that the following conditions are met:
     19 //
     20 //   * Redistribution's of source code must retain the above copyright notice,
     21 //     this list of conditions and the following disclaimer.
     22 //
     23 //   * Redistribution's in binary form must reproduce the above copyright notice,
     24 //     this list of conditions and the following disclaimer in the documentation
     25 //     and/or other materials provided with the distribution.
     26 //
     27 //   * The name of the copyright holders may not be used to endorse or promote products
     28 //     derived from this software without specific prior written permission.
     29 //
     30 // This software is provided by the copyright holders and contributors "as is" and
     31 // any express or implied warranties, including, but not limited to, the implied
     32 // warranties of merchantability and fitness for a particular purpose are disclaimed.
     33 // In no event shall the Intel Corporation or contributors be liable for any direct,
     34 // indirect, incidental, special, exemplary, or consequential damages
     35 // (including, but not limited to, procurement of substitute goods or services;
     36 // loss of use, data, or profits; or business interruption) however caused
     37 // and on any theory of liability, whether in contract, strict liability,
     38 // or tort (including negligence or otherwise) arising in any way out of
     39 // the use of this software, even if advised of the possibility of such damage.
     40 //
     41 //M*/
     42 
     43 /****************************************************************************************\
     44     A part of the file implements TIFF reader on base of libtiff library
     45     (see otherlibs/_graphics/readme.txt for copyright notice)
     46 \****************************************************************************************/
     47 
     48 #include "precomp.hpp"
     49 #include "grfmt_tiff.hpp"
     50 #include <opencv2/imgproc.hpp>
     51 #include <limits>
     52 
     53 namespace cv
     54 {
     55 static const char fmtSignTiffII[] = "II\x2a\x00";
     56 
     57 #ifdef HAVE_TIFF
     58 
     59 static const char fmtSignTiffMM[] = "MM\x00\x2a";
     60 
     61 #include "tiff.h"
     62 #include "tiffio.h"
     63 
     64 static int grfmt_tiff_err_handler_init = 0;
     65 static void GrFmtSilentTIFFErrorHandler( const char*, const char*, va_list ) {}
     66 
     67 TiffDecoder::TiffDecoder()
     68 {
     69     m_tif = 0;
     70     if( !grfmt_tiff_err_handler_init )
     71     {
     72         grfmt_tiff_err_handler_init = 1;
     73 
     74         TIFFSetErrorHandler( GrFmtSilentTIFFErrorHandler );
     75         TIFFSetWarningHandler( GrFmtSilentTIFFErrorHandler );
     76     }
     77     m_hdr = false;
     78 }
     79 
     80 
     81 void TiffDecoder::close()
     82 {
     83     if( m_tif )
     84     {
     85         TIFF* tif = (TIFF*)m_tif;
     86         TIFFClose( tif );
     87         m_tif = 0;
     88     }
     89 }
     90 
     91 TiffDecoder::~TiffDecoder()
     92 {
     93     close();
     94 }
     95 
     96 size_t TiffDecoder::signatureLength() const
     97 {
     98     return 4;
     99 }
    100 
    101 bool TiffDecoder::checkSignature( const String& signature ) const
    102 {
    103     return signature.size() >= 4 &&
    104         (memcmp(signature.c_str(), fmtSignTiffII, 4) == 0 ||
    105         memcmp(signature.c_str(), fmtSignTiffMM, 4) == 0);
    106 }
    107 
    108 int TiffDecoder::normalizeChannelsNumber(int channels) const
    109 {
    110     return channels > 4 ? 4 : channels;
    111 }
    112 
    113 ImageDecoder TiffDecoder::newDecoder() const
    114 {
    115     return makePtr<TiffDecoder>();
    116 }
    117 
    118 bool TiffDecoder::readHeader()
    119 {
    120     bool result = false;
    121 
    122     TIFF* tif = static_cast<TIFF*>(m_tif);
    123     if (!m_tif)
    124     {
    125         // TIFFOpen() mode flags are different to fopen().  A 'b' in mode "rb" has no effect when reading.
    126         // http://www.remotesensing.org/libtiff/man/TIFFOpen.3tiff.html
    127         tif = TIFFOpen(m_filename.c_str(), "r");
    128     }
    129 
    130     if( tif )
    131     {
    132         uint32 wdth = 0, hght = 0;
    133         uint16 photometric = 0;
    134         m_tif = tif;
    135 
    136         if( TIFFGetField( tif, TIFFTAG_IMAGEWIDTH, &wdth ) &&
    137             TIFFGetField( tif, TIFFTAG_IMAGELENGTH, &hght ) &&
    138             TIFFGetField( tif, TIFFTAG_PHOTOMETRIC, &photometric ))
    139         {
    140             uint16 bpp=8, ncn = photometric > 1 ? 3 : 1;
    141             TIFFGetField( tif, TIFFTAG_BITSPERSAMPLE, &bpp );
    142             TIFFGetField( tif, TIFFTAG_SAMPLESPERPIXEL, &ncn );
    143 
    144             m_width = wdth;
    145             m_height = hght;
    146             if((bpp == 32 && ncn == 3) || photometric == PHOTOMETRIC_LOGLUV)
    147             {
    148                 m_type = CV_32FC3;
    149                 m_hdr = true;
    150                 return true;
    151             }
    152             m_hdr = false;
    153 
    154             if( bpp > 8 &&
    155                ((photometric != 2 && photometric != 1) ||
    156                 (ncn != 1 && ncn != 3 && ncn != 4)))
    157                 bpp = 8;
    158 
    159             int wanted_channels = normalizeChannelsNumber(ncn);
    160             switch(bpp)
    161             {
    162                 case 8:
    163                     m_type = CV_MAKETYPE(CV_8U, photometric > 1 ? wanted_channels : 1);
    164                     break;
    165                 case 16:
    166                     m_type = CV_MAKETYPE(CV_16U, photometric > 1 ? wanted_channels : 1);
    167                     break;
    168 
    169                 case 32:
    170                     m_type = CV_MAKETYPE(CV_32F, photometric > 1 ? 3 : 1);
    171                     break;
    172                 case 64:
    173                     m_type = CV_MAKETYPE(CV_64F, photometric > 1 ? 3 : 1);
    174                     break;
    175 
    176                 default:
    177                     result = false;
    178             }
    179             result = true;
    180         }
    181     }
    182 
    183     if( !result )
    184         close();
    185 
    186     return result;
    187 }
    188 
    189 bool TiffDecoder::nextPage()
    190 {
    191     // Prepare the next page, if any.
    192     return m_tif &&
    193            TIFFReadDirectory(static_cast<TIFF*>(m_tif)) &&
    194            readHeader();
    195 }
    196 
    197 bool  TiffDecoder::readData( Mat& img )
    198 {
    199     if(m_hdr && img.type() == CV_32FC3)
    200     {
    201         return readHdrData(img);
    202     }
    203     bool result = false;
    204     bool color = img.channels() > 1;
    205     uchar* data = img.ptr();
    206 
    207     if( img.depth() != CV_8U && img.depth() != CV_16U && img.depth() != CV_32F && img.depth() != CV_64F )
    208         return false;
    209 
    210     if( m_tif && m_width && m_height )
    211     {
    212         TIFF* tif = (TIFF*)m_tif;
    213         uint32 tile_width0 = m_width, tile_height0 = 0;
    214         int x, y, i;
    215         int is_tiled = TIFFIsTiled(tif);
    216         uint16 photometric;
    217         TIFFGetField( tif, TIFFTAG_PHOTOMETRIC, &photometric );
    218         uint16 bpp = 8, ncn = photometric > 1 ? 3 : 1;
    219         TIFFGetField( tif, TIFFTAG_BITSPERSAMPLE, &bpp );
    220         TIFFGetField( tif, TIFFTAG_SAMPLESPERPIXEL, &ncn );
    221         const int bitsPerByte = 8;
    222         int dst_bpp = (int)(img.elemSize1() * bitsPerByte);
    223         int wanted_channels = normalizeChannelsNumber(img.channels());
    224 
    225         if(dst_bpp == 8)
    226         {
    227             char errmsg[1024];
    228             if(!TIFFRGBAImageOK( tif, errmsg ))
    229             {
    230                 close();
    231                 return false;
    232             }
    233         }
    234 
    235         if( (!is_tiled) ||
    236             (is_tiled &&
    237             TIFFGetField( tif, TIFFTAG_TILEWIDTH, &tile_width0 ) &&
    238             TIFFGetField( tif, TIFFTAG_TILELENGTH, &tile_height0 )))
    239         {
    240             if(!is_tiled)
    241                 TIFFGetField( tif, TIFFTAG_ROWSPERSTRIP, &tile_height0 );
    242 
    243             if( tile_width0 <= 0 )
    244                 tile_width0 = m_width;
    245 
    246             if( tile_height0 <= 0 ||
    247                (!is_tiled && tile_height0 == std::numeric_limits<uint32>::max()) )
    248                 tile_height0 = m_height;
    249 
    250             const size_t buffer_size = bpp * ncn * tile_height0 * tile_width0;
    251             AutoBuffer<uchar> _buffer( buffer_size );
    252             uchar* buffer = _buffer;
    253             ushort* buffer16 = (ushort*)buffer;
    254             float* buffer32 = (float*)buffer;
    255             double* buffer64 = (double*)buffer;
    256             int tileidx = 0;
    257 
    258             for( y = 0; y < m_height; y += tile_height0, data += img.step*tile_height0 )
    259             {
    260                 int tile_height = tile_height0;
    261 
    262                 if( y + tile_height > m_height )
    263                     tile_height = m_height - y;
    264 
    265                 for( x = 0; x < m_width; x += tile_width0, tileidx++ )
    266                 {
    267                     int tile_width = tile_width0, ok;
    268 
    269                     if( x + tile_width > m_width )
    270                         tile_width = m_width - x;
    271 
    272                     switch(dst_bpp)
    273                     {
    274                         case 8:
    275                         {
    276                             uchar * bstart = buffer;
    277                             if( !is_tiled )
    278                                 ok = TIFFReadRGBAStrip( tif, y, (uint32*)buffer );
    279                             else
    280                             {
    281                                 ok = TIFFReadRGBATile( tif, x, y, (uint32*)buffer );
    282                                 //Tiles fill the buffer from the bottom up
    283                                 bstart += (tile_height0 - tile_height) * tile_width0 * 4;
    284                             }
    285                             if( !ok )
    286                             {
    287                                 close();
    288                                 return false;
    289                             }
    290 
    291                             for( i = 0; i < tile_height; i++ )
    292                                 if( color )
    293                                 {
    294                                     if (wanted_channels == 4)
    295                                     {
    296                                         icvCvt_BGRA2RGBA_8u_C4R( bstart + i*tile_width0*4, 0,
    297                                                              data + x*4 + img.step*(tile_height - i - 1), 0,
    298                                                              cvSize(tile_width,1) );
    299                                     }
    300                                     else
    301                                     {
    302                                         icvCvt_BGRA2BGR_8u_C4C3R( bstart + i*tile_width0*4, 0,
    303                                                              data + x*3 + img.step*(tile_height - i - 1), 0,
    304                                                              cvSize(tile_width,1), 2 );
    305                                     }
    306                                 }
    307                                 else
    308                                     icvCvt_BGRA2Gray_8u_C4C1R( bstart + i*tile_width0*4, 0,
    309                                                               data + x + img.step*(tile_height - i - 1), 0,
    310                                                               cvSize(tile_width,1), 2 );
    311                             break;
    312                         }
    313 
    314                         case 16:
    315                         {
    316                             if( !is_tiled )
    317                                 ok = (int)TIFFReadEncodedStrip( tif, tileidx, (uint32*)buffer, buffer_size ) >= 0;
    318                             else
    319                                 ok = (int)TIFFReadEncodedTile( tif, tileidx, (uint32*)buffer, buffer_size ) >= 0;
    320 
    321                             if( !ok )
    322                             {
    323                                 close();
    324                                 return false;
    325                             }
    326 
    327                             for( i = 0; i < tile_height; i++ )
    328                             {
    329                                 if( color )
    330                                 {
    331                                     if( ncn == 1 )
    332                                     {
    333                                         icvCvt_Gray2BGR_16u_C1C3R(buffer16 + i*tile_width0*ncn, 0,
    334                                                                   (ushort*)(data + img.step*i) + x*3, 0,
    335                                                                   cvSize(tile_width,1) );
    336                                     }
    337                                     else if( ncn == 3 )
    338                                     {
    339                                         icvCvt_RGB2BGR_16u_C3R(buffer16 + i*tile_width0*ncn, 0,
    340                                                                (ushort*)(data + img.step*i) + x*3, 0,
    341                                                                cvSize(tile_width,1) );
    342                                     }
    343                                     else if (ncn == 4)
    344                                     {
    345                                         if (wanted_channels == 4)
    346                                         {
    347                                             icvCvt_BGRA2RGBA_16u_C4R(buffer16 + i*tile_width0*ncn, 0,
    348                                                 (ushort*)(data + img.step*i) + x * 4, 0,
    349                                                 cvSize(tile_width, 1));
    350                                         }
    351                                         else
    352                                         {
    353                                             icvCvt_BGRA2BGR_16u_C4C3R(buffer16 + i*tile_width0*ncn, 0,
    354                                                 (ushort*)(data + img.step*i) + x * 3, 0,
    355                                                 cvSize(tile_width, 1), 2);
    356                                         }
    357                                     }
    358                                     else
    359                                     {
    360                                         icvCvt_BGRA2BGR_16u_C4C3R(buffer16 + i*tile_width0*ncn, 0,
    361                                                                (ushort*)(data + img.step*i) + x*3, 0,
    362                                                                cvSize(tile_width,1), 2 );
    363                                     }
    364                                 }
    365                                 else
    366                                 {
    367                                     if( ncn == 1 )
    368                                     {
    369                                         memcpy((ushort*)(data + img.step*i)+x,
    370                                                buffer16 + i*tile_width0*ncn,
    371                                                tile_width*sizeof(buffer16[0]));
    372                                     }
    373                                     else
    374                                     {
    375                                         icvCvt_BGRA2Gray_16u_CnC1R(buffer16 + i*tile_width0*ncn, 0,
    376                                                                (ushort*)(data + img.step*i) + x, 0,
    377                                                                cvSize(tile_width,1), ncn, 2 );
    378                                     }
    379                                 }
    380                             }
    381                             break;
    382                         }
    383 
    384                         case 32:
    385                         case 64:
    386                         {
    387                             if( !is_tiled )
    388                                 ok = (int)TIFFReadEncodedStrip( tif, tileidx, buffer, buffer_size ) >= 0;
    389                             else
    390                                 ok = (int)TIFFReadEncodedTile( tif, tileidx, buffer, buffer_size ) >= 0;
    391 
    392                             if( !ok || ncn != 1 )
    393                             {
    394                                 close();
    395                                 return false;
    396                             }
    397 
    398                             for( i = 0; i < tile_height; i++ )
    399                             {
    400                                 if(dst_bpp == 32)
    401                                 {
    402                                     memcpy((float*)(data + img.step*i)+x,
    403                                            buffer32 + i*tile_width0*ncn,
    404                                            tile_width*sizeof(buffer32[0]));
    405                                 }
    406                                 else
    407                                 {
    408                                     memcpy((double*)(data + img.step*i)+x,
    409                                          buffer64 + i*tile_width0*ncn,
    410                                          tile_width*sizeof(buffer64[0]));
    411                                 }
    412                             }
    413 
    414                             break;
    415                         }
    416                         default:
    417                         {
    418                             close();
    419                             return false;
    420                         }
    421                     }
    422                 }
    423             }
    424 
    425             result = true;
    426         }
    427     }
    428 
    429     return result;
    430 }
    431 
    432 bool TiffDecoder::readHdrData(Mat& img)
    433 {
    434     int rows_per_strip = 0, photometric = 0;
    435     if(!m_tif)
    436     {
    437         return false;
    438     }
    439     TIFF *tif = static_cast<TIFF*>(m_tif);
    440     TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rows_per_strip);
    441     TIFFGetField( tif, TIFFTAG_PHOTOMETRIC, &photometric );
    442     TIFFSetField(tif, TIFFTAG_SGILOGDATAFMT, SGILOGDATAFMT_FLOAT);
    443     int size = 3 * m_width * m_height * sizeof (float);
    444     tstrip_t strip_size = 3 * m_width * rows_per_strip;
    445     float *ptr = img.ptr<float>();
    446     for (tstrip_t i = 0; i < TIFFNumberOfStrips(tif); i++, ptr += strip_size)
    447     {
    448         TIFFReadEncodedStrip(tif, i, ptr, size);
    449         size -= strip_size * sizeof(float);
    450     }
    451     close();
    452     if(photometric == PHOTOMETRIC_LOGLUV)
    453     {
    454         cvtColor(img, img, COLOR_XYZ2BGR);
    455     }
    456     else
    457     {
    458         cvtColor(img, img, COLOR_RGB2BGR);
    459     }
    460     return true;
    461 }
    462 
    463 #endif
    464 
    465 //////////////////////////////////////////////////////////////////////////////////////////
    466 
    467 TiffEncoder::TiffEncoder()
    468 {
    469     m_description = "TIFF Files (*.tiff;*.tif)";
    470 #ifdef HAVE_TIFF
    471     m_buf_supported = false;
    472 #else
    473     m_buf_supported = true;
    474 #endif
    475 }
    476 
    477 TiffEncoder::~TiffEncoder()
    478 {
    479 }
    480 
    481 ImageEncoder TiffEncoder::newEncoder() const
    482 {
    483     return makePtr<TiffEncoder>();
    484 }
    485 
    486 bool TiffEncoder::isFormatSupported( int depth ) const
    487 {
    488 #ifdef HAVE_TIFF
    489     return depth == CV_8U || depth == CV_16U || depth == CV_32F;
    490 #else
    491     return depth == CV_8U || depth == CV_16U;
    492 #endif
    493 }
    494 
    495 void  TiffEncoder::writeTag( WLByteStream& strm, TiffTag tag,
    496                              TiffFieldType fieldType,
    497                              int count, int value )
    498 {
    499     strm.putWord( tag );
    500     strm.putWord( fieldType );
    501     strm.putDWord( count );
    502     strm.putDWord( value );
    503 }
    504 
    505 #ifdef HAVE_TIFF
    506 
    507 static void readParam(const std::vector<int>& params, int key, int& value)
    508 {
    509     for(size_t i = 0; i + 1 < params.size(); i += 2)
    510         if(params[i] == key)
    511         {
    512             value = params[i+1];
    513             break;
    514         }
    515 }
    516 
    517 bool  TiffEncoder::writeLibTiff( const Mat& img, const std::vector<int>& params)
    518 {
    519     int channels = img.channels();
    520     int width = img.cols, height = img.rows;
    521     int depth = img.depth();
    522 
    523     int bitsPerChannel = -1;
    524     switch (depth)
    525     {
    526         case CV_8U:
    527         {
    528             bitsPerChannel = 8;
    529             break;
    530         }
    531         case CV_16U:
    532         {
    533             bitsPerChannel = 16;
    534             break;
    535         }
    536         default:
    537         {
    538             return false;
    539         }
    540     }
    541 
    542     const int bitsPerByte = 8;
    543     size_t fileStep = (width * channels * bitsPerChannel) / bitsPerByte;
    544 
    545     int rowsPerStrip = (int)((1 << 13)/fileStep);
    546     readParam(params, TIFFTAG_ROWSPERSTRIP, rowsPerStrip);
    547 
    548     if( rowsPerStrip < 1 )
    549         rowsPerStrip = 1;
    550 
    551     if( rowsPerStrip > height )
    552         rowsPerStrip = height;
    553 
    554 
    555     // do NOT put "wb" as the mode, because the b means "big endian" mode, not "binary" mode.
    556     // http://www.remotesensing.org/libtiff/man/TIFFOpen.3tiff.html
    557     TIFF* pTiffHandle = TIFFOpen(m_filename.c_str(), "w");
    558     if (!pTiffHandle)
    559     {
    560         return false;
    561     }
    562 
    563     // defaults for now, maybe base them on params in the future
    564     int   compression  = COMPRESSION_LZW;
    565     int   predictor    = PREDICTOR_HORIZONTAL;
    566 
    567     readParam(params, TIFFTAG_COMPRESSION, compression);
    568     readParam(params, TIFFTAG_PREDICTOR, predictor);
    569 
    570     int   colorspace = channels > 1 ? PHOTOMETRIC_RGB : PHOTOMETRIC_MINISBLACK;
    571 
    572     if ( !TIFFSetField(pTiffHandle, TIFFTAG_IMAGEWIDTH, width)
    573       || !TIFFSetField(pTiffHandle, TIFFTAG_IMAGELENGTH, height)
    574       || !TIFFSetField(pTiffHandle, TIFFTAG_BITSPERSAMPLE, bitsPerChannel)
    575       || !TIFFSetField(pTiffHandle, TIFFTAG_COMPRESSION, compression)
    576       || !TIFFSetField(pTiffHandle, TIFFTAG_PHOTOMETRIC, colorspace)
    577       || !TIFFSetField(pTiffHandle, TIFFTAG_SAMPLESPERPIXEL, channels)
    578       || !TIFFSetField(pTiffHandle, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG)
    579       || !TIFFSetField(pTiffHandle, TIFFTAG_ROWSPERSTRIP, rowsPerStrip)
    580        )
    581     {
    582         TIFFClose(pTiffHandle);
    583         return false;
    584     }
    585 
    586     if (compression != COMPRESSION_NONE && !TIFFSetField(pTiffHandle, TIFFTAG_PREDICTOR, predictor) )
    587     {
    588         TIFFClose(pTiffHandle);
    589         return false;
    590     }
    591 
    592     // row buffer, because TIFFWriteScanline modifies the original data!
    593     size_t scanlineSize = TIFFScanlineSize(pTiffHandle);
    594     AutoBuffer<uchar> _buffer(scanlineSize+32);
    595     uchar* buffer = _buffer;
    596     if (!buffer)
    597     {
    598         TIFFClose(pTiffHandle);
    599         return false;
    600     }
    601 
    602     for (int y = 0; y < height; ++y)
    603     {
    604         switch(channels)
    605         {
    606             case 1:
    607             {
    608                 memcpy(buffer, img.ptr(y), scanlineSize);
    609                 break;
    610             }
    611 
    612             case 3:
    613             {
    614                 if (depth == CV_8U)
    615                     icvCvt_BGR2RGB_8u_C3R( img.ptr(y), 0, buffer, 0, cvSize(width,1) );
    616                 else
    617                     icvCvt_BGR2RGB_16u_C3R( img.ptr<ushort>(y), 0, (ushort*)buffer, 0, cvSize(width,1) );
    618                 break;
    619             }
    620 
    621             case 4:
    622             {
    623                 if (depth == CV_8U)
    624                     icvCvt_BGRA2RGBA_8u_C4R( img.ptr(y), 0, buffer, 0, cvSize(width,1) );
    625                 else
    626                     icvCvt_BGRA2RGBA_16u_C4R( img.ptr<ushort>(y), 0, (ushort*)buffer, 0, cvSize(width,1) );
    627                 break;
    628             }
    629 
    630             default:
    631             {
    632                 TIFFClose(pTiffHandle);
    633                 return false;
    634             }
    635         }
    636 
    637         int writeResult = TIFFWriteScanline(pTiffHandle, buffer, y, 0);
    638         if (writeResult != 1)
    639         {
    640             TIFFClose(pTiffHandle);
    641             return false;
    642         }
    643     }
    644 
    645     TIFFClose(pTiffHandle);
    646     return true;
    647 }
    648 
    649 bool TiffEncoder::writeHdr(const Mat& _img)
    650 {
    651     Mat img;
    652     cvtColor(_img, img, COLOR_BGR2XYZ);
    653     TIFF* tif = TIFFOpen(m_filename.c_str(), "w");
    654     if (!tif)
    655     {
    656         return false;
    657     }
    658     TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, img.cols);
    659     TIFFSetField(tif, TIFFTAG_IMAGELENGTH, img.rows);
    660     TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3);
    661     TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_SGILOG);
    662     TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_LOGLUV);
    663     TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
    664     TIFFSetField(tif, TIFFTAG_SGILOGDATAFMT, SGILOGDATAFMT_FLOAT);
    665     TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, 1);
    666     int strip_size = 3 * img.cols;
    667     float *ptr = const_cast<float*>(img.ptr<float>());
    668     for (int i = 0; i < img.rows; i++, ptr += strip_size)
    669     {
    670         TIFFWriteEncodedStrip(tif, i, ptr, strip_size * sizeof(float));
    671     }
    672     TIFFClose(tif);
    673     return true;
    674 }
    675 
    676 #endif
    677 
    678 #ifdef HAVE_TIFF
    679 bool  TiffEncoder::write( const Mat& img, const std::vector<int>& params)
    680 #else
    681 bool  TiffEncoder::write( const Mat& img, const std::vector<int>& /*params*/)
    682 #endif
    683 {
    684     int channels = img.channels();
    685     int width = img.cols, height = img.rows;
    686     int depth = img.depth();
    687 #ifdef HAVE_TIFF
    688     if(img.type() == CV_32FC3)
    689     {
    690         return writeHdr(img);
    691     }
    692 #endif
    693 
    694     if (depth != CV_8U && depth != CV_16U)
    695         return false;
    696 
    697     int bytesPerChannel = depth == CV_8U ? 1 : 2;
    698     int fileStep = width * channels * bytesPerChannel;
    699 
    700     WLByteStream strm;
    701 
    702     if( m_buf )
    703     {
    704         if( !strm.open(*m_buf) )
    705             return false;
    706     }
    707     else
    708     {
    709 #ifdef HAVE_TIFF
    710       return writeLibTiff(img, params);
    711 #else
    712       if( !strm.open(m_filename) )
    713           return false;
    714 #endif
    715     }
    716 
    717     int rowsPerStrip = (1 << 13)/fileStep;
    718 
    719     if( rowsPerStrip < 1 )
    720         rowsPerStrip = 1;
    721 
    722     if( rowsPerStrip > height )
    723         rowsPerStrip = height;
    724 
    725     int i, stripCount = (height + rowsPerStrip - 1) / rowsPerStrip;
    726 
    727     if( m_buf )
    728         m_buf->reserve( alignSize(stripCount*8 + fileStep*height + 256, 256) );
    729 
    730 /*#if defined _DEBUG || !defined WIN32
    731     int uncompressedRowSize = rowsPerStrip * fileStep;
    732 #endif*/
    733     int directoryOffset = 0;
    734 
    735     AutoBuffer<int> stripOffsets(stripCount);
    736     AutoBuffer<short> stripCounts(stripCount);
    737     AutoBuffer<uchar> _buffer(fileStep+32);
    738     uchar* buffer = _buffer;
    739     int  stripOffsetsOffset = 0;
    740     int  stripCountsOffset = 0;
    741     int  bitsPerSample = 8 * bytesPerChannel;
    742     int  y = 0;
    743 
    744     strm.putBytes( fmtSignTiffII, 4 );
    745     strm.putDWord( directoryOffset );
    746 
    747     // write an image data first (the most reasonable way
    748     // for compressed images)
    749     for( i = 0; i < stripCount; i++ )
    750     {
    751         int limit = y + rowsPerStrip;
    752 
    753         if( limit > height )
    754             limit = height;
    755 
    756         stripOffsets[i] = strm.getPos();
    757 
    758         for( ; y < limit; y++ )
    759         {
    760             if( channels == 3 )
    761             {
    762                 if (depth == CV_8U)
    763                     icvCvt_BGR2RGB_8u_C3R( img.ptr(y), 0, buffer, 0, cvSize(width,1) );
    764                 else
    765                     icvCvt_BGR2RGB_16u_C3R( img.ptr<ushort>(y), 0, (ushort*)buffer, 0, cvSize(width,1) );
    766             }
    767             else
    768             {
    769               if( channels == 4 )
    770               {
    771                 if (depth == CV_8U)
    772                     icvCvt_BGRA2RGBA_8u_C4R( img.ptr(y), 0, buffer, 0, cvSize(width,1) );
    773                 else
    774                     icvCvt_BGRA2RGBA_16u_C4R( img.ptr<ushort>(y), 0, (ushort*)buffer, 0, cvSize(width,1) );
    775               }
    776             }
    777 
    778             strm.putBytes( channels > 1 ? buffer : img.ptr(y), fileStep );
    779         }
    780 
    781         stripCounts[i] = (short)(strm.getPos() - stripOffsets[i]);
    782         /*assert( stripCounts[i] == uncompressedRowSize ||
    783                 stripCounts[i] < uncompressedRowSize &&
    784                 i == stripCount - 1);*/
    785     }
    786 
    787     if( stripCount > 2 )
    788     {
    789         stripOffsetsOffset = strm.getPos();
    790         for( i = 0; i < stripCount; i++ )
    791             strm.putDWord( stripOffsets[i] );
    792 
    793         stripCountsOffset = strm.getPos();
    794         for( i = 0; i < stripCount; i++ )
    795             strm.putWord( stripCounts[i] );
    796     }
    797     else if(stripCount == 2)
    798     {
    799         stripOffsetsOffset = strm.getPos();
    800         for (i = 0; i < stripCount; i++)
    801         {
    802             strm.putDWord (stripOffsets [i]);
    803         }
    804         stripCountsOffset = stripCounts [0] + (stripCounts [1] << 16);
    805     }
    806     else
    807     {
    808         stripOffsetsOffset = stripOffsets[0];
    809         stripCountsOffset = stripCounts[0];
    810     }
    811 
    812     if( channels > 1 )
    813     {
    814         int bitsPerSamplePos = strm.getPos();
    815         strm.putWord(bitsPerSample);
    816         strm.putWord(bitsPerSample);
    817         strm.putWord(bitsPerSample);
    818         if( channels == 4 )
    819             strm.putWord(bitsPerSample);
    820         bitsPerSample = bitsPerSamplePos;
    821     }
    822 
    823     directoryOffset = strm.getPos();
    824 
    825     // write header
    826     strm.putWord( 9 );
    827 
    828     /* warning: specification 5.0 of Tiff want to have tags in
    829        ascending order. This is a non-fatal error, but this cause
    830        warning with some tools. So, keep this in ascending order */
    831 
    832     writeTag( strm, TIFF_TAG_WIDTH, TIFF_TYPE_LONG, 1, width );
    833     writeTag( strm, TIFF_TAG_HEIGHT, TIFF_TYPE_LONG, 1, height );
    834     writeTag( strm, TIFF_TAG_BITS_PER_SAMPLE,
    835               TIFF_TYPE_SHORT, channels, bitsPerSample );
    836     writeTag( strm, TIFF_TAG_COMPRESSION, TIFF_TYPE_LONG, 1, TIFF_UNCOMP );
    837     writeTag( strm, TIFF_TAG_PHOTOMETRIC, TIFF_TYPE_SHORT, 1, channels > 1 ? 2 : 1 );
    838 
    839     writeTag( strm, TIFF_TAG_STRIP_OFFSETS, TIFF_TYPE_LONG,
    840               stripCount, stripOffsetsOffset );
    841 
    842     writeTag( strm, TIFF_TAG_SAMPLES_PER_PIXEL, TIFF_TYPE_SHORT, 1, channels );
    843     writeTag( strm, TIFF_TAG_ROWS_PER_STRIP, TIFF_TYPE_LONG, 1, rowsPerStrip );
    844 
    845     writeTag( strm, TIFF_TAG_STRIP_COUNTS,
    846               stripCount > 1 ? TIFF_TYPE_SHORT : TIFF_TYPE_LONG,
    847               stripCount, stripCountsOffset );
    848 
    849     strm.putDWord(0);
    850     strm.close();
    851 
    852     if( m_buf )
    853     {
    854         (*m_buf)[4] = (uchar)directoryOffset;
    855         (*m_buf)[5] = (uchar)(directoryOffset >> 8);
    856         (*m_buf)[6] = (uchar)(directoryOffset >> 16);
    857         (*m_buf)[7] = (uchar)(directoryOffset >> 24);
    858     }
    859     else
    860     {
    861         // write directory offset
    862         FILE* f = fopen( m_filename.c_str(), "r+b" );
    863         buffer[0] = (uchar)directoryOffset;
    864         buffer[1] = (uchar)(directoryOffset >> 8);
    865         buffer[2] = (uchar)(directoryOffset >> 16);
    866         buffer[3] = (uchar)(directoryOffset >> 24);
    867 
    868         fseek( f, 4, SEEK_SET );
    869         fwrite( buffer, 1, 4, f );
    870         fclose(f);
    871     }
    872 
    873     return true;
    874 }
    875 
    876 }
    877