org.eclipse.swt.internal.image.LZWCodec Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of org.eclipse.swt.macosx.x86_64 Show documentation
Show all versions of org.eclipse.swt.macosx.x86_64 Show documentation
The osx x86_64 swt jar as available in the Eclipse 4.6 (Neon) release for OSX. It is suitable for use with jface and other dependencies available from maven central in the org.eclipse.scout.sdk.deps group. The sources is copied from swt-4.6-cocoa-macosx-x86_64.zip from http://download.eclipse.org/eclipse/downloads/drops4/R-4.6-201606061100/ and javadoc is generated from sources.
The newest version!
/*******************************************************************************
* Copyright (c) 2000, 2011 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.swt.internal.image;
import org.eclipse.swt.*;
import org.eclipse.swt.graphics.*;
final class LZWCodec {
int bitsPerPixel, blockSize, blockIndex, currentByte, bitsLeft,
codeSize, clearCode, endCode, newCodes, topSlot, currentSlot,
imageWidth, imageHeight, imageX, imageY, pass, line, codeMask;
byte[] block, lineArray;
int[] stack, suffix, prefix;
LZWNode[] nodeStack;
LEDataInputStream inputStream;
LEDataOutputStream outputStream;
ImageData image;
ImageLoader loader;
boolean interlaced;
static final int[] MASK_TABLE = new int[] {
0x1, 0x3, 0x7, 0xF, 0x1F, 0x3F, 0x7F,
0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF
};
/**
* 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 = MASK_TABLE[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) {
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 = MASK_TABLE[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 = MASK_TABLE[codeSize - 1];
topSlot *= 2;
}
} else {
nextPutCode(clearCode);
for (int i = 0; i < nodeStack.length; i++)
nodeStack[i].children = null;
codeSize = bitsPerPixel + 1;
codeMask = MASK_TABLE[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;
codeMask = MASK_TABLE[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);
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 & MASK_TABLE[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);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy