home *** CD-ROM | disk | FTP | other *** search
- package Acme.JPM.Encoders;
-
- import Acme.IntHashtable;
- import java.awt.Image;
- import java.awt.image.ImageProducer;
- import java.io.IOException;
- import java.io.OutputStream;
- import java.util.Enumeration;
-
- public class GifEncoder extends ImageEncoder {
- private boolean interlace = false;
- int width;
- int height;
- int[][] rgbPixels;
- IntHashtable colorHash;
- int Width;
- int Height;
- boolean Interlace;
- int curx;
- int cury;
- int CountDown;
- int Pass;
- static final int EOF = -1;
- static final int BITS = 12;
- static final int HSIZE = 5003;
- int n_bits;
- int maxbits = 12;
- int maxcode;
- int maxmaxcode = 4096;
- int[] htab = new int[5003];
- int[] codetab = new int[5003];
- int hsize = 5003;
- int free_ent;
- boolean clear_flg = false;
- int g_init_bits;
- int ClearCode;
- int EOFCode;
- int cur_accum;
- int cur_bits;
- int[] masks = new int[]{0, 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191, 16383, 32767, 65535};
- int a_count;
- byte[] accum = new byte[256];
-
- public GifEncoder(Image img, OutputStream out) throws IOException {
- super(img, out);
- }
-
- public GifEncoder(Image img, OutputStream out, boolean interlace) throws IOException {
- super(img, out);
- this.interlace = interlace;
- }
-
- public GifEncoder(ImageProducer prod, OutputStream out) throws IOException {
- super(prod, out);
- }
-
- public GifEncoder(ImageProducer prod, OutputStream out, boolean interlace) throws IOException {
- super(prod, out);
- this.interlace = interlace;
- }
-
- void encodeStart(int width, int height) throws IOException {
- this.width = width;
- this.height = height;
- this.rgbPixels = new int[height][width];
- }
-
- void encodePixels(int x, int y, int w, int h, int[] rgbPixels, int off, int scansize) throws IOException {
- for(int row = 0; row < h; ++row) {
- System.arraycopy(rgbPixels, row * scansize + off, this.rgbPixels[y + row], x, w);
- }
-
- }
-
- void encodeDone() throws IOException {
- int transparentIndex = -1;
- int transparentRgb = -1;
- this.colorHash = new IntHashtable();
- int index = 0;
-
- for(int row = 0; row < this.height; ++row) {
- for(int col = 0; col < this.width; ++col) {
- int rgb = this.rgbPixels[row][col];
- boolean isTransparent = rgb >>> 24 < 128;
- if (isTransparent) {
- if (transparentIndex < 0) {
- transparentIndex = index;
- transparentRgb = rgb;
- } else if (rgb != transparentRgb) {
- int[] var10000 = this.rgbPixels[row];
- rgb = transparentRgb;
- var10000[col] = transparentRgb;
- }
- }
-
- GifEncoderHashitem item = (GifEncoderHashitem)this.colorHash.get(rgb);
- if (item == null) {
- if (index >= 256) {
- throw new IOException("too many colors for a GIF");
- }
-
- item = new GifEncoderHashitem(rgb, 1, index, isTransparent);
- ++index;
- this.colorHash.put(rgb, item);
- } else {
- ++item.count;
- }
- }
- }
-
- int logColors;
- if (index <= 2) {
- logColors = 1;
- } else if (index <= 4) {
- logColors = 2;
- } else if (index <= 16) {
- logColors = 4;
- } else {
- logColors = 8;
- }
-
- int mapSize = 1 << logColors;
- byte[] reds = new byte[mapSize];
- byte[] grns = new byte[mapSize];
- byte[] blus = new byte[mapSize];
-
- GifEncoderHashitem item;
- for(Enumeration e = this.colorHash.elements(); e.hasMoreElements(); blus[item.index] = (byte)(item.rgb & 255)) {
- item = (GifEncoderHashitem)e.nextElement();
- reds[item.index] = (byte)(item.rgb >> 16 & 255);
- grns[item.index] = (byte)(item.rgb >> 8 & 255);
- }
-
- this.GIFEncode(super.out, this.width, this.height, this.interlace, (byte)0, transparentIndex, logColors, reds, grns, blus);
- }
-
- byte GetPixel(int x, int y) throws IOException {
- GifEncoderHashitem item = (GifEncoderHashitem)this.colorHash.get(this.rgbPixels[y][x]);
- if (item == null) {
- throw new IOException("color not found");
- } else {
- return (byte)item.index;
- }
- }
-
- static void writeString(OutputStream out, String str) throws IOException {
- int len = str.length();
- byte[] buf = new byte[len];
- str.getBytes(0, len, buf, 0);
- out.write(buf);
- }
-
- void GIFEncode(OutputStream outs, int Width, int Height, boolean Interlace, byte Background, int Transparent, int BitsPerPixel, byte[] Red, byte[] Green, byte[] Blue) throws IOException {
- this.Width = Width;
- this.Height = Height;
- this.Interlace = Interlace;
- int ColorMapSize = 1 << BitsPerPixel;
- int TopOfs = 0;
- int LeftOfs = 0;
- this.CountDown = Width * Height;
- this.Pass = 0;
- int InitCodeSize;
- if (BitsPerPixel <= 1) {
- InitCodeSize = 2;
- } else {
- InitCodeSize = BitsPerPixel;
- }
-
- this.curx = 0;
- this.cury = 0;
- writeString(outs, "GIF89a");
- this.Putword(Width, outs);
- this.Putword(Height, outs);
- byte B = -128;
- B = (byte)(B | 112);
- B = (byte)(B | (byte)(BitsPerPixel - 1));
- this.Putbyte(B, outs);
- this.Putbyte(Background, outs);
- this.Putbyte((byte)0, outs);
-
- for(int i = 0; i < ColorMapSize; ++i) {
- this.Putbyte(Red[i], outs);
- this.Putbyte(Green[i], outs);
- this.Putbyte(Blue[i], outs);
- }
-
- if (Transparent != -1) {
- this.Putbyte((byte)33, outs);
- this.Putbyte((byte)-7, outs);
- this.Putbyte((byte)4, outs);
- this.Putbyte((byte)1, outs);
- this.Putbyte((byte)0, outs);
- this.Putbyte((byte)0, outs);
- this.Putbyte((byte)Transparent, outs);
- this.Putbyte((byte)0, outs);
- }
-
- this.Putbyte((byte)44, outs);
- this.Putword(LeftOfs, outs);
- this.Putword(TopOfs, outs);
- this.Putword(Width, outs);
- this.Putword(Height, outs);
- if (Interlace) {
- this.Putbyte((byte)64, outs);
- } else {
- this.Putbyte((byte)0, outs);
- }
-
- this.Putbyte((byte)InitCodeSize, outs);
- this.compress(InitCodeSize + 1, outs);
- this.Putbyte((byte)0, outs);
- this.Putbyte((byte)59, outs);
- }
-
- void BumpPixel() {
- ++this.curx;
- if (this.curx == this.Width) {
- this.curx = 0;
- if (!this.Interlace) {
- ++this.cury;
- return;
- }
-
- switch (this.Pass) {
- case 0:
- this.cury += 8;
- if (this.cury >= this.Height) {
- ++this.Pass;
- this.cury = 4;
- return;
- }
- break;
- case 1:
- this.cury += 8;
- if (this.cury >= this.Height) {
- ++this.Pass;
- this.cury = 2;
- return;
- }
- break;
- case 2:
- this.cury += 4;
- if (this.cury >= this.Height) {
- ++this.Pass;
- this.cury = 1;
- return;
- }
- break;
- case 3:
- this.cury += 2;
- return;
- }
- }
-
- }
-
- int GIFNextPixel() throws IOException {
- if (this.CountDown == 0) {
- return -1;
- } else {
- --this.CountDown;
- byte r = this.GetPixel(this.curx, this.cury);
- this.BumpPixel();
- return r & 255;
- }
- }
-
- void Putword(int w, OutputStream outs) throws IOException {
- this.Putbyte((byte)(w & 255), outs);
- this.Putbyte((byte)(w >> 8 & 255), outs);
- }
-
- void Putbyte(byte b, OutputStream outs) throws IOException {
- outs.write(b);
- }
-
- final int MAXCODE(int n_bits) {
- return (1 << n_bits) - 1;
- }
-
- void compress(int init_bits, OutputStream outs) throws IOException {
- this.g_init_bits = init_bits;
- this.clear_flg = false;
- this.n_bits = this.g_init_bits;
- this.maxcode = this.MAXCODE(this.n_bits);
- this.ClearCode = 1 << init_bits - 1;
- this.EOFCode = this.ClearCode + 1;
- this.free_ent = this.ClearCode + 2;
- this.char_init();
- int ent = this.GIFNextPixel();
- int hshift = 0;
-
- for(int fcode = this.hsize; fcode < 65536; fcode *= 2) {
- ++hshift;
- }
-
- hshift = 8 - hshift;
- int hsize_reg = this.hsize;
- this.cl_hash(hsize_reg);
- this.output(this.ClearCode, outs);
-
- int c;
- label42:
- while((c = this.GIFNextPixel()) != -1) {
- int var10 = (c << this.maxbits) + ent;
- int i = c << hshift ^ ent;
- if (this.htab[i] == var10) {
- ent = this.codetab[i];
- } else {
- if (this.htab[i] >= 0) {
- int disp = hsize_reg - i;
- if (i == 0) {
- disp = 1;
- }
-
- do {
- if ((i -= disp) < 0) {
- i += hsize_reg;
- }
-
- if (this.htab[i] == var10) {
- ent = this.codetab[i];
- continue label42;
- }
- } while(this.htab[i] >= 0);
- }
-
- this.output(ent, outs);
- ent = c;
- if (this.free_ent < this.maxmaxcode) {
- this.codetab[i] = this.free_ent++;
- this.htab[i] = var10;
- } else {
- this.cl_block(outs);
- }
- }
- }
-
- this.output(ent, outs);
- this.output(this.EOFCode, outs);
- }
-
- void output(int code, OutputStream outs) throws IOException {
- this.cur_accum &= this.masks[this.cur_bits];
- if (this.cur_bits > 0) {
- this.cur_accum |= code << this.cur_bits;
- } else {
- this.cur_accum = code;
- }
-
- for(this.cur_bits += this.n_bits; this.cur_bits >= 8; this.cur_bits -= 8) {
- this.char_out((byte)(this.cur_accum & 255), outs);
- this.cur_accum >>= 8;
- }
-
- if (this.free_ent > this.maxcode || this.clear_flg) {
- if (this.clear_flg) {
- this.maxcode = this.MAXCODE(this.n_bits = this.g_init_bits);
- this.clear_flg = false;
- } else {
- ++this.n_bits;
- if (this.n_bits == this.maxbits) {
- this.maxcode = this.maxmaxcode;
- } else {
- this.maxcode = this.MAXCODE(this.n_bits);
- }
- }
- }
-
- if (code == this.EOFCode) {
- while(this.cur_bits > 0) {
- this.char_out((byte)(this.cur_accum & 255), outs);
- this.cur_accum >>= 8;
- this.cur_bits -= 8;
- }
-
- this.flush_char(outs);
- }
-
- }
-
- void cl_block(OutputStream outs) throws IOException {
- this.cl_hash(this.hsize);
- this.free_ent = this.ClearCode + 2;
- this.clear_flg = true;
- this.output(this.ClearCode, outs);
- }
-
- void cl_hash(int hsize) {
- for(int i = 0; i < hsize; ++i) {
- this.htab[i] = -1;
- }
-
- }
-
- void char_init() {
- this.a_count = 0;
- }
-
- void char_out(byte c, OutputStream outs) throws IOException {
- this.accum[this.a_count++] = c;
- if (this.a_count >= 254) {
- this.flush_char(outs);
- }
-
- }
-
- void flush_char(OutputStream outs) throws IOException {
- if (this.a_count > 0) {
- outs.write(this.a_count);
- outs.write(this.accum, 0, this.a_count);
- this.a_count = 0;
- }
-
- }
- }
-