comparison dwt/internal/image/LZWCodec.d @ 0:380af2bdd8e5

Upload of whole dwt tree
author Jacob Carlborg <doob@me.com> <jacob.carlborg@gmail.com>
date Sat, 09 Aug 2008 17:00:02 +0200
parents
children e831403a80a9
comparison
equal deleted inserted replaced
-1:000000000000 0:380af2bdd8e5
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 module dwt.internal.image;
12
13
14 import dwt.DWT;
15 import dwt.graphics.ImageData;
16 import dwt.graphics.ImageLoader;
17 import dwt.graphics.ImageLoaderEvent;
18
19 final class LZWCodec {
20 int bitsPerPixel, blockSize, blockIndex, currentByte, bitsLeft,
21 codeSize, clearCode, endCode, newCodes, topSlot, currentSlot,
22 imageWidth, imageHeight, imageX, imageY, pass, line, codeMask;
23 byte[] block, lineArray;
24 int[] stack, suffix, prefix;
25 LZWNode[] nodeStack;
26 LEDataInputStream inputStream;
27 LEDataOutputStream outputStream;
28 ImageData image;
29 ImageLoader loader;
30 bool interlaced;
31 static final int[] MASK_TABLE = new int[] {
32 0x1, 0x3, 0x7, 0xF, 0x1F, 0x3F, 0x7F,
33 0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF
34 };
35
36 /**
37 * Decode the input.
38 */
39 void decode() {
40 int code;
41 int oc = 0;
42 int fc = 0;
43 byte[] buf = new byte[imageWidth];
44 int stackIndex = 0;
45 int bufIndex = 0;
46 int c;
47 while ((c = nextCode()) !is endCode) {
48 if (c is clearCode) {
49 codeSize = bitsPerPixel + 1;
50 codeMask = MASK_TABLE[bitsPerPixel];
51 currentSlot = newCodes;
52 topSlot = 1 << codeSize;
53 while ((c = nextCode()) is clearCode) {}
54 if (c !is endCode) {
55 oc = fc = c;
56 buf[bufIndex] = (byte)c;
57 bufIndex++;
58 if (bufIndex is imageWidth) {
59 nextPutPixels(buf);
60 bufIndex = 0;
61 }
62 }
63 } else {
64 code = c;
65 if (code >= currentSlot) {
66 code = oc;
67 stack[stackIndex] = fc;
68 stackIndex++;
69 }
70 while (code >= newCodes) {
71 stack[stackIndex] = suffix[code];
72 stackIndex++;
73 code = prefix[code];
74 }
75 stack[stackIndex] = code;
76 stackIndex++;
77 if (currentSlot < topSlot) {
78 fc = code;
79 suffix[currentSlot] = fc;
80 prefix[currentSlot] = oc;
81 currentSlot++;
82 oc = c;
83 }
84 if (currentSlot >= topSlot) {
85 if (codeSize < 12) {
86 codeMask = MASK_TABLE[codeSize];
87 codeSize++;
88 topSlot = topSlot + topSlot;
89 }
90 }
91 while (stackIndex > 0) {
92 stackIndex--;
93 buf[bufIndex] = (byte)stack[stackIndex];
94 bufIndex++;
95 if (bufIndex is imageWidth) {
96 nextPutPixels(buf);
97 bufIndex = 0;
98 }
99 }
100 }
101 }
102 if (bufIndex !is 0 && line < imageHeight) {
103 nextPutPixels(buf);
104 }
105 }
106 /**
107 * Decode the LZW-encoded bytes in the given byte stream
108 * into the given DeviceIndependentImage.
109 */
110 public void decode(LEDataInputStream inputStream, ImageLoader loader, ImageData image, bool interlaced, int depth) {
111 this.inputStream = inputStream;
112 this.loader = loader;
113 this.image = image;
114 this.interlaced = interlaced;
115 this.bitsPerPixel = depth;
116 initializeForDecoding();
117 decode();
118 }
119 /**
120 * Encode the image.
121 */
122 void encode() {
123 nextPutCode(clearCode);
124 int lastPrefix = encodeLoop();
125 nextPutCode(lastPrefix);
126 nextPutCode(endCode);
127
128 // Write out last partial block
129 if (bitsLeft is 8) {
130 block[0] = (byte)(blockIndex - 1); // Nothing in last byte
131 } else {
132 block[0] = (byte)(blockIndex); // Last byte has data
133 }
134 writeBlock();
135
136 // Write out empty block to indicate the end (if needed)
137 if (block[0] !is 0) {
138 block[0] = 0;
139 writeBlock();
140 }
141 }
142 /**
143 * Encode the bytes into the given byte stream
144 * from the given DeviceIndependentImage.
145 */
146 public void encode(LEDataOutputStream byteStream, ImageData image) {
147 this.outputStream = byteStream;
148 this.image = image;
149 initializeForEncoding();
150 encode();
151 }
152 /**
153 * Encoding loop broken out to allow early return.
154 */
155 int encodeLoop() {
156 int pixel = nextPixel();
157 bool found;
158 LZWNode node;
159 while (true) {
160 int currentPrefix = pixel;
161 node = nodeStack[currentPrefix];
162 found = true;
163 pixel = nextPixel();
164 if (pixel < 0)
165 return currentPrefix;
166 while (found && (node.children !is null)) {
167 node = node.children;
168 while (found && (node.suffix !is pixel)) {
169 if (pixel < node.suffix) {
170 if (node.left is null) {
171 node.left = new LZWNode();
172 found = false;
173 }
174 node = node.left;
175 } else {
176 if (node.right is null) {
177 node.right = new LZWNode();
178 found = false;
179 }
180 node = node.right;
181 }
182 }
183 if (found) {
184 currentPrefix = node.code;
185 pixel = nextPixel();
186 if (pixel < 0)
187 return currentPrefix;
188 }
189 }
190 if (found) {
191 node.children = new LZWNode();
192 node = node.children;
193 }
194 node.children = null;
195 node.left = null;
196 node.right = null;
197 node.code = currentSlot;
198 node.prefix = currentPrefix;
199 node.suffix = pixel;
200 nextPutCode(currentPrefix);
201 currentSlot++;
202 // Off by one?
203 if (currentSlot < 4096) {
204 if (currentSlot > topSlot) {
205 codeSize++;
206 codeMask = MASK_TABLE[codeSize - 1];
207 topSlot *= 2;
208 }
209 } else {
210 nextPutCode(clearCode);
211 for (int i = 0; i < nodeStack.length; i++)
212 nodeStack[i].children = null;
213 codeSize = bitsPerPixel + 1;
214 codeMask = MASK_TABLE[codeSize - 1];
215 currentSlot = newCodes;
216 topSlot = 1 << codeSize;
217 }
218 }
219 }
220 /**
221 * Initialize the receiver for decoding the given
222 * byte array.
223 */
224 void initializeForDecoding() {
225 pass = 1;
226 line = 0;
227 codeSize = bitsPerPixel + 1;
228 topSlot = 1 << codeSize;
229 clearCode = 1 << bitsPerPixel;
230 endCode = clearCode + 1;
231 newCodes = currentSlot = endCode + 1;
232 currentByte = -1;
233 blockSize = bitsLeft = 0;
234 blockIndex = 0;
235 codeMask = MASK_TABLE[codeSize - 1];
236 stack = new int[4096];
237 suffix = new int[4096];
238 prefix = new int[4096];
239 block = new byte[256];
240 imageWidth = image.width;
241 imageHeight = image.height;
242 }
243 /**
244 * Initialize the receiver for encoding the given
245 * byte array.
246 */
247 void initializeForEncoding() {
248 interlaced = false;
249 bitsPerPixel = image.depth;
250 codeSize = bitsPerPixel + 1;
251 topSlot = 1 << codeSize;
252 clearCode = 1 << bitsPerPixel;
253 endCode = clearCode + 1;
254 newCodes = currentSlot = endCode + 1;
255 bitsLeft = 8;
256 currentByte = 0;
257 blockIndex = 1;
258 blockSize = 255;
259 block = new byte[blockSize];
260 block[0] = (byte)(blockSize - 1);
261 nodeStack = new LZWNode[1 << bitsPerPixel];
262 for (int i = 0; i < nodeStack.length; i++) {
263 LZWNode node = new LZWNode();
264 node.code = i + 1;
265 node.prefix = -1;
266 node.suffix = i + 1;
267 nodeStack[i] = node;
268 }
269 imageWidth = image.width;
270 imageHeight = image.height;
271 imageY = -1;
272 lineArray = new byte[imageWidth];
273 imageX = imageWidth + 1; // Force a read
274 }
275 /**
276 * Answer the next code from the input byte array.
277 */
278 int nextCode() {
279 int code;
280 if (bitsLeft is 0) {
281 if (blockIndex >= blockSize) {
282 blockSize = readBlock();
283 blockIndex = 0;
284 if (blockSize is 0) return endCode;
285 }
286 blockIndex++;
287 currentByte = block[blockIndex] & 0xFF;
288 bitsLeft = 8;
289 code = currentByte;
290 } else {
291 int shift = bitsLeft - 8;
292 if (shift < 0)
293 code = currentByte >> (0 - shift);
294 else
295 code = currentByte << shift;
296 }
297 while (codeSize > bitsLeft) {
298 if (blockIndex >= blockSize) {
299 blockSize = readBlock();
300 blockIndex = 0;
301 if (blockSize is 0) return endCode;
302 }
303 blockIndex++;
304 currentByte = block[blockIndex] & 0xFF;
305 code += currentByte << bitsLeft;
306 bitsLeft += 8;
307 }
308 bitsLeft -= codeSize;
309 return code & codeMask;
310 }
311 /**
312 * Answer the next pixel to encode in the image
313 */
314 int nextPixel() {
315 imageX++;
316 if (imageX > imageWidth) {
317 imageY++;
318 if (imageY >= imageHeight) {
319 return -1;
320 } else {
321 nextPixels(lineArray, imageWidth);
322 }
323 imageX = 1;
324 }
325 return this.lineArray[imageX - 1] & 0xFF;
326 }
327 /**
328 * Copy a row of pixel values from the image.
329 */
330 void nextPixels(byte[] buf, int lineWidth) {
331 if (image.depth is 8) {
332 System.arraycopy(image.data, imageY * image.bytesPerLine, buf, 0, lineWidth);
333 } else {
334 image.getPixels(0, imageY, lineWidth, buf, 0);
335 }
336 }
337 /**
338 * Output aCode to the output stream.
339 */
340 void nextPutCode(int aCode) {
341 int codeToDo = aCode;
342 int codeBitsToDo = codeSize;
343 // Fill in the remainder of the current byte with the
344 // *high-order* bits of the code.
345 int c = codeToDo & MASK_TABLE[bitsLeft - 1];
346 currentByte = currentByte | (c << (8 - bitsLeft));
347 block[blockIndex] = (byte)currentByte;
348 codeBitsToDo -= bitsLeft;
349 if (codeBitsToDo < 1) {
350 // The whole code fit in the first byte, so we are done.
351 bitsLeft -= codeSize;
352 if (bitsLeft is 0) {
353 // We used the whole last byte, so get ready
354 // for the next one.
355 bitsLeft = 8;
356 blockIndex++;
357 if (blockIndex >= blockSize) {
358 writeBlock();
359 blockIndex = 1;
360 }
361 currentByte = 0;
362 }
363 return;
364 }
365 codeToDo = codeToDo >> bitsLeft;
366
367 // Fill in any remaining whole bytes (i.e. not the last one!)
368 blockIndex++;
369 if (blockIndex >= blockSize) {
370 writeBlock();
371 blockIndex = 1;
372 }
373 while (codeBitsToDo >= 8) {
374 currentByte = codeToDo & 0xFF;
375 block[blockIndex] = (byte)currentByte;
376 codeToDo = codeToDo >> 8;
377 codeBitsToDo -= 8;
378 blockIndex++;
379 if (blockIndex >= blockSize) {
380 writeBlock();
381 blockIndex = 1;
382 }
383 }
384 // Fill the *low-order* bits of the last byte with the remainder
385 bitsLeft = 8 - codeBitsToDo;
386 currentByte = codeToDo;
387 block[blockIndex] = (byte)currentByte;
388 }
389 /**
390 * Copy a row of pixel values to the image.
391 */
392 void nextPutPixels(byte[] buf) {
393 if (image.depth is 8) {
394 // Slight optimization for depth = 8.
395 int start = line * image.bytesPerLine;
396 for (int i = 0; i < imageWidth; i++)
397 image.data[start + i] = buf[i];
398 } else {
399 image.setPixels(0, line, imageWidth, buf, 0);
400 }
401 if (interlaced) {
402 if (pass is 1) {
403 copyRow(buf, 7);
404 line += 8;
405 } else if (pass is 2) {
406 copyRow(buf, 3);
407 line += 8;
408 } else if (pass is 3) {
409 copyRow(buf, 1);
410 line += 4;
411 } else if (pass is 4) {
412 line += 2;
413 } else if (pass is 5) {
414 line += 0;
415 }
416 if (line >= imageHeight) {
417 pass++;
418 if (pass is 2) line = 4;
419 else if (pass is 3) line = 2;
420 else if (pass is 4) line = 1;
421 else if (pass is 5) line = 0;
422 if (pass < 5) {
423 if (loader.hasListeners()) {
424 ImageData imageCopy = (ImageData) image.clone();
425 loader.notifyListeners(
426 new ImageLoaderEvent(loader, imageCopy, pass - 2, false));
427 }
428 }
429 }
430 if (line >= imageHeight) line = 0;
431 } else {
432 line++;
433 }
434 }
435 /**
436 * Copy duplicate rows of pixel values to the image.
437 * This is to fill in rows if the image is interlaced.
438 */
439 void copyRow(byte[] buf, int copies) {
440 for (int i = 1; i <= copies; i++) {
441 if (line + i < imageHeight) {
442 image.setPixels(0, line + i, imageWidth, buf, 0);
443 }
444 }
445 }
446 /**
447 * Read a block from the byte stream.
448 * Return the number of bytes read.
449 * Throw an exception if the block could not be read.
450 */
451 int readBlock() {
452 int size = -1;
453 try {
454 size = inputStream.read();
455 if (size is -1) {
456 DWT.error(DWT.ERROR_INVALID_IMAGE);
457 }
458 block[0] = (byte)size;
459 size = inputStream.read(block, 1, size);
460 if (size is -1) {
461 DWT.error(DWT.ERROR_INVALID_IMAGE);
462 }
463 } catch (Exception e) {
464 DWT.error(DWT.ERROR_IO, e);
465 }
466 return size;
467 }
468 /**
469 * Write a block to the byte stream.
470 * Throw an exception if the block could not be written.
471 */
472 void writeBlock() {
473 try {
474 outputStream.write(block, 0, (block[0] & 0xFF) + 1);
475 } catch (Exception e) {
476 DWT.error(DWT.ERROR_IO, e);
477 }
478 }
479 }