Skip to content

Commit

Permalink
Merge pull request #192 from kszafran/1.2.x
Browse files Browse the repository at this point in the history
#58 Support for floating point predictor (type 3) in TIFF Deflate decompressor (1.2.x)
  • Loading branch information
dromagnoli committed Jan 25, 2019
2 parents 66520b7 + c0c4a93 commit dc5d173
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -777,7 +777,14 @@ public class BaselineTIFFTagSet extends TIFFTagSet {
* @see #TAG_PREDICTOR
*/
public static final int PREDICTOR_HORIZONTAL_DIFFERENCING = 2;


/**
* A value to be used with the "Predictor" tag.
*
* @see #TAG_PREDICTOR
*/
public static final int PREDICTOR_FLOATING_POINT = 3;

/**
* Constant specifying the "WhitePoint" tag.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,12 @@

import java.io.IOException;
import java.nio.ByteOrder;
import java.util.Arrays;
import java.util.zip.DataFormatException;
import java.util.zip.Inflater;

import javax.imageio.IIOException;


public class TIFFDeflateDecompressor extends TIFFDecompressor {

private static final boolean DEBUG = false;
Expand All @@ -94,11 +94,10 @@ public class TIFFDeflateDecompressor extends TIFFDecompressor {
public TIFFDeflateDecompressor(int predictor) throws IIOException {
inflater = new Inflater();

if (predictor != BaselineTIFFTagSet.PREDICTOR_NONE &&
predictor !=
BaselineTIFFTagSet.PREDICTOR_HORIZONTAL_DIFFERENCING) {
throw new IIOException("Illegal value for Predictor in " +
"TIFF file");
if (predictor != BaselineTIFFTagSet.PREDICTOR_NONE &&
predictor != BaselineTIFFTagSet.PREDICTOR_HORIZONTAL_DIFFERENCING &&
predictor != BaselineTIFFTagSet.PREDICTOR_FLOATING_POINT) {
throw new IIOException("Illegal value for Predictor in TIFF file");
}

if(DEBUG) {
Expand All @@ -114,25 +113,49 @@ public synchronized void decodeRaw(byte[] b,
int scanlineStride) throws IOException {

// Check bitsPerSample.
if (predictor ==
BaselineTIFFTagSet.PREDICTOR_HORIZONTAL_DIFFERENCING) {
if (predictor == BaselineTIFFTagSet.PREDICTOR_HORIZONTAL_DIFFERENCING) {
int len = bitsPerSample.length;
final int bps=bitsPerSample[0];
final int bps = bitsPerSample[0];
if (bps != 8 && bps != 16) {
throw new IIOException
(bps + "-bit samples " +
"are not supported for Horizontal " +
"differencing Predictor");
}
for (int i = 0; i < len; i++) {
if( bitsPerSample[i] != bps) {
if (bitsPerSample[i] != bps) {
throw new IIOException
("Varying sample width is not " +
"supported for Horizontal " +
"differencing Predictor (first: " +
bps + ", unexpected:" + bitsPerSample[i] + ")");
}
}
} else if (predictor == BaselineTIFFTagSet.PREDICTOR_FLOATING_POINT) {
int len = bitsPerSample.length;
final int bps = bitsPerSample[0];
if (bps != 16 && bps != 24 && bps != 32 && bps != 64) {
throw new IIOException
(bps + "-bit samples " +
"are not supported for Floating " +
"point Predictor");
}
for (int i = 0; i < len; i++) {
if (bitsPerSample[i] != bps) {
throw new IIOException
("Varying sample width is not " +
"supported for Floating " +
"point Predictor (first: " +
bps + ", unexpected:" + bitsPerSample[i] + ")");
}
}
for (int sf : sampleFormat) {
if (sf != BaselineTIFFTagSet.SAMPLE_FORMAT_FLOATING_POINT) {
throw new IIOException
("Floating point Predictor not supported" +
"with " + sf + " data format");
}
}
}

// Seek to current tile data offset.
Expand Down Expand Up @@ -207,6 +230,39 @@ else if(bitsPerSample[0]==16) {
}
}
else throw new IIOException("Unexpected branch of Horizontal differencing Predictor, bps="+bitsPerSample[0]);
} else if (predictor == BaselineTIFFTagSet.PREDICTOR_FLOATING_POINT) {
int bytesPerSample = bitsPerSample[0] / 8;
if (bytesPerRow % (bytesPerSample * samplesPerPixel) != 0) {
throw new IIOException
("The number of bytes in a row (" + bytesPerRow + ") is not divisible" +
"by the number of bytes per pixel (" + bytesPerSample * samplesPerPixel + ")");
}

for (int j = 0; j < srcHeight; j++) {
int offset = bufOffset + j * bytesPerRow;
int count = offset + samplesPerPixel;
for (int i = samplesPerPixel; i < bytesPerRow; i++) {
buf[count] += buf[count - samplesPerPixel];
count++;
}

// Reorder the semi-BigEndian bytes.
byte[] tmp = Arrays.copyOfRange(buf, offset, offset + bytesPerRow);
int samplesPerRow = srcWidth * samplesPerPixel;
if (stream.getByteOrder() == ByteOrder.BIG_ENDIAN) {
for (int i = 0; i < samplesPerRow; i++) {
for (int k = 0; k < bytesPerSample; k++) {
buf[offset + i * bytesPerSample + k] = tmp[k * samplesPerRow + i];
}
}
} else {
for (int i = 0; i < samplesPerRow; i++) {
for (int k = 0; k < bytesPerSample; k++) {
buf[offset + i * bytesPerSample + k] = tmp[(bytesPerSample - k - 1) * samplesPerRow + i];
}
}
}
}
}

if(bytesPerRow != scanlineStride) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import java.awt.image.SampleModel;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.nio.ByteOrder;
import java.util.logging.Level;
Expand Down Expand Up @@ -630,35 +631,44 @@ public void readWithEmptyTiles() throws IOException {
public void readLZWWithHorizontalDifferencingPredictorOn16Bits() throws IOException {
// This image has been created from test.tif using the command:
// gdal_translate -OT UInt16 -co COMPRESS=LZW -co PREDICTOR=2 test.tif lzwtest.tif
final File file = TestData.file(this, "lzwtest.tif");
assertImagesEqual(readTiff("test.tif"), readTiff("lzwtest.tif"));
}

final TIFFImageReader reader = (TIFFImageReader) new TIFFImageReaderSpi()
.createReaderInstance();
@Test
public void readDeflateWithHorizontalDifferencingPredictorOn16Bits() throws IOException {
// This image has been created from test.tif using the command:
// gdal_translate -OT UInt16 -co COMPRESS=DEFLATE -co PREDICTOR=2 test.tif deflatetest.tif
assertImagesEqual(readTiff("test.tif"), readTiff("deflatetest.tif"));
}

FileImageInputStream inputStream = new FileImageInputStream(file);
try {
reader.setInput(inputStream);
BufferedImage image = reader.read(0);
image.flush();
image = null;
} finally {
@Test
public void readDeflateWithFloatingPointPredictor() throws IOException {
// This image has been created from test.tif using the command:
// gdal_translate -ot Float32 -co COMPRESS=DEFLATE -co PREDICTOR=3 test.tif deflate_predictor_3.tif
assertImagesEqual(readTiff("test.tif"), readTiff("deflate_predictor_3.tif"));
}

if (inputStream != null) {
inputStream.flush();
inputStream.close();
}
private void assertImagesEqual(BufferedImage expected, BufferedImage actual) {
assertEquals("Widths are different", expected.getWidth(), actual.getWidth());
assertEquals("Heights are different", expected.getHeight(), actual.getHeight());
int w = expected.getRaster().getWidth();
int h = expected.getRaster().getHeight();
assertArrayEquals(
"Rasters are different",
toByteArray(expected.getRaster().getDataElements(0, 0, w, h, null)),
toByteArray(actual.getRaster().getDataElements(0, 0, w, h, null)));
}

if (reader != null) {
reader.dispose();
}
private byte[] toByteArray(Object arr) {
byte[] result = new byte[Array.getLength(arr)];
for (int i = 0; i < result.length; i++) {
result[i] = ((Number) Array.get(arr, i)).byteValue();
}
return result;
}

@Test
public void readDeflateWithHorizontalDifferencingPredictorOn16Bits() throws IOException {
// This image has been created from test.tif using the command:
// gdal_translate -OT UInt16 -co COMPRESS=DEFLATE -co PREDICTOR=2 test.tif deflatetest.tif
final File file = TestData.file(this, "deflatetest.tif");
private BufferedImage readTiff(String filename) throws IOException {
final File file = TestData.file(this, filename);

final TIFFImageReader reader = (TIFFImageReader) new TIFFImageReaderSpi()
.createReaderInstance();
Expand All @@ -668,17 +678,11 @@ public void readDeflateWithHorizontalDifferencingPredictorOn16Bits() throws IOEx
reader.setInput(inputStream);
BufferedImage image = reader.read(0);
image.flush();
image = null;
return image;
} finally {

if (inputStream != null) {
inputStream.flush();
inputStream.close();
}

if (reader != null) {
reader.dispose();
}
inputStream.flush();
inputStream.close();
reader.dispose();
}
}

Expand Down
Binary file not shown.

0 comments on commit dc5d173

Please sign in to comment.