From e145de01f38fbf428207f157728505e526b06f17 Mon Sep 17 00:00:00 2001 From: Oliver Schmidtmer Date: Wed, 20 Jan 2016 00:22:46 +0100 Subject: [PATCH] corrected IFD & strip width calculations for sequence writer --- .../imageio/plugins/tiff/TIFFImageWriter.java | 29 ++++++-------- .../plugins/tiff/TIFFImageWriterTest.java | 40 ++++++++++++++----- 2 files changed, 43 insertions(+), 26 deletions(-) diff --git a/imageio/imageio-tiff/src/main/java/com/twelvemonkeys/imageio/plugins/tiff/TIFFImageWriter.java b/imageio/imageio-tiff/src/main/java/com/twelvemonkeys/imageio/plugins/tiff/TIFFImageWriter.java index 814e0a25..ead830c5 100644 --- a/imageio/imageio-tiff/src/main/java/com/twelvemonkeys/imageio/plugins/tiff/TIFFImageWriter.java +++ b/imageio/imageio-tiff/src/main/java/com/twelvemonkeys/imageio/plugins/tiff/TIFFImageWriter.java @@ -361,9 +361,11 @@ public final class TIFFImageWriter extends ImageWriterBase { // TODO: If tiled, write tile indexes etc // Depending on param.getTilingMode long nextIFDPointer = -1; + long stripOffset = -1; + long stripByteCount = 0; if (compression == TIFFBaseline.COMPRESSION_NONE) { // This implementation, allows semi-streaming-compatible uncompressed TIFFs - long streamOffset = exifWriter.computeIFDSize(entries.values()) + 12; // 12 == 4 byte magic, 4 byte IDD 0 pointer, 4 byte EOF + long streamOffset = imageOutput.getStreamPosition() + exifWriter.computeIFDSize(entries.values()) + 4; // IFD + 4 byte EOF, (header, ifd0 + n images already written) entries.remove(dummyStripByteCounts); entries.put(TIFF.TAG_STRIP_BYTE_COUNTS, new TIFFEntry(TIFF.TAG_STRIP_BYTE_COUNTS, @@ -373,16 +375,15 @@ public final class TIFFImageWriter extends ImageWriterBase { long idfOffset = exifWriter.writeIFD(entries.values(), imageOutput); // NOTE: Writer takes case of ordering tags nextIFDPointer = imageOutput.getStreamPosition(); - imageOutput.writeInt(0); // Next IFD (none) - long streamPosition = imageOutput.getStreamPosition(); - // Update IFD0 pointer imageOutput.seek(lastIFDPointer); imageOutput.writeInt((int) idfOffset); - imageOutput.seek(streamPosition); - imageOutput.flushBefore(nextIFDPointer); + imageOutput.seek(nextIFDPointer); + imageOutput.flush(); + imageOutput.writeInt(0); // EOF } + stripOffset = imageOutput.getStreamPosition(); // TODO: Create compressor stream per Tile/Strip if (compression == TIFFExtension.COMPRESSION_JPEG) { Iterator writers = ImageIO.getImageWritersByFormatName("JPEG"); @@ -406,26 +407,23 @@ public final class TIFFImageWriter extends ImageWriterBase { writeImageData(createCompressorStream(renderedImage, param, entries), renderedImage, numComponents, bandOffsets, bitOffsets); } + stripByteCount = imageOutput.getStreamPosition() - stripOffset; // Update IFD0-pointer, and write IFD if (compression != TIFFBaseline.COMPRESSION_NONE) { - long thisIFD = imageOutput.getStreamPosition(); - entries.remove(dummyStripOffsets); - entries.put(TIFF.TAG_STRIP_OFFSETS, new TIFFEntry(TIFF.TAG_STRIP_OFFSETS, 8)); + entries.put(TIFF.TAG_STRIP_OFFSETS, new TIFFEntry(TIFF.TAG_STRIP_OFFSETS, stripOffset)); entries.remove(dummyStripByteCounts); - entries.put(TIFF.TAG_STRIP_BYTE_COUNTS, new TIFFEntry(TIFF.TAG_STRIP_BYTE_COUNTS, thisIFD - 8)); + entries.put(TIFF.TAG_STRIP_BYTE_COUNTS, new TIFFEntry(TIFF.TAG_STRIP_BYTE_COUNTS, stripByteCount)); long idfOffset = exifWriter.writeIFD(entries.values(), imageOutput); // NOTE: Writer takes case of ordering tags nextIFDPointer = imageOutput.getStreamPosition(); - imageOutput.writeInt(0); // Next IFD (none) - long streamPosition = imageOutput.getStreamPosition(); - // Update IFD0 pointer imageOutput.seek(lastIFDPointer); imageOutput.writeInt((int) idfOffset); - imageOutput.seek(streamPosition); - imageOutput.flushBefore(nextIFDPointer); + imageOutput.seek(nextIFDPointer); + imageOutput.flush(); + imageOutput.writeInt(0); // EOF } return nextIFDPointer; @@ -892,7 +890,6 @@ public final class TIFFImageWriter extends ImageWriterBase { if (!isWritingSequence) { throw new IllegalStateException("prepareWriteSequence() must be called before writeToSequence()!"); } - sequenceLastIFDPos = writePage(image, param, sequenceExifWriter, sequenceLastIFDPos); } diff --git a/imageio/imageio-tiff/src/test/java/com/twelvemonkeys/imageio/plugins/tiff/TIFFImageWriterTest.java b/imageio/imageio-tiff/src/test/java/com/twelvemonkeys/imageio/plugins/tiff/TIFFImageWriterTest.java index 07e93d28..86d6e135 100644 --- a/imageio/imageio-tiff/src/test/java/com/twelvemonkeys/imageio/plugins/tiff/TIFFImageWriterTest.java +++ b/imageio/imageio-tiff/src/test/java/com/twelvemonkeys/imageio/plugins/tiff/TIFFImageWriterTest.java @@ -43,12 +43,10 @@ import javax.imageio.metadata.IIOMetadataFormatImpl; import javax.imageio.metadata.IIOMetadataNode; import javax.imageio.stream.ImageInputStream; import javax.imageio.stream.ImageOutputStream; +import java.awt.*; import java.awt.image.BufferedImage; import java.awt.image.RenderedImage; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.FileOutputStream; -import java.io.IOException; +import java.io.*; import java.util.Arrays; import java.util.List; @@ -285,7 +283,25 @@ public class TIFFImageWriterTest extends ImageWriterAbstractTestCase { ImageOutputStream stream = ImageIO.createImageOutputStream(buffer); writer.setOutput(stream); - RenderedImage image = getTestData(0); + Graphics2D g2d = null; + BufferedImage image[] = new BufferedImage[] { + new BufferedImage(100, 100, BufferedImage.TYPE_INT_RGB), + new BufferedImage(100, 100, BufferedImage.TYPE_INT_RGB), + new BufferedImage(100, 100, BufferedImage.TYPE_INT_RGB) + }; + g2d = image[0].createGraphics(); + g2d.setColor(Color.red); + g2d.fillRect(0,0,100,100); + g2d.dispose(); + g2d = image[1].createGraphics(); + g2d.setColor(Color.green); + g2d.fillRect(0,0,100,100); + g2d.dispose(); + g2d = image[2].createGraphics(); + g2d.setColor(Color.blue); + g2d.fillRect(0,0,100,100); + g2d.dispose(); + ImageWriteParam params = writer.getDefaultWriteParam(); params.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); @@ -295,12 +311,13 @@ public class TIFFImageWriterTest extends ImageWriterAbstractTestCase { try { writer.prepareWriteSequence(null); - params.setCompressionType("None"); - writer.writeToSequence(new IIOImage(image, null, null), params); - writer.writeToSequence(new IIOImage(image, null, null), params); params.setCompressionType("JPEG"); - writer.writeToSequence(new IIOImage(image, null, null), params); - + writer.writeToSequence(new IIOImage(image[0], null, null), params); + params.setCompressionType("None"); + writer.writeToSequence(new IIOImage(image[1], null, null), params); + params.setCompressionType("JPEG"); + writer.writeToSequence(new IIOImage(image[2], null, null), params); + g2d.dispose(); writer.endWriteSequence(); } catch (IOException e) { @@ -314,5 +331,8 @@ public class TIFFImageWriterTest extends ImageWriterAbstractTestCase { ImageReader reader = ImageIO.getImageReaders(input).next(); reader.setInput(input); assertEquals("wrong image count", 3, reader.getNumImages(true)); + for(int i = 0; i < reader.getNumImages(true); i++){ + reader.read(i); + } } }