home *** CD-ROM | disk | FTP | other *** search
/ PC Plus SuperCD (UK) 2000 March / pcp161b.iso / handson / archive / Issue159 / files / java / lib / LZWCompressor.java < prev   
Encoding:
Java Source  |  1999-09-28  |  8.7 KB  |  349 lines

  1. /*
  2. ** The code for this class is based on code from Thomas' Boutell's
  3. ** gd GIF graphics library. The condition upon using the code is that
  4. ** the following notices appear.
  5. **
  6. ** David Griffiths 28th September, 1999.
  7. */
  8.  
  9. /*
  10. ** gd 1.2 is copyright 1994, 1995, Quest Protein Database Center, Cold Spring Harbor Labs.
  11. ** Permission granted to copy and distribute this work provided that this notice remains intact. 
  12. ** Credit for the library must be given to the Quest Protein Database Center, Cold Spring 
  13. ** Harbor Labs, in all derived works. This does not affect your ownership of the derived work 
  14. ** itself, and the intent is to assure proper credit for Quest, not to interfere with your use of gd. 
  15. ** If you have questions, ask. ("Derived works" includes all programs that utilize the library.
  16. ** Credit must be given in user-visible documentation.)
  17. ** gd 1.2 was written by Thomas Boutell and is currently distributed by boutell.com, Inc.
  18. ** If you wish to release modifications to gd, please clear them first by sending email to 
  19. ** boutell@boutell.com; if this is not done, any modified version of the gd library must be clearly
  20. ** labeled as such.
  21. ** The Quest Protein Database Center is funded under Grant P41-RR02188 by the National
  22. ** Institutes of Health.
  23. ** Written by Thomas Boutell (http://sunsite.unc.edu/boutell/index.html), 2/94 - 8/95.
  24. ** The GIF compression code is based on that found in the pbmplus utilities, which in turn is based 
  25. ** on GIFENCOD by David Rowley. See the notice below:
  26. */
  27.  
  28. /*
  29. ** Based on GIFENCOD by David Rowley .A
  30. ** Lempel-Zim compression based on "compress".
  31. **
  32. ** Modified by Marcel Wijkstra
  33. **
  34. ** Copyright (C) 1989 by Jef Poskanzer.
  35. **
  36. ** Permission to use, copy, modify, and distribute this software and its
  37. ** documentation for any purpose and without fee is hereby granted, provided
  38. ** that the above copyright notice appear in all copies and that both that
  39. ** copyright notice and this permission notice appear in supporting
  40. ** documentation.  This software is provided "as is" without express or
  41. ** implied warranty.
  42. **
  43. ** The Graphics Interchange Format(c) is the Copyright property of
  44. ** CompuServe Incorporated.  GIF(sm) is a Service Mark property of
  45. ** CompuServe Incorporated.
  46. */
  47.  
  48. /*
  49. ** The GIF decompression is based on that found in the pbmplus utilities,
  50. ** which in turn is based on GIFDECOD by David Koblas. See the notice below:
  51. */
  52.  
  53. /* +-------------------------------------------------------------------+ */
  54. /* | Copyright 1990, 1991, 1993, David Koblas.  (koblas@netcom.com)    | */
  55. /* |   Permission to use, copy, modify, and distribute this software   | */
  56. /* |   and its documentation for any purpose and without fee is hereby | */
  57. /* |   granted, provided that the above copyright notice appear in all | */
  58. /* |   copies and that both that copyright notice and this permission  | */
  59. /* |   notice appear in supporting documentation.  This software is    | */
  60. /* |   provided "as is" without express or implied warranty.           | */
  61. /* +-------------------------------------------------------------------+ */
  62.  
  63. import java.net.*;
  64. import java.io.*;
  65.  
  66. import java.lang.String;
  67. import java.net.MalformedURLException;
  68. import java.net.URL;
  69. import java.awt.*;
  70. import java.awt.event.*;
  71. import java.applet.Applet;
  72. import java.applet.AppletContext;
  73. import java.io.*;
  74. import java.net.*;
  75. import java.awt.image.*;
  76.  
  77. public class LZWCompressor {
  78.     // Constants
  79.     private final static int EOF = -1;
  80.  
  81.     // Attributes
  82.  
  83.     private boolean interlace;
  84.  
  85.     public void setInterlace(boolean newInterlace) {
  86.         this.interlace = newInterlace;
  87.     }
  88.  
  89.     public boolean isInterlace() {
  90.         return this.interlace;
  91.     }
  92.  
  93.     private PrintStream pStream;
  94.  
  95.     public void setPrintStream(PrintStream newPrintStream) {
  96.         this.pStream = newPrintStream;
  97.     }
  98.  
  99.     public PrintStream getPrintStream() {
  100.         return pStream;
  101.     }
  102.  
  103.     // Private vars
  104.     private boolean clearFlag = false;
  105.     private int CountDown;
  106.     private int curx, cury;
  107.     private int Pass = 0;
  108.     private int maxcode;
  109.     private int maxmaxcode = 1 << 12;
  110.     private int n_bits;
  111.     private int hashes[] = new int[5003];
  112.     private int codes[] = new int[5003];
  113.     private int freeEnt = 0;
  114.     private int numberIn = 1;
  115.     private int numberOut = 0;
  116.     private int curAccum = 0;
  117.     private int curBits = 0;
  118.     private int masks[] = new int[17];
  119.     private int offset;
  120.     private int g_init_bits;
  121.     private int clearCode;
  122.     private int EOFCode;
  123.  
  124.     public LZWCompressor(PrintStream pStream, boolean interlace) {
  125.         setPrintStream(pStream);
  126.         setInterlace(interlace);
  127.         masks[0] = 0;
  128.         for (int j = 1; j < 16; j++)
  129.             masks[j] = ((1 << j) - 1);
  130.         masks[16] = 0xFFFF;
  131.     }
  132.  
  133.     void compress(int init_bits, int theWidth, int theHeight, int[] pixels) {
  134.         int fcode;
  135.         int i;
  136.         int c;
  137.         int ent;
  138.         int disp;
  139.         int hshift;
  140.  
  141.         Pass = 0;
  142.         curBits = 0;
  143.         maxmaxcode = 1 << 12;
  144.         hashes = new int[5003];
  145.         codes = new int[5003];
  146.         curAccum = 0;
  147.         curx = cury = 0;
  148.         CountDown = theWidth * theHeight;
  149.  
  150.         g_init_bits = init_bits;
  151.         offset = 0;
  152.         numberOut = 0;
  153.         clearFlag = false;
  154.         numberIn = 1;
  155.         maxcode = maxCode(n_bits = g_init_bits);
  156.         clearCode = (1 << (init_bits - 1));
  157.         EOFCode = clearCode + 1;
  158.         freeEnt = clearCode + 2;
  159.         initBuffer();
  160.         ent = getNextPixel(pixels, theWidth, theHeight);
  161.         hshift = 0;
  162.  
  163.          pStream.write (init_bits - 1);    // LZW minimum code size
  164.  
  165.  
  166.         for (fcode = 5003; fcode < 65536; fcode *= 2)
  167.             ++hshift;
  168.         hshift = 8 - hshift;
  169.         clearHashes();                
  170.         output (clearCode);
  171.         while ((c = getNextPixel(pixels, theWidth, theHeight)) != EOF) {
  172.             ++numberIn;
  173.             fcode = ((c << 12) + ent);
  174.             i = ((c << hshift) ^ ent); 
  175.             if (hashes[i] == fcode) {
  176.                 ent = codes[i];
  177.                 continue;
  178.             } else if (hashes[i] < 0) {
  179.                 output(ent);
  180.                 ++numberOut;
  181.                 ent = c;
  182.                 if (freeEnt < maxmaxcode) {
  183.                     codes[i] = (freeEnt++);
  184.                     hashes[i] = fcode;
  185.                 } else
  186.                     clearBlock();
  187.                 continue;
  188.             }
  189.             disp = 5003 - i;                    
  190.             if (i == 0)
  191.                 disp = 1;
  192.             if ((i -= disp) < 0)
  193.                 i += 5003;
  194.             if (hashes[i] == fcode) {
  195.                 ent = codes[i];
  196.                 continue;
  197.             }
  198.             while (hashes[i] > 0) {
  199.                 if ((i -= disp) < 0)
  200.                     i += 5003;
  201.                 if (hashes[i] == fcode) {
  202.                     ent = codes[i];
  203.                     break;
  204.                 }
  205.             }
  206.             if (hashes[i] == fcode)
  207.                 continue;
  208.             output(ent);
  209.             ++numberOut;
  210.             ent = c;
  211.             if (freeEnt < maxmaxcode) {
  212.                 codes[i] = (freeEnt++);
  213.                 hashes[i] = fcode;
  214.             } else
  215.                 clearBlock();
  216.         }
  217.         output(ent);
  218.         ++numberOut;
  219.         output(EOFCode);
  220.     }
  221.  
  222.     void output(int code) {
  223.         curAccum &= masks[curBits];
  224.  
  225.         if (curBits > 0)
  226.             curAccum |= (code << curBits);
  227.         else
  228.             curAccum = code;
  229.         curBits += n_bits;
  230.         while (curBits >= 8) {
  231.             writeByte ((byte)(curAccum & 0xff));
  232.             curAccum >>= 8;
  233.             curBits -= 8;
  234.         }
  235.         if (freeEnt > maxcode || clearFlag) {
  236.             if (clearFlag) {
  237.                 maxcode = maxCode (n_bits = g_init_bits);
  238.                 clearFlag = false;
  239.             } else {
  240.                 ++n_bits;
  241.                 if (n_bits == 12)
  242.                     maxcode = maxmaxcode;
  243.                 else
  244.                     maxcode = maxCode(n_bits);
  245.             }
  246.         }
  247.  
  248.         if (code == EOFCode) {
  249.             while (curBits > 0) {
  250.                 writeByte ((byte)(curAccum & 0xff));
  251.                 curAccum >>= 8;
  252.                 curBits -= 8;
  253.             }
  254.             flushBuffer();
  255.         }
  256.     }
  257.  
  258.     void bumpPixel(int theWidth, int theHeight) {
  259.         ++curx;
  260.         if (curx == theWidth) {
  261.             curx = 0;
  262.             if (!interlace)
  263.                 ++cury;
  264.             else {
  265.                 switch (Pass) {
  266.                     case 0:
  267.                         cury += 8;
  268.                         if (cury >= theHeight) {
  269.                             ++Pass;
  270.                             cury = 4;
  271.                         }
  272.                         break;
  273.                     case 1:
  274.                         cury += 8;
  275.                         if (cury >= theHeight) {
  276.                             ++Pass;
  277.                             cury = 2;
  278.                         }
  279.                         break;
  280.                     case 2:
  281.                         cury += 4;
  282.                         if (cury >= theHeight) {
  283.                             ++Pass;
  284.                             cury = 1;
  285.                         }
  286.                         break;
  287.                     case 3:
  288.                         cury += 2;
  289.                         break;
  290.                 }
  291.             }
  292.         }
  293.     }
  294.  
  295.     int getNextPixel(int[] pixels, int theWidth, int theHeight) {
  296.         int r;
  297.         if (CountDown == 0)
  298.             return EOF;
  299.         --CountDown;
  300.         r = pixels[cury * theWidth + curx];
  301.         bumpPixel(theWidth, theHeight);
  302.         return r;
  303.     }
  304.  
  305.     public int maxCode(int n_bits) {
  306.         return ((1 << n_bits) - 1);
  307.     }
  308.  
  309.     void clearBlock() {
  310.         clearHashes();
  311.         freeEnt = clearCode + 2;
  312.         clearFlag = true;
  313.         output(clearCode);
  314.     }
  315.  
  316.     void clearHashes() {
  317.         for (int i = 0; i < 5003; i++)
  318.             hashes[i] = -1;
  319.     }
  320.  
  321.     /////////////////////////////////////////////
  322.     //
  323.     // Print calls - these use an internal buffer
  324.     //
  325.     /////////////////////////////////////////////
  326.  
  327.     private int nextByte;
  328.     private byte bufferByte[];
  329.  
  330.     void initBuffer() {
  331.         nextByte = 0;
  332.         bufferByte = new byte[256];
  333.     }
  334.  
  335.     void writeByte(byte c) {
  336.         bufferByte[nextByte++] = c;
  337.         if (nextByte >= 254)
  338.             flushBuffer();
  339.     }
  340.  
  341.     void flushBuffer() {
  342.         if (nextByte > 0) {
  343.             pStream.write(nextByte);
  344.             pStream.write(bufferByte, 0, nextByte);
  345.             nextByte = 0;
  346.         }
  347.     }
  348. }
  349.