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