corrected IFD & strip width calculations for sequence writer

This commit is contained in:
Oliver Schmidtmer 2016-01-20 00:22:46 +01:00
parent fc80ac2ee9
commit e145de01f3
2 changed files with 43 additions and 26 deletions

View File

@ -361,9 +361,11 @@ public final class TIFFImageWriter extends ImageWriterBase {
// TODO: If tiled, write tile indexes etc // TODO: If tiled, write tile indexes etc
// Depending on param.getTilingMode // Depending on param.getTilingMode
long nextIFDPointer = -1; long nextIFDPointer = -1;
long stripOffset = -1;
long stripByteCount = 0;
if (compression == TIFFBaseline.COMPRESSION_NONE) { if (compression == TIFFBaseline.COMPRESSION_NONE) {
// This implementation, allows semi-streaming-compatible uncompressed TIFFs // 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.remove(dummyStripByteCounts);
entries.put(TIFF.TAG_STRIP_BYTE_COUNTS, new TIFFEntry(TIFF.TAG_STRIP_BYTE_COUNTS, 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 long idfOffset = exifWriter.writeIFD(entries.values(), imageOutput); // NOTE: Writer takes case of ordering tags
nextIFDPointer = imageOutput.getStreamPosition(); nextIFDPointer = imageOutput.getStreamPosition();
imageOutput.writeInt(0); // Next IFD (none)
long streamPosition = imageOutput.getStreamPosition();
// Update IFD0 pointer // Update IFD0 pointer
imageOutput.seek(lastIFDPointer); imageOutput.seek(lastIFDPointer);
imageOutput.writeInt((int) idfOffset); imageOutput.writeInt((int) idfOffset);
imageOutput.seek(streamPosition); imageOutput.seek(nextIFDPointer);
imageOutput.flushBefore(nextIFDPointer); imageOutput.flush();
imageOutput.writeInt(0); // EOF
} }
stripOffset = imageOutput.getStreamPosition();
// TODO: Create compressor stream per Tile/Strip // TODO: Create compressor stream per Tile/Strip
if (compression == TIFFExtension.COMPRESSION_JPEG) { if (compression == TIFFExtension.COMPRESSION_JPEG) {
Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName("JPEG"); Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName("JPEG");
@ -406,26 +407,23 @@ public final class TIFFImageWriter extends ImageWriterBase {
writeImageData(createCompressorStream(renderedImage, param, entries), renderedImage, numComponents, bandOffsets, writeImageData(createCompressorStream(renderedImage, param, entries), renderedImage, numComponents, bandOffsets,
bitOffsets); bitOffsets);
} }
stripByteCount = imageOutput.getStreamPosition() - stripOffset;
// Update IFD0-pointer, and write IFD // Update IFD0-pointer, and write IFD
if (compression != TIFFBaseline.COMPRESSION_NONE) { if (compression != TIFFBaseline.COMPRESSION_NONE) {
long thisIFD = imageOutput.getStreamPosition();
entries.remove(dummyStripOffsets); 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.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 long idfOffset = exifWriter.writeIFD(entries.values(), imageOutput); // NOTE: Writer takes case of ordering tags
nextIFDPointer = imageOutput.getStreamPosition(); nextIFDPointer = imageOutput.getStreamPosition();
imageOutput.writeInt(0); // Next IFD (none)
long streamPosition = imageOutput.getStreamPosition();
// Update IFD0 pointer // Update IFD0 pointer
imageOutput.seek(lastIFDPointer); imageOutput.seek(lastIFDPointer);
imageOutput.writeInt((int) idfOffset); imageOutput.writeInt((int) idfOffset);
imageOutput.seek(streamPosition); imageOutput.seek(nextIFDPointer);
imageOutput.flushBefore(nextIFDPointer); imageOutput.flush();
imageOutput.writeInt(0); // EOF
} }
return nextIFDPointer; return nextIFDPointer;
@ -892,7 +890,6 @@ public final class TIFFImageWriter extends ImageWriterBase {
if (!isWritingSequence) { if (!isWritingSequence) {
throw new IllegalStateException("prepareWriteSequence() must be called before writeToSequence()!"); throw new IllegalStateException("prepareWriteSequence() must be called before writeToSequence()!");
} }
sequenceLastIFDPos = writePage(image, param, sequenceExifWriter, sequenceLastIFDPos); sequenceLastIFDPos = writePage(image, param, sequenceExifWriter, sequenceLastIFDPos);
} }

View File

@ -43,12 +43,10 @@ import javax.imageio.metadata.IIOMetadataFormatImpl;
import javax.imageio.metadata.IIOMetadataNode; import javax.imageio.metadata.IIOMetadataNode;
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.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.FileOutputStream;
import java.io.IOException;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
@ -285,7 +283,25 @@ public class TIFFImageWriterTest extends ImageWriterAbstractTestCase {
ImageOutputStream stream = ImageIO.createImageOutputStream(buffer); ImageOutputStream stream = ImageIO.createImageOutputStream(buffer);
writer.setOutput(stream); 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(); ImageWriteParam params = writer.getDefaultWriteParam();
params.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); params.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
@ -295,12 +311,13 @@ public class TIFFImageWriterTest extends ImageWriterAbstractTestCase {
try { try {
writer.prepareWriteSequence(null); 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"); 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(); writer.endWriteSequence();
} }
catch (IOException e) { catch (IOException e) {
@ -314,5 +331,8 @@ public class TIFFImageWriterTest extends ImageWriterAbstractTestCase {
ImageReader reader = ImageIO.getImageReaders(input).next(); ImageReader reader = ImageIO.getImageReaders(input).next();
reader.setInput(input); reader.setInput(input);
assertEquals("wrong image count", 3, reader.getNumImages(true)); assertEquals("wrong image count", 3, reader.getNumImages(true));
for(int i = 0; i < reader.getNumImages(true); i++){
reader.read(i);
}
} }
} }