1
44 package org.xwt.translators;
45
46 import org.xwt.*;
47 import org.xwt.util.*;
48 import java.io.BufferedInputStream;
49 import java.io.InputStream;
50 import java.io.IOException;
51 import java.io.PrintWriter;
52
53
54 public class GIF {
55
56
57
58 private GIF() { }
59
60 private static Queue instances = new Queue(10);
61
62 public static void load(InputStream is, Picture p) {
63 GIF g = (GIF)instances.remove(false);
64 if (g == null) g = new GIF();
65 try {
66 g._load(is, p);
67 } catch (Exception e) {
68 if (Log.on) Log.info(GIF.class, e);
69 return;
70 }
71
72
73 }
74
75 private void _load(InputStream is, Picture p) throws IOException {
76 this.p = p;
77 if (is instanceof BufferedInputStream) _in = (BufferedInputStream)is;
78 else _in = new BufferedInputStream(is);
79 decodeAsBufferedImage(0);
80 p.isLoaded = true;
81 p = null;
82 _in = null;
83 }
84
85
86
87 private void decodeAsBufferedImage(int page) throws IOException, IOException {
88
89
90 if (page <= index ) return;
91
92
93 if (index < 0 ) {
94 if (!readIntoBuf(6) || _buf[0] != 'G' || _buf[1] != 'I' || _buf[2] != 'F' ||
95 _buf[3] != '8' || !(_buf[4] == '7' || _buf[4] == '9') || _buf[5] != 'a')
96 throw new IOException("Not a GIF8Xa file.");
97 if (!readGlobalImageDescriptor()) throw new IOException("Unable to read GIF header.");
98 }
99
100
101 int block_identifier;
102 while (true) {
103 if(!readIntoBuf(1)) throw new IOException("Unexpected EOF(1)");
104 block_identifier = _buf[0];
105 if (block_identifier == ';') throw new IOException("No image data");
106 if (block_identifier == '!') {
107 if (!readExtensionBlock()) throw new IOException("Unexpected EOF(2)");
108 continue;
109 }
110
111
112 if (block_identifier != ',') continue;
113
114 if (!readLocalImageDescriptor()) throw new IOException("Unexpected EOF(3)");
115 p.data = new int[p.width * p.height];
116 readImage();
117
118
119
120
121
122 index++;
123 if (index < page) continue;
124
125
126 break;
127 }
128
129
130 return;
131 }
132
133
134 private void readImage()
135 throws IOException, IOException {
136 int len = p.width;
137 int rows = p.height;
138 int initialCodeSize;
139 int v;
140 intintintint, ypos = 0, pass = 0, i;
141 int prefix[] = new int[(1 << MAX_LWZ_BITS)];
142 int append[] = new int[(1 << MAX_LWZ_BITS)];
143 int stack[] = new int[(1 << MAX_LWZ_BITS)*2];
144 int top_idx;
145 intintintintintintintint inCode, endCode, oldCode, maxCode, code, firstCode;
146
147
148 if (!readIntoBuf(1)) throw new IOException("Unexpected EOF decoding image");
149 initialCodeSize = _buf[0];
150
151
152 int[] cmap = global_color_map;
153 if (hascmap) cmap = color_map;
154 if (trans_idx >= 0) cmap[trans_idx] = 0x00000000;
155
156
157
163 clearCode = 1 << initialCodeSize;
164 endCode = clearCode + 1;
165 codeSize = initialCodeSize + 1;
166 maxCode = clearCode + 2;
167 oldCode = -1;
168 firstCode = -1;
169
170 for (i = 0; i < clearCode; i++) append[i] = i;
171 top_idx = 0;
172
173 bitsInWindow = 0;
174 bytes = 0;
175 window = 0L;
176 done = false;
177 c = -1;
178
179
180 ypos = 0;
181 for (i = 0; i < rows; i++) {
182 for (xpos = 0; xpos < len;) {
183
184 if (top_idx == 0) {
185
186 code = getCode(codeSize);
187 if (code < 0) return;
188
189 if (code > maxCode || code == endCode) return;
190 if (code == clearCode) {
191 codeSize = initialCodeSize + 1;
192 maxCode = clearCode + 2;
193 oldCode = -1;
194 continue;
195 }
196
197
198
199
200
201
202
203 if (oldCode == -1) {
204 stack[top_idx++] = append[code];
205 oldCode = code;
206 firstCode = code;
207 continue;
208 }
209
210 inCode = code;
211
212
213
214
215
216 if (code == maxCode) {
217 stack[top_idx++] = firstCode;
218 code = oldCode;
219 }
220
221
222
223 while (code > clearCode) {
224 stack[top_idx++] = append[code];
225 code = prefix[code];
226 }
227 firstCode = append[code];
228
229
230
231 if (maxCode >= (1 << MAX_LWZ_BITS)) return;
232
233
234 stack[top_idx++] = firstCode;
235
236
237 prefix[maxCode] = oldCode;
238 append[maxCode] = firstCode;
239 maxCode++;
240
241
242
243
244
245 if ((maxCode >= (1 << codeSize)) && (maxCode < (1<<MAX_LWZ_BITS))) codeSize++;
246 oldCode = inCode;
247 }
248
249
250 v = stack[--top_idx];
251 if (v < 0) return;
252
253
254 p.data[xpos + ypos * p.width] = cmap[v];
255 xpos++;
256 }
257
258
259 if (interlaced) {
260 ypos += _interlaceStep[pass];
261 while (ypos >= rows) {
262 pass++;
263 if (pass > 3) return;
264 ypos = _interlaceStart[pass];
265 }
266 } else ypos++;
267 }
268 return;
269 }
270
271
272 private int getCode(int code_size) throws IOException {
273 int ret;
274
275 while (bitsInWindow < code_size) {
276
277 if (done) return -1;
278
279 if (bytes == 0) {
280
281 bytes = getDataBlock();
282 c = 0;
283 if (bytes <= 0) {
284 done = true;
285 break;
286 }
287 }
288
289 window += (_buf[c]) << bitsInWindow;
290 ++c;
291 bitsInWindow += 8;
292 bytes--;
293 }
294
295
296
297 ret = ((int)window) & ((1 << code_size) - 1);
298
299
300 window >>= code_size;
301 bitsInWindow -= code_size;
302 return ret;
303 }
304
305
306 private boolean readGlobalImageDescriptor() throws IOException {
307 int packed;
308 int aspect;
309 int ofs;
310
311 if (!readIntoBuf(7) ) return false;
312 global_width = _buf[0] | (_buf[1] << 8);
313 global_height = _buf[2] | (_buf[3] << 8);
314 packed = _buf[4];
315 global_bgcolor = _buf[5];
316 aspect = _buf[6];
317 global_cmapsize = 2 << (packed & 0x07);
318 global_hascmap = (packed & GLOBALCOLORMAP) == GLOBALCOLORMAP;
319 global_color_map = null;
320
321
322 if (global_hascmap) {
323 if (!readColorMap(global_cmapsize,true)) {
324 return false;
325 }
326 }
327
328 return true;
329 }
330
331
332 private boolean readLocalImageDescriptor() throws IOException {
333 int packed;
334
335 if (!readIntoBuf(9) ) return false;
336
337 left = _buf[0] | (_buf[1] << 8);
338 top = _buf[2] | (_buf[3] << 8);
339 p.width = _buf[4] | (_buf[5] << 8);
340 p.height = _buf[6] | (_buf[7] << 8);
341 packed = _buf[8];
342 hascmap = (packed & LOCALCOLORMAP) == LOCALCOLORMAP;
343 cmapsize = 2 << (packed & 0x07);
344 interlaced = (packed & INTERLACE) == INTERLACE;
345 color_map = null;
346
347
348 return !(hascmap && !readColorMap(cmapsize,false));
349 }
350
351
352 private boolean readColorMap(int nColors, boolean isGlobal)
353 throws IOException {
354 int[] map = new int[nColors];
355 for( int i=0; i < nColors; ++i) {
356 if (!readIntoBuf(3) ) return false;
357 map[i] = (_buf[0] << 16) | (_buf[1] << 8) | _buf[2] | 0xFF000000;
358 }
359 if (isGlobal) global_color_map = map;
360 else color_map = map;
361 return true;
362 }
363
364
365 private boolean readExtensionBlock() throws IOException {
366 if (!readIntoBuf(1) ) return false;
367 int label = _buf[0];
368 int count = -1;
369 switch (label) {
370 case 0x01:
371 case 0xff:
372 case 0xfe:
373 break;
374 case 0xf9:
375 count = getDataBlock();
376 if (count < 0) return true;
377
378 if ((_buf[0] & HASTRANSPARENCY) != 0) trans_idx = _buf[3];
379 else trans_idx = -1;
380 }
381 do { count = getDataBlock(); } while (count > 0);
382 return true;
383 }
384
385
386 private int getDataBlock() throws IOException {
387 if (!readIntoBuf(1) ) return -1;
388 int count = _buf[0];
389 if (count != 0) if (!readIntoBuf(count) ) return -1;
390 return count;
391 }
392
393
394 private boolean readIntoBuf(int count) throws IOException {
395 for(int i = 0; i < count; i++) if ((_buf[i] = _in.read()) == -1) return false;
396 return true;
397 }
398
399
400
401 private Picture p;
402
403
404 private int index = -1;
405 private BufferedInputStream _in = null;
406 private int[] _buf = new int[BUFSIZE];
407
408
409 private int trans_idx = -1;
410
411
412 private int global_width = 0;
413 private int global_height = 0;
414 private int global_bgcolor = 0;
415 private int global_cmapsize = 0;
416 private boolean global_hascmap = false;
417 private int[] global_color_map = null;
418
419
420 private int left = 0;
421 private int top = 0;
422 private int cmapsize = 0;
423 private boolean hascmap = false;
424 private boolean interlaced = false;
425 private int[] color_map = null;
426
427
428 private int bytes = 0;
429 private boolean done;
430 private int c;
431 private long window;
432 private int bitsInWindow = 0;
433
434
435 private static final int INTERLACE = 0x40;
436 private static final int GLOBALCOLORMAP = 0x80;
437 private static final int LOCALCOLORMAP = 0x80;
438 private static final int HASTRANSPARENCY = 0x01;
439 private static final int MAX_LWZ_BITS = 12;
440 private static final int BUFSIZE = 280;
441 private static final int[] _interlaceStep = { 8, 8, 4, 2 };
442 private static final int[] _interlaceStart = { 0, 4, 2, 1 };
443 }
444
445
446
447