• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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;
GrFmtSilentTIFFErrorHandler(const char *,const char *,va_list)65 static void GrFmtSilentTIFFErrorHandler( const char*, const char*, va_list ) {}
66 
TiffDecoder()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 
close()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 
~TiffDecoder()91 TiffDecoder::~TiffDecoder()
92 {
93     close();
94 }
95 
signatureLength() const96 size_t TiffDecoder::signatureLength() const
97 {
98     return 4;
99 }
100 
checkSignature(const String & signature) const101 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 
normalizeChannelsNumber(int channels) const108 int TiffDecoder::normalizeChannelsNumber(int channels) const
109 {
110     return channels > 4 ? 4 : channels;
111 }
112 
newDecoder() const113 ImageDecoder TiffDecoder::newDecoder() const
114 {
115     return makePtr<TiffDecoder>();
116 }
117 
readHeader()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 
nextPage()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 
readData(Mat & img)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 
readHdrData(Mat & img)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 
TiffEncoder()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 
~TiffEncoder()477 TiffEncoder::~TiffEncoder()
478 {
479 }
480 
newEncoder() const481 ImageEncoder TiffEncoder::newEncoder() const
482 {
483     return makePtr<TiffEncoder>();
484 }
485 
isFormatSupported(int depth) const486 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 
writeTag(WLByteStream & strm,TiffTag tag,TiffFieldType fieldType,int count,int value)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 
readParam(const std::vector<int> & params,int key,int & value)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 
writeLibTiff(const Mat & img,const std::vector<int> & params)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 
writeHdr(const Mat & _img)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
write(const Mat & img,const std::vector<int> & params)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