001: /*******************************************************************************
002: * Copyright (c) 2000, 2005 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.swt.internal.image;
011:
012: import org.eclipse.swt.*;
013: import org.eclipse.swt.graphics.*;
014:
015: final class LZWCodec {
016: int bitsPerPixel, blockSize, blockIndex, currentByte, bitsLeft,
017: codeSize, clearCode, endCode, newCodes, topSlot,
018: currentSlot, imageWidth, imageHeight, imageX, imageY, pass,
019: line, codeMask;
020: byte[] block, lineArray;
021: int[] stack, suffix, prefix;
022: LZWNode[] nodeStack;
023: LEDataInputStream inputStream;
024: LEDataOutputStream outputStream;
025: ImageData image;
026: ImageLoader loader;
027: boolean interlaced;
028: static final int[] MASK_TABLE = new int[] { 0x1, 0x3, 0x7, 0xF,
029: 0x1F, 0x3F, 0x7F, 0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF };
030:
031: /**
032: * Decode the input.
033: */
034: void decode() {
035: int code;
036: int oc = 0;
037: int fc = 0;
038: byte[] buf = new byte[imageWidth];
039: int stackIndex = 0;
040: int bufIndex = 0;
041: int c;
042: while ((c = nextCode()) != endCode) {
043: if (c == clearCode) {
044: codeSize = bitsPerPixel + 1;
045: codeMask = MASK_TABLE[bitsPerPixel];
046: currentSlot = newCodes;
047: topSlot = 1 << codeSize;
048: while ((c = nextCode()) == clearCode) {
049: }
050: if (c != endCode) {
051: oc = fc = c;
052: buf[bufIndex] = (byte) c;
053: bufIndex++;
054: if (bufIndex == imageWidth) {
055: nextPutPixels(buf);
056: bufIndex = 0;
057: }
058: }
059: } else {
060: code = c;
061: if (code >= currentSlot) {
062: code = oc;
063: stack[stackIndex] = fc;
064: stackIndex++;
065: }
066: while (code >= newCodes) {
067: stack[stackIndex] = suffix[code];
068: stackIndex++;
069: code = prefix[code];
070: }
071: stack[stackIndex] = code;
072: stackIndex++;
073: if (currentSlot < topSlot) {
074: fc = code;
075: suffix[currentSlot] = fc;
076: prefix[currentSlot] = oc;
077: currentSlot++;
078: oc = c;
079: }
080: if (currentSlot >= topSlot) {
081: if (codeSize < 12) {
082: codeMask = MASK_TABLE[codeSize];
083: codeSize++;
084: topSlot = topSlot + topSlot;
085: }
086: }
087: while (stackIndex > 0) {
088: stackIndex--;
089: buf[bufIndex] = (byte) stack[stackIndex];
090: bufIndex++;
091: if (bufIndex == imageWidth) {
092: nextPutPixels(buf);
093: bufIndex = 0;
094: }
095: }
096: }
097: }
098: if (bufIndex != 0 && line < imageHeight) {
099: nextPutPixels(buf);
100: }
101: }
102:
103: /**
104: * Decode the LZW-encoded bytes in the given byte stream
105: * into the given DeviceIndependentImage.
106: */
107: public void decode(LEDataInputStream inputStream,
108: ImageLoader loader, ImageData image, boolean interlaced,
109: int depth) {
110: this .inputStream = inputStream;
111: this .loader = loader;
112: this .image = image;
113: this .interlaced = interlaced;
114: this .bitsPerPixel = depth;
115: initializeForDecoding();
116: decode();
117: }
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 == 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] != 0) {
138: block[0] = 0;
139: writeBlock();
140: }
141: }
142:
143: /**
144: * Encode the bytes into the given byte stream
145: * from the given DeviceIndependentImage.
146: */
147: public void encode(LEDataOutputStream byteStream, ImageData image) {
148: this .outputStream = byteStream;
149: this .image = image;
150: initializeForEncoding();
151: encode();
152: }
153:
154: /**
155: * Encoding loop broken out to allow early return.
156: */
157: int encodeLoop() {
158: int pixel = nextPixel();
159: boolean found;
160: LZWNode node;
161: while (true) {
162: int currentPrefix = pixel;
163: node = nodeStack[currentPrefix];
164: found = true;
165: pixel = nextPixel();
166: if (pixel < 0)
167: return currentPrefix;
168: while (found && (node.children != null)) {
169: node = node.children;
170: while (found && (node.suffix != pixel)) {
171: if (pixel < node.suffix) {
172: if (node.left == null) {
173: node.left = new LZWNode();
174: found = false;
175: }
176: node = node.left;
177: } else {
178: if (node.right == null) {
179: node.right = new LZWNode();
180: found = false;
181: }
182: node = node.right;
183: }
184: }
185: if (found) {
186: currentPrefix = node.code;
187: pixel = nextPixel();
188: if (pixel < 0)
189: return currentPrefix;
190: }
191: }
192: if (found) {
193: node.children = new LZWNode();
194: node = node.children;
195: }
196: node.children = null;
197: node.left = null;
198: node.right = null;
199: node.code = currentSlot;
200: node.prefix = currentPrefix;
201: node.suffix = pixel;
202: nextPutCode(currentPrefix);
203: currentSlot++;
204: // Off by one?
205: if (currentSlot < 4096) {
206: if (currentSlot > topSlot) {
207: codeSize++;
208: codeMask = MASK_TABLE[codeSize - 1];
209: topSlot *= 2;
210: }
211: } else {
212: nextPutCode(clearCode);
213: for (int i = 0; i < nodeStack.length; i++)
214: nodeStack[i].children = null;
215: codeSize = bitsPerPixel + 1;
216: codeMask = MASK_TABLE[codeSize - 1];
217: currentSlot = newCodes;
218: topSlot = 1 << codeSize;
219: }
220: }
221: }
222:
223: /**
224: * Initialize the receiver for decoding the given
225: * byte array.
226: */
227: void initializeForDecoding() {
228: pass = 1;
229: line = 0;
230: codeSize = bitsPerPixel + 1;
231: topSlot = 1 << codeSize;
232: clearCode = 1 << bitsPerPixel;
233: endCode = clearCode + 1;
234: newCodes = currentSlot = endCode + 1;
235: currentByte = -1;
236: blockSize = bitsLeft = 0;
237: blockIndex = 0;
238: codeMask = MASK_TABLE[codeSize - 1];
239: stack = new int[4096];
240: suffix = new int[4096];
241: prefix = new int[4096];
242: block = new byte[256];
243: imageWidth = image.width;
244: imageHeight = image.height;
245: }
246:
247: /**
248: * Initialize the receiver for encoding the given
249: * byte array.
250: */
251: void initializeForEncoding() {
252: interlaced = false;
253: bitsPerPixel = image.depth;
254: codeSize = bitsPerPixel + 1;
255: topSlot = 1 << codeSize;
256: clearCode = 1 << bitsPerPixel;
257: endCode = clearCode + 1;
258: newCodes = currentSlot = endCode + 1;
259: bitsLeft = 8;
260: currentByte = 0;
261: blockIndex = 1;
262: blockSize = 255;
263: block = new byte[blockSize];
264: block[0] = (byte) (blockSize - 1);
265: nodeStack = new LZWNode[1 << bitsPerPixel];
266: for (int i = 0; i < nodeStack.length; i++) {
267: LZWNode node = new LZWNode();
268: node.code = i + 1;
269: node.prefix = -1;
270: node.suffix = i + 1;
271: nodeStack[i] = node;
272: }
273: imageWidth = image.width;
274: imageHeight = image.height;
275: imageY = -1;
276: lineArray = new byte[imageWidth];
277: imageX = imageWidth + 1; // Force a read
278: }
279:
280: /**
281: * Answer the next code from the input byte array.
282: */
283: int nextCode() {
284: int code;
285: if (bitsLeft == 0) {
286: if (blockIndex >= blockSize) {
287: blockSize = readBlock();
288: blockIndex = 0;
289: if (blockSize == 0)
290: return endCode;
291: }
292: blockIndex++;
293: currentByte = block[blockIndex] & 0xFF;
294: bitsLeft = 8;
295: code = currentByte;
296: } else {
297: int shift = bitsLeft - 8;
298: if (shift < 0)
299: code = currentByte >> (0 - shift);
300: else
301: code = currentByte << shift;
302: }
303: while (codeSize > bitsLeft) {
304: if (blockIndex >= blockSize) {
305: blockSize = readBlock();
306: blockIndex = 0;
307: if (blockSize == 0)
308: return endCode;
309: }
310: blockIndex++;
311: currentByte = block[blockIndex] & 0xFF;
312: code += currentByte << bitsLeft;
313: bitsLeft += 8;
314: }
315: bitsLeft -= codeSize;
316: return code & codeMask;
317: }
318:
319: /**
320: * Answer the next pixel to encode in the image
321: */
322: int nextPixel() {
323: imageX++;
324: if (imageX > imageWidth) {
325: imageY++;
326: if (imageY >= imageHeight) {
327: return -1;
328: } else {
329: nextPixels(lineArray, imageWidth);
330: }
331: imageX = 1;
332: }
333: return this .lineArray[imageX - 1] & 0xFF;
334: }
335:
336: /**
337: * Copy a row of pixel values from the image.
338: */
339: void nextPixels(byte[] buf, int lineWidth) {
340: if (image.depth == 8) {
341: System.arraycopy(image.data, imageY * image.bytesPerLine,
342: buf, 0, lineWidth);
343: } else {
344: image.getPixels(0, imageY, lineWidth, buf, 0);
345: }
346: }
347:
348: /**
349: * Output aCode to the output stream.
350: */
351: void nextPutCode(int aCode) {
352: int codeToDo = aCode;
353: int codeBitsToDo = codeSize;
354: // Fill in the remainder of the current byte with the
355: // *high-order* bits of the code.
356: int c = codeToDo & MASK_TABLE[bitsLeft - 1];
357: currentByte = currentByte | (c << (8 - bitsLeft));
358: block[blockIndex] = (byte) currentByte;
359: codeBitsToDo -= bitsLeft;
360: if (codeBitsToDo < 1) {
361: // The whole code fit in the first byte, so we are done.
362: bitsLeft -= codeSize;
363: if (bitsLeft == 0) {
364: // We used the whole last byte, so get ready
365: // for the next one.
366: bitsLeft = 8;
367: blockIndex++;
368: if (blockIndex >= blockSize) {
369: writeBlock();
370: blockIndex = 1;
371: }
372: currentByte = 0;
373: }
374: return;
375: }
376: codeToDo = codeToDo >> bitsLeft;
377:
378: // Fill in any remaining whole bytes (i.e. not the last one!)
379: blockIndex++;
380: if (blockIndex >= blockSize) {
381: writeBlock();
382: blockIndex = 1;
383: }
384: while (codeBitsToDo >= 8) {
385: currentByte = codeToDo & 0xFF;
386: block[blockIndex] = (byte) currentByte;
387: codeToDo = codeToDo >> 8;
388: codeBitsToDo -= 8;
389: blockIndex++;
390: if (blockIndex >= blockSize) {
391: writeBlock();
392: blockIndex = 1;
393: }
394: }
395: // Fill the *low-order* bits of the last byte with the remainder
396: bitsLeft = 8 - codeBitsToDo;
397: currentByte = codeToDo;
398: block[blockIndex] = (byte) currentByte;
399: }
400:
401: /**
402: * Copy a row of pixel values to the image.
403: */
404: void nextPutPixels(byte[] buf) {
405: if (image.depth == 8) {
406: // Slight optimization for depth = 8.
407: int start = line * image.bytesPerLine;
408: for (int i = 0; i < imageWidth; i++)
409: image.data[start + i] = buf[i];
410: } else {
411: image.setPixels(0, line, imageWidth, buf, 0);
412: }
413: if (interlaced) {
414: if (pass == 1) {
415: copyRow(buf, 7);
416: line += 8;
417: } else if (pass == 2) {
418: copyRow(buf, 3);
419: line += 8;
420: } else if (pass == 3) {
421: copyRow(buf, 1);
422: line += 4;
423: } else if (pass == 4) {
424: line += 2;
425: } else if (pass == 5) {
426: line += 0;
427: }
428: if (line >= imageHeight) {
429: pass++;
430: if (pass == 2)
431: line = 4;
432: else if (pass == 3)
433: line = 2;
434: else if (pass == 4)
435: line = 1;
436: else if (pass == 5)
437: line = 0;
438: if (pass < 5) {
439: if (loader.hasListeners()) {
440: ImageData imageCopy = (ImageData) image.clone();
441: loader.notifyListeners(new ImageLoaderEvent(
442: loader, imageCopy, pass - 2, false));
443: }
444: }
445: }
446: if (line >= imageHeight)
447: line = 0;
448: } else {
449: line++;
450: }
451: }
452:
453: /**
454: * Copy duplicate rows of pixel values to the image.
455: * This is to fill in rows if the image is interlaced.
456: */
457: void copyRow(byte[] buf, int copies) {
458: for (int i = 1; i <= copies; i++) {
459: if (line + i < imageHeight) {
460: image.setPixels(0, line + i, imageWidth, buf, 0);
461: }
462: }
463: }
464:
465: /**
466: * Read a block from the byte stream.
467: * Return the number of bytes read.
468: * Throw an exception if the block could not be read.
469: */
470: int readBlock() {
471: int size = -1;
472: try {
473: size = inputStream.read();
474: if (size == -1) {
475: SWT.error(SWT.ERROR_INVALID_IMAGE);
476: }
477: block[0] = (byte) size;
478: size = inputStream.read(block, 1, size);
479: if (size == -1) {
480: SWT.error(SWT.ERROR_INVALID_IMAGE);
481: }
482: } catch (Exception e) {
483: SWT.error(SWT.ERROR_IO, e);
484: }
485: return size;
486: }
487:
488: /**
489: * Write a block to the byte stream.
490: * Throw an exception if the block could not be written.
491: */
492: void writeBlock() {
493: try {
494: outputStream.write(block, 0, (block[0] & 0xFF) + 1);
495: } catch (Exception e) {
496: SWT.error(SWT.ERROR_IO, e);
497: }
498: }
499: }
|