我正在尝试用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;
}