/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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.
*/
/**
* The <code>output</code> case to an <code>ImageOutputStream</code>.
*/
/**
* 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.
*/
/**
* The index of the image being written.
*/
/**
* The number of bits represented by the value which should be a
* legal length for a color table.
*/
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:
}
return numBits;
}
/**
* Compute the source region and destination dimensions taking any
* parameter settings into account.
*/
ImageWriteParam p) {
int periodX = 1;
int periodY = 1;
if (p != null) {
int[] sourceBands = p.getSourceBands();
if (sourceBands != null &&
throw new IllegalArgumentException("Cannot sub-band image!");
}
// Get source region and subsampling factors
if (sourceRegion != null) {
// Clip to actual image bounds
}
// Adjust for subsampling offsets
int gridX = p.getSubsamplingXOffset();
int gridY = p.getSubsamplingYOffset();
sourceBounds.x += gridX;
sourceBounds.y += gridY;
// Get subsampling factors
periodX = p.getSourceXSubsampling();
periodY = p.getSourceYSubsampling();
}
// Compute output dimensions
throw new IllegalArgumentException("Empty source region!");
}
}
/**
* Create a color table from the image ColorModel and SampleModel.
*/
{
byte[] colorTable;
if (colorModel instanceof IndexColorModel) {
/**
* 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.
*/
/**
* fill tail of color component arrays by replica of first color
* in order to avoid appearance of extra colors in the color table
*/
}
int idx = 0;
for (int i = 0; i < ctSize; i++) {
}
// create gray-scaled color table for single-banded images
if (numBits > 8) {
numBits = 8;
}
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;
}
super(originatingProvider);
if (DEBUG) {
}
}
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.
*/
if (nativeFormatName != null &&
} else {
if (extraFormatNames != null) {
break;
}
}
}
}
if (formatName == null &&
}
if (formatName != null) {
try {
} catch(IIOInvalidTreeException e) {
// ignore
}
}
}
/**
* Creates a default stream metadata object and merges in the
* supplied metadata.
*/
throw new IllegalArgumentException("inData == null!");
}
return sm;
}
/**
* Creates a default image metadata object and merges in the
* supplied metadata.
*/
throw new IllegalArgumentException("inData == null!");
}
throw new IllegalArgumentException("imageType == null!");
}
param);
// Save interlace flag state.
// Undo change to interlace flag if not MODE_COPY_FROM_METADATA.
}
return im;
}
throw new IllegalStateException("output == null!");
}
if (!isWritingSequence) {
throw new IllegalStateException("prepareWriteSequence() was not invoked!");
}
writeTrailer();
resetLocal();
}
new GIFWritableImageMetadata();
// Image dimensions
sampleModel.getHeight());
// Interlacing
imageMetadata.interlaceFlag = false;
} else {
imageMetadata.interlaceFlag = true;
}
// Local color table
// Transparency
if (colorModel instanceof IndexColorModel) {
int transparentIndex =
if (transparentIndex != -1) {
imageMetadata.transparentColorFlag = true;
}
}
return imageMetadata;
}
new GIFWritableStreamMetadata();
return streamMetadata;
}
return new GIFImageWriteParam(getLocale());
}
throws IOException {
throw new IllegalStateException("Output is not set.");
}
resetLocal();
// Save the possibly converted stream metadata as an instance variable.
if (streamMetadata == null) {
this.theStreamMetadata =
} else {
this.theStreamMetadata = new GIFWritableStreamMetadata();
}
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;
}
if (!(output instanceof ImageOutputStream)) {
throw new
IllegalArgumentException("output is not an ImageOutputStream");
}
} else {
}
}
ImageWriteParam p) throws IOException {
throw new IllegalStateException("output == null!");
}
throw new IllegalArgumentException("iioimage == null!");
}
throw new UnsupportedOperationException("canWriteRasters() == false!");
}
resetLocal();
} else {
}
}
throws IOException {
throw new IllegalStateException("output == null!");
}
throw new IllegalArgumentException("image == null!");
}
throw new UnsupportedOperationException("canWriteRasters() == false!");
}
if (!isWritingSequence) {
throw new IllegalStateException("prepareWriteSequence() was not invoked!");
}
if (!wroteSequenceHeader) {
wroteSequenceHeader = true;
}
this.imageIndex++;
}
}
/**
* Writes any extension blocks, the Image Descriptor, the image data,
* and optionally the header (Signature and Logical Screen Descriptor)
* and trailer (Block Terminator).
*
* @param writeHeader Whether to write the header.
* @param writeTrailer Whether to write the trailer.
* @param sm The stream metadata or <code>null</code> if
* <code>writeHeader</code> is <code>false</code>.
* @param iioimage The image and image metadata.
* @param p The write parameters.
*
* @throws IllegalArgumentException if the number of bands is not 1.
* @throws IllegalArgumentException if the number of bits per sample is
* greater than 8.
* @throws IllegalArgumentException if the color component size is
* greater than 8.
* @throws IllegalArgumentException if <code>writeHeader</code> is
* <code>true</code> and <code>sm</code> is <code>null</code>.
* @throws IllegalArgumentException if <code>writeHeader</code> is
* <code>false</code> and a sequence is not being written.
*/
boolean writeTrailer,
ImageWriteParam p) throws IOException {
// Check for ability to encode image.
if (needToCreateIndex(image)) {
}
// Determine source region and destination dimensions.
// Convert any provided image metadata.
imageMetadata = new GIFWritableImageMetadata();
// Converted rgb image can use palette different from global.
// In order to avoid color artefacts we want to be sure we use
// appropriate palette. For this we initialize local color table
// from current color and sample models.
// At this point we can guarantee that local color table can be
// build because image was already converted to indexed or
// gray-scale representations
// in case of indexed image we should take care of
// transparent pixels
if (colorModel instanceof IndexColorModel) {
}
/* NB: transparentColorFlag might have not beed reset for
greyscale images but explicitly reseting it here
is potentially not right thing to do until we have way
to find whether current value was explicitly set by
the user.
*/
}
}
}
// Global color table values.
byte[] globalColorTable = null;
// Write the header (Signature+Logical Screen Descriptor+
// Global Color Table).
if (writeHeader) {
throw new IllegalArgumentException("Cannot write null header!");
}
// Set the version if not set.
}
// Set the Logical Screen Desriptor if not set.
if (streamMetadata.logicalScreenWidth ==
{
}
{
}
if (streamMetadata.colorResolution ==
{
}
// Set the Global Color Table if not set, i.e., if not
// provided in the stream metadata.
// Writing a sequence and a local color table was
// provided in the metadata of the first image: use it.
} else if (imageMetadata == null ||
// Create a color table.
}
}
// Set the Global Color Table. At this point it should be
// A) the global color table provided in stream metadata, if any;
// B) the local color table of the image metadata, if any, if
// writing a sequence;
// C) a table created on the basis of the first image ColorModel
// and SampleModel if no local color table is available; or
// D) null if none of the foregoing conditions obtain (which
// should only be if a sequence is not being written and
// a local color table is provided in image metadata).
// Write the header.
int bitsPerPixel;
if (globalColorTable != null) {
} else if (imageMetadata != null &&
} else {
}
} else if (isWritingSequence) {
} else {
throw new IllegalArgumentException("Must write header for single image!");
}
// Write extension blocks, Image Descriptor, and image data.
// Write the trailer.
if (writeTrailer) {
writeTrailer();
}
}
/**
* Writes any extension blocks, the Image Descriptor, and the image data
*
* @param iioimage The image and image metadata.
* @param param The write parameters.
* @param globalColorTable The Global Color Table.
* @param sourceBounds The source region.
* @param destSize The destination dimensions.
*/
throws IOException {
boolean writeGraphicsControlExtension;
if (imageMetadata == null) {
// Create default metadata.
// Set GraphicControlExtension flag only if there is
// transparency.
} else {
// Check for GraphicControlExtension element.
try {
} catch(IllegalArgumentException iae) {
// Should never happen.
}
// Set GraphicControlExtension flag if element present.
// If progressive mode is not MODE_COPY_FROM_METADATA, ensure
// the interlacing is set per the ImageWriteParam mode setting.
if (param.getProgressiveMode() ==
imageMetadata.interlaceFlag = false;
} else if (param.getProgressiveMode() ==
imageMetadata.interlaceFlag = true;
}
}
}
// Unset local color table if equal to global color table.
}
// Override dimensions
// Write Graphics Control Extension.
}
// Write extension blocks.
// Write Image Descriptor
int bitsPerPixel =
(globalColorTable == null ?
// Write image data
}
int numRowsWritten, int progressReportRowPeriod)
throws IOException {
if (abortRequested()) {
return;
}
}
}
}
}
int numRowsWritten, int progressReportRowPeriod)
throws IOException {
lineStride *= ddy;
if (abortRequested()) {
return;
}
}
offset += lineStride;
}
}
boolean interlaceFlag) throws IOException {
int sourceXOffset = sourceBounds.x;
int sourceYOffset = sourceBounds.y;
int periodX;
int periodY;
periodX = 1;
periodY = 1;
} else {
}
int initCodeSize = bitsPerPixel;
if (initCodeSize == 1) {
initCodeSize++;
}
/* At this moment we know that input image is indexed image.
* We can directly copy data iff:
* - no subsampling required (periodX = 1, periodY = 0)
* - we can access data directly (image is non-tiled,
* i.e. image data are in single block)
* - we can calculate offset in data buffer (next 3 lines)
*/
boolean isOptimizedCase =
sampleModel instanceof ComponentSampleModel &&
int numRowsWritten = 0;
if (interlaceFlag) {
if (isOptimizedCase) {
// take into account the raster data offset
if (abortRequested()) {
return;
}
if (abortRequested()) {
return;
}
if (abortRequested()) {
return;
}
} else {
if (abortRequested()) {
return;
}
if (abortRequested()) {
return;
}
if (abortRequested()) {
return;
}
}
} else {
if (isOptimizedCase) {
} else {
}
}
if (abortRequested()) {
return;
}
processImageProgress(100.0F);
compressor.flush();
}
int logicalScreenWidth,
int logicalScreenHeight,
int colorResolution,
int pixelAspectRatio,
int backgroundColorIndex,
boolean sortFlag,
int bitsPerPixel,
byte[] globalColorTable) throws IOException {
try {
// Signature
// Screen Descriptor
// Width
// Height
// Global Color Table
// Packed fields
if (sortFlag) {
packedFields |= 0x8;
}
// Background color index
// Pixel aspect ratio
// Global Color Table
if (globalColorTable != null) {
}
} catch (IOException e) {
throw new IIOException("I/O error writing header!", e);
}
}
throws IOException {
if (streamMetadata instanceof GIFWritableStreamMetadata) {
} else {
sm = new GIFWritableStreamMetadata();
}
}
boolean userInputFlag,
boolean transparentColorFlag,
int delayTime,
throws IOException {
try {
if (userInputFlag) {
packedFields |= 0x2;
}
if (transparentColorFlag) {
packedFields |= 0x1;
}
} catch (IOException e) {
throw new IIOException("I/O error writing Graphic Control Extension!", e);
}
}
throws IOException {
}
int offset = 0;
}
}
}
throws IOException {
if (im.hasPlainTextExtension) {
try {
} catch (IOException e) {
throw new IIOException("I/O error writing Plain Text Extension!", e);
}
}
}
throws IOException {
try {
} catch (IOException e) {
throw new IIOException("I/O error writing Application Extension!", e);
}
}
}
}
throws IOException {
try {
}
} catch (IOException e) {
throw new IIOException("I/O error writing Comment Extension!", e);
}
}
}
int imageTopPosition,
int imageWidth,
int imageHeight,
boolean interlaceFlag,
boolean sortFlag,
int bitsPerPixel,
byte[] localColorTable)
throws IOException {
try {
if (interlaceFlag) {
packedFields |= 0x40;
}
if (sortFlag) {
packedFields |= 0x8;
}
if (localColorTable != null) {
}
} catch (IOException e) {
throw new IIOException("I/O error writing Image Descriptor!", e);
}
}
int bitsPerPixel)
throws IOException {
}
}
}
super(locale);
this.canWriteCompressed = true;
this.canWriteProgressive = true;
}
if (mode == MODE_DISABLED) {
throw new UnsupportedOperationException("MODE_DISABLED is not supported.");
}
super.setCompressionMode(mode);
}
}