From b4d0dff4c597a2c2b8949dd2281f4f022894b37a Mon Sep 17 00:00:00 2001 From: Andrey Kamaev Date: Tue, 29 Jan 2013 20:13:09 +0400 Subject: [PATCH 1/2] Added minimal support for tiff encoder parameters and test for issue #2161 --- modules/highgui/src/grfmt_tiff.cpp | 18 +++++++++++++++++- modules/highgui/test/test_grfmt.cpp | 19 +++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/modules/highgui/src/grfmt_tiff.cpp b/modules/highgui/src/grfmt_tiff.cpp index d2321ceb5e..07fe6445d2 100644 --- a/modules/highgui/src/grfmt_tiff.cpp +++ b/modules/highgui/src/grfmt_tiff.cpp @@ -402,7 +402,18 @@ void TiffEncoder::writeTag( WLByteStream& strm, TiffTag tag, } #ifdef HAVE_TIFF -bool TiffEncoder::writeLibTiff( const Mat& img, const vector& /*params*/) + +static void readParam(const vector& params, int key, int& value) +{ + for(size_t i = 0; i + 1 < params.size(); i += 2) + if(params[i] == key) + { + value = params[i+1]; + break; + } +} + +bool TiffEncoder::writeLibTiff( const Mat& img, const vector& params) { int channels = img.channels(); int width = img.cols, height = img.rows; @@ -429,7 +440,9 @@ bool TiffEncoder::writeLibTiff( const Mat& img, const vector& /*params*/) const int bitsPerByte = 8; size_t fileStep = (width * channels * bitsPerChannel) / bitsPerByte; + int rowsPerStrip = (int)((1 << 13)/fileStep); + readParam(params, TIFFTAG_ROWSPERSTRIP, rowsPerStrip); if( rowsPerStrip < 1 ) rowsPerStrip = 1; @@ -450,6 +463,9 @@ bool TiffEncoder::writeLibTiff( const Mat& img, const vector& /*params*/) int compression = COMPRESSION_LZW; int predictor = PREDICTOR_HORIZONTAL; + readParam(params, TIFFTAG_COMPRESSION, compression); + readParam(params, TIFFTAG_PREDICTOR, predictor); + int colorspace = channels > 1 ? PHOTOMETRIC_RGB : PHOTOMETRIC_MINISBLACK; if ( !TIFFSetField(pTiffHandle, TIFFTAG_IMAGEWIDTH, width) diff --git a/modules/highgui/test/test_grfmt.cpp b/modules/highgui/test/test_grfmt.cpp index 7226ebf7cb..28d30c9b07 100644 --- a/modules/highgui/test/test_grfmt.cpp +++ b/modules/highgui/test/test_grfmt.cpp @@ -291,3 +291,22 @@ TEST(Highgui_Jpeg, encode_empty) ASSERT_THROW(cv::imencode(".jpg", img, jpegImg), cv::Exception); } #endif + + +#ifdef HAVE_TIFF +#include "tiff.h" +TEST(Highgui_Tiff, decode_tile16384x16384) +{ + // see issue #2161 + cv::Mat big(16384, 16384, CV_8UC1, cv::Scalar::all(0)); + string file = cv::tempfile(".tiff"); + std::vector params; + params.push_back(TIFFTAG_ROWSPERSTRIP); + params.push_back(big.rows); + cv::imwrite(file, big, params); + big.release(); + + EXPECT_NO_THROW(cv::imread(file)); + remove(file.c_str()); +} +#endif From 62ce815197e7575c7018cf352c908cfb9798cfff Mon Sep 17 00:00:00 2001 From: Andrey Kamaev Date: Tue, 29 Jan 2013 20:29:31 +0400 Subject: [PATCH 2/2] Fix rollover when computing buffer size in tiff decoder (bug #2161) --- modules/highgui/src/grfmt_tiff.cpp | 31 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/modules/highgui/src/grfmt_tiff.cpp b/modules/highgui/src/grfmt_tiff.cpp index 07fe6445d2..5179531f50 100644 --- a/modules/highgui/src/grfmt_tiff.cpp +++ b/modules/highgui/src/grfmt_tiff.cpp @@ -168,7 +168,6 @@ bool TiffDecoder::readData( Mat& img ) bool result = false; bool color = img.channels() > 1; uchar* data = img.data; - int step = (int)img.step; if( img.depth() != CV_8U && img.depth() != CV_16U && img.depth() != CV_32F && img.depth() != CV_64F ) return false; @@ -211,14 +210,14 @@ bool TiffDecoder::readData( Mat& img ) if( tile_height0 <= 0 ) tile_height0 = m_height; - AutoBuffer _buffer(tile_height0*tile_width0*8); + AutoBuffer _buffer( size_t(8) * tile_height0*tile_width0); uchar* buffer = _buffer; ushort* buffer16 = (ushort*)buffer; float* buffer32 = (float*)buffer; double* buffer64 = (double*)buffer; int tileidx = 0; - for( y = 0; y < m_height; y += tile_height0, data += step*tile_height0 ) + for( y = 0; y < m_height; y += tile_height0, data += img.step*tile_height0 ) { int tile_height = tile_height0; @@ -250,11 +249,11 @@ bool TiffDecoder::readData( Mat& img ) for( i = 0; i < tile_height; i++ ) if( color ) icvCvt_BGRA2BGR_8u_C4C3R( buffer + i*tile_width*4, 0, - data + x*3 + step*(tile_height - i - 1), 0, + data + x*3 + img.step*(tile_height - i - 1), 0, cvSize(tile_width,1), 2 ); else icvCvt_BGRA2Gray_8u_C4C1R( buffer + i*tile_width*4, 0, - data + x + step*(tile_height - i - 1), 0, + data + x + img.step*(tile_height - i - 1), 0, cvSize(tile_width,1), 2 ); break; } @@ -279,19 +278,19 @@ bool TiffDecoder::readData( Mat& img ) if( ncn == 1 ) { icvCvt_Gray2BGR_16u_C1C3R(buffer16 + i*tile_width*ncn, 0, - (ushort*)(data + step*i) + x*3, 0, + (ushort*)(data + img.step*i) + x*3, 0, cvSize(tile_width,1) ); } else if( ncn == 3 ) { icvCvt_RGB2BGR_16u_C3R(buffer16 + i*tile_width*ncn, 0, - (ushort*)(data + step*i) + x*3, 0, + (ushort*)(data + img.step*i) + x*3, 0, cvSize(tile_width,1) ); } else { icvCvt_BGRA2BGR_16u_C4C3R(buffer16 + i*tile_width*ncn, 0, - (ushort*)(data + step*i) + x*3, 0, + (ushort*)(data + img.step*i) + x*3, 0, cvSize(tile_width,1), 2 ); } } @@ -299,14 +298,14 @@ bool TiffDecoder::readData( Mat& img ) { if( ncn == 1 ) { - memcpy((ushort*)(data + step*i)+x, + memcpy((ushort*)(data + img.step*i)+x, buffer16 + i*tile_width*ncn, tile_width*sizeof(buffer16[0])); } else { icvCvt_BGRA2Gray_16u_CnC1R(buffer16 + i*tile_width*ncn, 0, - (ushort*)(data + step*i) + x, 0, + (ushort*)(data + img.step*i) + x, 0, cvSize(tile_width,1), ncn, 2 ); } } @@ -332,13 +331,13 @@ bool TiffDecoder::readData( Mat& img ) { if(dst_bpp == 32) { - memcpy((float*)(data + step*i)+x, + memcpy((float*)(data + img.step*i)+x, buffer32 + i*tile_width*ncn, tile_width*sizeof(buffer32[0])); } else { - memcpy((double*)(data + step*i)+x, + memcpy((double*)(data + img.step*i)+x, buffer64 + i*tile_width*ncn, tile_width*sizeof(buffer64[0])); } @@ -485,7 +484,7 @@ bool TiffEncoder::writeLibTiff( const Mat& img, const vector& params) // row buffer, because TIFFWriteScanline modifies the original data! size_t scanlineSize = TIFFScanlineSize(pTiffHandle); - AutoBuffer _buffer(scanlineSize+32); + AutoBuffer _buffer(scanlineSize+32); uchar* buffer = _buffer; if (!buffer) { @@ -593,9 +592,9 @@ bool TiffEncoder::write( const Mat& img, const vector& /*params*/) #endif*/ int directoryOffset = 0; - AutoBuffer stripOffsets(stripCount); - AutoBuffer stripCounts(stripCount); - AutoBuffer _buffer(fileStep+32); + AutoBuffer stripOffsets(stripCount); + AutoBuffer stripCounts(stripCount); + AutoBuffer _buffer(fileStep+32); uchar* buffer = _buffer; int stripOffsetsOffset = 0; int stripCountsOffset = 0;