home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 25 / CDROM25.iso / Share / prog / VJ11 / VJTRIAL.EXE / IE30Java.exe / classd.exe / sun / awt / image / GifImageDecoder.java < prev    next >
Encoding:
Java Source  |  1997-01-27  |  7.8 KB  |  308 lines

  1. /*
  2.  * @(#)GifImageDecoder.java    1.24 96/03/26 Patrick Naughton, Arthur van Hoff
  3.  *
  4.  * Copyright (c) 1994 Sun Microsystems, Inc. All Rights Reserved.
  5.  *
  6.  * Permission to use, copy, modify, and distribute this software
  7.  * and its documentation for NON-COMMERCIAL purposes and without
  8.  * fee is hereby granted provided that this copyright notice
  9.  * appears in all copies. Please refer to the file "copyright.html"
  10.  * for further important copyright and licensing information.
  11.  *
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
  13.  * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
  14.  * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  15.  * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
  16.  * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
  17.  * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
  18.  */
  19.  
  20. /*-
  21.  *    Reads GIF images from an InputStream and reports the
  22.  *    image data to an InputStreamImageSource object.
  23.  *
  24.  * The algorithm is copyright of CompuServe.
  25.  */
  26. package sun.awt.image;
  27.  
  28. import java.util.Vector;
  29. import java.util.Hashtable;
  30. import java.io.InputStream;
  31. import java.io.IOException;
  32. import java.awt.image.*;
  33.  
  34. /**
  35.  * Gif Image converter
  36.  * 
  37.  * @version 1.24 03/26/96
  38.  * @author Arthur van Hoff
  39.  */
  40. public class GifImageDecoder extends ImageDecoder {
  41.     private final boolean verbose = false;
  42.  
  43.     private static final int IMAGESEP         = 0x2c;
  44.     private static final int EXBLOCK         = 0x21;
  45.     private static final int EX_GRAPHICS_CONTROL= 0xf9;
  46.     private static final int EX_COMMENT     = 0xfe;
  47.     private static final int EX_APPLICATION     = 0xff;
  48.     private static final int TERMINATOR     = 0x3b;
  49.     private static final int INTERLACEMASK     = 0x40;
  50.     private static final int COLORMAPMASK     = 0x80;
  51.  
  52.     PixelStore8 store;
  53.     int num_colors;
  54.     byte[] colormap;
  55.     IndexColorModel model;
  56.     Hashtable props = new Hashtable();
  57.  
  58.     public GifImageDecoder(InputStreamImageSource src, InputStream is) {
  59.     super(src, is);
  60.     }
  61.  
  62.     public synchronized boolean catchupConsumer(InputStreamImageSource src,
  63.                         ImageConsumer ic)
  64.     {
  65.     return ((store == null) || store.replay(src, ic));
  66.     }
  67.  
  68.     public synchronized void makeStore(int width, int height) {
  69.     store = new PixelStore8(width, height);
  70.     }
  71.  
  72.     /**
  73.      * An error has occurred. Throw an exception.
  74.      */
  75.     private static void error(String s1) throws ImageFormatException {
  76.     throw new ImageFormatException(s1);
  77.     }
  78.  
  79.     /**
  80.      * Read a number of bytes into a buffer.
  81.      */
  82.     boolean readBytes(byte buf[], int off, int len) {
  83.     while (len > 0) {
  84.         int n;
  85.         try {
  86.         n = input.read(buf, off, len);
  87.         } catch (IOException e) {
  88.         n = -1;
  89.         }
  90.         if (n < 0) {
  91.         return false;
  92.         }
  93.         off += n;
  94.         len -= n;
  95.     }
  96.     return true;
  97.     }
  98.  
  99.     /**
  100.      * produce an image from the stream.
  101.      */
  102.     public void produceImage() throws IOException, ImageFormatException {
  103.     int trans_pixel = -1;
  104.     try {
  105.         readHeader();
  106.  
  107.         while (true) {
  108.         int code;
  109.  
  110.         switch (code = input.read()) {
  111.           case EXBLOCK:
  112.             switch (code = input.read()) {
  113.               case EX_GRAPHICS_CONTROL: {
  114.             byte buf[] = new byte[6];
  115.             if (!readBytes(buf, 0, 6)) {
  116.                 return;//error("corrupt GIF file");
  117.             }
  118.             if ((buf[0] != 4) || (buf[5] != 0)) {
  119.                 return;//error("corrupt GIF file (GCE size)");
  120.             }
  121.             // Get the index of the transparent color
  122.             trans_pixel = buf[4] & 0xFF;
  123.             break;
  124.               }
  125.  
  126.               case EX_COMMENT:
  127.               case EX_APPLICATION:
  128.               default:
  129.             String comment = "";
  130.             while (true) {
  131.                 int n = input.read();
  132.                 if (n == 0) {
  133.                 break;
  134.                 }
  135.                 byte buf[] = new byte[n];
  136.                 if (!readBytes(buf, 0, n)) {
  137.                 return;//error("corrupt GIF file");
  138.                 }
  139.                 if (code == EX_COMMENT) {
  140.                 comment += new String(buf, 0);
  141.                 }
  142.             }
  143.             if (code == EX_COMMENT) {
  144.                 props.put("comment", comment);
  145.             }
  146.             break;
  147.             }
  148.             break;
  149.  
  150.           case IMAGESEP:
  151.             try {
  152.             model = new IndexColorModel(8, num_colors, colormap,
  153.                             0, false, trans_pixel);
  154.             colormap = null;
  155.             if (readImage()) {
  156.                 store.imageComplete();
  157.                 if (store.getBitState() != PixelStore.BITS_LOST) {
  158.                 source.setPixelStore(store);
  159.                 }
  160.                 source.imageComplete(ImageConsumer.STATICIMAGEDONE);
  161.             }
  162.             } catch (ArrayIndexOutOfBoundsException e) {
  163.             if (verbose) {
  164.                 e.printStackTrace();
  165.             }
  166.             }
  167.             return;
  168.  
  169.           case TERMINATOR:
  170.             return;
  171.  
  172.           case -1:
  173.             return;
  174.  
  175.           default:
  176.             return;//error("corrupt GIF file (parse) [" + code + "].");
  177.             //break;
  178.         }
  179.         }
  180.     } finally {
  181.         try {
  182.         input.close();
  183.         } catch (IOException e) {
  184.         }
  185.     }
  186.     }
  187.  
  188.     /**
  189.      * Read Image header
  190.      */
  191.     private void readHeader() throws IOException, ImageFormatException {
  192.     // Create a buffer
  193.     byte buf[] = new byte[13];
  194.  
  195.     // Read the header
  196.     if (!readBytes(buf, 0, 13)) {
  197.         throw new IOException();
  198.     }
  199.  
  200.     // Check header
  201.     if ((buf[0] != 'G') || (buf[1] != 'I') || (buf[2] != 'F')) {
  202.         error("not a GIF file.");
  203.     }
  204.  
  205.     // colormap info
  206.     int ch = buf[10] & 0xFF;
  207.     if ((ch & COLORMAPMASK) == 0) {
  208.         error("no global colormap in GIF file.");
  209.     }
  210.     num_colors = 1 << ((ch & 0x7) + 1);
  211.  
  212.     // supposed to be NULL
  213.     if (buf[12] != 0) {
  214.         props.put("aspectratio", ""+(((buf[12] & 0xff) + 15) / 64.0));
  215.     }
  216.  
  217.     // Read colors
  218.     colormap = new byte[num_colors * 3];
  219.     if (!readBytes(colormap, 0, num_colors * 3)) {
  220.         throw new IOException();
  221.     }
  222.     }
  223.  
  224.     /**
  225.      * The ImageConsumer hints flag for a non-interlaced GIF image.
  226.      */
  227.     private static final int normalflags =
  228.     ImageConsumer.TOPDOWNLEFTRIGHT | ImageConsumer.COMPLETESCANLINES |
  229.     ImageConsumer.SINGLEPASS | ImageConsumer.SINGLEFRAME;
  230.  
  231.     /**
  232.      * The ImageConsumer hints flag for an interlaced GIF image.
  233.      */
  234.     private static final int interlaceflags =
  235.     ImageConsumer.RANDOMPIXELORDER | ImageConsumer.COMPLETESCANLINES |
  236.     ImageConsumer.SINGLEPASS | ImageConsumer.SINGLEFRAME;
  237.  
  238.     private native boolean parseImage(int width, int height,
  239.                       boolean interlace, int initCodeSize,
  240.                       byte block[], byte rasline[]);
  241.  
  242.     private int sendPixels(int y, int width, byte rasline[]) {
  243.  
  244.     int count = source.setPixels(0, y, width, 1, model,
  245.                      rasline, 0, width);
  246.     if (store.setPixels(0, y, width, 1, rasline, 0, width)) {
  247.         count++;
  248.     }
  249.     return count;
  250.     }
  251.  
  252.     /**
  253.      * Read Image data
  254.      */
  255.     private boolean readImage() throws IOException {
  256.     long tm = 0;
  257.  
  258.     if (verbose) {
  259.         tm = System.currentTimeMillis();
  260.     }
  261.  
  262.     // Allocate the buffer
  263.     byte block[] = new byte[256 + 3];
  264.  
  265.     // Read the image descriptor
  266.     if (!readBytes(block, 0, 10)) {
  267.         throw new IOException();
  268.     }
  269.     int width = (block[4] & 0xFF) | (block[5] << 8);
  270.     int height = (block[6] & 0xFF) | (block[7] << 8);
  271.     boolean interlace = (block[8] & INTERLACEMASK) != 0;
  272.     int initCodeSize = block[9] & 0xFF;
  273.  
  274.     // Notify the consumers
  275.     source.setDimensions(width, height);
  276.     makeStore(width, height);
  277.  
  278.     source.setProperties(props);
  279.     store.setProperties(props);
  280.  
  281.     source.setColorModel(model);
  282.     store.setColorModel(model);
  283.  
  284.     int hints = (interlace ? interlaceflags : normalflags);
  285.     source.setHints(hints);
  286.     store.setHints(hints);
  287.  
  288.     // allocate the raster data
  289.     byte rasline[] = new byte[width];
  290.  
  291.     if (verbose) {
  292.         System.out.print("Reading a " + width + " by " + height + " " +
  293.               (interlace ? "" : "non-") + "interlaced image...");
  294.     }
  295.  
  296.     boolean ret = parseImage(width, height, interlace, initCodeSize,
  297.                  block, rasline);
  298.  
  299.     if (verbose) {
  300.         System.out.println("done in "
  301.                    + (System.currentTimeMillis() - tm)
  302.                    + "ms");
  303.     }
  304.  
  305.     return ret;
  306.     }
  307. }
  308.