📄 gifimagereader.java
字号:
/* * @(#)GIFImageReader.java 1.46 05/12/01 * * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */package com.sun.imageio.plugins.gif;import java.awt.Point;import java.awt.Rectangle;import java.awt.image.BufferedImage;import java.awt.image.DataBuffer;import java.awt.image.WritableRaster;import java.io.BufferedInputStream;import java.io.DataInputStream;import java.io.EOFException;import java.io.InputStream;import java.io.IOException;import java.nio.ByteOrder;import java.util.ArrayList;import java.util.Arrays;import java.util.Iterator;import java.util.List;import javax.imageio.IIOException;import javax.imageio.ImageReader;import javax.imageio.ImageReadParam;import javax.imageio.ImageTypeSpecifier;import javax.imageio.metadata.IIOMetadata;import javax.imageio.spi.ImageReaderSpi;import javax.imageio.stream.ImageInputStream;import com.sun.imageio.plugins.common.ReaderUtil;/** * @version 0.5 */public class GIFImageReader extends ImageReader { // The current ImageInputStream source. ImageInputStream stream = null; // Per-stream settings // True if the file header including stream metadata has been read. boolean gotHeader = false; // Global metadata, read once per input setting. GIFStreamMetadata streamMetadata = null; // The current image index int currIndex = -1; // Metadata for image at 'currIndex', or null. GIFImageMetadata imageMetadata = null; // A List of Longs indicating the stream positions of the // start of the metadata for each image. Entries are added // as needed. List imageStartPosition = new ArrayList(); // Length of metadata for image at 'currIndex', valid only if // imageMetadata != null. int imageMetadataLength; // The number of images in the stream, if known, otherwise -1. int numImages = -1; // Variables used by the LZW decoding process byte[] block = new byte[255]; int blockLength = 0; int bitPos = 0; int nextByte = 0; int initCodeSize; int clearCode; int eofCode; // 32-bit lookahead buffer int next32Bits = 0; // Try if the end of the data blocks has been found, // and we are simply draining the 32-bit buffer boolean lastBlockFound = false; // The image to be written. BufferedImage theImage = null; // The image's tile. WritableRaster theTile = null; // The image dimensions (from the stream). int width = -1, height = -1; // The pixel currently being decoded (in the stream's coordinates). int streamX = -1, streamY = -1; // The number of rows decoded int rowsDone = 0; // The current interlace pass, starting with 0. int interlacePass = 0; // End per-stream settings // Constants used to control interlacing. static final int[] interlaceIncrement = { 8, 8, 4, 2, -1 }; static final int[] interlaceOffset = { 0, 4, 2, 1, -1 }; public GIFImageReader(ImageReaderSpi originatingProvider) { super(originatingProvider); } // Take input from an ImageInputStream public void setInput(Object input, boolean seekForwardOnly, boolean ignoreMetadata) { super.setInput(input, seekForwardOnly, ignoreMetadata); if (input != null) { if (!(input instanceof ImageInputStream)) { throw new IllegalArgumentException ("input not an ImageInputStream!"); } this.stream = (ImageInputStream)input; } else { this.stream = null; } // Clear all values based on the previous stream contents resetStreamSettings(); } public int getNumImages(boolean allowSearch) throws IIOException { if (stream == null) { throw new IllegalStateException("Input not set!"); } if (seekForwardOnly && allowSearch) { throw new IllegalStateException ("seekForwardOnly and allowSearch can't both be true!"); } if (numImages > 0) { return numImages; } if (allowSearch) { this.numImages = locateImage(Integer.MAX_VALUE) + 1; } return numImages; } // Throw an IndexOutOfBoundsException if index < minIndex, // and bump minIndex if required. private void checkIndex(int imageIndex) { if (imageIndex < minIndex) { throw new IndexOutOfBoundsException("imageIndex < minIndex!"); } if (seekForwardOnly) { minIndex = imageIndex; } } public int getWidth(int imageIndex) throws IIOException { checkIndex(imageIndex); int index = locateImage(imageIndex); if (index != imageIndex) { throw new IndexOutOfBoundsException(); } readMetadata(); return imageMetadata.imageWidth; } public int getHeight(int imageIndex) throws IIOException { checkIndex(imageIndex); int index = locateImage(imageIndex); if (index != imageIndex) { throw new IndexOutOfBoundsException(); } readMetadata(); return imageMetadata.imageHeight; } public Iterator getImageTypes(int imageIndex) throws IIOException { checkIndex(imageIndex); int index = locateImage(imageIndex); if (index != imageIndex) { throw new IndexOutOfBoundsException(); } readMetadata(); List l = new ArrayList(1); byte[] colorTable; if (imageMetadata.localColorTable != null) { colorTable = imageMetadata.localColorTable; } else { colorTable = streamMetadata.globalColorTable; } // Normalize color table length to 2^1, 2^2, 2^4, or 2^8 int length = colorTable.length/3; int bits; if (length == 2) { bits = 1; } else if (length == 4) { bits = 2; } else if (length == 8 || length == 16) { // Bump from 3 to 4 bits bits = 4; } else { // Bump to 8 bits bits = 8; } int lutLength = 1 << bits; byte[] r = new byte[lutLength]; byte[] g = new byte[lutLength]; byte[] b = new byte[lutLength]; // Entries from length + 1 to lutLength - 1 will be 0 int rgbIndex = 0; for (int i = 0; i < length; i++) { r[i] = colorTable[rgbIndex++]; g[i] = colorTable[rgbIndex++]; b[i] = colorTable[rgbIndex++]; } byte[] a = null; if (imageMetadata.transparentColorFlag) { a = new byte[lutLength]; Arrays.fill(a, (byte)255); // Some files erroneously have a transparent color index // of 255 even though there are fewer than 256 colors. int idx = Math.min(imageMetadata.transparentColorIndex, lutLength - 1); a[idx] = (byte)0; } int[] bitsPerSample = new int[1]; bitsPerSample[0] = bits; l.add(ImageTypeSpecifier.createIndexed(r, g, b, a, bits, DataBuffer.TYPE_BYTE)); return l.iterator(); } public ImageReadParam getDefaultReadParam() { return new ImageReadParam(); } public IIOMetadata getStreamMetadata() throws IIOException { readHeader(); return streamMetadata; } public IIOMetadata getImageMetadata(int imageIndex) throws IIOException { checkIndex(imageIndex); int index = locateImage(imageIndex); if (index != imageIndex) { throw new IndexOutOfBoundsException("Bad image index!"); } readMetadata(); return imageMetadata; } // BEGIN LZW STUFF private void initNext32Bits() { next32Bits = block[0] & 0xff; next32Bits |= (block[1] & 0xff) << 8; next32Bits |= (block[2] & 0xff) << 16; next32Bits |= block[3] << 24; nextByte = 4; } // Load a block (1-255 bytes) at a time, and maintain // a 32-bit lookahead buffer that is filled from the left // and extracted from the right. // // When the last block is found, we continue to // private int getCode(int codeSize, int codeMask) throws IOException { if (bitPos + codeSize > 32) { return eofCode; // No more data available } int code = (next32Bits >> bitPos) & codeMask; bitPos += codeSize; // Shift in a byte of new data at a time while (bitPos >= 8 && !lastBlockFound) { next32Bits >>>= 8; bitPos -= 8; // Check if current block is out of bytes if (nextByte >= blockLength) { // Get next block size blockLength = stream.readUnsignedByte(); if (blockLength == 0) { lastBlockFound = true; return code; } else { int left = blockLength; int off = 0; while (left > 0) { int nbytes = stream.read(block, off, left); off += nbytes; left -= nbytes; } nextByte = 0; } } next32Bits |= block[nextByte++] << 24; } return code; } public void initializeStringTable(int[] prefix, byte[] suffix, byte[] initial, int[] length) { int numEntries = 1 << initCodeSize; for (int i = 0; i < numEntries; i++) { prefix[i] = -1; suffix[i] = (byte)i; initial[i] = (byte)i; length[i] = 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -