Skip to content

Commit

Permalink
Refactor generic TIFF tile logic
Browse files Browse the repository at this point in the history
  • Loading branch information
melissalinkert committed Apr 9, 2024
1 parent 41eb29e commit e21ed51
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 74 deletions.
69 changes: 69 additions & 0 deletions components/formats-bsd/src/loci/formats/in/MinimalTiffReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -705,4 +705,73 @@ protected void initTiffParser() {
tiffParser.setUse64BitOffsets(use64Bit);
}

/**
* Get the index of the tile corresponding to given IFD (plane)
* and tile XY indexes.
*
* @param ifd IFD for the requested tile's plane
* @param x tile X index
* @param y tile Y index
* @return corresponding tile index
*/
protected int getTileIndex(IFD ifd, int x, int y) throws FormatException {
int rows = (int) ifd.getTilesPerColumn();
int cols = (int) ifd.getTilesPerRow();

if (x < 0 || x >= cols) {
throw new IllegalArgumentException("X index " + x + " not in range [0, " + cols + ")");
}
if (y < 0 || y >= rows) {
throw new IllegalArgumentException("Y index " + y + " not in range [0, " + rows + ")");
}

return (cols * y) + x;
}

protected long getCompressedByteCount(IFD ifd, int x, int y) throws FormatException, IOException {
long[] byteCounts = ifd.getStripByteCounts();
int tileIndex = getTileIndex(ifd, x, y);
byte[] jpegTable = (byte[]) ifd.getIFDValue(IFD.JPEG_TABLES);
int jpegTableBytes = jpegTable == null ? 0 : jpegTable.length - 2;
long expectedBytes = byteCounts[tileIndex];
if (expectedBytes > 0) {
expectedBytes += jpegTableBytes;
}
if (expectedBytes < 0 || expectedBytes > Integer.MAX_VALUE) {
throw new IOException("Invalid compressed tile size: " + expectedBytes);
}
return expectedBytes;
}

protected byte[] copyTile(IFD ifd, byte[] buf, int x, int y) throws FormatException, IOException {
long[] offsets = ifd.getStripOffsets();
long[] byteCounts = ifd.getStripByteCounts();

int tileIndex = getTileIndex(ifd, x, y);

byte[] jpegTable = (byte[]) ifd.getIFDValue(IFD.JPEG_TABLES);
int jpegTableBytes = jpegTable == null ? 0 : jpegTable.length - 2;
long expectedBytes = getCompressedByteCount(ifd, x, y);

if (buf.length < expectedBytes) {
throw new IllegalArgumentException("Tile buffer too small: expected >=" +
expectedBytes + ", got " + buf.length);
}
else if (expectedBytes < 0 || expectedBytes > Integer.MAX_VALUE) {
throw new IOException("Invalid compressed tile size: " + expectedBytes);
}

if (jpegTable != null && expectedBytes > 0) {
System.arraycopy(jpegTable, 0, buf, 0, jpegTable.length - 2);
// skip over the duplicate SOI marker
tiffParser.getStream().seek(offsets[tileIndex] + 2);
tiffParser.getStream().readFully(buf, jpegTable.length - 2, (int) byteCounts[tileIndex]);
}
else if (byteCounts[tileIndex] > 0) {
tiffParser.getStream().seek(offsets[tileIndex]);
tiffParser.getStream().readFully(buf, 0, (int) byteCounts[tileIndex]);
}
return buf;
}

}
7 changes: 3 additions & 4 deletions components/formats-gpl/src/loci/formats/in/NDPIReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,8 @@ public byte[] openCompressedBytes(int no, int x, int y) throws FormatException,
IFD ifd = ifds.get(ifdIndex);

if (useTiffParser(ifd)) {
// TODO
return null;
byte[] buf = new byte[(int) getCompressedByteCount(ifd, x, y)];
return openCompressedBytes(no, buf, x, y);
}

if (initializedSeries != getCoreIndex() || initializedPlane != no) {
Expand All @@ -169,8 +169,7 @@ public byte[] openCompressedBytes(int no, byte[] buf, int x, int y) throws Forma
IFD ifd = ifds.get(ifdIndex);

if (useTiffParser(ifd)) {
// TODO
return buf;
return copyTile(ifd, buf, x, y);
}

if (initializedSeries != getCoreIndex() || initializedPlane != no) {
Expand Down
72 changes: 2 additions & 70 deletions components/formats-gpl/src/loci/formats/in/SVSReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -306,60 +306,15 @@ public int getTileColumns(int no) {
public byte[] openCompressedBytes(int no, int x, int y) throws FormatException, IOException {
FormatTools.assertId(currentId, true, 1);
IFD ifd = getIFD(no);
long[] byteCounts = ifd.getStripByteCounts();
int tileIndex = getTileIndex(ifd, x, y);

byte[] jpegTable = (byte[]) ifd.getIFDValue(IFD.JPEG_TABLES);
int jpegTableBytes = jpegTable == null ? 0 : jpegTable.length - 2;
long expectedBytes = byteCounts[tileIndex];
if (expectedBytes > 0) {
expectedBytes += jpegTableBytes;
}

if (expectedBytes < 0 || expectedBytes > Integer.MAX_VALUE) {
throw new IOException("Invalid compressed tile size: " + expectedBytes);
}

byte[] buf = new byte[(int) expectedBytes];
byte[] buf = new byte[(int) getCompressedByteCount(ifd, x, y)];
return openCompressedBytes(no, buf, x, y);
}

@Override
public byte[] openCompressedBytes(int no, byte[] buf, int x, int y) throws FormatException, IOException {
FormatTools.assertId(currentId, true, 1);
IFD ifd = getIFD(no);
long[] offsets = ifd.getStripOffsets();
long[] byteCounts = ifd.getStripByteCounts();

int tileIndex = getTileIndex(ifd, x, y);

byte[] jpegTable = (byte[]) ifd.getIFDValue(IFD.JPEG_TABLES);
int jpegTableBytes = jpegTable == null ? 0 : jpegTable.length - 2;
long expectedBytes = byteCounts[tileIndex];
if (expectedBytes > 0) {
expectedBytes += jpegTableBytes;
}

if (buf.length < expectedBytes) {
throw new IllegalArgumentException("Tile buffer too small: expected >=" +
expectedBytes + ", got " + buf.length);
}
else if (expectedBytes < 0 || expectedBytes > Integer.MAX_VALUE) {
throw new IOException("Invalid compressed tile size: " + expectedBytes);
}

if (jpegTable != null && expectedBytes > 0) {
System.arraycopy(jpegTable, 0, buf, 0, jpegTable.length - 2);
// skip over the duplicate SOI marker
tiffParser.getStream().seek(offsets[tileIndex] + 2);
tiffParser.getStream().readFully(buf, jpegTable.length - 2, (int) byteCounts[tileIndex]);
}
else if (byteCounts[tileIndex] > 0) {
tiffParser.getStream().seek(offsets[tileIndex]);
tiffParser.getStream().readFully(buf, 0, (int) byteCounts[tileIndex]);
}

return buf;
return copyTile(ifd, buf, x, y);
}

@Override
Expand Down Expand Up @@ -873,27 +828,4 @@ protected IFD getIFD(int no) {
return ifds.get(ifd);
}

/**
* Get the index of the tile corresponding to given IFD (plane)
* and tile XY indexes.
*
* @param ifd IFD for the requested tile's plane
* @param x tile X index
* @param y tile Y index
* @return corresponding tile index
*/
protected int getTileIndex(IFD ifd, int x, int y) throws FormatException {
int rows = (int) ifd.getTilesPerColumn();
int cols = (int) ifd.getTilesPerRow();

if (x < 0 || x >= cols) {
throw new IllegalArgumentException("X index " + x + " not in range [0, " + cols + ")");
}
if (y < 0 || y >= rows) {
throw new IllegalArgumentException("Y index " + y + " not in range [0, " + rows + ")");
}

return (cols * y) + x;
}

}

0 comments on commit e21ed51

Please sign in to comment.