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