GIF LZW decompression

GIF LZW decompression

本文关键字:decompression LZW GIF      更新时间:2023-10-16

我正在尝试用c++实现一个简单的Gif阅读器

我目前一直在解压缩Imagedata。如果图像包含清除代码,我的解压缩算法将失败

清除代码之后,我重建代码表,将代码大小重置为最小LzwCodeSize+1
然后我阅读下一个代码并将其添加到索引流中。问题是,清除后,下一个代码包含的值大于当前码表的大小
例如,来自wikipedia:rotating-earth.gif的示例文件的代码值为262,但GlobalColorTable仅为256

我该如何处理
我根据gif规范实现了lzw解压缩。

以下是解压缩的主要代码部分:

int prevCode = GetCode(ptr, offset, codeSize);
codeStream.push_back(prevCode);
while (true)
{
auto code = GetCode(ptr, offset, codeSize);
//
//Clear code
//
if (code == IndexClearCode)
{
    //reset codesize
    codeSize = blockA.LZWMinimumCodeSize + 1;
    currentNodeValue = pow(2, codeSize) - 1;
    //reset codeTable
    codeTable.resize(colorTable.size() + 2);
    //read next code
    prevCode = GetCode(ptr, offset, codeSize);
    codeStream.push_back(prevCode);
    continue;
}
else if (code == IndexEndOfInformationCode)
    break;

//exists in dictionary
if (codeTable.size() > code)
{
    if (prevCode >= codeTable.size())
    {
        prevCode = code;
        continue;
    }
    for (auto c : codeTable[code])
        codeStream.push_back(c);
    newEntry = codeTable[prevCode];
    newEntry.push_back(codeTable[code][0]);
    codeTable.push_back(newEntry);
    prevCode = code;
    if (codeTable.size() - 1 == currentNodeValue)
    {
        codeSize++;
        currentNodeValue = pow(2, codeSize) - 1;
    }
}
else
{
    if (prevCode >= codeTable.size())
    {
        prevCode = code;
        continue;
    }
    newEntry = codeTable[prevCode];
    newEntry.push_back(codeTable[prevCode][0]);
    for (auto c : newEntry)
        codeStream.push_back(c);
    codeTable.push_back(newEntry);
    prevCode = codeTable.size() - 1;
    if (codeTable.size() - 1 == currentNodeValue)
    {
        codeSize++;
        currentNodeValue = pow(2, codeSize) - 1;
    }
}
}

找到了解决方案。它被称为延迟清除代码
因此,当我检查codeSize是否需要增加时,我还需要检查codeSize是不是已经是最大值(12),因为可以获得最大代码大小的代码
参见规范gif89a.txt.

if (codeTable.size() - 1 == currentNodeValue && codeSize < 12)
{
   codeSize++;
   currentNodeValue = (1 << codeSize) - 1;
}