mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2025-08-04 03:55:28 -04:00
#306 TIFF LZW IndexColorModel issue + sequence index
This commit is contained in:
parent
10b8c11a8e
commit
762b59674b
@ -38,11 +38,13 @@ import com.twelvemonkeys.imageio.metadata.tiff.TIFFEntry;
|
|||||||
import com.twelvemonkeys.imageio.metadata.tiff.TIFFWriter;
|
import com.twelvemonkeys.imageio.metadata.tiff.TIFFWriter;
|
||||||
import com.twelvemonkeys.imageio.stream.SubImageOutputStream;
|
import com.twelvemonkeys.imageio.stream.SubImageOutputStream;
|
||||||
import com.twelvemonkeys.imageio.util.IIOUtil;
|
import com.twelvemonkeys.imageio.util.IIOUtil;
|
||||||
|
import com.twelvemonkeys.imageio.util.ProgressListenerBase;
|
||||||
import com.twelvemonkeys.io.enc.EncoderStream;
|
import com.twelvemonkeys.io.enc.EncoderStream;
|
||||||
import com.twelvemonkeys.io.enc.PackBitsEncoder;
|
import com.twelvemonkeys.io.enc.PackBitsEncoder;
|
||||||
import com.twelvemonkeys.lang.Validate;
|
import com.twelvemonkeys.lang.Validate;
|
||||||
|
|
||||||
import javax.imageio.*;
|
import javax.imageio.*;
|
||||||
|
import javax.imageio.event.IIOWriteWarningListener;
|
||||||
import javax.imageio.metadata.IIOInvalidTreeException;
|
import javax.imageio.metadata.IIOInvalidTreeException;
|
||||||
import javax.imageio.metadata.IIOMetadata;
|
import javax.imageio.metadata.IIOMetadata;
|
||||||
import javax.imageio.metadata.IIOMetadataFormatImpl;
|
import javax.imageio.metadata.IIOMetadataFormatImpl;
|
||||||
@ -69,19 +71,12 @@ import static com.twelvemonkeys.imageio.plugins.tiff.TIFFStreamMetadata.configur
|
|||||||
* @version $Id: TIFFImageWriter.java,v 1.0 18.09.13 12:46 haraldk Exp$
|
* @version $Id: TIFFImageWriter.java,v 1.0 18.09.13 12:46 haraldk Exp$
|
||||||
*/
|
*/
|
||||||
public final class TIFFImageWriter extends ImageWriterBase {
|
public final class TIFFImageWriter extends ImageWriterBase {
|
||||||
// Short term
|
|
||||||
// TODO: Support more of the ImageIO metadata (ie. compression from metadata, etc)
|
|
||||||
|
|
||||||
// Long term
|
// Long term
|
||||||
// TODO: Support tiling
|
// TODO: Support tiling
|
||||||
// TODO: Support thumbnails
|
// TODO: Support thumbnails
|
||||||
// TODO: Support CCITT Modified Huffman compression (2)
|
|
||||||
// TODO: Full "Baseline TIFF" support (pending CCITT compression 2)
|
|
||||||
// TODO: CCITT compressions T.4 and T.6
|
|
||||||
// TODO: Support JPEG compression of CMYK data (pending JPEGImageWriter CMYK write support)
|
// TODO: Support JPEG compression of CMYK data (pending JPEGImageWriter CMYK write support)
|
||||||
// ----
|
// ----
|
||||||
// TODO: Support storing multiple images in one stream (multi-page TIFF)
|
// TODO: Support use-case: Transcode multi-layer PSD to multi-page TIFF with metadata (hard, as Photoshop don't store layers as multi-page TIFF...)
|
||||||
// TODO: Support use-case: Transcode multi-layer PSD to multi-page TIFF with metadata
|
|
||||||
// TODO: Support use-case: Transcode multi-page TIFF to multiple single-page TIFFs with metadata
|
// TODO: Support use-case: Transcode multi-page TIFF to multiple single-page TIFFs with metadata
|
||||||
// TODO: Support use-case: Losslessly transcode JPEG to JPEG-in-TIFF with (EXIF) metadata (and back)
|
// TODO: Support use-case: Losslessly transcode JPEG to JPEG-in-TIFF with (EXIF) metadata (and back)
|
||||||
|
|
||||||
@ -99,18 +94,25 @@ public final class TIFFImageWriter extends ImageWriterBase {
|
|||||||
// Support JPEG compression (7) - might need extra input to allow multiple images with single DQT
|
// Support JPEG compression (7) - might need extra input to allow multiple images with single DQT
|
||||||
// Use sensible defaults for compression based on input? None is sensible... :-)
|
// Use sensible defaults for compression based on input? None is sensible... :-)
|
||||||
// Support resolution, resolution unit and software tags from ImageIO metadata
|
// Support resolution, resolution unit and software tags from ImageIO metadata
|
||||||
|
// Support CCITT Modified Huffman compression (2)
|
||||||
|
// Full "Baseline TIFF" support (pending CCITT compression 2)
|
||||||
|
// CCITT compressions T.4 and T.6
|
||||||
|
// Support storing multiple images in one stream (multi-page TIFF)
|
||||||
|
// Support more of the ImageIO metadata (ie. compression from metadata, etc)
|
||||||
|
|
||||||
private static final Rational STANDARD_DPI = new Rational(72);
|
private static final Rational STANDARD_DPI = new Rational(72);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flag for active sequence writing
|
* Flag for active sequence writing
|
||||||
*/
|
*/
|
||||||
private boolean isWritingSequence = false;
|
private boolean writingSequence = false;
|
||||||
|
|
||||||
|
private int sequenceIndex = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Metadata writer for sequence writing
|
* Metadata writer for sequence writing
|
||||||
*/
|
*/
|
||||||
private TIFFWriter sequenceTiffWriter = null;
|
private TIFFWriter sequenceTIFFWriter = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Position of last IFD Pointer on active sequence writing
|
* Position of last IFD Pointer on active sequence writing
|
||||||
@ -137,12 +139,12 @@ public final class TIFFImageWriter extends ImageWriterBase {
|
|||||||
TIFFWriter tiffWriter = new TIFFWriter();
|
TIFFWriter tiffWriter = new TIFFWriter();
|
||||||
tiffWriter.writeTIFFHeader(imageOutput);
|
tiffWriter.writeTIFFHeader(imageOutput);
|
||||||
|
|
||||||
writePage(image, param, tiffWriter, imageOutput.getStreamPosition());
|
writePage(0, image, param, tiffWriter, imageOutput.getStreamPosition());
|
||||||
|
|
||||||
imageOutput.flush();
|
imageOutput.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
private long writePage(IIOImage image, ImageWriteParam param, TIFFWriter tiffWriter, long lastIFDPointerOffset)
|
private long writePage(int imageIndex, IIOImage image, ImageWriteParam param, TIFFWriter tiffWriter, long lastIFDPointerOffset)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
RenderedImage renderedImage = image.getRenderedImage();
|
RenderedImage renderedImage = image.getRenderedImage();
|
||||||
|
|
||||||
@ -246,7 +248,9 @@ public final class TIFFImageWriter extends ImageWriterBase {
|
|||||||
entries.put(TIFF.TAG_PHOTOMETRIC_INTERPRETATION, new TIFFEntry(TIFF.TAG_PHOTOMETRIC_INTERPRETATION, photometric));
|
entries.put(TIFF.TAG_PHOTOMETRIC_INTERPRETATION, new TIFFEntry(TIFF.TAG_PHOTOMETRIC_INTERPRETATION, photometric));
|
||||||
|
|
||||||
if (photometric == TIFFBaseline.PHOTOMETRIC_PALETTE && colorModel instanceof IndexColorModel) {
|
if (photometric == TIFFBaseline.PHOTOMETRIC_PALETTE && colorModel instanceof IndexColorModel) {
|
||||||
entries.put(TIFF.TAG_COLOR_MAP, new TIFFEntry(TIFF.TAG_COLOR_MAP, createColorMap((IndexColorModel) colorModel)));
|
// TODO: Fix consistency between sampleModel.getSampleSize() and colorModel.getPixelSize()...
|
||||||
|
// We should be able to support 1, 2, 4 and 8 bits per sample at least, and probably 3, 5, 6 and 7 too
|
||||||
|
entries.put(TIFF.TAG_COLOR_MAP, new TIFFEntry(TIFF.TAG_COLOR_MAP, createColorMap((IndexColorModel) colorModel, sampleModel.getSampleSize(0))));
|
||||||
entries.put(TIFF.TAG_SAMPLES_PER_PIXEL, new TIFFEntry(TIFF.TAG_SAMPLES_PER_PIXEL, 1));
|
entries.put(TIFF.TAG_SAMPLES_PER_PIXEL, new TIFFEntry(TIFF.TAG_SAMPLES_PER_PIXEL, 1));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -353,6 +357,9 @@ public final class TIFFImageWriter extends ImageWriterBase {
|
|||||||
ImageWriter jpegWriter = writers.next();
|
ImageWriter jpegWriter = writers.next();
|
||||||
try {
|
try {
|
||||||
jpegWriter.setOutput(new SubImageOutputStream(imageOutput));
|
jpegWriter.setOutput(new SubImageOutputStream(imageOutput));
|
||||||
|
ListenerDelegate listener = new ListenerDelegate(imageIndex);
|
||||||
|
jpegWriter.addIIOWriteProgressListener(listener);
|
||||||
|
jpegWriter.addIIOWriteWarningListener(listener);
|
||||||
jpegWriter.write(renderedImage);
|
jpegWriter.write(renderedImage);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
@ -361,7 +368,7 @@ public final class TIFFImageWriter extends ImageWriterBase {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Write image data
|
// Write image data
|
||||||
writeImageData(createCompressorStream(renderedImage, param, entries), renderedImage, numBands, bandOffsets, bitOffsets);
|
writeImageData(createCompressorStream(renderedImage, param, entries), imageIndex, renderedImage, numBands, bandOffsets, bitOffsets);
|
||||||
}
|
}
|
||||||
|
|
||||||
long stripByteCount = imageOutput.getStreamPosition() - stripOffset;
|
long stripByteCount = imageOutput.getStreamPosition() - stripOffset;
|
||||||
@ -451,6 +458,9 @@ public final class TIFFImageWriter extends ImageWriterBase {
|
|||||||
output.length: 12600399
|
output.length: 12600399
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
int samplesPerPixel = (Integer) entries.get(TIFF.TAG_SAMPLES_PER_PIXEL).getValue();
|
||||||
|
int bitPerSample = ((short[]) entries.get(TIFF.TAG_BITS_PER_SAMPLE).getValue())[0];
|
||||||
|
|
||||||
// Use predictor by default for LZW and ZLib/Deflate
|
// Use predictor by default for LZW and ZLib/Deflate
|
||||||
// TODO: Unless explicitly disabled in TIFFImageWriteParam
|
// TODO: Unless explicitly disabled in TIFFImageWriteParam
|
||||||
int compression = (int) entries.get(TIFF.TAG_COMPRESSION).getValue();
|
int compression = (int) entries.get(TIFF.TAG_COMPRESSION).getValue();
|
||||||
@ -489,16 +499,16 @@ public final class TIFFImageWriter extends ImageWriterBase {
|
|||||||
stream = IIOUtil.createStreamAdapter(imageOutput);
|
stream = IIOUtil.createStreamAdapter(imageOutput);
|
||||||
stream = new DeflaterOutputStream(stream, new Deflater(deflateSetting), 1024);
|
stream = new DeflaterOutputStream(stream, new Deflater(deflateSetting), 1024);
|
||||||
if (entries.containsKey(TIFF.TAG_PREDICTOR) && entries.get(TIFF.TAG_PREDICTOR).getValue().equals(TIFFExtension.PREDICTOR_HORIZONTAL_DIFFERENCING)) {
|
if (entries.containsKey(TIFF.TAG_PREDICTOR) && entries.get(TIFF.TAG_PREDICTOR).getValue().equals(TIFFExtension.PREDICTOR_HORIZONTAL_DIFFERENCING)) {
|
||||||
stream = new HorizontalDifferencingStream(stream, image.getTileWidth(), image.getTile(0, 0).getNumBands(), image.getColorModel().getComponentSize(0), imageOutput.getByteOrder());
|
stream = new HorizontalDifferencingStream(stream, image.getTileWidth(), samplesPerPixel, bitPerSample, imageOutput.getByteOrder());
|
||||||
}
|
}
|
||||||
|
|
||||||
return new DataOutputStream(stream);
|
return new DataOutputStream(stream);
|
||||||
|
|
||||||
case TIFFExtension.COMPRESSION_LZW:
|
case TIFFExtension.COMPRESSION_LZW:
|
||||||
stream = IIOUtil.createStreamAdapter(imageOutput);
|
stream = IIOUtil.createStreamAdapter(imageOutput);
|
||||||
stream = new EncoderStream(stream, new LZWEncoder((image.getTileWidth() * image.getTileHeight() * image.getColorModel().getPixelSize() + 7) / 8));
|
stream = new EncoderStream(stream, new LZWEncoder((image.getTileWidth() * image.getTileHeight() * samplesPerPixel * bitPerSample + 7) / 8));
|
||||||
if (entries.containsKey(TIFF.TAG_PREDICTOR) && entries.get(TIFF.TAG_PREDICTOR).getValue().equals(TIFFExtension.PREDICTOR_HORIZONTAL_DIFFERENCING)) {
|
if (entries.containsKey(TIFF.TAG_PREDICTOR) && entries.get(TIFF.TAG_PREDICTOR).getValue().equals(TIFFExtension.PREDICTOR_HORIZONTAL_DIFFERENCING)) {
|
||||||
stream = new HorizontalDifferencingStream(stream, image.getTileWidth(), image.getTile(0, 0).getNumBands(), image.getColorModel().getComponentSize(0), imageOutput.getByteOrder());
|
stream = new HorizontalDifferencingStream(stream, image.getTileWidth(), samplesPerPixel, bitPerSample, imageOutput.getByteOrder());
|
||||||
}
|
}
|
||||||
|
|
||||||
return new DataOutputStream(stream);
|
return new DataOutputStream(stream);
|
||||||
@ -553,12 +563,12 @@ public final class TIFFImageWriter extends ImageWriterBase {
|
|||||||
throw new IllegalArgumentException("Can't determine PhotometricInterpretation for color model: " + colorModel);
|
throw new IllegalArgumentException("Can't determine PhotometricInterpretation for color model: " + colorModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
private short[] createColorMap(final IndexColorModel colorModel) {
|
private short[] createColorMap(final IndexColorModel colorModel, final int sampleSize) {
|
||||||
// TIFF6.pdf p. 23:
|
// TIFF6.pdf p. 23:
|
||||||
// A TIFF color map is stored as type SHORT, count = 3 * (2^BitsPerSample)
|
// A TIFF color map is stored as type SHORT, count = 3 * (2^BitsPerSample)
|
||||||
// "In a TIFF ColorMap, all the Red values come first, followed by the Green values, then the Blue values.
|
// "In a TIFF ColorMap, all the Red values come first, followed by the Green values, then the Blue values.
|
||||||
// In the ColorMap, black is represented by 0,0,0 and white is represented by 65535, 65535, 65535."
|
// In the ColorMap, black is represented by 0,0,0 and white is represented by 65535, 65535, 65535."
|
||||||
short[] colorMap = new short[(int) (3 * Math.pow(2, colorModel.getPixelSize()))];
|
short[] colorMap = new short[(int) (3 * Math.pow(2, sampleSize))];
|
||||||
|
|
||||||
for (int i = 0; i < colorModel.getMapSize(); i++) {
|
for (int i = 0; i < colorModel.getMapSize(); i++) {
|
||||||
int color = colorModel.getRGB(i);
|
int color = colorModel.getRGB(i);
|
||||||
@ -584,14 +594,14 @@ public final class TIFFImageWriter extends ImageWriterBase {
|
|||||||
return shorts;
|
return shorts;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeImageData(DataOutput stream, RenderedImage renderedImage, int numComponents, int[] bandOffsets, int[] bitOffsets) throws IOException {
|
private void writeImageData(DataOutput stream, int imageIndex, RenderedImage renderedImage, int numComponents, int[] bandOffsets, int[] bitOffsets) throws IOException {
|
||||||
// Store 3BYTE, 4BYTE as is (possibly need to re-arrange to RGB order)
|
// Store 3BYTE, 4BYTE as is (possibly need to re-arrange to RGB order)
|
||||||
// Store INT_RGB as 3BYTE, INT_ARGB as 4BYTE?, INT_ABGR must be re-arranged
|
// Store INT_RGB as 3BYTE, INT_ARGB as 4BYTE?, INT_ABGR must be re-arranged
|
||||||
// Store IndexColorModel as is
|
// Store IndexColorModel as is
|
||||||
// Store BYTE_GRAY as is
|
// Store BYTE_GRAY as is
|
||||||
// Store USHORT_GRAY as is
|
// Store USHORT_GRAY as is
|
||||||
|
|
||||||
processImageStarted(0);
|
processImageStarted(imageIndex);
|
||||||
|
|
||||||
final int minTileY = renderedImage.getMinTileY();
|
final int minTileY = renderedImage.getMinTileY();
|
||||||
final int maxYTiles = minTileY + renderedImage.getNumYTiles();
|
final int maxYTiles = minTileY + renderedImage.getNumYTiles();
|
||||||
@ -777,7 +787,7 @@ public final class TIFFImageWriter extends ImageWriterBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Report better progress
|
// TODO: Report better progress
|
||||||
processImageProgress((100f * yTile) / maxYTiles);
|
processImageProgress((100f * (yTile + 1)) / maxYTiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stream instanceof DataOutputStream) {
|
if (stream instanceof DataOutputStream) {
|
||||||
@ -884,21 +894,22 @@ public final class TIFFImageWriter extends ImageWriterBase {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void prepareWriteSequence(IIOMetadata streamMetadata) throws IOException {
|
public void prepareWriteSequence(IIOMetadata streamMetadata) throws IOException {
|
||||||
if (isWritingSequence) {
|
if (writingSequence) {
|
||||||
throw new IllegalStateException("sequence writing has already been started!");
|
throw new IllegalStateException("sequence writing has already been started!");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ignore streamMetadata. ByteOrder is determined from OutputStream
|
|
||||||
assertOutput();
|
assertOutput();
|
||||||
isWritingSequence = true;
|
configureStreamByteOrder(streamMetadata, imageOutput);
|
||||||
sequenceTiffWriter = new TIFFWriter();
|
|
||||||
sequenceTiffWriter.writeTIFFHeader(imageOutput);
|
writingSequence = true;
|
||||||
|
sequenceTIFFWriter = new TIFFWriter();
|
||||||
|
sequenceTIFFWriter.writeTIFFHeader(imageOutput);
|
||||||
sequenceLastIFDPos = imageOutput.getStreamPosition();
|
sequenceLastIFDPos = imageOutput.getStreamPosition();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeToSequence(IIOImage image, ImageWriteParam param) throws IOException {
|
public void writeToSequence(IIOImage image, ImageWriteParam param) throws IOException {
|
||||||
if (!isWritingSequence) {
|
if (!writingSequence) {
|
||||||
throw new IllegalStateException("prepareWriteSequence() must be called before writeToSequence()!");
|
throw new IllegalStateException("prepareWriteSequence() must be called before writeToSequence()!");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -906,17 +917,18 @@ public final class TIFFImageWriter extends ImageWriterBase {
|
|||||||
imageOutput.flushBefore(sequenceLastIFDPos);
|
imageOutput.flushBefore(sequenceLastIFDPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
sequenceLastIFDPos = writePage(image, param, sequenceTiffWriter, sequenceLastIFDPos);
|
sequenceLastIFDPos = writePage(sequenceIndex++, image, param, sequenceTIFFWriter, sequenceLastIFDPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void endWriteSequence() throws IOException {
|
public void endWriteSequence() throws IOException {
|
||||||
if (!isWritingSequence) {
|
if (!writingSequence) {
|
||||||
throw new IllegalStateException("prepareWriteSequence() must be called before endWriteSequence()!");
|
throw new IllegalStateException("prepareWriteSequence() must be called before endWriteSequence()!");
|
||||||
}
|
}
|
||||||
|
|
||||||
isWritingSequence = false;
|
writingSequence = false;
|
||||||
sequenceTiffWriter = null;
|
sequenceIndex = 0;
|
||||||
|
sequenceTIFFWriter = null;
|
||||||
sequenceLastIFDPos = -1;
|
sequenceLastIFDPos = -1;
|
||||||
imageOutput.flush();
|
imageOutput.flush();
|
||||||
}
|
}
|
||||||
@ -925,8 +937,9 @@ public final class TIFFImageWriter extends ImageWriterBase {
|
|||||||
protected void resetMembers() {
|
protected void resetMembers() {
|
||||||
super.resetMembers();
|
super.resetMembers();
|
||||||
|
|
||||||
isWritingSequence = false;
|
writingSequence = false;
|
||||||
sequenceTiffWriter = null;
|
sequenceIndex = 0;
|
||||||
|
sequenceTIFFWriter = null;
|
||||||
sequenceLastIFDPos = -1;
|
sequenceLastIFDPos = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1046,7 +1059,6 @@ public final class TIFFImageWriter extends ImageWriterBase {
|
|||||||
|
|
||||||
System.err.println("output.length: " + output.length());
|
System.err.println("output.length: " + output.length());
|
||||||
|
|
||||||
// TODO: Support writing multipage TIFF
|
|
||||||
// ImageOutputStream stream = ImageIO.createImageOutputStream(output);
|
// ImageOutputStream stream = ImageIO.createImageOutputStream(output);
|
||||||
// try {
|
// try {
|
||||||
// writer.setOutput(stream);
|
// writer.setOutput(stream);
|
||||||
@ -1068,4 +1080,52 @@ public final class TIFFImageWriter extends ImageWriterBase {
|
|||||||
|
|
||||||
TIFFImageReader.showIt(read, output.getName());
|
TIFFImageReader.showIt(read, output.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class ListenerDelegate extends ProgressListenerBase implements IIOWriteWarningListener {
|
||||||
|
private final int imageIndex;
|
||||||
|
|
||||||
|
public ListenerDelegate(final int imageIndex) {
|
||||||
|
this.imageIndex = imageIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void imageComplete(ImageWriter source) {
|
||||||
|
processImageComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void imageProgress(ImageWriter source, float percentageDone) {
|
||||||
|
processImageProgress(percentageDone);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void imageStarted(ImageWriter source, int imageIndex) {
|
||||||
|
processImageStarted(this.imageIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void thumbnailComplete(ImageWriter source) {
|
||||||
|
processThumbnailComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void thumbnailProgress(ImageWriter source, float percentageDone) {
|
||||||
|
processThumbnailProgress(percentageDone);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void thumbnailStarted(ImageWriter source, int imageIndex, int thumbnailIndex) {
|
||||||
|
processThumbnailStarted(this.imageIndex, thumbnailIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeAborted(ImageWriter source) {
|
||||||
|
processWriteAborted();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void warningOccurred(ImageWriter source, int imageIndex, String warning) {
|
||||||
|
processWarningOccurred(this.imageIndex, warning);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,10 +36,12 @@ import com.twelvemonkeys.imageio.metadata.tiff.TIFFReader;
|
|||||||
import com.twelvemonkeys.imageio.stream.ByteArrayImageInputStream;
|
import com.twelvemonkeys.imageio.stream.ByteArrayImageInputStream;
|
||||||
import com.twelvemonkeys.imageio.util.ImageWriterAbstractTestCase;
|
import com.twelvemonkeys.imageio.util.ImageWriterAbstractTestCase;
|
||||||
import com.twelvemonkeys.io.FastByteArrayOutputStream;
|
import com.twelvemonkeys.io.FastByteArrayOutputStream;
|
||||||
|
import com.twelvemonkeys.io.NullOutputStream;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.w3c.dom.NodeList;
|
import org.w3c.dom.NodeList;
|
||||||
|
|
||||||
import javax.imageio.*;
|
import javax.imageio.*;
|
||||||
|
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;
|
||||||
@ -60,6 +62,7 @@ import static com.twelvemonkeys.imageio.plugins.tiff.TIFFImageMetadataTest.creat
|
|||||||
import static com.twelvemonkeys.imageio.util.ImageReaderAbstractTest.assertRGBEquals;
|
import static com.twelvemonkeys.imageio.util.ImageReaderAbstractTest.assertRGBEquals;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
import static org.junit.Assume.assumeNotNull;
|
import static org.junit.Assume.assumeNotNull;
|
||||||
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TIFFImageWriterTest
|
* TIFFImageWriterTest
|
||||||
@ -382,6 +385,50 @@ public class TIFFImageWriterTest extends ImageWriterAbstractTestCase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWriteSequenceProgress() throws IOException {
|
||||||
|
BufferedImage[] images = new BufferedImage[] {
|
||||||
|
new BufferedImage(100, 100, BufferedImage.TYPE_INT_RGB),
|
||||||
|
new BufferedImage(110, 100, BufferedImage.TYPE_INT_RGB),
|
||||||
|
new BufferedImage(120, 100, BufferedImage.TYPE_INT_RGB)
|
||||||
|
};
|
||||||
|
|
||||||
|
ImageWriter writer = createImageWriter();
|
||||||
|
IIOWriteProgressListener progress = mock(IIOWriteProgressListener.class, "progress");
|
||||||
|
writer.addIIOWriteProgressListener(progress);
|
||||||
|
|
||||||
|
try (ImageOutputStream output = ImageIO.createImageOutputStream(new NullOutputStream())) {
|
||||||
|
writer.setOutput(output);
|
||||||
|
|
||||||
|
try {
|
||||||
|
writer.prepareWriteSequence(null);
|
||||||
|
|
||||||
|
for (int i = 0; i < images.length; i++) {
|
||||||
|
reset(progress);
|
||||||
|
|
||||||
|
ImageWriteParam param = writer.getDefaultWriteParam();
|
||||||
|
|
||||||
|
if (i == images.length - 1) {
|
||||||
|
// Make sure that the JPEG delegation outputs the correct indexes
|
||||||
|
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
|
||||||
|
param.setCompressionType("JPEG");
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.writeToSequence(new IIOImage(images[i], null, null), param);
|
||||||
|
|
||||||
|
verify(progress, times(1)).imageStarted(writer, i);
|
||||||
|
verify(progress, atLeastOnce()).imageProgress(eq(writer), anyFloat());
|
||||||
|
verify(progress, times(1)).imageComplete(writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.endWriteSequence();
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
fail(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadWriteRead1BitLZW() throws IOException {
|
public void testReadWriteRead1BitLZW() throws IOException {
|
||||||
// Read original LZW compressed TIFF
|
// Read original LZW compressed TIFF
|
||||||
|
Loading…
x
Reference in New Issue
Block a user