gifimagedecoder.java

来自「This is a resource based on j2me embedde」· Java 代码 · 共 970 行 · 第 1/2 页

JAVA
970
字号
/* * @(#)GifImageDecoder.java	1.55 06/10/24 * * Copyright  1990-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER *  * This program 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.  *  * This program 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 at /legal/license.txt).  *  * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa * Clara, CA 95054 or visit www.sun.com if you need additional * information or have any questions.  *//*- *	Reads GIF images from an InputStream and reports the *	image data to an InputStreamImageSource object. */package sun.awt.image;import java.util.Vector;import java.util.Hashtable;import java.io.InputStream;import java.io.IOException;import java.awt.image.*;/** * Gif Image converter * * @version 1.41 01/05/01 * @author Arthur van Hoff * @author Jim Graham */public class GifImageDecoder extends ImageDecoder {    private static final boolean verbose = false;    private static final int IMAGESEP 		= 0x2c;    private static final int EXBLOCK 		= 0x21;    private static final int EX_GRAPHICS_CONTROL= 0xf9;    private static final int EX_COMMENT 	= 0xfe;    private static final int EX_APPLICATION 	= 0xff;    private static final int TERMINATOR 	= 0x3b;    private static final int TRANSPARENCYMASK 	= 0x01;    private static final int INTERLACEMASK 	= 0x40;    private static final int COLORMAPMASK 	= 0x80;    int num_global_colors;    byte[] global_colormap;    int trans_pixel = -1;    IndexColorModel global_model;    Hashtable props = new Hashtable();    byte[] saved_image;    IndexColorModel saved_model;    int global_width;    int global_height;    int global_bgpixel;    GifFrame curframe;    public GifImageDecoder(InputStreamImageSource src, InputStream is) {	super(src, is);    }    /**     * An error has occurred. Throw an exception.     */    private static void error(String s1) throws ImageFormatException {	throw new ImageFormatException(s1);    }    /**     * Read a number of bytes into a buffer.     * @return number of bytes that were not read due to EOF or error     */    private int readBytes(byte buf[], int off, int len) {	while (len > 0) {	    try {		int n = input.read(buf, off, len);		if (n < 0) {		    break;		}		off += n;		len -= n;	    } catch (IOException e) {		break;	    }	}	return len;    }    private static final int ExtractByte(byte buf[], int off) {	return (buf[off] & 0xFF);    }    private static final int ExtractWord(byte buf[], int off) {	return (buf[off] & 0xFF) | ((buf[off + 1] & 0xFF) << 8);    }    /**     * produce an image from the stream.     */    public void produceImage() throws IOException, ImageFormatException {	try {	    readHeader();	    int totalframes = 0;	    int frameno = 0;	    int nloops = -1;	    int disposal_method = 0;	    int delay = -1;	    boolean loopsRead = false;	    boolean isAnimation = false;	    while (!aborted) {		int code;		if (!ImageProductionMonitor.allowsProduction()) {		    abort();		    break;		}		switch (code = input.read()) {		  case EXBLOCK:		    switch (code = input.read()) {		      case EX_GRAPHICS_CONTROL: {			byte buf[] = new byte[6];			if (readBytes(buf, 0, 6) != 0) {			    return;//error("corrupt GIF file");			}			if ((buf[0] != 4) || (buf[5] != 0)) {			    return;//error("corrupt GIF file (GCE size)");			}			// Get the index of the transparent color			delay = ExtractWord(buf, 2) * 10;			if (delay > 0 && !isAnimation) {			    isAnimation = true;			    ImageFetcher.startingAnimation();			}			disposal_method = (buf[1] >> 2) & 7;			if ((buf[1] & TRANSPARENCYMASK) != 0) {			    trans_pixel = ExtractByte(buf, 4);			} else {			    trans_pixel = -1;			}			break;		      }		      case EX_COMMENT:		      case EX_APPLICATION:		      default:			boolean loop_tag = false;			String comment = "";			while (true) {			    int n = input.read();			    if (n <= 0) {				break;			    }			    byte buf[] = new byte[n];			    if (readBytes(buf, 0, n) != 0) {				return;//error("corrupt GIF file");			    }			    if (code == EX_COMMENT) {				comment += new String(buf);			    } else if (code == EX_APPLICATION) {				if (loop_tag) {				    if (n == 3 && buf[0] == 1) {				        if (loopsRead) {					    ExtractWord(buf, 1);					}					else {					    nloops = ExtractWord(buf, 1);					    loopsRead = true;					}				    } else {					loop_tag = false;				    }				}				if ("NETSCAPE2.0".equals(new String(buf))) {				    loop_tag = true;				}			    }			}			if (code == EX_COMMENT) {			    props.put("comment", comment);			}			if (loop_tag && !isAnimation) {			    isAnimation = true;			    ImageFetcher.startingAnimation();			}			break;		      case -1:			return; //error("corrupt GIF file");		    }		    break;		  case IMAGESEP:		    if (!isAnimation) {		        input.mark(0); // we don't need the mark buffer		    }		    try {			if (!readImage(totalframes == 0,				       disposal_method,				       delay)) {			    return;			}		    } catch (Exception e) {			if (verbose) {			    e.printStackTrace();			}			return;		    }		    frameno++;		    totalframes++;		    break;		  default:		  case -1:		    if (verbose) {			if (code == -1) {			    System.err.println("Premature EOF in GIF file," +					       " frame " + frameno);			} else {			    System.err.println("corrupt GIF file (parse) ["					       + code + "].");			}		    }		    if (frameno == 0) {			return;		    }		    // NOBREAK		  case TERMINATOR:		    if (nloops == 0 || nloops-- >= 0) {			try {			    if (curframe != null) {				curframe.dispose();				curframe = null;			    }			    input.reset();			    saved_image = null;			    saved_model = null;			    frameno = 0;			    break;			} catch (IOException e) {			    return; // Unable to reset input buffer			}		    }		    if (verbose && frameno != 1) {			System.out.println("processing GIF terminator,"					   + " frames: " + frameno					   + " total: " + totalframes);		    }		    imageComplete(ImageConsumer.STATICIMAGEDONE, true);		    return;		}	    }	} finally {	    close();	}    }    /**     * Read Image header     */    private void readHeader() throws IOException, ImageFormatException {	// Create a buffer	byte buf[] = new byte[13];	// Read the header	if (readBytes(buf, 0, 13) != 0) {	    throw new IOException();	}	// Check header	if ((buf[0] != 'G') || (buf[1] != 'I') || (buf[2] != 'F')) {	    error("not a GIF file.");	}	// Global width&height	global_width = ExtractWord(buf, 6);	global_height = ExtractWord(buf, 8);	// colormap info	int ch = ExtractByte(buf, 10);	if ((ch & COLORMAPMASK) == 0) {	    error("no global colormap in GIF file.");	}	num_global_colors = 1 << ((ch & 0x7) + 1);	global_bgpixel = ExtractByte(buf, 11);	if (buf[12] != 0) {	    props.put("aspectratio", ""+((ExtractByte(buf, 12) + 15) / 64.0));	}	// Read colors	global_colormap = new byte[num_global_colors * 3];	if (readBytes(global_colormap, 0, num_global_colors * 3) != 0) {	    throw new IOException();	}        input.mark(1000000); // set this mark in case this is an animated GIF    }    /**     * The ImageConsumer hints flag for a non-interlaced GIF image.     */    private static final int normalflags =	ImageConsumer.TOPDOWNLEFTRIGHT | ImageConsumer.COMPLETESCANLINES |	ImageConsumer.SINGLEPASS | ImageConsumer.SINGLEFRAME;    /**     * The ImageConsumer hints flag for an interlaced GIF image.     */    private static final int interlaceflags =	ImageConsumer.RANDOMPIXELORDER | ImageConsumer.COMPLETESCANLINES |	ImageConsumer.SINGLEPASS | ImageConsumer.SINGLEFRAME;    private short prefix[]  = new short[4096];    private byte  suffix[]  = new byte[4096];    private byte  outCode[] = new byte[4097];    //private native boolean parseImage(int x, int y, int width, int height,    //				      boolean interlace, int initCodeSize,    //				      byte block[], byte rasline[],    //				      IndexColorModel model);    /*      * This is converted from the native version. The java version is      * much faster when we have JIT.     */    private boolean parseImage(int relx, int rely, int width, int height,                               boolean interlace, int initCodeSize,                               byte block[], byte rasline[],                               IndexColorModel model) {        int OUTCODELENGTH = 4097;        int clearCode = (1 << initCodeSize);        int eofCode = clearCode + 1;        int bitMask;        int curCode;        int outCount = OUTCODELENGTH;        /* Variables used to form reading data */        boolean blockEnd = false;        int remain = 0;        int byteoff = 0;        int accumbits = 0;        int accumdata = 0;        /* Variables used to decompress the data */        int codeSize = initCodeSize + 1;        int maxCode = 1 << codeSize;        int codeMask = maxCode - 1;        int freeCode = clearCode + 2;        int code = 0;        int oldCode = 0;        char prevChar = 0;        //int blockLength = 0;        int blockLength = 0;        /* Variables used for writing pixels */        int x = width;        int y = 0;        int off = 0;        int passinc = interlace ? 8 : 1;        int passht = passinc;        int len;        bitMask = model.getMapSize() - 1;        /* Read codes until the eofCode is encountered */        for (;;) {            if (accumbits < codeSize) {                boolean lastByte = false;                /* fill the buffer if needed */                while (remain < 2) {                    if (blockEnd) {                        /* Sometimes we have one last byte to process... */                        if (remain == 1 && accumbits + 8 >= codeSize) {                            break;                        }                        if (off > 0) {//                             sendPixels(relx, rely+y, width, passht, rasline, model);                             sendPixels(relx, rely+y, width, 1, rasline, model);                        }                        /* quietly accept truncated GIF images */                        return false;                    }                    /* move remaining bytes to the beginning of the buffer */                    block[0] = block[byteoff];                    byteoff = 0;                    /* fill the block */                    len = readBytes(block, remain, blockLength + 1);                    remain += blockLength;                    if (len > 0) {                        remain -= (len - 1);                        blockLength = 0;                    } else {                        blockLength = (block[remain] & 0xff);                    }                    if (blockLength == 0) {                        blockEnd = true;                    }                }                /* 2 bytes at a time saves checking for accumbits < codeSize.                 * We know we'll get enough and also that we can't overflow                 * since codeSize <= 12.                 */                if (!lastByte) {                    remain -= 2;                    accumdata += (block[byteoff++] & 0xff) << accumbits;                    accumbits += 8;                    accumdata += (block[byteoff++] & 0xff) << accumbits;                    accumbits += 8;                } else {                    remain--;                    accumdata += (block[byteoff++] & 0xff) << accumbits;                    accumbits += 8;                }            }            /* Compute the code */            code = accumdata & codeMask;            accumdata >>= codeSize;            accumbits -= codeSize;            /*             * Interpret the code             */            if (code == clearCode) {                /* Clear code sets everything back to its initial value, then                 * reads the immediately subsequent code as uncompressed data.                 */                /* Note that freeCode is one less than it is supposed to be,                 * this is because it will be incremented next time round the                  * loop                 */                freeCode = clearCode + 1;                codeSize = initCodeSize + 1;                maxCode = 1 << codeSize;                codeMask = maxCode - 1;                /* Continue if we've NOT reached the end, some Gif images                 * contain bogus codes after the last clear code.                 */                if (y < height) {                    continue;                }                /* pretend we've reached the end of the data */                code = eofCode;            }            if (code == eofCode) {                /* make sure we read the whole block of pixels. */                while (!blockEnd) {                    if (readBytes(block, 0, blockLength + 1) != 0) {                        /* quietly accept truncated GIF images */                        return false;                    }                    blockLength = block[blockLength];                    blockEnd = (blockLength == 0);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?