mirror of
https://github.com/opencv/opencv.git
synced 2026-09-11 04:43:22 -05:00
imgcodecs(tiff): support reading images with more than 4 channels
This commit is contained in:
@@ -236,8 +236,10 @@ bool TiffDecoder::checkSignature( const String& signature ) const
|
||||
|
||||
int TiffDecoder::normalizeChannelsNumber(int channels) const
|
||||
{
|
||||
CV_Check(channels, channels >= 1 && channels <= 4, "Unsupported number of channels");
|
||||
return channels;
|
||||
CV_Check(channels, channels >= 1, "Unsupported number of channels");
|
||||
// TIFFs may have >4 samples per pixel (CMYK, CMYK + alpha, ...); libtiff's RGBA
|
||||
// reader collapses them to 4 channels, so clamp instead of rejecting.
|
||||
return std::min(channels, 4);
|
||||
}
|
||||
|
||||
ImageDecoder TiffDecoder::newDecoder() const
|
||||
@@ -744,7 +746,10 @@ bool TiffDecoder::readData( Mat& img )
|
||||
CV_Assert((int)tile_width0 > 0 && (int)tile_width0 <= TILE_MAX_WIDTH);
|
||||
CV_Assert((int)tile_height0 > 0 && (int)tile_height0 <= TILE_MAX_HEIGHT);
|
||||
const uint64_t MAX_TILE_SIZE = (CV_BIG_UINT(1) << 30);
|
||||
CV_CheckLE((int)ncn, 4, "");
|
||||
// 8-bit images are read via libtiff's RGBA reader, which handles >4 samples
|
||||
// per pixel; deeper depths read raw samples and support at most 4 channels.
|
||||
if (dst_bpp != 8)
|
||||
CV_CheckLE((int)ncn, 4, "");
|
||||
CV_CheckLE((int)bpp, 64, "");
|
||||
|
||||
if (dst_bpp == 8)
|
||||
|
||||
@@ -1293,6 +1293,60 @@ TEST(Imgcodecs_Tiff, read_junk) {
|
||||
ASSERT_TRUE(img.empty());
|
||||
}
|
||||
|
||||
TEST(Imgcodecs_Tiff, read_multi_channel_tiff_26771)
|
||||
{
|
||||
// Minimal 4x4, 8-bit, uncompressed, contiguous TIFF with 5 samples per pixel
|
||||
// (PHOTOMETRIC_SEPARATED / CMYK + one extra sample), reproducing issue #26771.
|
||||
// libtiff collapses the samples to RGBA, so the image must be readable via the
|
||||
// usual color/grayscale/unchanged paths instead of throwing on the channel count.
|
||||
const unsigned char tiff[] = {
|
||||
0x49, 0x49, 0x2a, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x01,
|
||||
0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x01,
|
||||
0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x01,
|
||||
0x03, 0x00, 0x05, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x03, 0x01,
|
||||
0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x01,
|
||||
0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x11, 0x01,
|
||||
0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x00, 0x15, 0x01,
|
||||
0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x16, 0x01,
|
||||
0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x17, 0x01,
|
||||
0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x1c, 0x01,
|
||||
0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x52, 0x01,
|
||||
0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00,
|
||||
0x00, 0x00, 0x00, 0x0a, 0xff, 0x28, 0x00, 0x14, 0x0a, 0xff, 0x50, 0x00,
|
||||
0x28, 0x0a, 0xff, 0x78, 0x00, 0x3c, 0x0a, 0xff, 0x00, 0x28, 0x14, 0x0a,
|
||||
0xff, 0x28, 0x28, 0x28, 0x0a, 0xff, 0x50, 0x28, 0x3c, 0x0a, 0xff, 0x78,
|
||||
0x28, 0x50, 0x0a, 0xff, 0x00, 0x50, 0x28, 0x0a, 0xff, 0x28, 0x50, 0x3c,
|
||||
0x0a, 0xff, 0x50, 0x50, 0x50, 0x0a, 0xff, 0x78, 0x50, 0x64, 0x0a, 0xff,
|
||||
0x00, 0x78, 0x3c, 0x0a, 0xff, 0x28, 0x78, 0x50, 0x0a, 0xff, 0x50, 0x78,
|
||||
0x64, 0x0a, 0xff, 0x78, 0x78, 0x78, 0x0a, 0xff
|
||||
};
|
||||
const Mat buf(1, (int)sizeof(tiff), CV_8UC1, (void*)tiff);
|
||||
|
||||
Mat color;
|
||||
ASSERT_NO_THROW(color = imdecode(buf, IMREAD_COLOR));
|
||||
ASSERT_FALSE(color.empty());
|
||||
EXPECT_EQ(4, color.cols);
|
||||
EXPECT_EQ(4, color.rows);
|
||||
EXPECT_EQ(3, color.channels());
|
||||
|
||||
Mat gray;
|
||||
ASSERT_NO_THROW(gray = imdecode(buf, IMREAD_GRAYSCALE));
|
||||
ASSERT_FALSE(gray.empty());
|
||||
EXPECT_EQ(Size(4, 4), gray.size());
|
||||
EXPECT_EQ(1, gray.channels());
|
||||
|
||||
Mat unchanged;
|
||||
ASSERT_NO_THROW(unchanged = imdecode(buf, IMREAD_UNCHANGED));
|
||||
ASSERT_FALSE(unchanged.empty());
|
||||
EXPECT_EQ(Size(4, 4), unchanged.size());
|
||||
// A >4-channel TIFF is decoded via libtiff's RGBA reader, so the result has 4 channels.
|
||||
EXPECT_EQ(4, unchanged.channels());
|
||||
double mn = 0.0, mx = 0.0;
|
||||
minMaxLoc(unchanged, &mn, &mx);
|
||||
EXPECT_LT(mn, mx);
|
||||
}
|
||||
|
||||
|
||||
typedef int Imgcodecs_Tiff_32F_Compressions_32F_Values;
|
||||
typedef testing::TestWithParam<Imgcodecs_Tiff_32F_Compressions_32F_Values> Imgcodecs_Tiff_32F_Compressions_32F;
|
||||
|
||||
Reference in New Issue
Block a user