From 64fd54ffb4994103d82a34b4039d4938fdb87e46 Mon Sep 17 00:00:00 2001 From: Matti Picus Date: Fri, 24 Jan 2014 13:03:47 +0200 Subject: [PATCH 1/4] fix tiled read for reading tiles into partial blocks in image --- modules/highgui/src/grfmt_tiff.cpp | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/modules/highgui/src/grfmt_tiff.cpp b/modules/highgui/src/grfmt_tiff.cpp index 5179531f50..4b4d8011e8 100644 --- a/modules/highgui/src/grfmt_tiff.cpp +++ b/modules/highgui/src/grfmt_tiff.cpp @@ -246,13 +246,15 @@ bool TiffDecoder::readData( Mat& img ) return false; } + uchar * bstart = buffer + (tile_height0 - tile_height) * tile_width0 * 4; + for( i = 0; i < tile_height; i++ ) if( color ) - icvCvt_BGRA2BGR_8u_C4C3R( buffer + i*tile_width*4, 0, + icvCvt_BGRA2BGR_8u_C4C3R( bstart + i*tile_width0*4, 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, + icvCvt_BGRA2Gray_8u_C4C1R( bstart + i*tile_width0*4, 0, data + x + img.step*(tile_height - i - 1), 0, cvSize(tile_width,1), 2 ); break; @@ -271,25 +273,27 @@ bool TiffDecoder::readData( Mat& img ) return false; } + uint16 * bstart = buffer16 + (tile_height0 - tile_height) * tile_width0 * ncn; + for( i = 0; i < tile_height; i++ ) { if( color ) { if( ncn == 1 ) { - icvCvt_Gray2BGR_16u_C1C3R(buffer16 + i*tile_width*ncn, 0, + icvCvt_Gray2BGR_16u_C1C3R(bstart + i*tile_width0*ncn, 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, + icvCvt_RGB2BGR_16u_C3R(bstart + i*tile_width0*ncn, 0, (ushort*)(data + img.step*i) + x*3, 0, cvSize(tile_width,1) ); } else { - icvCvt_BGRA2BGR_16u_C4C3R(buffer16 + i*tile_width*ncn, 0, + icvCvt_BGRA2BGR_16u_C4C3R(bstart + i*tile_width0*ncn, 0, (ushort*)(data + img.step*i) + x*3, 0, cvSize(tile_width,1), 2 ); } @@ -299,12 +303,12 @@ bool TiffDecoder::readData( Mat& img ) if( ncn == 1 ) { memcpy((ushort*)(data + img.step*i)+x, - buffer16 + i*tile_width*ncn, + bstart + i*tile_width0*ncn, tile_width*sizeof(buffer16[0])); } else { - icvCvt_BGRA2Gray_16u_CnC1R(buffer16 + i*tile_width*ncn, 0, + icvCvt_BGRA2Gray_16u_CnC1R(bstart + i*tile_width0*ncn, 0, (ushort*)(data + img.step*i) + x, 0, cvSize(tile_width,1), ncn, 2 ); } @@ -327,18 +331,21 @@ bool TiffDecoder::readData( Mat& img ) return false; } + float * fstart = buffer32 + (tile_height0 - tile_height) * tile_width0 * sizeof(buffer32[0]); + double * dstart = buffer64 + (tile_height0 - tile_height) * tile_width0 * sizeof(buffer64[0]); + for( i = 0; i < tile_height; i++ ) { if(dst_bpp == 32) { memcpy((float*)(data + img.step*i)+x, - buffer32 + i*tile_width*ncn, + fstart + i*tile_width0*ncn, tile_width*sizeof(buffer32[0])); } else { memcpy((double*)(data + img.step*i)+x, - buffer64 + i*tile_width*ncn, + dstart + i*tile_width0*ncn, tile_width*sizeof(buffer64[0])); } } From 46d128e073a0736f93301f98446f3e721a3e3fd1 Mon Sep 17 00:00:00 2001 From: Matti Picus Date: Thu, 20 Feb 2014 22:10:22 +0200 Subject: [PATCH 2/4] add test (needs updated opencv_extra repo) --- modules/highgui/test/test_grfmt.cpp | 42 +++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/modules/highgui/test/test_grfmt.cpp b/modules/highgui/test/test_grfmt.cpp index 86954e3e10..1fdf2c515a 100644 --- a/modules/highgui/test/test_grfmt.cpp +++ b/modules/highgui/test/test_grfmt.cpp @@ -419,4 +419,46 @@ TEST(Highgui_Tiff, decode_tile16384x16384) remove(file3.c_str()); remove(file4.c_str()); } + +class CV_GrfmtReadTifTiledWithNotFullTiles: public cvtest::BaseTest +{ +public: + void run(int) + { + try + { + /* see issue #3472 - dealing with tiled images where the tile size is + * not a multiple of image size. + * The tiled images were created with 'convert' from ImageMagick, + * using the command 'convert -define tiff:tile-geometry=128x128 -depth [8|16] + * Note that the conversion to 16 bits expands the range from 0-255 to 0-255*255, + * so the test converts back but rounding errors cause small differences. + */ + cv::Mat img = imread(string(ts->get_data_path()) + "readwrite/non_tiled.tif",-1); + if (img.empty()) ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_TEST_DATA); + ASSERT_TRUE(img.channels() == 3); + cv::Mat tiled8 = imread(string(ts->get_data_path()) + "readwrite/tiled_8.tif", -1); + if (tiled8.empty()) ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_TEST_DATA); + ASSERT_PRED_FORMAT2(cvtest::MatComparator(0, 0), img, tiled8); + + cv::Mat tiled16 = imread(string(ts->get_data_path()) + "readwrite/tiled_16.tif", -1); + if (tiled16.empty()) ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_TEST_DATA); + ASSERT_TRUE(tiled16.elemSize() == 6); + tiled16.convertTo(tiled8, CV_8UC3, 1./256.); + ASSERT_PRED_FORMAT2(cvtest::MatComparator(2, 0), img, tiled8); + // What about 32, 64 bit? + } + catch(...) + { + ts->set_failed_test_info(cvtest::TS::FAIL_EXCEPTION); + } + ts->set_failed_test_info(cvtest::TS::OK); + } +}; + +TEST(Highgui_Tiff, decode_tile_remainder) +{ + CV_GrfmtReadTifTiledWithNotFullTiles test; test.safe_run(); +} + #endif From 31c8f2ec57138aa2708aa2b59f930d4102c0d7e8 Mon Sep 17 00:00:00 2001 From: Matti Picus Date: Thu, 20 Feb 2014 22:12:22 +0200 Subject: [PATCH 3/4] fix code, it turns out only TIFFReadRGBATile needs buffer pointer mangling --- modules/highgui/src/grfmt_tiff.cpp | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/modules/highgui/src/grfmt_tiff.cpp b/modules/highgui/src/grfmt_tiff.cpp index 4b4d8011e8..614d001231 100644 --- a/modules/highgui/src/grfmt_tiff.cpp +++ b/modules/highgui/src/grfmt_tiff.cpp @@ -235,19 +235,21 @@ bool TiffDecoder::readData( Mat& img ) { case 8: { + uchar * bstart = buffer; if( !is_tiled ) ok = TIFFReadRGBAStrip( tif, y, (uint32*)buffer ); else + { ok = TIFFReadRGBATile( tif, x, y, (uint32*)buffer ); - + //Tiles fill the buffer from the bottom up + bstart += (tile_height0 - tile_height) * tile_width0 * 4; + } if( !ok ) { close(); return false; } - uchar * bstart = buffer + (tile_height0 - tile_height) * tile_width0 * 4; - for( i = 0; i < tile_height; i++ ) if( color ) icvCvt_BGRA2BGR_8u_C4C3R( bstart + i*tile_width0*4, 0, @@ -273,27 +275,25 @@ bool TiffDecoder::readData( Mat& img ) return false; } - uint16 * bstart = buffer16 + (tile_height0 - tile_height) * tile_width0 * ncn; - for( i = 0; i < tile_height; i++ ) { if( color ) { if( ncn == 1 ) { - icvCvt_Gray2BGR_16u_C1C3R(bstart + i*tile_width0*ncn, 0, + icvCvt_Gray2BGR_16u_C1C3R(buffer16 + i*tile_width0*ncn, 0, (ushort*)(data + img.step*i) + x*3, 0, cvSize(tile_width,1) ); } else if( ncn == 3 ) { - icvCvt_RGB2BGR_16u_C3R(bstart + i*tile_width0*ncn, 0, + icvCvt_RGB2BGR_16u_C3R(buffer16 + i*tile_width0*ncn, 0, (ushort*)(data + img.step*i) + x*3, 0, cvSize(tile_width,1) ); } else { - icvCvt_BGRA2BGR_16u_C4C3R(bstart + i*tile_width0*ncn, 0, + icvCvt_BGRA2BGR_16u_C4C3R(buffer16 + i*tile_width0*ncn, 0, (ushort*)(data + img.step*i) + x*3, 0, cvSize(tile_width,1), 2 ); } @@ -303,12 +303,12 @@ bool TiffDecoder::readData( Mat& img ) if( ncn == 1 ) { memcpy((ushort*)(data + img.step*i)+x, - bstart + i*tile_width0*ncn, + buffer16 + i*tile_width0*ncn, tile_width*sizeof(buffer16[0])); } else { - icvCvt_BGRA2Gray_16u_CnC1R(bstart + i*tile_width0*ncn, 0, + icvCvt_BGRA2Gray_16u_CnC1R(buffer16 + i*tile_width0*ncn, 0, (ushort*)(data + img.step*i) + x, 0, cvSize(tile_width,1), ncn, 2 ); } @@ -331,21 +331,18 @@ bool TiffDecoder::readData( Mat& img ) return false; } - float * fstart = buffer32 + (tile_height0 - tile_height) * tile_width0 * sizeof(buffer32[0]); - double * dstart = buffer64 + (tile_height0 - tile_height) * tile_width0 * sizeof(buffer64[0]); - for( i = 0; i < tile_height; i++ ) { if(dst_bpp == 32) { memcpy((float*)(data + img.step*i)+x, - fstart + i*tile_width0*ncn, + buffer32 + i*tile_width0*ncn, tile_width*sizeof(buffer32[0])); } else { memcpy((double*)(data + img.step*i)+x, - dstart + i*tile_width0*ncn, + buffer64 + i*tile_width0*ncn, tile_width*sizeof(buffer64[0])); } } From dc50dc72548a9b7c970610ee95a7797e644040be Mon Sep 17 00:00:00 2001 From: Matti Picus Date: Fri, 21 Feb 2014 13:54:58 +0200 Subject: [PATCH 4/4] fix merge --- modules/highgui/test/test_grfmt.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/highgui/test/test_grfmt.cpp b/modules/highgui/test/test_grfmt.cpp index bd9e79ad02..f451036ab9 100644 --- a/modules/highgui/test/test_grfmt.cpp +++ b/modules/highgui/test/test_grfmt.cpp @@ -420,7 +420,7 @@ TEST(Highgui_Tiff, decode_tile16384x16384) remove(file4.c_str()); } -class CV_GrfmtReadTifTiledWithNotFullTiles: public cvtest::BaseTest +TEST(Highgui_Tiff, write_read_16bit_big_little_endian) { // see issue #2601 "16-bit Grayscale TIFF Load Failures Due to Buffer Underflow and Endianness"