#401 #334 Work around for stream position issue in FileCacheImageOutputStream causing garbled output for multipage TIFF files

+ Added regression tests.
This commit is contained in:
Harald Kuhr 2017-12-22 22:01:10 +01:00
parent 921dba89f7
commit 63830a26e5
2 changed files with 101 additions and 15 deletions

View File

@ -947,9 +947,9 @@ public final class TIFFImageWriter extends ImageWriterBase {
throw new IllegalStateException("prepareWriteSequence() must be called before writeToSequence()!"); throw new IllegalStateException("prepareWriteSequence() must be called before writeToSequence()!");
} }
if (sequenceLastIFDPos > 0) { if (sequenceIndex > 0) {
imageOutput.seek(imageOutput.length());
imageOutput.flushBefore(sequenceLastIFDPos); imageOutput.flushBefore(sequenceLastIFDPos);
imageOutput.seek(imageOutput.length());
} }
sequenceLastIFDPos = writePage(sequenceIndex++, image, param, sequenceTIFFWriter, sequenceLastIFDPos); sequenceLastIFDPos = writePage(sequenceIndex++, image, param, sequenceTIFFWriter, sequenceLastIFDPos);

View File

@ -45,14 +45,14 @@ import javax.imageio.event.IIOWriteProgressListener;
import javax.imageio.metadata.IIOMetadata; import javax.imageio.metadata.IIOMetadata;
import javax.imageio.metadata.IIOMetadataFormatImpl; import javax.imageio.metadata.IIOMetadataFormatImpl;
import javax.imageio.metadata.IIOMetadataNode; import javax.imageio.metadata.IIOMetadataNode;
import javax.imageio.stream.FileCacheImageOutputStream;
import javax.imageio.stream.FileImageOutputStream;
import javax.imageio.stream.ImageInputStream; import javax.imageio.stream.ImageInputStream;
import javax.imageio.stream.ImageOutputStream; import javax.imageio.stream.ImageOutputStream;
import java.awt.*; import java.awt.*;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage; import java.awt.image.RenderedImage;
import java.io.ByteArrayInputStream; import java.io.*;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URL; import java.net.URL;
import java.nio.ByteOrder; import java.nio.ByteOrder;
import java.util.ArrayList; import java.util.ArrayList;
@ -337,6 +337,101 @@ public class TIFFImageWriterTest extends ImageWriterAbstractTestCase {
} }
} }
private void assertWriteSequence(Class<? extends ImageOutputStream> iosClass, String... compression) throws IOException {
BufferedImage image = new BufferedImage(13, 13, BufferedImage.TYPE_BYTE_GRAY);
Graphics2D g2d = image.createGraphics();
try {
g2d.setColor(Color.WHITE);
g2d.fillRect(image.getWidth() / 4, image.getHeight() / 4, image.getWidth() / 2, image.getHeight() / 2);
}
finally {
g2d.dispose();
}
boolean isFileDirect = iosClass == FileImageOutputStream.class;
Object destination = isFileDirect
? File.createTempFile("temp-", ".tif")
: new ByteArrayOutputStream(1024);
ImageWriter writer = createImageWriter();
try (ImageOutputStream output = isFileDirect
? new FileImageOutputStream((File) destination)
: new FileCacheImageOutputStream((OutputStream) destination, ImageIO.getCacheDirectory())) {
writer.setOutput(output);
ImageWriteParam params = writer.getDefaultWriteParam();
params.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
try {
writer.prepareWriteSequence(null);
for (String compressionType : compression) {
params.setCompressionType(compressionType);
writer.writeToSequence(new IIOImage(image, null, null), params);
}
writer.endWriteSequence();
}
catch (IOException e) {
fail(e.getMessage());
}
}
try (ImageInputStream input = ImageIO.createImageInputStream(isFileDirect
? destination
: new ByteArrayInputStream(((ByteArrayOutputStream) destination).toByteArray()))) {
ImageReader reader = ImageIO.getImageReaders(input).next();
reader.setInput(input);
assertEquals("wrong image count", compression.length, reader.getNumImages(true));
for (int i = 0; i < reader.getNumImages(true); i++) {
assertImageEquals("image " + i + " differs", image, reader.read(i), 5); // Allow room for JPEG compression
}
}
}
@Test
public void testWriteSequenceFileImageOutputStreamUncompressed() throws IOException {
assertWriteSequence(FileImageOutputStream.class, "None", "None");
}
@Test
public void testWriteSequenceFileImageOutputCompressed() throws IOException {
assertWriteSequence(FileImageOutputStream.class, "LZW", "Deflate");
}
@Test
public void testWriteSequenceFileImageOutputStreamUncompressedCompressed() throws IOException {
assertWriteSequence(FileImageOutputStream.class, "None", "LZW", "None");
}
@Test
public void testWriteSequenceFileImageOutputStreamCompressedUncompressed() throws IOException {
assertWriteSequence(FileImageOutputStream.class, "Deflate", "None", "Deflate");
}
@Test
public void testWriteSequenceFileCacheImageOutputStreamUncompressed() throws IOException {
assertWriteSequence(FileCacheImageOutputStream.class, "None", "None");
}
@Test
public void testWriteSequenceFileCacheImageOutputStreamCompressed() throws IOException {
assertWriteSequence(FileCacheImageOutputStream.class, "Deflate", "LZW");
}
@Test
public void testWriteSequenceFileCacheImageOutputStreamCompressedUncompressed() throws IOException {
assertWriteSequence(FileCacheImageOutputStream.class, "LZW", "None", "LZW");
}
@Test
public void testWriteSequenceFileCacheImageOutputStreamUncompressedCompressed() throws IOException {
assertWriteSequence(FileCacheImageOutputStream.class, "None", "Deflate", "None");
}
@Test @Test
public void testWriteSequence() throws IOException { public void testWriteSequence() throws IOException {
BufferedImage[] images = new BufferedImage[] { BufferedImage[] images = new BufferedImage[] {
@ -409,16 +504,7 @@ public class TIFFImageWriterTest extends ImageWriterAbstractTestCase {
assertEquals("wrong image count", images.length, reader.getNumImages(true)); assertEquals("wrong image count", images.length, reader.getNumImages(true));
for (int i = 0; i < reader.getNumImages(true); i++) { for (int i = 0; i < reader.getNumImages(true); i++) {
BufferedImage image = reader.read(i); assertImageEquals("image " + i + " differs", images[i], reader.read(i), 5); // Allow room for JPEG compression
assertEquals(images[i].getWidth(), image.getWidth());
assertEquals(images[i].getHeight(), image.getHeight());
for (int y = 0; y < image.getHeight(); y++) {
for (int x = 0; x < image.getWidth(); x++) {
assertRGBEquals("RGB differ for image " + i + " (" + x + "," + y + ")", images[i].getRGB(x, y), image.getRGB(x, y), 5); // Allow room for JPEG compression
}
}
} }
} }
} }