GIF LZW减压

时间:2014-11-12 19:18:24

标签: c++ decode gif compression

我正在尝试用c ++实现一个简单的Gif-Reader。

我目前坚持解压缩Imagedata。 如果图像包含清除代码,则我的解压缩算法失败
清除代码之后,我重建了 CodeTable ,将 CodeSize 重置为 MinimumLzwCodeSize + 1。 然后我阅读下一个代码并将其添加到indexstream。问题是清除后,下一个代码包含的值大于当前代码表的大小。
例如,来自维基百科的示例文件:rotating-earth.gif的代码值为262,但GlobalColorTable仅为256.

如何处理?
我根据gif spec.实现了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;
    }
}
}

1 个答案:

答案 0 :(得分:4)

找到解决方案。 它被称为延迟明确代码
因此,当我检查codeSize是否需要递增时,我还需要检查codeSize是否已经是max(12),因为可以获得具有最大代码大小的代码。
请参阅spec-gif89a.txt

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