KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > swt > internal > image > LZWCodec


1 /*******************************************************************************
2  * Copyright (c) 2000, 2005 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.swt.internal.image;
12
13
14 import org.eclipse.swt.*;
15 import org.eclipse.swt.graphics.*;
16
17 final class LZWCodec {
18     int bitsPerPixel, blockSize, blockIndex, currentByte, bitsLeft,
19         codeSize, clearCode, endCode, newCodes, topSlot, currentSlot,
20         imageWidth, imageHeight, imageX, imageY, pass, line, codeMask;
21     byte[] block, lineArray;
22     int[] stack, suffix, prefix;
23     LZWNode[] nodeStack;
24     LEDataInputStream inputStream;
25     LEDataOutputStream outputStream;
26     ImageData image;
27     ImageLoader loader;
28     boolean interlaced;
29     static final int[] MASK_TABLE = new int[] {
30         0x1, 0x3, 0x7, 0xF, 0x1F, 0x3F, 0x7F,
31         0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF
32     };
33
34 /**
35  * Decode the input.
36  */

37 void decode() {
38     int code;
39     int oc = 0;
40     int fc = 0;
41     byte[] buf = new byte[imageWidth];
42     int stackIndex = 0;
43     int bufIndex = 0;
44     int c;
45     while ((c = nextCode()) != endCode) {
46         if (c == clearCode) {
47             codeSize = bitsPerPixel + 1;
48             codeMask = MASK_TABLE[bitsPerPixel];
49             currentSlot = newCodes;
50             topSlot = 1 << codeSize;
51             while ((c = nextCode()) == clearCode) {}
52             if (c != endCode) {
53                 oc = fc = c;
54                 buf[bufIndex] = (byte)c;
55                 bufIndex++;
56                 if (bufIndex == imageWidth) {
57                     nextPutPixels(buf);
58                     bufIndex = 0;
59                 }
60             }
61         } else {
62             code = c;
63             if (code >= currentSlot) {
64                 code = oc;
65                 stack[stackIndex] = fc;
66                 stackIndex++;
67             }
68             while (code >= newCodes) {
69                 stack[stackIndex] = suffix[code];
70                 stackIndex++;
71                 code = prefix[code];
72             }
73             stack[stackIndex] = code;
74             stackIndex++;
75             if (currentSlot < topSlot) {
76                 fc = code;
77                 suffix[currentSlot] = fc;
78                 prefix[currentSlot] = oc;
79                 currentSlot++;
80                 oc = c;
81             }
82             if (currentSlot >= topSlot) {
83                 if (codeSize < 12) {
84                     codeMask = MASK_TABLE[codeSize];
85                     codeSize++;
86                     topSlot = topSlot + topSlot;
87                 }
88             }
89             while (stackIndex > 0) {
90                 stackIndex--;
91                 buf[bufIndex] = (byte)stack[stackIndex];
92                 bufIndex++;
93                 if (bufIndex == imageWidth) {
94                     nextPutPixels(buf);
95                     bufIndex = 0;
96                 }
97             }
98         }
99     }
100     if (bufIndex != 0 && line < imageHeight) {
101         nextPutPixels(buf);
102     }
103 }
104 /**
105  * Decode the LZW-encoded bytes in the given byte stream
106  * into the given DeviceIndependentImage.
107  */

108 public void decode(LEDataInputStream inputStream, ImageLoader loader, ImageData image, boolean interlaced, int depth) {
109     this.inputStream = inputStream;
110     this.loader = loader;
111     this.image = image;
112     this.interlaced = interlaced;
113     this.bitsPerPixel = depth;
114     initializeForDecoding();
115     decode();
116 }
117 /**
118  * Encode the image.
119  */

120 void encode() {
121     nextPutCode(clearCode);
122     int lastPrefix = encodeLoop();
123     nextPutCode(lastPrefix);
124     nextPutCode(endCode);
125
126     // Write out last partial block
127
if (bitsLeft == 8) {
128         block[0] = (byte)(blockIndex - 1); // Nothing in last byte
129
} else {
130         block[0] = (byte)(blockIndex); // Last byte has data
131
}
132     writeBlock();
133
134     // Write out empty block to indicate the end (if needed)
135
if (block[0] != 0) {
136         block[0] = 0;
137         writeBlock();
138     }
139 }
140 /**
141  * Encode the bytes into the given byte stream
142  * from the given DeviceIndependentImage.
143  */

144 public void encode(LEDataOutputStream byteStream, ImageData image) {
145     this.outputStream = byteStream;
146     this.image = image;
147     initializeForEncoding();
148     encode();
149 }
150 /**
151  * Encoding loop broken out to allow early return.
152  */

153 int encodeLoop() {
154     int pixel = nextPixel();
155     boolean found;
156     LZWNode node;
157     while (true) {
158         int currentPrefix = pixel;
159         node = nodeStack[currentPrefix];
160         found = true;
161         pixel = nextPixel();
162         if (pixel < 0)
163             return currentPrefix;
164         while (found && (node.children != null)) {
165             node = node.children;
166             while (found && (node.suffix != pixel)) {
167                 if (pixel < node.suffix) {
168                     if (node.left == null) {
169                         node.left = new LZWNode();
170                         found = false;
171                     }
172                     node = node.left;
173                 } else {
174                     if (node.right == null) {
175                         node.right = new LZWNode();
176                         found = false;
177                     }
178                     node = node.right;
179                 }
180             }
181             if (found) {
182                 currentPrefix = node.code;
183                 pixel = nextPixel();
184                 if (pixel < 0)
185                     return currentPrefix;
186             }
187         }
188         if (found) {
189             node.children = new LZWNode();
190             node = node.children;
191         }
192         node.children = null;
193         node.left = null;
194         node.right = null;
195         node.code = currentSlot;
196         node.prefix = currentPrefix;
197         node.suffix = pixel;
198         nextPutCode(currentPrefix);
199         currentSlot++;
200         // Off by one?
201
if (currentSlot < 4096) {
202             if (currentSlot > topSlot) {
203                 codeSize++;
204                 codeMask = MASK_TABLE[codeSize - 1];
205                 topSlot *= 2;
206             }
207         } else {
208             nextPutCode(clearCode);
209             for (int i = 0; i < nodeStack.length; i++)
210                 nodeStack[i].children = null;
211             codeSize = bitsPerPixel + 1;
212             codeMask = MASK_TABLE[codeSize - 1];
213             currentSlot = newCodes;
214             topSlot = 1 << codeSize;
215         }
216     }
217 }
218 /**
219  * Initialize the receiver for decoding the given
220  * byte array.
221  */

222 void initializeForDecoding() {
223     pass = 1;
224     line = 0;
225     codeSize = bitsPerPixel + 1;
226     topSlot = 1 << codeSize;
227     clearCode = 1 << bitsPerPixel;
228     endCode = clearCode + 1;
229     newCodes = currentSlot = endCode + 1;
230     currentByte = -1;
231     blockSize = bitsLeft = 0;
232     blockIndex = 0;
233     codeMask = MASK_TABLE[codeSize - 1];
234     stack = new int[4096];
235     suffix = new int[4096];
236     prefix = new int[4096];
237     block = new byte[256];
238     imageWidth = image.width;
239     imageHeight = image.height;
240 }
241 /**
242  * Initialize the receiver for encoding the given
243  * byte array.
244  */

245 void initializeForEncoding() {
246     interlaced = false;
247     bitsPerPixel = image.depth;
248     codeSize = bitsPerPixel + 1;
249     topSlot = 1 << codeSize;
250     clearCode = 1 << bitsPerPixel;
251     endCode = clearCode + 1;
252     newCodes = currentSlot = endCode + 1;
253     bitsLeft = 8;
254     currentByte = 0;
255     blockIndex = 1;
256     blockSize = 255;
257     block = new byte[blockSize];
258     block[0] = (byte)(blockSize - 1);
259     nodeStack = new LZWNode[1 << bitsPerPixel];
260     for (int i = 0; i < nodeStack.length; i++) {
261         LZWNode node = new LZWNode();
262         node.code = i + 1;
263         node.prefix = -1;
264         node.suffix = i + 1;
265         nodeStack[i] = node;
266     }
267     imageWidth = image.width;
268     imageHeight = image.height;
269     imageY = -1;
270     lineArray = new byte[imageWidth];
271     imageX = imageWidth + 1; // Force a read
272
}
273 /**
274  * Answer the next code from the input byte array.
275  */

276 int nextCode() {
277     int code;
278     if (bitsLeft == 0) {
279         if (blockIndex >= blockSize) {
280             blockSize = readBlock();
281             blockIndex = 0;
282             if (blockSize == 0) return endCode;
283         }
284         blockIndex++;
285         currentByte = block[blockIndex] & 0xFF;
286         bitsLeft = 8;
287         code = currentByte;
288     } else {
289         int shift = bitsLeft - 8;
290         if (shift < 0)
291             code = currentByte >> (0 - shift);
292         else
293             code = currentByte << shift;
294     }
295     while (codeSize > bitsLeft) {
296         if (blockIndex >= blockSize) {
297             blockSize = readBlock();
298             blockIndex = 0;
299             if (blockSize == 0) return endCode;
300         }
301         blockIndex++;
302         currentByte = block[blockIndex] & 0xFF;
303         code += currentByte << bitsLeft;
304         bitsLeft += 8;
305     }
306     bitsLeft -= codeSize;
307     return code & codeMask;
308 }
309 /**
310  * Answer the next pixel to encode in the image
311  */

312 int nextPixel() {
313     imageX++;
314     if (imageX > imageWidth) {
315         imageY++;
316         if (imageY >= imageHeight) {
317             return -1;
318         } else {
319             nextPixels(lineArray, imageWidth);
320         }
321         imageX = 1;
322     }
323     return this.lineArray[imageX - 1] & 0xFF;
324 }
325 /**
326  * Copy a row of pixel values from the image.
327  */

328 void nextPixels(byte[] buf, int lineWidth) {
329     if (image.depth == 8) {
330         System.arraycopy(image.data, imageY * image.bytesPerLine, buf, 0, lineWidth);
331     } else {
332         image.getPixels(0, imageY, lineWidth, buf, 0);
333     }
334 }
335 /**
336  * Output aCode to the output stream.
337  */

338 void nextPutCode(int aCode) {
339     int codeToDo = aCode;
340     int codeBitsToDo = codeSize;
341     // Fill in the remainder of the current byte with the
342
// *high-order* bits of the code.
343
int c = codeToDo & MASK_TABLE[bitsLeft - 1];
344     currentByte = currentByte | (c << (8 - bitsLeft));
345     block[blockIndex] = (byte)currentByte;
346     codeBitsToDo -= bitsLeft;
347     if (codeBitsToDo < 1) {
348         // The whole code fit in the first byte, so we are done.
349
bitsLeft -= codeSize;
350         if (bitsLeft == 0) {
351             // We used the whole last byte, so get ready
352
// for the next one.
353
bitsLeft = 8;
354             blockIndex++;
355             if (blockIndex >= blockSize) {
356                 writeBlock();
357                 blockIndex = 1;
358             }
359             currentByte = 0;
360         }
361         return;
362     }
363     codeToDo = codeToDo >> bitsLeft;
364
365     // Fill in any remaining whole bytes (i.e. not the last one!)
366
blockIndex++;
367     if (blockIndex >= blockSize) {
368         writeBlock();
369         blockIndex = 1;
370     }
371     while (codeBitsToDo >= 8) {
372         currentByte = codeToDo & 0xFF;
373         block[blockIndex] = (byte)currentByte;
374         codeToDo = codeToDo >> 8;
375         codeBitsToDo -= 8;
376         blockIndex++;
377         if (blockIndex >= blockSize) {
378             writeBlock();
379             blockIndex = 1;
380         }
381     }
382     // Fill the *low-order* bits of the last byte with the remainder
383
bitsLeft = 8 - codeBitsToDo;
384     currentByte = codeToDo;
385     block[blockIndex] = (byte)currentByte;
386 }
387 /**
388  * Copy a row of pixel values to the image.
389  */

390 void nextPutPixels(byte[] buf) {
391     if (image.depth == 8) {
392         // Slight optimization for depth = 8.
393
int start = line * image.bytesPerLine;
394         for (int i = 0; i < imageWidth; i++)
395             image.data[start + i] = buf[i];
396     } else {
397         image.setPixels(0, line, imageWidth, buf, 0);
398     }
399     if (interlaced) {
400         if (pass == 1) {
401             copyRow(buf, 7);
402             line += 8;
403         } else if (pass == 2) {
404             copyRow(buf, 3);
405             line += 8;
406         } else if (pass == 3) {
407             copyRow(buf, 1);
408             line += 4;
409         } else if (pass == 4) {
410             line += 2;
411         } else if (pass == 5) {
412             line += 0;
413         }
414         if (line >= imageHeight) {
415             pass++;
416             if (pass == 2) line = 4;
417             else if (pass == 3) line = 2;
418             else if (pass == 4) line = 1;
419             else if (pass == 5) line = 0;
420             if (pass < 5) {
421                 if (loader.hasListeners()) {
422                     ImageData imageCopy = (ImageData) image.clone();
423                     loader.notifyListeners(
424                         new ImageLoaderEvent(loader, imageCopy, pass - 2, false));
425                 }
426             }
427         }
428         if (line >= imageHeight) line = 0;
429     } else {
430         line++;
431     }
432 }
433 /**
434  * Copy duplicate rows of pixel values to the image.
435  * This is to fill in rows if the image is interlaced.
436  */

437 void copyRow(byte[] buf, int copies) {
438     for (int i = 1; i <= copies; i++) {
439         if (line + i < imageHeight) {
440             image.setPixels(0, line + i, imageWidth, buf, 0);
441         }
442     }
443 }
444 /**
445  * Read a block from the byte stream.
446  * Return the number of bytes read.
447  * Throw an exception if the block could not be read.
448  */

449 int readBlock() {
450     int size = -1;
451     try {
452         size = inputStream.read();
453         if (size == -1) {
454             SWT.error(SWT.ERROR_INVALID_IMAGE);
455         }
456         block[0] = (byte)size;
457         size = inputStream.read(block, 1, size);
458         if (size == -1) {
459             SWT.error(SWT.ERROR_INVALID_IMAGE);
460         }
461     } catch (Exception JavaDoc e) {
462         SWT.error(SWT.ERROR_IO, e);
463     }
464     return size;
465 }
466 /**
467  * Write a block to the byte stream.
468  * Throw an exception if the block could not be written.
469  */

470 void writeBlock() {
471     try {
472         outputStream.write(block, 0, (block[0] & 0xFF) + 1);
473     } catch (Exception JavaDoc e) {
474         SWT.error(SWT.ERROR_IO, e);
475     }
476 }
477 }
478
Popular Tags