1 package org.catacomb.movie.gif;
2
3
4 import java.io.IOException;
5 import java.io.OutputStream;
6
7
8
9
10
11 class LZWEncoder {
12
13 private static final int EOF = -1;
14
15 private int imgW, imgH;
16 private byte[] pixAry;
17 private int initCodeSize;
18 private int remaining;
19 private int curPixel;
20
21
22
23
24
25
26
27
28 static final int BITS = 12;
29
30 static final int HSIZE = 5003;
31
32
33
34
35
36
37
38
39
40
41
42
43 int n_bits;
44 int maxbits = BITS;
45 int maxcode;
46 int maxmaxcode = 1 << BITS;
47
48 int[] htab = new int[HSIZE];
49 int[] codetab = new int[HSIZE];
50
51 int hsize = HSIZE;
52
53 int free_ent = 0;
54
55
56
57 boolean clear_flg = false;
58
59
60
61
62
63
64
65
66
67
68
69
70
71 int g_init_bits;
72
73 int ClearCode;
74 int EOFCode;
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91 int cur_accum = 0;
92 int cur_bits = 0;
93
94 int masks[] =
95 {
96 0x0000,
97 0x0001,
98 0x0003,
99 0x0007,
100 0x000F,
101 0x001F,
102 0x003F,
103 0x007F,
104 0x00FF,
105 0x01FF,
106 0x03FF,
107 0x07FF,
108 0x0FFF,
109 0x1FFF,
110 0x3FFF,
111 0x7FFF,
112 0xFFFF
113 };
114
115
116 int a_count;
117
118
119 byte[] accum = new byte[256];
120
121
122 LZWEncoder(int width, int height, byte[] pixels, int color_depth) {
123 imgW = width;
124 imgH = height;
125 pixAry = pixels;
126 initCodeSize = Math.max(2, color_depth);
127 }
128
129
130
131 void char_out(byte c, OutputStream outs) throws IOException {
132 accum[a_count++] = c;
133 if (a_count >= 254) {
134 flush_char(outs);
135 }
136 }
137
138
139
140
141 void cl_block(OutputStream outs) throws IOException {
142 cl_hash(hsize);
143 free_ent = ClearCode + 2;
144 clear_flg = true;
145
146 output(ClearCode, outs);
147 }
148
149
150 void cl_hash(int lhsize) {
151 for (int i = 0; i < lhsize; ++i) {
152 htab[i] = -1;
153 }
154 }
155
156 void compress(int init_bits, OutputStream outs) throws IOException {
157 int fcode;
158 int i
159 int c;
160 int ent;
161 int disp;
162 int hsize_reg;
163 int hshift;
164
165
166 g_init_bits = init_bits;
167
168
169 clear_flg = false;
170 n_bits = g_init_bits;
171 maxcode = MAXCODE(n_bits);
172
173 ClearCode = 1 << (init_bits - 1);
174 EOFCode = ClearCode + 1;
175 free_ent = ClearCode + 2;
176
177 a_count = 0;
178
179 ent = nextPixel();
180
181 hshift = 0;
182 for (fcode = hsize; fcode < 65536; fcode *= 2) {
183 ++hshift;
184 }
185 hshift = 8 - hshift;
186
187 hsize_reg = hsize;
188 cl_hash(hsize_reg);
189
190 output(ClearCode, outs);
191
192 outer_loop : while ((c = nextPixel()) != EOF) {
193 fcode = (c << maxbits) + ent;
194 i = (c << hshift) ^ ent;
195
196 if (htab[i] == fcode) {
197 ent = codetab[i];
198 continue;
199 } else if (htab[i] >= 0)
200 {
201 disp = hsize_reg - i;
202 if (i == 0) {
203 disp = 1;
204 }
205 do {
206 if ((i -= disp) < 0) {
207 i += hsize_reg;
208 }
209
210 if (htab[i] == fcode) {
211 ent = codetab[i];
212 continue outer_loop;
213 }
214 } while (htab[i] >= 0);
215 }
216 output(ent, outs);
217 ent = c;
218 if (free_ent < maxmaxcode) {
219 codetab[i] = free_ent++;
220 htab[i] = fcode;
221 } else {
222 cl_block(outs);
223 }
224 }
225
226 output(ent, outs);
227 output(EOFCode, outs);
228 }
229
230
231 void encode(OutputStream os) throws IOException {
232 os.write(initCodeSize);
233
234 remaining = imgW * imgH;
235 curPixel = 0;
236
237 compress(initCodeSize + 1, os);
238
239 os.write(0);
240 }
241
242
243 void flush_char(OutputStream outs) throws IOException {
244 if (a_count > 0) {
245 outs.write(a_count);
246 outs.write(accum, 0, a_count);
247 a_count = 0;
248 }
249 }
250
251 final int MAXCODE(int ln_bits) {
252 return (1 << ln_bits) - 1;
253 }
254
255
256
257
258 private int nextPixel() {
259 if (remaining == 0) {
260 return EOF;
261 }
262
263 --remaining;
264
265 byte pix = pixAry[curPixel++];
266
267 return pix & 0xff;
268 }
269
270 void output(int code, OutputStream outs) throws IOException {
271 cur_accum &= masks[cur_bits];
272
273 if (cur_bits > 0) {
274 cur_accum |= (code << cur_bits);
275 } else {
276 cur_accum = code;
277 }
278
279 cur_bits += n_bits;
280
281 while (cur_bits >= 8) {
282 char_out((byte)(cur_accum & 0xff), outs);
283 cur_accum >>= 8;
284 cur_bits -= 8;
285 }
286
287
288
289 if (free_ent > maxcode || clear_flg) {
290 if (clear_flg) {
291 maxcode = MAXCODE(n_bits = g_init_bits);
292 clear_flg = false;
293 } else {
294 ++n_bits;
295 if (n_bits == maxbits) {
296 maxcode = maxmaxcode;
297 } else {
298 maxcode = MAXCODE(n_bits);
299 }
300 }
301 }
302
303 if (code == EOFCode) {
304
305 while (cur_bits > 0) {
306 char_out((byte)(cur_accum & 0xff), outs);
307 cur_accum >>= 8;
308 cur_bits -= 8;
309 }
310
311 flush_char(outs);
312 }
313 }
314 }