Java LZW GIF解压缩

时间:2015-03-01 15:13:42

标签: java logic gif compression

我尝试使用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现在是否正确。

有人可以确认这是正确的吗?

0 个答案:

没有答案