Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/LZWCodec.java')
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/LZWCodec.java479
1 files changed, 479 insertions, 0 deletions
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/LZWCodec.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/LZWCodec.java
new file mode 100755
index 0000000000..fcf71f81a9
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/LZWCodec.java
@@ -0,0 +1,479 @@
+package org.eclipse.swt.internal.image;
+
+/*
+ * Licensed Materials - Property of IBM,
+ * WebSphere Studio Workbench
+ * (c) Copyright IBM Corp 2000
+ */
+
+/* Imports */
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+
+/* Class Definition */
+final class LZWCodec {
+ int bitsPerPixel, blockSize, blockIndex, currentByte, bitsLeft,
+ codeSize, clearCode, endCode, newCodes, topSlot, currentSlot,
+ imageWidth, imageHeight, imageX, imageY, pass, line, codeMask, buffer;
+ byte[] block, lineArray;
+ int[] maskTable, stack, suffix, prefix;
+ LZWNode[] nodeStack;
+ LEDataInputStream inputStream;
+ LEDataOutputStream outputStream;
+ ImageData image;
+ ImageLoader loader;
+ boolean interlaced;
+/**
+ * Decode the input.
+ */
+void decode() {
+ int code;
+ int oc = 0;
+ int fc = 0;
+ byte[] buf = new byte[imageWidth];
+ int stackIndex = 0;
+ int bufIndex = 0;
+ int c;
+ while ((c = nextCode()) != endCode) {
+ if (c == clearCode) {
+ codeSize = bitsPerPixel + 1;
+ codeMask = maskTable[bitsPerPixel];
+ currentSlot = newCodes;
+ topSlot = 1 << codeSize;
+ while ((c = nextCode()) == clearCode) {};
+ if (c != endCode) {
+ oc = fc = c;
+ buf[bufIndex] = (byte)c;
+ bufIndex++;
+ if (bufIndex == imageWidth) {
+ nextPutPixels(buf);
+ bufIndex = 0;
+ }
+ }
+ } else {
+ code = c;
+ if (code >= currentSlot) {
+ if (code > currentSlot)
+ SWT.error(SWT.ERROR_INVALID_IMAGE);
+ code = oc;
+ stack[stackIndex] = fc;
+ stackIndex++;
+ }
+ while (code >= newCodes) {
+ stack[stackIndex] = suffix[code];
+ stackIndex++;
+ code = prefix[code];
+ }
+ stack[stackIndex] = code;
+ stackIndex++;
+ if (currentSlot < topSlot) {
+ fc = code;
+ suffix[currentSlot] = fc;
+ prefix[currentSlot] = oc;
+ currentSlot++;
+ oc = c;
+ }
+ if (currentSlot >= topSlot) {
+ if (codeSize < 12) {
+ codeMask = maskTable[codeSize];
+ codeSize++;
+ topSlot = topSlot + topSlot;
+ }
+ }
+ while (stackIndex > 0) {
+ stackIndex--;
+ buf[bufIndex] = (byte)stack[stackIndex];
+ bufIndex++;
+ if (bufIndex == imageWidth) {
+ nextPutPixels(buf);
+ bufIndex = 0;
+ }
+ }
+ }
+ }
+ if (bufIndex != 0 && line < imageHeight) {
+ nextPutPixels(buf);
+ }
+}
+/**
+ * Decode the LZW-encoded bytes in the given byte stream
+ * into the given DeviceIndependentImage.
+ */
+public void decode(LEDataInputStream inputStream, ImageLoader loader, ImageData image, boolean interlaced, int depth) {
+ this.inputStream = inputStream;
+ this.loader = loader;
+ this.image = image;
+ this.interlaced = interlaced;
+ this.bitsPerPixel = depth;
+ initializeForDecoding();
+ decode();
+}
+/**
+ * Encode the image.
+ */
+void encode() {
+ nextPutCode(clearCode);
+ int lastPrefix = encodeLoop();
+ nextPutCode(lastPrefix);
+ nextPutCode(endCode);
+
+ // Write out last partial block
+ if (bitsLeft == 8) {
+ block[0] = (byte)(blockIndex - 1); // Nothing in last byte
+ } else {
+ block[0] = (byte)(blockIndex); // Last byte has data
+ }
+ writeBlock();
+
+ // Write out empty block to indicate the end (if needed)
+ if (block[0] != 0) {
+ block[0] = 0;
+ writeBlock();
+ }
+}
+/**
+ * Encode the bytes into the given byte stream
+ * from the given DeviceIndependentImage.
+ */
+public void encode(LEDataOutputStream byteStream, ImageData image) {
+ this.outputStream = byteStream;
+ this.image = image;
+ initializeForEncoding();
+ encode();
+}
+/**
+ * Encoding loop broken out to allow early return.
+ */
+int encodeLoop() {
+ int pixel = nextPixel();
+ boolean found;
+ LZWNode node;
+ while (true) {
+ int currentPrefix = pixel;
+ node = nodeStack[currentPrefix];
+ found = true;
+ pixel = nextPixel();
+ if (pixel < 0)
+ return currentPrefix;
+ while (found && (node.children != null)) {
+ node = node.children;
+ while (found && (node.suffix != pixel)) {
+ if (pixel < node.suffix) {
+ if (node.left == null) {
+ node.left = new LZWNode();
+ found = false;
+ }
+ node = node.left;
+ } else {
+ if (node.right == null) {
+ node.right = new LZWNode();
+ found = false;
+ }
+ node = node.right;
+ }
+ }
+ if (found) {
+ currentPrefix = node.code;
+ pixel = nextPixel();
+ if (pixel < 0)
+ return currentPrefix;
+ }
+ }
+ if (found) {
+ node.children = new LZWNode();
+ node = node.children;
+ }
+ node.children = null;
+ node.left = null;
+ node.right = null;
+ node.code = currentSlot;
+ node.prefix = currentPrefix;
+ node.suffix = pixel;
+ nextPutCode(currentPrefix);
+ currentSlot++;
+ // Off by one?
+ if (currentSlot < 4096) {
+ if (currentSlot > topSlot) {
+ codeSize++;
+ codeMask = maskTable[codeSize - 1];
+ topSlot *= 2;
+ }
+ } else {
+ nextPutCode(clearCode);
+ for (int i = 0; i < nodeStack.length; i++)
+ nodeStack[i].children = null;
+ codeSize = bitsPerPixel + 1;
+ codeMask = maskTable[codeSize - 1];
+ currentSlot = newCodes;
+ topSlot = 1 << codeSize;
+ }
+ }
+}
+/**
+ * Initialize the receiver for decoding the given
+ * byte array.
+ */
+void initializeForDecoding() {
+ pass = 1;
+ line = 0;
+ codeSize = bitsPerPixel + 1;
+ topSlot = 1 << codeSize;
+ clearCode = 1 << bitsPerPixel;
+ endCode = clearCode + 1;
+ newCodes = currentSlot = endCode + 1;
+ currentByte = -1;
+ blockSize = bitsLeft = 0;
+ blockIndex = 0;
+ maskTable = new int[] {
+ 0x1, 0x3, 0x7, 0xF, 0x1F, 0x3F, 0x7F,
+ 0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF
+ };
+ codeMask = maskTable[codeSize - 1];
+ stack = new int[4096];
+ suffix = new int[4096];
+ prefix = new int[4096];
+ block = new byte[256];
+ imageWidth = image.width;
+ imageHeight = image.height;
+}
+/**
+ * Initialize the receiver for encoding the given
+ * byte array.
+ */
+void initializeForEncoding() {
+ interlaced = false;
+ bitsPerPixel = image.depth;
+ codeSize = bitsPerPixel + 1;
+ topSlot = 1 << codeSize;
+ clearCode = 1 << bitsPerPixel;
+ endCode = clearCode + 1;
+ newCodes = currentSlot = endCode + 1;
+ bitsLeft = 8;
+ currentByte = 0;
+ blockIndex = 1;
+ blockSize = 255;
+ block = new byte[blockSize];
+ block[0] = (byte)(blockSize - 1);
+ maskTable = new int[] {
+ 0x1, 0x3, 0x7, 0xF, 0x1F, 0x3F, 0x7F,
+ 0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF
+ };
+ nodeStack = new LZWNode[1 << bitsPerPixel];
+ for (int i = 0; i < nodeStack.length; i++) {
+ LZWNode node = new LZWNode();
+ node.code = i + 1;
+ node.prefix = -1;
+ node.suffix = i + 1;
+ nodeStack[i] = node;
+ }
+ imageWidth = image.width;
+ imageHeight = image.height;
+ imageY = -1;
+ lineArray = new byte[imageWidth];
+ imageX = imageWidth + 1; // Force a read
+}
+/**
+ * Answer the next code from the input byte array.
+ */
+int nextCode() {
+ int code;
+ if (bitsLeft == 0) {
+ if (blockIndex >= blockSize) {
+ blockSize = readBlock();
+ blockIndex = 0;
+ if (blockSize == 0) return endCode;
+ }
+ blockIndex++;
+ currentByte = block[blockIndex] & 0xFF;
+ bitsLeft = 8;
+ code = currentByte;
+ } else {
+ int shift = bitsLeft - 8;
+ if (shift < 0)
+ code = currentByte >> (0 - shift);
+ else
+ code = currentByte << shift;
+ }
+ while (codeSize > bitsLeft) {
+ if (blockIndex >= blockSize) {
+ blockSize = readBlock();
+ blockIndex = 0;
+ if (blockSize == 0) return endCode;
+ }
+ blockIndex++;
+ currentByte = block[blockIndex] & 0xFF;
+ code += currentByte << bitsLeft;
+ bitsLeft += 8;
+ }
+ bitsLeft -= codeSize;
+ return code & codeMask;
+}
+/**
+ * Answer the next pixel to encode in the image
+ */
+int nextPixel() {
+ imageX++;
+ if (imageX > imageWidth) {
+ imageY++;
+ if (imageY >= imageHeight) {
+ return -1;
+ } else {
+ nextPixels(lineArray, imageWidth);
+ }
+ imageX = 1;
+ }
+ return this.lineArray[imageX - 1] & 0xFF;
+}
+/**
+ * Copy a row of pixel values from the image.
+ */
+void nextPixels(byte[] buf, int lineWidth) {
+ if (image.depth == 8) {
+ System.arraycopy(image.data, imageY * image.bytesPerLine, buf, 0, lineWidth);
+ } else {
+ image.getPixels(0, imageY, lineWidth, buf, 0);
+ }
+}
+/**
+ * Output aCode to the output stream.
+ */
+void nextPutCode(int aCode) {
+ int codeToDo = aCode;
+ int codeBitsToDo = codeSize;
+ // Fill in the remainder of the current byte with the
+ // *high-order* bits of the code.
+ int c = codeToDo & maskTable[bitsLeft - 1];
+ currentByte = currentByte | (c << (8 - bitsLeft));
+ block[blockIndex] = (byte)currentByte;
+ codeBitsToDo -= bitsLeft;
+ if (codeBitsToDo < 1) {
+ // The whole code fit in the first byte, so we are done.
+ bitsLeft -= codeSize;
+ if (bitsLeft == 0) {
+ // We used the whole last byte, so get ready
+ // for the next one.
+ bitsLeft = 8;
+ blockIndex++;
+ if (blockIndex >= blockSize) {
+ writeBlock();
+ blockIndex = 1;
+ }
+ currentByte = 0;
+ }
+ return;
+ }
+ codeToDo = codeToDo >> bitsLeft;
+
+ // Fill in any remaining whole bytes (i.e. not the last one!)
+ blockIndex++;
+ if (blockIndex >= blockSize) {
+ writeBlock();
+ blockIndex = 1;
+ }
+ while (codeBitsToDo >= 8) {
+ currentByte = codeToDo & 0xFF;
+ block[blockIndex] = (byte)currentByte;
+ codeToDo = codeToDo >> 8;
+ codeBitsToDo -= 8;
+ blockIndex++;
+ if (blockIndex >= blockSize) {
+ writeBlock();
+ blockIndex = 1;
+ }
+ }
+ // Fill the *low-order* bits of the last byte with the remainder
+ bitsLeft = 8 - codeBitsToDo;
+ currentByte = codeToDo;
+ block[blockIndex] = (byte)currentByte;
+}
+/**
+ * Copy a row of pixel values to the image.
+ */
+void nextPutPixels(byte[] buf) {
+ if (image.depth == 8) {
+ // Slight optimization for depth = 8.
+ int start = line * image.bytesPerLine;
+ for (int i = 0; i < imageWidth; i++)
+ image.data[start + i] = buf[i];
+ } else {
+ image.setPixels(0, line, imageWidth, buf, 0);
+ }
+ if (interlaced) {
+ if (pass == 1) {
+ copyRow(buf, 7);
+ line += 8;
+ } else if (pass == 2) {
+ copyRow(buf, 3);
+ line += 8;
+ } else if (pass == 3) {
+ copyRow(buf, 1);
+ line += 4;
+ } else if (pass == 4) {
+ line += 2;
+ } else if (pass == 5) {
+ line += 0;
+ }
+ if (line >= imageHeight) {
+ pass++;
+ if (pass == 2) line = 4;
+ else if (pass == 3) line = 2;
+ else if (pass == 4) line = 1;
+ else if (pass == 5) line = 0;
+ if (pass < 5) {
+ if (loader.hasListeners()) {
+ ImageData imageCopy = (ImageData) image.clone();
+ loader.notifyListeners(
+ new ImageLoaderEvent(loader, imageCopy, pass - 2, false));
+ }
+ }
+ }
+ if (line >= imageHeight) line = 0;
+ } else {
+ line++;
+ }
+}
+/**
+ * Copy duplicate rows of pixel values to the image.
+ * This is to fill in rows if the image is interlaced.
+ */
+void copyRow(byte[] buf, int copies) {
+ for (int i = 1; i <= copies; i++) {
+ if (line + i < imageHeight) {
+ image.setPixels(0, line + i, imageWidth, buf, 0);
+ }
+ }
+}
+/**
+ * Read a block from the byte stream.
+ * Return the number of bytes read.
+ * Throw an exception if the block could not be read.
+ */
+int readBlock() {
+ int size = -1;
+ try {
+ size = inputStream.read();
+ if (size == -1) {
+ SWT.error(SWT.ERROR_INVALID_IMAGE);
+ }
+ block[0] = (byte)size;
+ size = inputStream.read(block, 1, size);
+ if (size == -1) {
+ SWT.error(SWT.ERROR_INVALID_IMAGE);
+ }
+ } catch (Exception e) {
+ SWT.error(SWT.ERROR_IO, e);
+ }
+ return size;
+}
+/**
+ * Write a block to the byte stream.
+ * Throw an exception if the block could not be written.
+ */
+void writeBlock() {
+ try {
+ outputStream.write(block, 0, (block[0] & 0xFF) + 1);
+ } catch (Exception e) {
+ SWT.error(SWT.ERROR_IO, e);
+ }
+}
+}

Back to the top