Commit 0460b1ee authored by Utkarsh Ayachit's avatar Utkarsh Ayachit

Support random access in compressed tiff files.

In compressed tiff files with RowsPerStrip > 1, TIFFReadScanline does
not support readom access that reading scan lines in arbitrary order.
This fixes that issue. In such cases, we read the initial scan lines and
discard them before reading the scan lines of interest. This also
requires that we read the file in row order in the file (rather than the
output image).

Test added in parent commit demonstrates the issue. This commit fixes
that issue.
parent f814879b
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <string> #include <string>
#include <algorithm>
extern "C" { extern "C" {
#include "vtk_tiff.h" #include "vtk_tiff.h"
...@@ -43,23 +44,75 @@ int GetFileRow(int row, int, FlipFalse) ...@@ -43,23 +44,75 @@ int GetFileRow(int row, int, FlipFalse)
return row; return row;
} }
// This is inverse of GetFileRow(), which is same as calling GetFileRow()
// again.
template <class Flip>
int GetImageRow(int file_row, int height, Flip flip)
{
return GetFileRow(file_row, height, flip);
}
bool SupportsRandomAccess(TIFF* image)
{
unsigned int rowsPerStrip;
unsigned short compression;
TIFFGetFieldDefaulted(image, TIFFTAG_COMPRESSION, &compression);
TIFFGetFieldDefaulted(image, TIFFTAG_ROWSPERSTRIP, &rowsPerStrip);
return (compression == COMPRESSION_NONE || rowsPerStrip == 1);
}
bool PurgeInitialScanLinesIfNeeded(int fileStartRow, TIFF* image)
{
if (fileStartRow == 0 || SupportsRandomAccess(image))
{
return true;
}
// File doesn't support random access and we want to start at a non-0 row. We
// read (and discard) initial scanlines.
unsigned int isize = TIFFScanlineSize(image);
tdata_t buf = _TIFFmalloc(isize);
for (int i = 0; i < fileStartRow; ++i)
{
if (TIFFReadScanline(image, buf, i, 0) <= 0)
{
_TIFFfree(buf);
return false;
}
}
_TIFFfree(buf);
return true;
}
// Simple scan line copy of a slice in a volume with tightly packed memory. // Simple scan line copy of a slice in a volume with tightly packed memory.
template<typename T, typename Flip> template<typename T, typename Flip>
bool ReadTemplatedImage(T* out, Flip flip, bool ReadTemplatedImage(T* out, Flip flip,
int startCol, int endCol, int startCol, int endCol,
int startRow, int endRow, int startRow, int endRow,
int yIncrements, int yIncrements,
unsigned int height, TIFF *image) unsigned int height,
TIFF *image)
{ {
int fileStartRow = GetFileRow(startRow, height, flip);
int fileEndRow = GetFileRow(endRow, height, flip);
int minFileRow = std::min(fileStartRow, fileEndRow);
int maxFileRow = std::max(fileStartRow, fileEndRow);
if (!PurgeInitialScanLinesIfNeeded(minFileRow, image))
{
return false;
}
unsigned int isize = TIFFScanlineSize(image); unsigned int isize = TIFFScanlineSize(image);
size_t scanLineSize = endCol - startCol + 1; size_t scanLineSize = endCol - startCol + 1;
if (scanLineSize * sizeof(T) == isize) if (scanLineSize * sizeof(T) == isize)
{ {
// We can copy straight into the image data output. // We can copy straight into the image data output.
for (int i = startRow; i <= endRow; ++i) for (int fi = minFileRow; fi <= maxFileRow; ++fi)
{ {
int i = GetImageRow(fi, height, flip);
T* tmp = out + (i - startRow) * yIncrements; T* tmp = out + (i - startRow) * yIncrements;
if (TIFFReadScanline(image, tmp, GetFileRow(i, height, flip), 0) <= 0) if (TIFFReadScanline(image, tmp, fi, 0) <= 0)
{ {
return false; return false;
} }
...@@ -69,10 +122,11 @@ bool ReadTemplatedImage(T* out, Flip flip, ...@@ -69,10 +122,11 @@ bool ReadTemplatedImage(T* out, Flip flip,
{ {
// Copy into a buffer of the appropriate size, then subset into the output. // Copy into a buffer of the appropriate size, then subset into the output.
tdata_t buf = _TIFFmalloc(isize); tdata_t buf = _TIFFmalloc(isize);
for (int i = startRow; i <= endRow; ++i) for (int fi = minFileRow; fi <= maxFileRow; ++fi)
{ {
int i = GetImageRow(fi, height, flip);
T* tmp = out + (i - startRow) * yIncrements; T* tmp = out + (i - startRow) * yIncrements;
if (TIFFReadScanline(image, buf, GetFileRow(i, height, flip), 0) <= 0) if (TIFFReadScanline(image, buf, fi, 0) <= 0)
{ {
_TIFFfree(buf); _TIFFfree(buf);
return false; return false;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment