Fix reading of 16-bit TIFF images on big endian host.
Use correct integer types for arguments to TIFFGetField to avoid corruption of values and failed loads of TIFF file when using cv::imread(). Added test where both big and little endian TIFF files are read using imread(). Fixed build of 3rdparty libtiff on big endian hosts. Reduced memory required during decode_tile16384x16384 test by not converting large grayscale test image to color image during read.
This commit is contained in:
parent
bb4199b177
commit
8bbce0a2a2
2
3rdparty/libtiff/CMakeLists.txt
vendored
2
3rdparty/libtiff/CMakeLists.txt
vendored
@ -6,6 +6,7 @@ project(${TIFF_LIBRARY})
|
||||
|
||||
include(CheckFunctionExists)
|
||||
include(CheckIncludeFile)
|
||||
include(TestBigEndian)
|
||||
|
||||
check_include_file(assert.h HAVE_ASSERT_H)
|
||||
check_include_file(fcntl.h HAVE_FCNTL_H)
|
||||
@ -16,6 +17,7 @@ check_include_file(search.h HAVE_SEARCH_H)
|
||||
check_include_file(string.h HAVE_STRING_H)
|
||||
check_include_file(sys/types.h HAVE_SYS_TYPES_H)
|
||||
check_include_file(unistd.h HAVE_UNISTD_H)
|
||||
test_big_endian(HOST_BIGENDIAN)
|
||||
|
||||
if(WIN32 AND NOT HAVE_WINRT)
|
||||
set(USE_WIN32_FILEIO 1)
|
||||
|
2
3rdparty/libtiff/tif_config.h.cmakein
vendored
2
3rdparty/libtiff/tif_config.h.cmakein
vendored
@ -54,7 +54,7 @@
|
||||
|
||||
/* Native cpu byte order: 1 if big-endian (Motorola) or 0 if little-endian
|
||||
(Intel) */
|
||||
#define HOST_BIGENDIAN 0
|
||||
#define HOST_BIGENDIAN @HOST_BIGENDIAN@
|
||||
|
||||
/* Set the native cpu bit order (FILLORDER_LSB2MSB or FILLORDER_MSB2LSB) */
|
||||
#define HOST_FILLORDER FILLORDER_LSB2MSB
|
||||
|
@ -111,18 +111,21 @@ bool TiffDecoder::readHeader()
|
||||
bool result = false;
|
||||
|
||||
close();
|
||||
TIFF* tif = TIFFOpen( m_filename.c_str(), "rb" );
|
||||
// TIFFOpen() mode flags are different to fopen(). A 'b' in mode "rb" has no effect when reading.
|
||||
// http://www.remotesensing.org/libtiff/man/TIFFOpen.3tiff.html
|
||||
TIFF* tif = TIFFOpen( m_filename.c_str(), "r" );
|
||||
|
||||
if( tif )
|
||||
{
|
||||
int wdth = 0, hght = 0, photometric = 0;
|
||||
uint wdth = 0, hght = 0;
|
||||
ushort photometric = 0;
|
||||
m_tif = tif;
|
||||
|
||||
if( TIFFGetField( tif, TIFFTAG_IMAGEWIDTH, &wdth ) &&
|
||||
TIFFGetField( tif, TIFFTAG_IMAGELENGTH, &hght ) &&
|
||||
TIFFGetField( tif, TIFFTAG_PHOTOMETRIC, &photometric ))
|
||||
{
|
||||
int bpp=8, ncn = photometric > 1 ? 3 : 1;
|
||||
ushort bpp=8, ncn = photometric > 1 ? 3 : 1;
|
||||
TIFFGetField( tif, TIFFTAG_BITSPERSAMPLE, &bpp );
|
||||
TIFFGetField( tif, TIFFTAG_SAMPLESPERPIXEL, &ncn );
|
||||
|
||||
@ -175,12 +178,12 @@ bool TiffDecoder::readData( Mat& img )
|
||||
if( m_tif && m_width && m_height )
|
||||
{
|
||||
TIFF* tif = (TIFF*)m_tif;
|
||||
int tile_width0 = m_width, tile_height0 = 0;
|
||||
uint tile_width0 = m_width, tile_height0 = 0;
|
||||
int x, y, i;
|
||||
int is_tiled = TIFFIsTiled(tif);
|
||||
int photometric;
|
||||
ushort photometric;
|
||||
TIFFGetField( tif, TIFFTAG_PHOTOMETRIC, &photometric );
|
||||
int bpp = 8, ncn = photometric > 1 ? 3 : 1;
|
||||
ushort bpp = 8, ncn = photometric > 1 ? 3 : 1;
|
||||
TIFFGetField( tif, TIFFTAG_BITSPERSAMPLE, &bpp );
|
||||
TIFFGetField( tif, TIFFTAG_SAMPLESPERPIXEL, &ncn );
|
||||
const int bitsPerByte = 8;
|
||||
|
@ -408,8 +408,8 @@ TEST(Highgui_Tiff, decode_tile16384x16384)
|
||||
|
||||
try
|
||||
{
|
||||
cv::imread(file3);
|
||||
EXPECT_NO_THROW(cv::imread(file4));
|
||||
cv::imread(file3, CV_LOAD_IMAGE_UNCHANGED);
|
||||
EXPECT_NO_THROW(cv::imread(file4, CV_LOAD_IMAGE_UNCHANGED));
|
||||
}
|
||||
catch(const std::bad_alloc&)
|
||||
{
|
||||
@ -419,4 +419,52 @@ TEST(Highgui_Tiff, decode_tile16384x16384)
|
||||
remove(file3.c_str());
|
||||
remove(file4.c_str());
|
||||
}
|
||||
|
||||
TEST(Highgui_Tiff, write_read_16bit_big_little_endian)
|
||||
{
|
||||
// see issue #2601 "16-bit Grayscale TIFF Load Failures Due to Buffer Underflow and Endianness"
|
||||
|
||||
// Setup data for two minimal 16-bit grayscale TIFF files in both endian formats
|
||||
uchar tiff_sample_data[2][86] = { {
|
||||
// Little endian
|
||||
0x49, 0x49, 0x2a, 0x00, 0x0c, 0x00, 0x00, 0x00, 0xad, 0xde, 0xef, 0xbe, 0x06, 0x00, 0x00, 0x01,
|
||||
0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x00, 0x01, 0x00,
|
||||
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00,
|
||||
0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x11, 0x01,
|
||||
0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x17, 0x01, 0x04, 0x00, 0x01, 0x00,
|
||||
0x00, 0x00, 0x04, 0x00, 0x00, 0x00 }, {
|
||||
// Big endian
|
||||
0x4d, 0x4d, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x0c, 0xde, 0xad, 0xbe, 0xef, 0x00, 0x06, 0x01, 0x00,
|
||||
0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x01, 0x01, 0x00, 0x03, 0x00, 0x00,
|
||||
0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x10,
|
||||
0x00, 0x00, 0x01, 0x06, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x11,
|
||||
0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x01, 0x17, 0x00, 0x04, 0x00, 0x00,
|
||||
0x00, 0x01, 0x00, 0x00, 0x00, 0x04 }
|
||||
};
|
||||
|
||||
// Test imread() for both a little endian TIFF and big endian TIFF
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
string filename = cv::tempfile(".tiff");
|
||||
|
||||
// Write sample TIFF file
|
||||
FILE* fp = fopen(filename.c_str(), "wb");
|
||||
ASSERT_TRUE(fp != NULL);
|
||||
ASSERT_EQ((size_t)1, fwrite(tiff_sample_data, 86, 1, fp));
|
||||
fclose(fp);
|
||||
|
||||
Mat img = imread(filename, CV_LOAD_IMAGE_UNCHANGED);
|
||||
|
||||
EXPECT_EQ(1, img.rows);
|
||||
EXPECT_EQ(2, img.cols);
|
||||
EXPECT_EQ(CV_16U, img.type());
|
||||
EXPECT_EQ(sizeof(ushort), img.elemSize());
|
||||
EXPECT_EQ(1, img.channels());
|
||||
EXPECT_EQ(0xDEAD, img.at<ushort>(0,0));
|
||||
EXPECT_EQ(0xBEEF, img.at<ushort>(0,1));
|
||||
|
||||
remove(filename.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user