Using new sequence support in exising writers.

This commit is contained in:
Harald Kuhr
2026-03-13 11:38:28 +01:00
parent dc3d77ad95
commit 177eec06cc
3 changed files with 28 additions and 66 deletions
@@ -32,6 +32,7 @@ package com.twelvemonkeys.imageio.plugins.bmp;
import com.twelvemonkeys.imageio.stream.SubImageOutputStream; import com.twelvemonkeys.imageio.stream.SubImageOutputStream;
import com.twelvemonkeys.imageio.util.ProgressListenerBase; import com.twelvemonkeys.imageio.util.ProgressListenerBase;
import com.twelvemonkeys.imageio.util.SequenceSupport;
import javax.imageio.IIOException; import javax.imageio.IIOException;
import javax.imageio.IIOImage; import javax.imageio.IIOImage;
@@ -64,7 +65,7 @@ public final class ICOImageWriter extends DIBImageWriter {
private static final int ICO_MAX_DIMENSION = 256; private static final int ICO_MAX_DIMENSION = 256;
private static final int INITIAL_ENTRY_COUNT = 8; private static final int INITIAL_ENTRY_COUNT = 8;
private int sequenceIndex = -1; private final SequenceSupport sequence = new SequenceSupport();
private ImageWriter pngDelegate; private ImageWriter pngDelegate;
@@ -74,7 +75,7 @@ public final class ICOImageWriter extends DIBImageWriter {
@Override @Override
protected void resetMembers() { protected void resetMembers() {
sequenceIndex = -1; sequence.reset();
if (pngDelegate != null) { if (pngDelegate != null) {
pngDelegate.dispose(); pngDelegate.dispose();
@@ -107,16 +108,12 @@ public final class ICOImageWriter extends DIBImageWriter {
@Override @Override
public void prepareWriteSequence(final IIOMetadata streamMetadata) throws IOException { public void prepareWriteSequence(final IIOMetadata streamMetadata) throws IOException {
assertOutput(); assertOutput();
sequence.start();
if (sequenceIndex >= 0) {
throw new IllegalStateException("writeSequence already started");
}
writeICOHeader(); writeICOHeader();
// Count: Needs to be updated for each new image // Count: Needs to be updated for each new image
imageOutput.writeShort(0); imageOutput.writeShort(0);
sequenceIndex = 0;
// TODO: Allow passing the initial size of the directory in the stream metadata? // TODO: Allow passing the initial size of the directory in the stream metadata?
// - as this is much more efficient than growing... // - as this is much more efficient than growing...
@@ -130,27 +127,19 @@ public final class ICOImageWriter extends DIBImageWriter {
@Override @Override
public void endWriteSequence() { public void endWriteSequence() {
assertOutput(); assertOutput();
sequence.end();
if (sequenceIndex < 0) {
throw new IllegalStateException("prepareWriteSequence not called");
}
sequenceIndex = -1;
} }
@Override @Override
public void writeToSequence(final IIOImage image, final ImageWriteParam param) throws IOException { public void writeToSequence(final IIOImage image, final ImageWriteParam param) throws IOException {
assertOutput(); assertOutput();
int imageIndex = sequence.advance();
if (sequenceIndex < 0) {
throw new IllegalStateException("prepareWriteSequence not called");
}
if (image.hasRaster()) { if (image.hasRaster()) {
throw new UnsupportedOperationException("Raster not supported"); throw new UnsupportedOperationException("Raster not supported");
} }
if (sequenceIndex >= INITIAL_ENTRY_COUNT) { if (imageIndex >= INITIAL_ENTRY_COUNT) {
growIfNecessary(); growIfNecessary();
} }
@@ -172,7 +161,7 @@ public final class ICOImageWriter extends DIBImageWriter {
// Uncompressed, RLE4/RLE8 or PNG compressed // Uncompressed, RLE4/RLE8 or PNG compressed
boolean pngCompression = param != null && "BI_PNG".equals(param.getCompressionType()); boolean pngCompression = param != null && "BI_PNG".equals(param.getCompressionType());
processImageStarted(sequenceIndex); processImageStarted(imageIndex);
if (pngCompression) { if (pngCompression) {
// NOTE: Embedding a PNG in a ICO is slightly different than a BMP with BI_PNG compression, // NOTE: Embedding a PNG in a ICO is slightly different than a BMP with BI_PNG compression,
@@ -198,17 +187,15 @@ public final class ICOImageWriter extends DIBImageWriter {
// Update count // Update count
imageOutput.seek(4); imageOutput.seek(4);
imageOutput.writeShort(sequenceIndex + 1); imageOutput.writeShort(imageIndex + 1);
// Write entry // Write entry
int entryPosition = 6 + sequenceIndex * ENTRY_SIZE; int entryPosition = 6 + imageIndex * ENTRY_SIZE;
imageOutput.seek(entryPosition); imageOutput.seek(entryPosition);
long size = nextPosition - imageOffset; long size = nextPosition - imageOffset;
writeEntry(width, height, colorModel, (int) size, (int) imageOffset); writeEntry(width, height, colorModel, (int) size, (int) imageOffset);
sequenceIndex++;
imageOutput.seek(nextPosition); imageOutput.seek(nextPosition);
} }
@@ -265,7 +252,7 @@ public final class ICOImageWriter extends DIBImageWriter {
pngDelegate.addIIOWriteWarningListener(new IIOWriteWarningListener() { pngDelegate.addIIOWriteWarningListener(new IIOWriteWarningListener() {
@Override @Override
public void warningOccurred(ImageWriter source, int imageIndex, String warning) { public void warningOccurred(ImageWriter source, int imageIndex, String warning) {
processWarningOccurred(sequenceIndex, warning); processWarningOccurred(sequence.current(), warning);
} }
}); });
} }
@@ -33,6 +33,7 @@ package com.twelvemonkeys.imageio.plugins.icns;
import com.twelvemonkeys.imageio.ImageWriterBase; import com.twelvemonkeys.imageio.ImageWriterBase;
import com.twelvemonkeys.imageio.stream.SubImageOutputStream; import com.twelvemonkeys.imageio.stream.SubImageOutputStream;
import com.twelvemonkeys.imageio.util.ProgressListenerBase; import com.twelvemonkeys.imageio.util.ProgressListenerBase;
import com.twelvemonkeys.imageio.util.SequenceSupport;
import javax.imageio.IIOException; import javax.imageio.IIOException;
import javax.imageio.IIOImage; import javax.imageio.IIOImage;
@@ -55,7 +56,7 @@ import java.util.Iterator;
*/ */
public final class ICNSImageWriter extends ImageWriterBase { public final class ICNSImageWriter extends ImageWriterBase {
private int sequenceIndex = -1; private final SequenceSupport sequence = new SequenceSupport();
private ImageWriter pngDelegate; private ImageWriter pngDelegate;
ICNSImageWriter(ImageWriterSpi provider) { ICNSImageWriter(ImageWriterSpi provider) {
@@ -64,7 +65,7 @@ public final class ICNSImageWriter extends ImageWriterBase {
@Override @Override
protected void resetMembers() { protected void resetMembers() {
sequenceIndex = -1; sequence.reset();
if (pngDelegate != null) { if (pngDelegate != null) {
pngDelegate.dispose(); pngDelegate.dispose();
@@ -97,41 +98,29 @@ public final class ICNSImageWriter extends ImageWriterBase {
@Override @Override
public void prepareWriteSequence(final IIOMetadata streamMetadata) throws IOException { public void prepareWriteSequence(final IIOMetadata streamMetadata) throws IOException {
assertOutput(); assertOutput();
sequence.start();
// TODO: Allow TOC resource to be passed as stream metadata? // TODO: Allow TOC resource to be passed as stream metadata?
// - We only need number of icons to be written later // - We only need number of icons to be written later
// - The contents of the TOC could be updated while adding to the sequence // - The contents of the TOC could be updated while adding to the sequence
if (sequenceIndex >= 0) {
throw new IllegalStateException("writeSequence already started");
}
writeICNSHeader(); writeICNSHeader();
sequenceIndex = 0;
} }
@SuppressWarnings("RedundantThrows") @SuppressWarnings("RedundantThrows")
@Override @Override
public void endWriteSequence() throws IOException { public void endWriteSequence() throws IOException {
assertOutput(); assertOutput();
sequence.end();
if (sequenceIndex < 0) {
throw new IllegalStateException("prepareWriteSequence not called");
}
// TODO: Now that we know the number of icon resources, we could move all data backwards // TODO: Now that we know the number of icon resources, we could move all data backwards
// and write a TOC... But I don't think the benefit will outweigh the cost. // and write a TOC... But I don't think the benefit will outweigh the cost.
sequenceIndex = -1;
} }
@Override @Override
public void writeToSequence(final IIOImage image, final ImageWriteParam param) throws IOException { public void writeToSequence(final IIOImage image, final ImageWriteParam param) throws IOException {
assertOutput(); assertOutput();
int imageIndex = sequence.advance();
if (sequenceIndex < 0) {
throw new IllegalStateException("prepareWriteSequence not called");
}
if (image.hasRaster()) { if (image.hasRaster()) {
throw new UnsupportedOperationException("image has a Raster"); throw new UnsupportedOperationException("image has a Raster");
@@ -148,7 +137,7 @@ public final class ICNSImageWriter extends ImageWriterBase {
imageOutput.writeInt(IconResource.typeFromImage(image.getRenderedImage(), "PNG")); imageOutput.writeInt(IconResource.typeFromImage(image.getRenderedImage(), "PNG"));
imageOutput.writeInt(0); // Size, update later imageOutput.writeInt(0); // Size, update later
processImageStarted(sequenceIndex); processImageStarted(imageIndex);
// Write icon in PNG format // Write icon in PNG format
ImageWriter writer = getPNGDelegate(); ImageWriter writer = getPNGDelegate();
@@ -208,7 +197,7 @@ public final class ICNSImageWriter extends ImageWriterBase {
pngDelegate.addIIOWriteWarningListener(new IIOWriteWarningListener() { pngDelegate.addIIOWriteWarningListener(new IIOWriteWarningListener() {
@Override @Override
public void warningOccurred(ImageWriter source, int imageIndex, String warning) { public void warningOccurred(ImageWriter source, int imageIndex, String warning) {
processWarningOccurred(sequenceIndex, warning); processWarningOccurred(sequence.current(), warning);
} }
}); });
} }
@@ -42,6 +42,7 @@ import com.twelvemonkeys.imageio.stream.SubImageOutputStream;
import com.twelvemonkeys.imageio.util.IIOUtil; import com.twelvemonkeys.imageio.util.IIOUtil;
import com.twelvemonkeys.imageio.util.ImageTypeSpecifiers; import com.twelvemonkeys.imageio.util.ImageTypeSpecifiers;
import com.twelvemonkeys.imageio.util.ProgressListenerBase; import com.twelvemonkeys.imageio.util.ProgressListenerBase;
import com.twelvemonkeys.imageio.util.SequenceSupport;
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;
@@ -110,12 +111,7 @@ public final class TIFFImageWriter extends ImageWriterBase {
// Support storing multiple images in one stream (multi-page TIFF) // Support storing multiple images in one stream (multi-page TIFF)
// Support more of the ImageIO metadata (ie. compression from metadata, etc) // Support more of the ImageIO metadata (ie. compression from metadata, etc)
/** private final SequenceSupport sequence = new SequenceSupport();
* Flag for active sequence writing
*/
private boolean writingSequence = false;
private int sequenceIndex = 0;
/** /**
* Metadata writer for sequence writing * Metadata writer for sequence writing
@@ -751,7 +747,7 @@ public final class TIFFImageWriter extends ImageWriterBase {
ifd = ((TIFFImageMetadata) inData).getIFD(); ifd = ((TIFFImageMetadata) inData).getIFD();
} }
else { else {
TIFFImageMetadata outData = new TIFFImageMetadata(Collections.<Entry>emptySet()); TIFFImageMetadata outData = new TIFFImageMetadata(Collections.emptySet());
try { try {
if (Arrays.asList(inData.getMetadataFormatNames()).contains(SUN_NATIVE_IMAGE_METADATA_FORMAT_NAME)) { if (Arrays.asList(inData.getMetadataFormatNames()).contains(SUN_NATIVE_IMAGE_METADATA_FORMAT_NAME)) {
@@ -766,7 +762,7 @@ public final class TIFFImageWriter extends ImageWriterBase {
} }
} }
catch (IIOInvalidTreeException e) { catch (IIOInvalidTreeException e) {
processWarningOccurred(sequenceIndex, "Could not convert image meta data: " + e.getMessage()); processWarningOccurred(sequence.current(), "Could not convert image meta data: " + e.getMessage());
} }
ifd = outData.getIFD(); ifd = outData.getIFD();
@@ -966,14 +962,11 @@ public final class TIFFImageWriter extends ImageWriterBase {
@Override @Override
public void prepareWriteSequence(final IIOMetadata streamMetadata) throws IOException { public void prepareWriteSequence(final IIOMetadata streamMetadata) throws IOException {
if (writingSequence) { sequence.start();
throw new IllegalStateException("sequence writing has already been started!");
}
assertOutput(); assertOutput();
configureStreamByteOrder(streamMetadata, imageOutput); configureStreamByteOrder(streamMetadata, imageOutput);
writingSequence = true;
sequenceTIFFWriter = new TIFFWriter(isBigTIFF() ? 8 : 4); sequenceTIFFWriter = new TIFFWriter(isBigTIFF() ? 8 : 4);
sequenceTIFFWriter.writeTIFFHeader(imageOutput); sequenceTIFFWriter.writeTIFFHeader(imageOutput);
sequenceLastIFDPos = imageOutput.getStreamPosition(); sequenceLastIFDPos = imageOutput.getStreamPosition();
@@ -985,26 +978,20 @@ public final class TIFFImageWriter extends ImageWriterBase {
@Override @Override
public void writeToSequence(final IIOImage image, final ImageWriteParam param) throws IOException { public void writeToSequence(final IIOImage image, final ImageWriteParam param) throws IOException {
if (!writingSequence) { int sequenceIndex = sequence.advance();
throw new IllegalStateException("prepareWriteSequence() must be called before writeToSequence()!");
}
if (sequenceIndex > 0) { if (sequenceIndex > 0) {
imageOutput.flushBefore(sequenceLastIFDPos); imageOutput.flushBefore(sequenceLastIFDPos);
imageOutput.seek(imageOutput.length()); imageOutput.seek(imageOutput.length());
} }
sequenceLastIFDPos = writePage(sequenceIndex++, image, param, sequenceTIFFWriter, sequenceLastIFDPos); sequenceLastIFDPos = writePage(sequenceIndex, image, param, sequenceTIFFWriter, sequenceLastIFDPos);
} }
@Override @Override
public void endWriteSequence() throws IOException { public void endWriteSequence() throws IOException {
if (!writingSequence) { sequence.end();
throw new IllegalStateException("prepareWriteSequence() must be called before endWriteSequence()!");
}
writingSequence = false;
sequenceIndex = 0;
sequenceTIFFWriter = null; sequenceTIFFWriter = null;
sequenceLastIFDPos = -1; sequenceLastIFDPos = -1;
imageOutput.flush(); imageOutput.flush();
@@ -1014,8 +1001,7 @@ public final class TIFFImageWriter extends ImageWriterBase {
protected void resetMembers() { protected void resetMembers() {
super.resetMembers(); super.resetMembers();
writingSequence = false; sequence.reset();
sequenceIndex = 0;
sequenceTIFFWriter = null; sequenceTIFFWriter = null;
sequenceLastIFDPos = -1; sequenceLastIFDPos = -1;
} }