home *** CD-ROM | disk | FTP | other *** search
Java Source | 1999-09-28 | 8.7 KB | 349 lines |
- /*
- ** The code for this class is based on code from Thomas' Boutell's
- ** gd GIF graphics library. The condition upon using the code is that
- ** the following notices appear.
- **
- ** David Griffiths 28th September, 1999.
- */
-
- /*
- ** gd 1.2 is copyright 1994, 1995, Quest Protein Database Center, Cold Spring Harbor Labs.
- ** Permission granted to copy and distribute this work provided that this notice remains intact.
- ** Credit for the library must be given to the Quest Protein Database Center, Cold Spring
- ** Harbor Labs, in all derived works. This does not affect your ownership of the derived work
- ** itself, and the intent is to assure proper credit for Quest, not to interfere with your use of gd.
- ** If you have questions, ask. ("Derived works" includes all programs that utilize the library.
- ** Credit must be given in user-visible documentation.)
- ** gd 1.2 was written by Thomas Boutell and is currently distributed by boutell.com, Inc.
- ** If you wish to release modifications to gd, please clear them first by sending email to
- ** boutell@boutell.com; if this is not done, any modified version of the gd library must be clearly
- ** labeled as such.
- ** The Quest Protein Database Center is funded under Grant P41-RR02188 by the National
- ** Institutes of Health.
- ** Written by Thomas Boutell (http://sunsite.unc.edu/boutell/index.html), 2/94 - 8/95.
- ** The GIF compression code is based on that found in the pbmplus utilities, which in turn is based
- ** on GIFENCOD by David Rowley. See the notice below:
- */
-
- /*
- ** Based on GIFENCOD by David Rowley .A
- ** Lempel-Zim compression based on "compress".
- **
- ** Modified by Marcel Wijkstra
- **
- ** Copyright (C) 1989 by Jef Poskanzer.
- **
- ** Permission to use, copy, modify, and distribute this software and its
- ** documentation for any purpose and without fee is hereby granted, provided
- ** that the above copyright notice appear in all copies and that both that
- ** copyright notice and this permission notice appear in supporting
- ** documentation. This software is provided "as is" without express or
- ** implied warranty.
- **
- ** The Graphics Interchange Format(c) is the Copyright property of
- ** CompuServe Incorporated. GIF(sm) is a Service Mark property of
- ** CompuServe Incorporated.
- */
-
- /*
- ** The GIF decompression is based on that found in the pbmplus utilities,
- ** which in turn is based on GIFDECOD by David Koblas. See the notice below:
- */
-
- /* +-------------------------------------------------------------------+ */
- /* | Copyright 1990, 1991, 1993, David Koblas. (koblas@netcom.com) | */
- /* | Permission to use, copy, modify, and distribute this software | */
- /* | and its documentation for any purpose and without fee is hereby | */
- /* | granted, provided that the above copyright notice appear in all | */
- /* | copies and that both that copyright notice and this permission | */
- /* | notice appear in supporting documentation. This software is | */
- /* | provided "as is" without express or implied warranty. | */
- /* +-------------------------------------------------------------------+ */
-
- import java.net.*;
- import java.io.*;
-
- import java.lang.String;
- import java.net.MalformedURLException;
- import java.net.URL;
- import java.awt.*;
- import java.awt.event.*;
- import java.applet.Applet;
- import java.applet.AppletContext;
- import java.io.*;
- import java.net.*;
- import java.awt.image.*;
-
- public class LZWCompressor {
- // Constants
- private final static int EOF = -1;
-
- // Attributes
-
- private boolean interlace;
-
- public void setInterlace(boolean newInterlace) {
- this.interlace = newInterlace;
- }
-
- public boolean isInterlace() {
- return this.interlace;
- }
-
- private PrintStream pStream;
-
- public void setPrintStream(PrintStream newPrintStream) {
- this.pStream = newPrintStream;
- }
-
- public PrintStream getPrintStream() {
- return pStream;
- }
-
- // Private vars
- private boolean clearFlag = false;
- private int CountDown;
- private int curx, cury;
- private int Pass = 0;
- private int maxcode;
- private int maxmaxcode = 1 << 12;
- private int n_bits;
- private int hashes[] = new int[5003];
- private int codes[] = new int[5003];
- private int freeEnt = 0;
- private int numberIn = 1;
- private int numberOut = 0;
- private int curAccum = 0;
- private int curBits = 0;
- private int masks[] = new int[17];
- private int offset;
- private int g_init_bits;
- private int clearCode;
- private int EOFCode;
-
- public LZWCompressor(PrintStream pStream, boolean interlace) {
- setPrintStream(pStream);
- setInterlace(interlace);
- masks[0] = 0;
- for (int j = 1; j < 16; j++)
- masks[j] = ((1 << j) - 1);
- masks[16] = 0xFFFF;
- }
-
- void compress(int init_bits, int theWidth, int theHeight, int[] pixels) {
- int fcode;
- int i;
- int c;
- int ent;
- int disp;
- int hshift;
-
- Pass = 0;
- curBits = 0;
- maxmaxcode = 1 << 12;
- hashes = new int[5003];
- codes = new int[5003];
- curAccum = 0;
- curx = cury = 0;
- CountDown = theWidth * theHeight;
-
- g_init_bits = init_bits;
- offset = 0;
- numberOut = 0;
- clearFlag = false;
- numberIn = 1;
- maxcode = maxCode(n_bits = g_init_bits);
- clearCode = (1 << (init_bits - 1));
- EOFCode = clearCode + 1;
- freeEnt = clearCode + 2;
- initBuffer();
- ent = getNextPixel(pixels, theWidth, theHeight);
- hshift = 0;
-
- pStream.write (init_bits - 1); // LZW minimum code size
-
-
- for (fcode = 5003; fcode < 65536; fcode *= 2)
- ++hshift;
- hshift = 8 - hshift;
- clearHashes();
- output (clearCode);
- while ((c = getNextPixel(pixels, theWidth, theHeight)) != EOF) {
- ++numberIn;
- fcode = ((c << 12) + ent);
- i = ((c << hshift) ^ ent);
- if (hashes[i] == fcode) {
- ent = codes[i];
- continue;
- } else if (hashes[i] < 0) {
- output(ent);
- ++numberOut;
- ent = c;
- if (freeEnt < maxmaxcode) {
- codes[i] = (freeEnt++);
- hashes[i] = fcode;
- } else
- clearBlock();
- continue;
- }
- disp = 5003 - i;
- if (i == 0)
- disp = 1;
- if ((i -= disp) < 0)
- i += 5003;
- if (hashes[i] == fcode) {
- ent = codes[i];
- continue;
- }
- while (hashes[i] > 0) {
- if ((i -= disp) < 0)
- i += 5003;
- if (hashes[i] == fcode) {
- ent = codes[i];
- break;
- }
- }
- if (hashes[i] == fcode)
- continue;
- output(ent);
- ++numberOut;
- ent = c;
- if (freeEnt < maxmaxcode) {
- codes[i] = (freeEnt++);
- hashes[i] = fcode;
- } else
- clearBlock();
- }
- output(ent);
- ++numberOut;
- output(EOFCode);
- }
-
- void output(int code) {
- curAccum &= masks[curBits];
-
- if (curBits > 0)
- curAccum |= (code << curBits);
- else
- curAccum = code;
- curBits += n_bits;
- while (curBits >= 8) {
- writeByte ((byte)(curAccum & 0xff));
- curAccum >>= 8;
- curBits -= 8;
- }
- if (freeEnt > maxcode || clearFlag) {
- if (clearFlag) {
- maxcode = maxCode (n_bits = g_init_bits);
- clearFlag = false;
- } else {
- ++n_bits;
- if (n_bits == 12)
- maxcode = maxmaxcode;
- else
- maxcode = maxCode(n_bits);
- }
- }
-
- if (code == EOFCode) {
- while (curBits > 0) {
- writeByte ((byte)(curAccum & 0xff));
- curAccum >>= 8;
- curBits -= 8;
- }
- flushBuffer();
- }
- }
-
- void bumpPixel(int theWidth, int theHeight) {
- ++curx;
- if (curx == theWidth) {
- curx = 0;
- if (!interlace)
- ++cury;
- else {
- switch (Pass) {
- case 0:
- cury += 8;
- if (cury >= theHeight) {
- ++Pass;
- cury = 4;
- }
- break;
- case 1:
- cury += 8;
- if (cury >= theHeight) {
- ++Pass;
- cury = 2;
- }
- break;
- case 2:
- cury += 4;
- if (cury >= theHeight) {
- ++Pass;
- cury = 1;
- }
- break;
- case 3:
- cury += 2;
- break;
- }
- }
- }
- }
-
- int getNextPixel(int[] pixels, int theWidth, int theHeight) {
- int r;
- if (CountDown == 0)
- return EOF;
- --CountDown;
- r = pixels[cury * theWidth + curx];
- bumpPixel(theWidth, theHeight);
- return r;
- }
-
- public int maxCode(int n_bits) {
- return ((1 << n_bits) - 1);
- }
-
- void clearBlock() {
- clearHashes();
- freeEnt = clearCode + 2;
- clearFlag = true;
- output(clearCode);
- }
-
- void clearHashes() {
- for (int i = 0; i < 5003; i++)
- hashes[i] = -1;
- }
-
- /////////////////////////////////////////////
- //
- // Print calls - these use an internal buffer
- //
- /////////////////////////////////////////////
-
- private int nextByte;
- private byte bufferByte[];
-
- void initBuffer() {
- nextByte = 0;
- bufferByte = new byte[256];
- }
-
- void writeByte(byte c) {
- bufferByte[nextByte++] = c;
- if (nextByte >= 254)
- flushBuffer();
- }
-
- void flushBuffer() {
- if (nextByte > 0) {
- pStream.write(nextByte);
- pStream.write(bufferByte, 0, nextByte);
- nextByte = 0;
- }
- }
- }
-