home *** CD-ROM | disk | FTP | other *** search
Java Source | 1997-01-27 | 7.8 KB | 308 lines |
- /*
- * @(#)GifImageDecoder.java 1.24 96/03/26 Patrick Naughton, Arthur van Hoff
- *
- * Copyright (c) 1994 Sun Microsystems, Inc. All Rights Reserved.
- *
- * Permission to use, copy, modify, and distribute this software
- * and its documentation for NON-COMMERCIAL purposes and without
- * fee is hereby granted provided that this copyright notice
- * appears in all copies. Please refer to the file "copyright.html"
- * for further important copyright and licensing information.
- *
- * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
- * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
- * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
- * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
- * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
- * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
- */
-
- /*-
- * Reads GIF images from an InputStream and reports the
- * image data to an InputStreamImageSource object.
- *
- * The algorithm is copyright of CompuServe.
- */
- 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.24 03/26/96
- * @author Arthur van Hoff
- */
- public class GifImageDecoder extends ImageDecoder {
- private 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 INTERLACEMASK = 0x40;
- private static final int COLORMAPMASK = 0x80;
-
- PixelStore8 store;
- int num_colors;
- byte[] colormap;
- IndexColorModel model;
- Hashtable props = new Hashtable();
-
- public GifImageDecoder(InputStreamImageSource src, InputStream is) {
- super(src, is);
- }
-
- public synchronized boolean catchupConsumer(InputStreamImageSource src,
- ImageConsumer ic)
- {
- return ((store == null) || store.replay(src, ic));
- }
-
- public synchronized void makeStore(int width, int height) {
- store = new PixelStore8(width, height);
- }
-
- /**
- * 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.
- */
- boolean readBytes(byte buf[], int off, int len) {
- while (len > 0) {
- int n;
- try {
- n = input.read(buf, off, len);
- } catch (IOException e) {
- n = -1;
- }
- if (n < 0) {
- return false;
- }
- off += n;
- len -= n;
- }
- return true;
- }
-
- /**
- * produce an image from the stream.
- */
- public void produceImage() throws IOException, ImageFormatException {
- int trans_pixel = -1;
- try {
- readHeader();
-
- while (true) {
- int code;
-
- switch (code = input.read()) {
- case EXBLOCK:
- switch (code = input.read()) {
- case EX_GRAPHICS_CONTROL: {
- byte buf[] = new byte[6];
- if (!readBytes(buf, 0, 6)) {
- 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
- trans_pixel = buf[4] & 0xFF;
- break;
- }
-
- case EX_COMMENT:
- case EX_APPLICATION:
- default:
- String comment = "";
- while (true) {
- int n = input.read();
- if (n == 0) {
- break;
- }
- byte buf[] = new byte[n];
- if (!readBytes(buf, 0, n)) {
- return;//error("corrupt GIF file");
- }
- if (code == EX_COMMENT) {
- comment += new String(buf, 0);
- }
- }
- if (code == EX_COMMENT) {
- props.put("comment", comment);
- }
- break;
- }
- break;
-
- case IMAGESEP:
- try {
- model = new IndexColorModel(8, num_colors, colormap,
- 0, false, trans_pixel);
- colormap = null;
- if (readImage()) {
- store.imageComplete();
- if (store.getBitState() != PixelStore.BITS_LOST) {
- source.setPixelStore(store);
- }
- source.imageComplete(ImageConsumer.STATICIMAGEDONE);
- }
- } catch (ArrayIndexOutOfBoundsException e) {
- if (verbose) {
- e.printStackTrace();
- }
- }
- return;
-
- case TERMINATOR:
- return;
-
- case -1:
- return;
-
- default:
- return;//error("corrupt GIF file (parse) [" + code + "].");
- //break;
- }
- }
- } finally {
- try {
- input.close();
- } catch (IOException e) {
- }
- }
- }
-
- /**
- * 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)) {
- throw new IOException();
- }
-
- // Check header
- if ((buf[0] != 'G') || (buf[1] != 'I') || (buf[2] != 'F')) {
- error("not a GIF file.");
- }
-
- // colormap info
- int ch = buf[10] & 0xFF;
- if ((ch & COLORMAPMASK) == 0) {
- error("no global colormap in GIF file.");
- }
- num_colors = 1 << ((ch & 0x7) + 1);
-
- // supposed to be NULL
- if (buf[12] != 0) {
- props.put("aspectratio", ""+(((buf[12] & 0xff) + 15) / 64.0));
- }
-
- // Read colors
- colormap = new byte[num_colors * 3];
- if (!readBytes(colormap, 0, num_colors * 3)) {
- throw new IOException();
- }
- }
-
- /**
- * 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 native boolean parseImage(int width, int height,
- boolean interlace, int initCodeSize,
- byte block[], byte rasline[]);
-
- private int sendPixels(int y, int width, byte rasline[]) {
-
- int count = source.setPixels(0, y, width, 1, model,
- rasline, 0, width);
- if (store.setPixels(0, y, width, 1, rasline, 0, width)) {
- count++;
- }
- return count;
- }
-
- /**
- * Read Image data
- */
- private boolean readImage() throws IOException {
- long tm = 0;
-
- if (verbose) {
- tm = System.currentTimeMillis();
- }
-
- // Allocate the buffer
- byte block[] = new byte[256 + 3];
-
- // Read the image descriptor
- if (!readBytes(block, 0, 10)) {
- throw new IOException();
- }
- int width = (block[4] & 0xFF) | (block[5] << 8);
- int height = (block[6] & 0xFF) | (block[7] << 8);
- boolean interlace = (block[8] & INTERLACEMASK) != 0;
- int initCodeSize = block[9] & 0xFF;
-
- // Notify the consumers
- source.setDimensions(width, height);
- makeStore(width, height);
-
- source.setProperties(props);
- store.setProperties(props);
-
- source.setColorModel(model);
- store.setColorModel(model);
-
- int hints = (interlace ? interlaceflags : normalflags);
- source.setHints(hints);
- store.setHints(hints);
-
- // allocate the raster data
- byte rasline[] = new byte[width];
-
- if (verbose) {
- System.out.print("Reading a " + width + " by " + height + " " +
- (interlace ? "" : "non-") + "interlaced image...");
- }
-
- boolean ret = parseImage(width, height, interlace, initCodeSize,
- block, rasline);
-
- if (verbose) {
- System.out.println("done in "
- + (System.currentTimeMillis() - tm)
- + "ms");
- }
-
- return ret;
- }
- }
-