Skip to content

Commit 3bb66e2

Browse files
committed
fix(tiff): fix loading of edge tiles/strips when not even divide
1 parent b1b868d commit 3bb66e2

1 file changed

Lines changed: 17 additions & 19 deletions

File tree

src/imageio/TiffImageLoader.cpp

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1586,12 +1586,12 @@ Task<ImageData> decodeJpeg(
15861586

15871587
const auto numJpegSamples = numJpegPixels * numComponents;
15881588
const auto numTileSamples = numTilePixels * tileNumComponents;
1589+
const auto numSamples = std::max(numJpegSamples, numTileSamples);
15891590

1590-
if (numJpegSamples < numTileSamples) {
1591-
throw ImageLoadError{fmt::format(
1592-
"Decompressed JPEG has fewer samples ({}) than expected from the tile size and samples per pixel ({}).", numJpegSamples, numTileSamples
1593-
)};
1594-
}
1591+
// There are situations in which either the jpeg is smaller than the tile size (e.g. last strip of an image, where the strip height does
1592+
// not evenly divide the image height) or the jpeg is larger than the tile size (some DNG; we ignore the extra data). Hence make our
1593+
// buffer large enough for either case.
1594+
auto buf = PixelBuffer::alloc(numSamples, pixelFormat);
15951595

15961596
const float scale = 1.0f / (float)((1ull << precision) - 1);
15971597

@@ -1611,8 +1611,6 @@ Task<ImageData> decodeJpeg(
16111611
// (int)cinfo.jpeg_color_space
16121612
// );
16131613

1614-
auto buf = PixelBuffer::alloc(width * height * numComponents, pixelFormat);
1615-
16161614
if (cinfo.data_precision <= 8) {
16171615
HeapArray<JSAMPROW> rowPointers(height);
16181616
for (size_t y = 0; y < height; ++y) {
@@ -2193,18 +2191,6 @@ Task<ImageData> readTiffImage(
21932191
};
21942192
}
21952193

2196-
const auto tileSize = Vector2i{(int)tile.width, (int)tile.height};
2197-
for (auto& channel : tmpImage.channels) {
2198-
if (channel.size() != tileSize) {
2199-
throw ImageLoadError{fmt::format(
2200-
"Tile channel '{}' has unexpected dimensions: expected {}, got {}",
2201-
channel.name(),
2202-
tileSize,
2203-
tmpImage.channels.front().size()
2204-
)};
2205-
}
2206-
}
2207-
22082194
// Rescale embedded image data according to its true bits per sample. E.g. when a 10 bit TIFF encodes data with only
22092195
// 16 bits of JXL precision, as can happen when JXL codestreams are embedded in TIFF files. Curiously, when the
22102196
// situation is reversed (e.g. 16 bit TIFF with 14 bit JXL data), the data shouldn't get rescaled. Hence the clamp.
@@ -2224,6 +2210,18 @@ Task<ImageData> readTiffImage(
22242210
const int yStart = (int)tileY * tile.height;
22252211
const int yEnd = std::min((int)((tileY + 1) * tile.height), size.y());
22262212

2213+
const auto tileSize = Vector2i{xEnd - xStart, yEnd - yStart};
2214+
for (auto& channel : tmpImage.channels) {
2215+
if (channel.size().x() < tileSize.x() || channel.size().y() < tileSize.y()) {
2216+
throw ImageLoadError{fmt::format(
2217+
"Tile channel '{}' has unexpected dimensions: expected {}, got {}",
2218+
channel.name(),
2219+
tileSize,
2220+
tmpImage.channels.front().size()
2221+
)};
2222+
}
2223+
}
2224+
22272225
const size_t numPixels = (size_t)(xEnd - xStart) * (yEnd - yStart);
22282226

22292227
auto* const data = buf.data<float>();

0 commit comments

Comments
 (0)