我尝试使用this作为参考解压缩LZW压缩GIF。
虽然我认为我理解了基础逻辑,但我在阅读" codeStream"正确。据我了解," ImageData"的第一个byte
block存储用于" pack"的bits
的数量。以下代码,不包括两个特殊的(clearCode& EOI)。所以我使用的实际值是第一个byte
+ 1 的值(让我们调用此值 bitsPerCode )。
如果其值等于(2 ^ bitsPerCode-1),我检查每个代码后检查,如果是,则意味着我们达到了 bitsPerCode bits
,所以我将 bitsPerCode 递增1.
我还会在每次阅读后将 bitsPerCode 重置为原始值(第一个byte
+ 1的值<)> clearCode 。
&#34; codeStream&#34;据推测,它被划分为子块,其中每个子块的第一个byte
表示将跟随多少bytes
个数据,以及何时读取值为0的byte
我们已经到了&#34; ImageData&#34;的末尾。如果当前代码没有被完全读取,我不确定每个子块之间应该做什么。我应该按原样使用它吗?我应该丢弃它吗?我应该继续阅读,好像什么也没发生过?或者我应该重置 bitsPerCode ?我的代码没有做到它应该做的事情也是一个很好的可能性。
以下代码尝试仅读取代码,而不是按方法名称建议解压缩它们:
private List<Integer> decompressCodeStream(InputStream is) throws IOException {
ArrayList<Integer> result = new ArrayList<Integer>();
// "is" assumed to be at the start of ImageData stream
int lzwMinCodeSize = is.read(); // 8
int bitsToRead = lzwMinCodeSize + 1; // 9 to account for the 2 extra codes
int clearCode = (int) Math.pow(2, lzwMinCodeSize); // 256
int eoi = clearCode + 1; // 257
int bitsRead = 0;
int currCode = 0;
byte bitMask = 0b00000001;
int blockSize;
while ((blockSize = is.read()) != 0) { // ImageData stream is assumed to be in data blocks
for (int i = 0; i < blockSize; i++) {
byte b = (byte) is.read();
for (int j = 0; j < 8; j++) {
currCode = currCode | (((b >> j) & bitMask) << bitsRead);
bitsRead++;
if (bitsRead == bitsToRead) {
result.add(currCode);
bitsRead = 0;
if (currCode == Math.pow(2, bitsToRead) - 1) {
bitsToRead++;
}
if (currCode == clearCode) {
bitsToRead = lzwMinCodeSize + 1;
}
currCode = 0;
}
}
}
}
assert result.get(0) == clearCode; // passes
assert result.get(result.size() - 1) == eoi; // fails
return result;
}
根据guide,代码必须以 EOI(本例中为257)代码结尾。但事实并非如此。
我是否正确阅读了这些代码?
修改
我将代码中的阅读方法更改为:
private List<Integer> readCodeStream(InputStream is, int minCodeSize, int clearCode) throws IOException {
ArrayList<Integer> result = new ArrayList<Integer>();
// "is" assumed to be at the start of ImageData stream
int bitsToRead = minCodeSize + 1; // 9 to account for the 2 extra codes
int blockSize;
while ((blockSize = is.read()) != 0) { // ImageData stream is assumed to be in data blocks
BitStream bs = new BitStream(is, blockSize);
while (bs.readLimit() > 0) {
int currCode = bs.getBitsAsInt(bitsToRead);
result.add(currCode);
if (currCode == clearCode) {
bitsToRead = minCodeSize + 1;
} else if (currCode == Math.pow(2, bitsToRead) - 1) {
bitsToRead++;
}
}
}
return result;
}
BitStream
班级:
public class BitStream {
private static final byte BIT_MASK = 0x01;
private static final int MAX_BITS = 8;
private InputStream is;
private int readLimit;
private int leftOver;
private byte currByte;
private int bytesRead;
public BitStream(InputStream is, int readLimitBytes) {
this.is = is;
this.readLimit = readLimitBytes;
this.leftOver = 0;
this.bytesRead = 0;
}
public int getBitsAsInt(int bitsToRead) throws IOException {
int bitsRead = 0;
int result = 0;
for (; bitsToRead > 0; bitsToRead--) {
if (leftOver == 0) {
if (readLimit < 1)
return result;
currByte = (byte) is.read();
bytesRead++;
readLimit--;
leftOver = MAX_BITS;
}
result = result | (((currByte >> (MAX_BITS - leftOver)) & BIT_MASK) << (bitsRead));
bitsRead++;
leftOver--;
}
return result;
}
public int readLimit() {
return readLimit;
}
public int leftOver() {
return leftOver;
}
public int bytesRead() {
return bytesRead;
}
}
接缝codeStream现在是否正确。
有人可以确认这是正确的吗?