convert
创建的文件还是有些奇怪,它会生成字典中还没有的LZW代码,并且我不知道如何处理。
大多数时候,LZW流中尚未包含在字典中的9到12位代码是我的解码算法将尝试将其放入字典中的下一个代码(我不确定应该是这是一个问题,尽管我的算法在包含此类情况的图像上失败了),但有时甚至可能是未来的数百个代码。在一种情况下,清除代码(256)之后的第一个代码是364,考虑到清除代码清除了我所有258以上代码的字典,这似乎是不可能的;在另一种情况下,当我的字典仅增加到317时,代码是501 !
我不知道如何处理它,但似乎我是唯一遇到此问题的人,其他程序中的解码器可以很好地加载此类图像。那他们怎么做呢?
这是我解码算法的核心,显然,由于涉及大量代码,因此我无法以紧凑的方式提供完整的可编译代码,但是由于这是算法逻辑问题,因此就足够了。它严格遵循官方TIFF specification(第61页)中描述的算法,实际上,大多数规范的伪代码都在注释中。
void tiff_lzw_decode(uint8_t *coded, buffer_t *dec)
{
buffer_t word={0}, outstring={0};
size_t coded_pos; // position in bits
int i, new_index, code, maxcode, bpc;
buffer_t *dict={0};
size_t dict_as=0;
bpc = 9; // starts with 9 bits per code, increases later
tiff_lzw_calc_maxcode(bpc, &maxcode);
new_index = 258; // index at which new dict entries begin
coded_pos = 0; // bit position
lzw_dict_init(&dict, &dict_as);
while ((code = get_bits_in_stream(coded, coded_pos, bpc)) != 257) // while ((Code = GetNextCode()) != EoiCode)
{
coded_pos += bpc;
if (code >= new_index)
printf("Out of range code %d (new_index %d)\n", code, new_index);
if (code == 256) // if (Code == ClearCode)
{
lzw_dict_init(&dict, &dict_as); // InitializeTable();
bpc = 9;
tiff_lzw_calc_maxcode(bpc, &maxcode);
new_index = 258;
code = get_bits_in_stream(coded, coded_pos, bpc); // Code = GetNextCode();
coded_pos += bpc;
if (code == 257) // if (Code == EoiCode)
break;
append_buf(dec, &dict[code]); // WriteString(StringFromCode(Code));
clear_buf(&word);
append_buf(&word, &dict[code]); // OldCode = Code;
}
else if (code < 4096)
{
if (dict[code].len) // if (IsInTable(Code))
{
append_buf(dec, &dict[code]); // WriteString(StringFromCode(Code));
lzw_add_to_dict(&dict, &dict_as, new_index, 0, word.buf, word.len, &bpc);
lzw_add_to_dict(&dict, &dict_as, new_index, 1, dict[code].buf, 1, &bpc); // AddStringToTable
new_index++;
tiff_lzw_calc_bpc(new_index, &bpc, &maxcode);
clear_buf(&word);
append_buf(&word, &dict[code]); // OldCode = Code;
}
else
{
clear_buf(&outstring);
append_buf(&outstring, &word);
bufwrite(&outstring, word.buf, 1); // OutString = StringFromCode(OldCode) + FirstChar(StringFromCode(OldCode));
append_buf(dec, &outstring); // WriteString(OutString);
lzw_add_to_dict(&dict, &dict_as, new_index, 0, outstring.buf, outstring.len, &bpc); // AddStringToTable
new_index++;
tiff_lzw_calc_bpc(new_index, &bpc, &maxcode);
clear_buf(&word);
append_buf(&word, &dict[code]); // OldCode = Code;
}
}
}
free_buf(&word);
free_buf(&outstring);
for (i=0; i < dict_as; i++)
free_buf(&dict[i]);
free(dict);
}
对于我的代码在这种情况下产生的结果,从外观上可以很清楚地看出,只有很少的代码被错误地解码,前后的所有内容都被正确解码了,但显然在大多数情况下,后续的图像是由于将解码后的字节的其余部分移动了几个位置,这些神秘的未来代码中的一部分被破坏了。这意味着我对9到12位代码流的读取是正确的,所以这实际上意味着我在256个清除字典的代码之后立即看到364个代码。
编辑:Here's an example file,其中包含此类奇怪的代码。我还发现了一个small TIFF LZW loading library,它也遇到同样的问题,it crashes,在这里我的加载程序在该图像中找到第一个奇怪的代码(当字典最多到2051时为代码3073)。好处是,由于它是一个小型库,因此您可以使用以下代码对其进行测试:
#include "loadtiff.h"
#include "loadtiff.c"
void loadtiff_test(char *path)
{
int width, height, format;
floadtiff(fopen(path, "rb"), &width, &height, &format);
}
如果有人坚持要深入研究我的代码(这是不必要的,这是一个很大的库)here's where to start。
答案 0 :(得分:1)
伪造的代码来自试图解码超出我们预期的范围。问题在于,LZW条带有时可能不会以信息结尾257代码结尾,因此当输出一定数量的已解码字节时,解码循环必须停止。每条带的字节数由TIFF标签ROWSPERSTRIP * IMAGEWIDTH * BITSPERSAMPLE / 8决定,如果PLANARCONFIG为1(表示与平面相反的交错通道),则将其全部乘以SAMPLESPERPIXEL。因此,除了在遇到代码257时停止解码循环之外,还必须在达到解码字节数之后停止循环。