/* * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.imageio.plugins.gif; import java.awt.Dimension;import java.awt.Rectangle;import java.awt.image.ColorModel;import java.awt.image.ComponentSampleModel;import java.awt.image.DataBufferByte;import java.awt.image.IndexColorModel;import java.awt.image.Raster;import java.awt.image.RenderedImage;import java.awt.image.SampleModel;import java.awt.image.WritableRaster;import java.io.IOException;import java.nio.ByteOrder;import java.util.Arrays;import java.util.Iterator;import java.util.Locale;import javax.imageio.IIOException;import javax.imageio.IIOImage;import javax.imageio.ImageTypeSpecifier;import javax.imageio.ImageWriteParam;import javax.imageio.ImageWriter;import javax.imageio.spi.ImageWriterSpi;import javax.imageio.metadata.IIOInvalidTreeException;import javax.imageio.metadata.IIOMetadata;import javax.imageio.metadata.IIOMetadataFormatImpl;import javax.imageio.metadata.IIOMetadataNode;import javax.imageio.stream.ImageOutputStream;import org.w3c.dom.Node;import org.w3c.dom.NodeList;import com.sun.imageio.plugins.common.LZWCompressor;import com.sun.imageio.plugins.common.PaletteBuilder;import sun.awt.image.ByteComponentRaster; public class GIFImageWriter extends ImageWriter { private static final boolean DEBUG = false; // XXX false for release! static final String STANDARD_METADATA_NAME = IIOMetadataFormatImpl.standardMetadataFormatName; static final String STREAM_METADATA_NAME = GIFWritableStreamMetadata.NATIVE_FORMAT_NAME; static final String IMAGE_METADATA_NAME = GIFWritableImageMetadata.NATIVE_FORMAT_NAME; /** * The <code>output</code> case to an <code>ImageOutputStream</code>. */ private ImageOutputStream stream = null; /** * Whether a sequence is being written. */ private boolean isWritingSequence = false; /** * Whether the header has been written. */ private boolean wroteSequenceHeader = false; /** * The stream metadata of a sequence. */ private GIFWritableStreamMetadata theStreamMetadata = null; /** * The index of the image being written. */ private int imageIndex = 0; /** * The number of bits represented by the value which should be a * legal length for a color table. */ private static int getNumBits(int value) throws IOException { int numBits; switch(value) { case 2: numBits = 1; break; case 4: numBits = 2; break; case 8: numBits = 3; break; case 16: numBits = 4; break; case 32: numBits = 5; break; case 64: numBits = 6; break; case 128: numBits = 7; break; case 256: numBits = 8; break; default: throw new IOException("Bad palette length: "+value+"!"); } return numBits; } /** * Compute the source region and destination dimensions taking any * parameter settings into account. */ private static void computeRegions(Rectangle sourceBounds, Dimension destSize, ImageWriteParam p) { ImageWriteParam param; int periodX = 1; int periodY = 1; if (p != null) { int[] sourceBands = p.getSourceBands(); if (sourceBands != null && (sourceBands.length != 1 || sourceBands[0] != 0)) { throw new IllegalArgumentException("Cannot sub-band image!"); } // Get source region and subsampling factors Rectangle sourceRegion = p.getSourceRegion(); if (sourceRegion != null) { // Clip to actual image bounds sourceRegion = sourceRegion.intersection(sourceBounds); sourceBounds.setBounds(sourceRegion); } // Adjust for subsampling offsets int gridX = p.getSubsamplingXOffset(); int gridY = p.getSubsamplingYOffset(); sourceBounds.x += gridX; sourceBounds.y += gridY; sourceBounds.width -= gridX; sourceBounds.height -= gridY; // Get subsampling factors periodX = p.getSourceXSubsampling(); periodY = p.getSourceYSubsampling(); } // Compute output dimensions destSize.setSize((sourceBounds.width + periodX - 1)/periodX, (sourceBounds.height + periodY - 1)/periodY); if (destSize.width <= 0 || destSize.height <= 0) { throw new IllegalArgumentException("Empty source region!"); } } /** * Create a color table from the image ColorModel and SampleModel. */ private static byte[] createColorTable(ColorModel colorModel, SampleModel sampleModel) { byte[] colorTable; if (colorModel instanceof IndexColorModel) { IndexColorModel icm = (IndexColorModel)colorModel; int mapSize = icm.getMapSize(); /** * The GIF image format assumes that size of image palette * is power of two. We will use closest larger power of two * as size of color table. */ int ctSize = getGifPaletteSize(mapSize); byte[] reds = new byte[ctSize]; byte[] greens = new byte[ctSize]; byte[] blues = new byte[ctSize]; icm.getReds(reds); icm.getGreens(greens); icm.getBlues(blues); /** * fill tail of color component arrays by replica of first color * in order to avoid appearance of extra colors in the color table */ for (int i = mapSize; i < ctSize; i++) { reds[i] = reds[0]; greens[i] = greens[0]; blues[i] = blues[0]; } colorTable = new byte[3*ctSize]; int idx = 0; for (int i = 0; i < ctSize; i++) { colorTable[idx++] = reds[i]; colorTable[idx++] = greens[i]; colorTable[idx++] = blues[i]; } } else if (sampleModel.getNumBands() == 1) { // create gray-scaled color table for single-banded images int numBits = sampleModel.getSampleSize()[0]; if (numBits > 8) { numBits = 8; } int colorTableLength = 3*(1 << numBits); colorTable = new byte[colorTableLength]; for (int i = 0; i < colorTableLength; i++) { colorTable[i] = (byte)(i/3); } } else { // We do not have enough information here // to create well-fit color table for RGB image. colorTable = null; } return colorTable; } /** * According do GIF specification size of clor table (palette here) * must be in range from 2 to 256 and must be power of 2. */ private static int getGifPaletteSize(int x) { if (x <= 2) { return 2; } x = x - 1; x = x | (x >> 1); x = x | (x >> 2); x = x | (x >> 4); x = x | (x >> 8); x = x | (x >> 16); return x + 1; } public GIFImageWriter(GIFImageWriterSpi originatingProvider) { super(originatingProvider); if (DEBUG) { System.err.println("GIF Writer is created"); } } public boolean canWriteSequence() { return true; } /** * Merges <code>inData</code> into <code>outData</code>. The supplied * metadata format name is attempted first and failing that the standard * metadata format name is attempted. */ private void convertMetadata(String metadataFormatName, IIOMetadata inData, IIOMetadata outData) { String formatName = null; String nativeFormatName = inData.getNativeMetadataFormatName(); if (nativeFormatName != null && nativeFormatName.equals(metadataFormatName)) { formatName = metadataFormatName; } else { String[] extraFormatNames = inData.getExtraMetadataFormatNames(); if (extraFormatNames != null) { for (int i = 0; i < extraFormatNames.length; i++) { if (extraFormatNames[i].equals(metadataFormatName)) { formatName = metadataFormatName; break; } } } } if (formatName == null && inData.isStandardMetadataFormatSupported()) { formatName = STANDARD_METADATA_NAME; } if (formatName != null) { try { Node root = inData.getAsTree(formatName); outData.mergeTree(formatName, root); } catch(IIOInvalidTreeException e) { // ignore } } } /** * Creates a default stream metadata object and merges in the * supplied metadata. */ public IIOMetadata convertStreamMetadata(IIOMetadata inData, ImageWriteParam param) { if (inData == null) { throw new IllegalArgumentException("inData == null!"); } IIOMetadata sm = getDefaultStreamMetadata(param); convertMetadata(STREAM_METADATA_NAME, inData, sm); return sm; } /** * Creates a default image metadata object and merges in the * supplied metadata. */ public IIOMetadata convertImageMetadata(IIOMetadata inData, ImageTypeSpecifier imageType, ImageWriteParam param) { if (inData == null) { throw new IllegalArgumentException("inData == null!"); } if (imageType == null) { throw new IllegalArgumentException("imageType == null!"); } GIFWritableImageMetadata im = (GIFWritableImageMetadata)getDefaultImageMetadata(imageType, param); // Save interlace flag state. boolean isProgressive = im.interlaceFlag; convertMetadata(IMAGE_METADATA_NAME, inData, im); // Undo change to interlace flag if not MODE_COPY_FROM_METADATA. if (param != null && param.canWriteProgressive() && param.getProgressiveMode() != param.MODE_COPY_FROM_METADATA) { im.interlaceFlag = isProgressive; } return im; } public void endWriteSequence() throws IOException { if (stream == null) { throw new IllegalStateException("output == null!"); } if (!isWritingSequence) { throw new IllegalStateException("prepareWriteSequence() was not invoked!"); } writeTrailer(); resetLocal(); } public IIOMetadata getDefaultImageMetadata(ImageTypeSpecifier imageType, ImageWriteParam param) { GIFWritableImageMetadata imageMetadata = new GIFWritableImageMetadata(); // Image dimensions SampleModel sampleModel = imageType.getSampleModel(); Rectangle sourceBounds = new Rectangle(sampleModel.getWidth(), sampleModel.getHeight()); Dimension destSize = new Dimension(); computeRegions(sourceBounds, destSize, param); imageMetadata.imageWidth = destSize.width; imageMetadata.imageHeight = destSize.height; // Interlacing if (param != null && param.canWriteProgressive() && param.getProgressiveMode() == ImageWriteParam.MODE_DISABLED) { imageMetadata.interlaceFlag = false; } else { imageMetadata.interlaceFlag = true; } // Local color table ColorModel colorModel = imageType.getColorModel(); imageMetadata.localColorTable = createColorTable(colorModel, sampleModel); // Transparency if (colorModel instanceof IndexColorModel) { int transparentIndex = ((IndexColorModel)colorModel).getTransparentPixel(); if (transparentIndex != -1) { imageMetadata.transparentColorFlag = true; imageMetadata.transparentColorIndex = transparentIndex; } } return imageMetadata; } public IIOMetadata getDefaultStreamMetadata(ImageWriteParam param) { GIFWritableStreamMetadata streamMetadata = new GIFWritableStreamMetadata(); streamMetadata.version = "89a"; return streamMetadata; } public ImageWriteParam getDefaultWriteParam() { return new GIFImageWriteParam(getLocale()); } public void prepareWriteSequence(IIOMetadata streamMetadata) throws IOException { if (stream == null) { throw new IllegalStateException("Output is not set."); } resetLocal(); // Save the possibly converted stream metadata as an instance variable. if (streamMetadata == null) { this.theStreamMetadata = (GIFWritableStreamMetadata)getDefaultStreamMetadata(null); } else { this.theStreamMetadata = new GIFWritableStreamMetadata(); convertMetadata(STREAM_METADATA_NAME, streamMetadata, theStreamMetadata); } this.isWritingSequence = true; } public void reset() { super.reset(); resetLocal(); } /** * Resets locally defined instance variables. */ private void resetLocal() { this.isWritingSequence = false; this.wroteSequenceHeader = false; this.theStreamMetadata = null; this.imageIndex = 0; } public void setOutput(Object output) { super.setOutput(output); if (output != null) { if (!(output instanceof ImageOutputStream)) { throw new IllegalArgumentException("output is not an ImageOutputStream"); } this.stream = (ImageOutputStream)output; this.stream.setByteOrder(ByteOrder.LITTLE_ENDIAN); } else { this.stream = null; } } public void write(IIOMetadata sm, IIOImage iioimage, ImageWriteParam p) throws IOException { if (stream == null) { throw new IllegalStateException("output == null!"); } if (iioimage == null) { throw new IllegalArgumentException("iioimage == null!"); } if (iioimage.hasRaster()) { throw new UnsupportedOperationException("canWriteRasters() == false!"); } resetLocal();Lines 1–500 of 1317. Load more
/* * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.imageio.plugins.gif; import java.awt.Dimension; import java.awt.Rectangle; import java.awt.image.ColorModel; import java.awt.image.ComponentSampleModel; import java.awt.image.DataBufferByte; import java.awt.image.IndexColorModel; import java.awt.image.Raster; import java.awt.image.RenderedImage; import java.awt.image.SampleModel; import java.awt.image.WritableRaster; import java.io.IOException; import java.nio.ByteOrder; import java.util.Arrays; import java.util.Iterator; import java.util.Locale; import javax.imageio.IIOException; import javax.imageio.IIOImage; import javax.imageio.ImageTypeSpecifier; import javax.imageio.ImageWriteParam; import javax.imageio.ImageWriter; import javax.imageio.spi.ImageWriterSpi; import javax.imageio.metadata.IIOInvalidTreeException; import javax.imageio.metadata.IIOMetadata; import javax.imageio.metadata.IIOMetadataFormatImpl; import javax.imageio.metadata.IIOMetadataNode; import javax.imageio.stream.ImageOutputStream; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import com.sun.imageio.plugins.common.LZWCompressor; import com.sun.imageio.plugins.common.PaletteBuilder; import sun.awt.image.ByteComponentRaster; public class GIFImageWriter extends ImageWriter { private static final boolean DEBUG = false; // XXX false for release! static final String STANDARD_METADATA_NAME = IIOMetadataFormatImpl.standardMetadataFormatName; static final String STREAM_METADATA_NAME = GIFWritableStreamMetadata.NATIVE_FORMAT_NAME; static final String IMAGE_METADATA_NAME = GIFWritableImageMetadata.NATIVE_FORMAT_NAME; /** * The <code>output</code> case to an <code>ImageOutputStream</code>. */ private ImageOutputStream stream = null; /** * Whether a sequence is being written. */ private boolean isWritingSequence = false; /** * Whether the header has been written. */ private boolean wroteSequenceHeader = false; /** * The stream metadata of a sequence. */ private GIFWritableStreamMetadata theStreamMetadata = null; /** * The index of the image being written. */ private int imageIndex = 0; /** * The number of bits represented by the value which should be a * legal length for a color table. */ private static int getNumBits(int value) throws IOException { int numBits; switch(value) { case 2: numBits = 1; break; case 4: numBits = 2; break; case 8: numBits = 3; break; case 16: numBits = 4; break; case 32: numBits = 5; break; case 64: numBits = 6; break; case 128: numBits = 7; break; case 256: numBits = 8; break; default: throw new IOException("Bad palette length: "+value+"!"); } return numBits; } /** * Compute the source region and destination dimensions taking any * parameter settings into account. */ private static void computeRegions(Rectangle sourceBounds, Dimension destSize, ImageWriteParam p) { ImageWriteParam param; int periodX = 1; int periodY = 1; if (p != null) { int[] sourceBands = p.getSourceBands(); if (sourceBands != null && (sourceBands.length != 1 || sourceBands[0] != 0)) { throw new IllegalArgumentException("Cannot sub-band image!"); } // Get source region and subsampling factors Rectangle sourceRegion = p.getSourceRegion(); if (sourceRegion != null) { // Clip to actual image bounds sourceRegion = sourceRegion.intersection(sourceBounds); sourceBounds.setBounds(sourceRegion); } // Adjust for subsampling offsets int gridX = p.getSubsamplingXOffset(); int gridY = p.getSubsamplingYOffset(); sourceBounds.x += gridX; sourceBounds.y += gridY; sourceBounds.width -= gridX; sourceBounds.height -= gridY; // Get subsampling factors periodX = p.getSourceXSubsampling(); periodY = p.getSourceYSubsampling(); } // Compute output dimensions destSize.setSize((sourceBounds.width + periodX - 1)/periodX, (sourceBounds.height + periodY - 1)/periodY); if (destSize.width <= 0 || destSize.height <= 0) { throw new IllegalArgumentException("Empty source region!"); } } /** * Create a color table from the image ColorModel and SampleModel. */ private static byte[] createColorTable(ColorModel colorModel, SampleModel sampleModel) { byte[] colorTable; if (colorModel instanceof IndexColorModel) { IndexColorModel icm = (IndexColorModel)colorModel; int mapSize = icm.getMapSize(); /** * The GIF image format assumes that size of image palette * is power of two. We will use closest larger power of two * as size of color table. */ int ctSize = getGifPaletteSize(mapSize); byte[] reds = new byte[ctSize]; byte[] greens = new byte[ctSize]; byte[] blues = new byte[ctSize]; icm.getReds(reds); icm.getGreens(greens); icm.getBlues(blues); /** * fill tail of color component arrays by replica of first color * in order to avoid appearance of extra colors in the color table */ for (int i = mapSize; i < ctSize; i++) { reds[i] = reds[0]; greens[i] = greens[0]; blues[i] = blues[0]; } colorTable = new byte[3*ctSize]; int idx = 0; for (int i = 0; i < ctSize; i++) { colorTable[idx++] = reds[i]; colorTable[idx++] = greens[i]; colorTable[idx++] = blues[i]; } } else if (sampleModel.getNumBands() == 1) { // create gray-scaled color table for single-banded images int numBits = sampleModel.getSampleSize()[0]; if (numBits > 8) { numBits = 8; } int colorTableLength = 3*(1 << numBits); colorTable = new byte[colorTableLength]; for (int i = 0; i < colorTableLength; i++) { colorTable[i] = (byte)(i/3); } } else { // We do not have enough information here // to create well-fit color table for RGB image. colorTable = null; } return colorTable; } /** * According do GIF specification size of clor table (palette here) * must be in range from 2 to 256 and must be power of 2. */ private static int getGifPaletteSize(int x) { if (x <= 2) { return 2; } x = x - 1; x = x | (x >> 1); x = x | (x >> 2); x = x | (x >> 4); x = x | (x >> 8); x = x | (x >> 16); return x + 1; } public GIFImageWriter(GIFImageWriterSpi originatingProvider) { super(originatingProvider); if (DEBUG) { System.err.println("GIF Writer is created"); } } public boolean canWriteSequence() { return true; } /** * Merges <code>inData</code> into <code>outData</code>. The supplied * metadata format name is attempted first and failing that the standard * metadata format name is attempted. */ private void convertMetadata(String metadataFormatName, IIOMetadata inData, IIOMetadata outData) { String formatName = null; String nativeFormatName = inData.getNativeMetadataFormatName(); if (nativeFormatName != null && nativeFormatName.equals(metadataFormatName)) { formatName = metadataFormatName; } else { String[] extraFormatNames = inData.getExtraMetadataFormatNames(); if (extraFormatNames != null) { for (int i = 0; i < extraFormatNames.length; i++) { if (extraFormatNames[i].equals(metadataFormatName)) { formatName = metadataFormatName; break; } } } } if (formatName == null && inData.isStandardMetadataFormatSupported()) { formatName = STANDARD_METADATA_NAME; } if (formatName != null) { try { Node root = inData.getAsTree(formatName); outData.mergeTree(formatName, root); } catch(IIOInvalidTreeException e) { // ignore } } } /** * Creates a default stream metadata object and merges in the * supplied metadata. */ public IIOMetadata convertStreamMetadata(IIOMetadata inData, ImageWriteParam param) { if (inData == null) { throw new IllegalArgumentException("inData == null!"); } IIOMetadata sm = getDefaultStreamMetadata(param); convertMetadata(STREAM_METADATA_NAME, inData, sm); return sm; } /** * Creates a default image metadata object and merges in the * supplied metadata. */ public IIOMetadata convertImageMetadata(IIOMetadata inData, ImageTypeSpecifier imageType, ImageWriteParam param) { if (inData == null) { throw new IllegalArgumentException("inData == null!"); } if (imageType == null) { throw new IllegalArgumentException("imageType == null!"); } GIFWritableImageMetadata im = (GIFWritableImageMetadata)getDefaultImageMetadata(imageType, param); // Save interlace flag state. boolean isProgressive = im.interlaceFlag; convertMetadata(IMAGE_METADATA_NAME, inData, im); // Undo change to interlace flag if not MODE_COPY_FROM_METADATA. if (param != null && param.canWriteProgressive() && param.getProgressiveMode() != param.MODE_COPY_FROM_METADATA) { im.interlaceFlag = isProgressive; } return im; } public void endWriteSequence() throws IOException { if (stream == null) { throw new IllegalStateException("output == null!"); } if (!isWritingSequence) { throw new IllegalStateException("prepareWriteSequence() was not invoked!"); } writeTrailer(); resetLocal(); } public IIOMetadata getDefaultImageMetadata(ImageTypeSpecifier imageType, ImageWriteParam param) { GIFWritableImageMetadata imageMetadata = new GIFWritableImageMetadata(); // Image dimensions SampleModel sampleModel = imageType.getSampleModel(); Rectangle sourceBounds = new Rectangle(sampleModel.getWidth(), sampleModel.getHeight()); Dimension destSize = new Dimension(); computeRegions(sourceBounds, destSize, param); imageMetadata.imageWidth = destSize.width; imageMetadata.imageHeight = destSize.height; // Interlacing if (param != null && param.canWriteProgressive() && param.getProgressiveMode() == ImageWriteParam.MODE_DISABLED) { imageMetadata.interlaceFlag = false; } else { imageMetadata.interlaceFlag = true; } // Local color table ColorModel colorModel = imageType.getColorModel(); imageMetadata.localColorTable = createColorTable(colorModel, sampleModel); // Transparency if (colorModel instanceof IndexColorModel) { int transparentIndex = ((IndexColorModel)colorModel).getTransparentPixel(); if (transparentIndex != -1) { imageMetadata.transparentColorFlag = true; imageMetadata.transparentColorIndex = transparentIndex; } } return imageMetadata; } public IIOMetadata getDefaultStreamMetadata(ImageWriteParam param) { GIFWritableStreamMetadata streamMetadata = new GIFWritableStreamMetadata(); streamMetadata.version = "89a"; return streamMetadata; } public ImageWriteParam getDefaultWriteParam() { return new GIFImageWriteParam(getLocale()); } public void prepareWriteSequence(IIOMetadata streamMetadata) throws IOException { if (stream == null) { throw new IllegalStateException("Output is not set."); } resetLocal(); // Save the possibly converted stream metadata as an instance variable. if (streamMetadata == null) { this.theStreamMetadata = (GIFWritableStreamMetadata)getDefaultStreamMetadata(null); } else { this.theStreamMetadata = new GIFWritableStreamMetadata(); convertMetadata(STREAM_METADATA_NAME, streamMetadata, theStreamMetadata); } this.isWritingSequence = true; } public void reset() { super.reset(); resetLocal(); } /** * Resets locally defined instance variables. */ private void resetLocal() { this.isWritingSequence = false; this.wroteSequenceHeader = false; this.theStreamMetadata = null; this.imageIndex = 0; } public void setOutput(Object output) { super.setOutput(output); if (output != null) { if (!(output instanceof ImageOutputStream)) { throw new IllegalArgumentException("output is not an ImageOutputStream"); } this.stream = (ImageOutputStream)output; this.stream.setByteOrder(ByteOrder.LITTLE_ENDIAN); } else { this.stream = null; } } public void write(IIOMetadata sm, IIOImage iioimage, ImageWriteParam p) throws IOException { if (stream == null) { throw new IllegalStateException("output == null!"); } if (iioimage == null) { throw new IllegalArgumentException("iioimage == null!"); } if (iioimage.hasRaster()) { throw new UnsupportedOperationException("canWriteRasters() == false!"); } resetLocal();