在过去的4个小时里,我一直在研究CRC算法。我相信我已经掌握了它。
我正在尝试编写一个png编码器,我不希望使用外部库进行CRC计算,也不希望使用外部库进行png编码本身。
我的程序已经能够获得与教程上相同的CRC结果,例如在维基百科上:
使用与示例中相同的多项式和消息,在这两种情况下我都能够产生相同的结果。我还可以为其他几个示例做到这一点。
然而,我似乎无法正确地计算png文件的CRC。我通过在画图中创建一个空的、一个像素大小的.png文件,并使用它的CRC作为比较来测试这一点。我复制了png的IDAT块中的数据(从中计算CRC),并使用png规范中提供的多项式计算了它的CRC。
在png规范中提供的多项式如下:x32 + x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x + 1
应该翻译为:
1 00000100 11000001 00011101 10110111
使用该多项式,我尝试计算以下数据的CRC:
01001001 01000100 01000001 01010100
00011000 01010111 01100011 11101000
11101100 11101100 00000100 00000000
00000011 00111010 00000001 10011100
这就是我得到的:
01011111 11000101 01100001 01101000 (MSB First)
10111011 00010011 00101010 11001100 (LSB First)
这是实际的CRC:
11111010 00010110 10110110 11110111
我不确定如何修复这个问题,但我的猜测是我正错误地处理了从规范中得到的这个部分:
我并不完全确定我能够理解所有这些。在PNG中,32位CRC被初始化为全1,然后从最低有效位(1)到最高有效位(128)处理每个字节的数据。处理完所有的数据字节后,将反转CRC(取其反码)。该值被传输(存储在数据流中)以MSB优先的方式。为了分离成字节和排序,32位CRC的最低有效位被定义为x31项的系数。
此外,这是我用于获取CRC的代码:
public BitArray GetCRC(BitArray data)
{
// Prepare the divident; Append the proper amount of zeros to the end
BitArray divident = new BitArray(data.Length + polynom.Length - 1);
for (int i = 0; i < divident.Length; i++)
{
if (i < data.Length)
{
divident[i] = data[i];
}
else
{
divident[i] = false;
}
}
// Calculate CRC
for (int i = 0; i < divident.Length - polynom.Length + 1; i++)
{
if (divident[i] && polynom[0])
{
for (int j = 0; j < polynom.Length; j++)
{
if ((divident[i + j] && polynom[j]) || (!divident[i + j] && !polynom[j]))
{
divident[i + j] = false;
}
else
{
divident[i + j] = true;
}
}
}
}
// Strip the CRC off the divident
BitArray crc = new BitArray(polynom.Length - 1);
for (int i = data.Length, j = 0; i < divident.Length; i++, j++)
{
crc[j] = divident[i];
}
return crc;
}
那么,我该如何修复它以符合PNG规范呢?