home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 1999 April / DPPCPRO0499.ISO / April / Notes / 50b2wic.exe / DATA1.CAB / NotesProgramFilesJavaSupport / Notes.jar / Acme / JPM / Encoders / GifEncoder.class (.txt) next >
Encoding:
Java Class File  |  1998-11-16  |  9.6 KB  |  417 lines

  1. package Acme.JPM.Encoders;
  2.  
  3. import Acme.IntHashtable;
  4. import java.awt.Image;
  5. import java.awt.image.ImageProducer;
  6. import java.io.IOException;
  7. import java.io.OutputStream;
  8. import java.util.Enumeration;
  9.  
  10. public class GifEncoder extends ImageEncoder {
  11.    private boolean interlace = false;
  12.    int width;
  13.    int height;
  14.    int[][] rgbPixels;
  15.    IntHashtable colorHash;
  16.    int Width;
  17.    int Height;
  18.    boolean Interlace;
  19.    int curx;
  20.    int cury;
  21.    int CountDown;
  22.    int Pass;
  23.    static final int EOF = -1;
  24.    static final int BITS = 12;
  25.    static final int HSIZE = 5003;
  26.    int n_bits;
  27.    int maxbits = 12;
  28.    int maxcode;
  29.    int maxmaxcode = 4096;
  30.    int[] htab = new int[5003];
  31.    int[] codetab = new int[5003];
  32.    int hsize = 5003;
  33.    int free_ent;
  34.    boolean clear_flg = false;
  35.    int g_init_bits;
  36.    int ClearCode;
  37.    int EOFCode;
  38.    int cur_accum;
  39.    int cur_bits;
  40.    int[] masks = new int[]{0, 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191, 16383, 32767, 65535};
  41.    int a_count;
  42.    byte[] accum = new byte[256];
  43.  
  44.    public GifEncoder(Image img, OutputStream out) throws IOException {
  45.       super(img, out);
  46.    }
  47.  
  48.    public GifEncoder(Image img, OutputStream out, boolean interlace) throws IOException {
  49.       super(img, out);
  50.       this.interlace = interlace;
  51.    }
  52.  
  53.    public GifEncoder(ImageProducer prod, OutputStream out) throws IOException {
  54.       super(prod, out);
  55.    }
  56.  
  57.    public GifEncoder(ImageProducer prod, OutputStream out, boolean interlace) throws IOException {
  58.       super(prod, out);
  59.       this.interlace = interlace;
  60.    }
  61.  
  62.    void encodeStart(int width, int height) throws IOException {
  63.       this.width = width;
  64.       this.height = height;
  65.       this.rgbPixels = new int[height][width];
  66.    }
  67.  
  68.    void encodePixels(int x, int y, int w, int h, int[] rgbPixels, int off, int scansize) throws IOException {
  69.       for(int row = 0; row < h; ++row) {
  70.          System.arraycopy(rgbPixels, row * scansize + off, this.rgbPixels[y + row], x, w);
  71.       }
  72.  
  73.    }
  74.  
  75.    void encodeDone() throws IOException {
  76.       int transparentIndex = -1;
  77.       int transparentRgb = -1;
  78.       this.colorHash = new IntHashtable();
  79.       int index = 0;
  80.  
  81.       for(int row = 0; row < this.height; ++row) {
  82.          for(int col = 0; col < this.width; ++col) {
  83.             int rgb = this.rgbPixels[row][col];
  84.             boolean isTransparent = rgb >>> 24 < 128;
  85.             if (isTransparent) {
  86.                if (transparentIndex < 0) {
  87.                   transparentIndex = index;
  88.                   transparentRgb = rgb;
  89.                } else if (rgb != transparentRgb) {
  90.                   int[] var10000 = this.rgbPixels[row];
  91.                   rgb = transparentRgb;
  92.                   var10000[col] = transparentRgb;
  93.                }
  94.             }
  95.  
  96.             GifEncoderHashitem item = (GifEncoderHashitem)this.colorHash.get(rgb);
  97.             if (item == null) {
  98.                if (index >= 256) {
  99.                   throw new IOException("too many colors for a GIF");
  100.                }
  101.  
  102.                item = new GifEncoderHashitem(rgb, 1, index, isTransparent);
  103.                ++index;
  104.                this.colorHash.put(rgb, item);
  105.             } else {
  106.                ++item.count;
  107.             }
  108.          }
  109.       }
  110.  
  111.       int logColors;
  112.       if (index <= 2) {
  113.          logColors = 1;
  114.       } else if (index <= 4) {
  115.          logColors = 2;
  116.       } else if (index <= 16) {
  117.          logColors = 4;
  118.       } else {
  119.          logColors = 8;
  120.       }
  121.  
  122.       int mapSize = 1 << logColors;
  123.       byte[] reds = new byte[mapSize];
  124.       byte[] grns = new byte[mapSize];
  125.       byte[] blus = new byte[mapSize];
  126.  
  127.       GifEncoderHashitem item;
  128.       for(Enumeration e = this.colorHash.elements(); e.hasMoreElements(); blus[item.index] = (byte)(item.rgb & 255)) {
  129.          item = (GifEncoderHashitem)e.nextElement();
  130.          reds[item.index] = (byte)(item.rgb >> 16 & 255);
  131.          grns[item.index] = (byte)(item.rgb >> 8 & 255);
  132.       }
  133.  
  134.       this.GIFEncode(super.out, this.width, this.height, this.interlace, (byte)0, transparentIndex, logColors, reds, grns, blus);
  135.    }
  136.  
  137.    byte GetPixel(int x, int y) throws IOException {
  138.       GifEncoderHashitem item = (GifEncoderHashitem)this.colorHash.get(this.rgbPixels[y][x]);
  139.       if (item == null) {
  140.          throw new IOException("color not found");
  141.       } else {
  142.          return (byte)item.index;
  143.       }
  144.    }
  145.  
  146.    static void writeString(OutputStream out, String str) throws IOException {
  147.       int len = str.length();
  148.       byte[] buf = new byte[len];
  149.       str.getBytes(0, len, buf, 0);
  150.       out.write(buf);
  151.    }
  152.  
  153.    void GIFEncode(OutputStream outs, int Width, int Height, boolean Interlace, byte Background, int Transparent, int BitsPerPixel, byte[] Red, byte[] Green, byte[] Blue) throws IOException {
  154.       this.Width = Width;
  155.       this.Height = Height;
  156.       this.Interlace = Interlace;
  157.       int ColorMapSize = 1 << BitsPerPixel;
  158.       int TopOfs = 0;
  159.       int LeftOfs = 0;
  160.       this.CountDown = Width * Height;
  161.       this.Pass = 0;
  162.       int InitCodeSize;
  163.       if (BitsPerPixel <= 1) {
  164.          InitCodeSize = 2;
  165.       } else {
  166.          InitCodeSize = BitsPerPixel;
  167.       }
  168.  
  169.       this.curx = 0;
  170.       this.cury = 0;
  171.       writeString(outs, "GIF89a");
  172.       this.Putword(Width, outs);
  173.       this.Putword(Height, outs);
  174.       byte B = -128;
  175.       B = (byte)(B | 112);
  176.       B = (byte)(B | (byte)(BitsPerPixel - 1));
  177.       this.Putbyte(B, outs);
  178.       this.Putbyte(Background, outs);
  179.       this.Putbyte((byte)0, outs);
  180.  
  181.       for(int i = 0; i < ColorMapSize; ++i) {
  182.          this.Putbyte(Red[i], outs);
  183.          this.Putbyte(Green[i], outs);
  184.          this.Putbyte(Blue[i], outs);
  185.       }
  186.  
  187.       if (Transparent != -1) {
  188.          this.Putbyte((byte)33, outs);
  189.          this.Putbyte((byte)-7, outs);
  190.          this.Putbyte((byte)4, outs);
  191.          this.Putbyte((byte)1, outs);
  192.          this.Putbyte((byte)0, outs);
  193.          this.Putbyte((byte)0, outs);
  194.          this.Putbyte((byte)Transparent, outs);
  195.          this.Putbyte((byte)0, outs);
  196.       }
  197.  
  198.       this.Putbyte((byte)44, outs);
  199.       this.Putword(LeftOfs, outs);
  200.       this.Putword(TopOfs, outs);
  201.       this.Putword(Width, outs);
  202.       this.Putword(Height, outs);
  203.       if (Interlace) {
  204.          this.Putbyte((byte)64, outs);
  205.       } else {
  206.          this.Putbyte((byte)0, outs);
  207.       }
  208.  
  209.       this.Putbyte((byte)InitCodeSize, outs);
  210.       this.compress(InitCodeSize + 1, outs);
  211.       this.Putbyte((byte)0, outs);
  212.       this.Putbyte((byte)59, outs);
  213.    }
  214.  
  215.    void BumpPixel() {
  216.       ++this.curx;
  217.       if (this.curx == this.Width) {
  218.          this.curx = 0;
  219.          if (!this.Interlace) {
  220.             ++this.cury;
  221.             return;
  222.          }
  223.  
  224.          switch (this.Pass) {
  225.             case 0:
  226.                this.cury += 8;
  227.                if (this.cury >= this.Height) {
  228.                   ++this.Pass;
  229.                   this.cury = 4;
  230.                   return;
  231.                }
  232.                break;
  233.             case 1:
  234.                this.cury += 8;
  235.                if (this.cury >= this.Height) {
  236.                   ++this.Pass;
  237.                   this.cury = 2;
  238.                   return;
  239.                }
  240.                break;
  241.             case 2:
  242.                this.cury += 4;
  243.                if (this.cury >= this.Height) {
  244.                   ++this.Pass;
  245.                   this.cury = 1;
  246.                   return;
  247.                }
  248.                break;
  249.             case 3:
  250.                this.cury += 2;
  251.                return;
  252.          }
  253.       }
  254.  
  255.    }
  256.  
  257.    int GIFNextPixel() throws IOException {
  258.       if (this.CountDown == 0) {
  259.          return -1;
  260.       } else {
  261.          --this.CountDown;
  262.          byte r = this.GetPixel(this.curx, this.cury);
  263.          this.BumpPixel();
  264.          return r & 255;
  265.       }
  266.    }
  267.  
  268.    void Putword(int w, OutputStream outs) throws IOException {
  269.       this.Putbyte((byte)(w & 255), outs);
  270.       this.Putbyte((byte)(w >> 8 & 255), outs);
  271.    }
  272.  
  273.    void Putbyte(byte b, OutputStream outs) throws IOException {
  274.       outs.write(b);
  275.    }
  276.  
  277.    final int MAXCODE(int n_bits) {
  278.       return (1 << n_bits) - 1;
  279.    }
  280.  
  281.    void compress(int init_bits, OutputStream outs) throws IOException {
  282.       this.g_init_bits = init_bits;
  283.       this.clear_flg = false;
  284.       this.n_bits = this.g_init_bits;
  285.       this.maxcode = this.MAXCODE(this.n_bits);
  286.       this.ClearCode = 1 << init_bits - 1;
  287.       this.EOFCode = this.ClearCode + 1;
  288.       this.free_ent = this.ClearCode + 2;
  289.       this.char_init();
  290.       int ent = this.GIFNextPixel();
  291.       int hshift = 0;
  292.  
  293.       for(int fcode = this.hsize; fcode < 65536; fcode *= 2) {
  294.          ++hshift;
  295.       }
  296.  
  297.       hshift = 8 - hshift;
  298.       int hsize_reg = this.hsize;
  299.       this.cl_hash(hsize_reg);
  300.       this.output(this.ClearCode, outs);
  301.  
  302.       int c;
  303.       label42:
  304.       while((c = this.GIFNextPixel()) != -1) {
  305.          int var10 = (c << this.maxbits) + ent;
  306.          int i = c << hshift ^ ent;
  307.          if (this.htab[i] == var10) {
  308.             ent = this.codetab[i];
  309.          } else {
  310.             if (this.htab[i] >= 0) {
  311.                int disp = hsize_reg - i;
  312.                if (i == 0) {
  313.                   disp = 1;
  314.                }
  315.  
  316.                do {
  317.                   if ((i -= disp) < 0) {
  318.                      i += hsize_reg;
  319.                   }
  320.  
  321.                   if (this.htab[i] == var10) {
  322.                      ent = this.codetab[i];
  323.                      continue label42;
  324.                   }
  325.                } while(this.htab[i] >= 0);
  326.             }
  327.  
  328.             this.output(ent, outs);
  329.             ent = c;
  330.             if (this.free_ent < this.maxmaxcode) {
  331.                this.codetab[i] = this.free_ent++;
  332.                this.htab[i] = var10;
  333.             } else {
  334.                this.cl_block(outs);
  335.             }
  336.          }
  337.       }
  338.  
  339.       this.output(ent, outs);
  340.       this.output(this.EOFCode, outs);
  341.    }
  342.  
  343.    void output(int code, OutputStream outs) throws IOException {
  344.       this.cur_accum &= this.masks[this.cur_bits];
  345.       if (this.cur_bits > 0) {
  346.          this.cur_accum |= code << this.cur_bits;
  347.       } else {
  348.          this.cur_accum = code;
  349.       }
  350.  
  351.       for(this.cur_bits += this.n_bits; this.cur_bits >= 8; this.cur_bits -= 8) {
  352.          this.char_out((byte)(this.cur_accum & 255), outs);
  353.          this.cur_accum >>= 8;
  354.       }
  355.  
  356.       if (this.free_ent > this.maxcode || this.clear_flg) {
  357.          if (this.clear_flg) {
  358.             this.maxcode = this.MAXCODE(this.n_bits = this.g_init_bits);
  359.             this.clear_flg = false;
  360.          } else {
  361.             ++this.n_bits;
  362.             if (this.n_bits == this.maxbits) {
  363.                this.maxcode = this.maxmaxcode;
  364.             } else {
  365.                this.maxcode = this.MAXCODE(this.n_bits);
  366.             }
  367.          }
  368.       }
  369.  
  370.       if (code == this.EOFCode) {
  371.          while(this.cur_bits > 0) {
  372.             this.char_out((byte)(this.cur_accum & 255), outs);
  373.             this.cur_accum >>= 8;
  374.             this.cur_bits -= 8;
  375.          }
  376.  
  377.          this.flush_char(outs);
  378.       }
  379.  
  380.    }
  381.  
  382.    void cl_block(OutputStream outs) throws IOException {
  383.       this.cl_hash(this.hsize);
  384.       this.free_ent = this.ClearCode + 2;
  385.       this.clear_flg = true;
  386.       this.output(this.ClearCode, outs);
  387.    }
  388.  
  389.    void cl_hash(int hsize) {
  390.       for(int i = 0; i < hsize; ++i) {
  391.          this.htab[i] = -1;
  392.       }
  393.  
  394.    }
  395.  
  396.    void char_init() {
  397.       this.a_count = 0;
  398.    }
  399.  
  400.    void char_out(byte c, OutputStream outs) throws IOException {
  401.       this.accum[this.a_count++] = c;
  402.       if (this.a_count >= 254) {
  403.          this.flush_char(outs);
  404.       }
  405.  
  406.    }
  407.  
  408.    void flush_char(OutputStream outs) throws IOException {
  409.       if (this.a_count > 0) {
  410.          outs.write(this.a_count);
  411.          outs.write(this.accum, 0, this.a_count);
  412.          this.a_count = 0;
  413.       }
  414.  
  415.    }
  416. }
  417.