目录
前文
上篇看png,由于只看了一篇参考文章,对其概念还不是很了解。发现了几个忽略的点。
块布局
每个块由三个或四个字段组成 。块数据字段可能为空
长度
一个四字节无符号整数,给出块数据字段中的字节数。长度仅 计算数据字段,而不计算其本身、块类型或 CRC。零是有效长度。尽管编码器和解码器应将长度视为无符号,但其值不应超过 231-1 字节。
块类型
定义
定义块类型的四个字节序列。块类型的每个字节都被限制为十进制值 65 到 90 和 97 到 122。为了方便描述和检查 PNG 数据流,它们分别对应于大写和小写 ISO 646 字母(A - Z和a - z)。编码器和解码器应将块类型视为固定的二进制值,而不是字符串。例如,用 UCS 2 字符集中这些字母的等价物来表示块类型IDAT是不正确的。
在我认出测试图片中的pHYs 块时,我是把所有的块十进制标识转化成十六进制进行查找。当时对“块类型 IHDR标识(ascii码为IHDR)”中的ascii码为IHDR还不知所云。
IHDR标识
49484452
73 72 68 82
(('73 72 68 82'.split(' ')).map(function(item){return (item*1).toString(16)})).join('')
IHDR
(('73 72 68 82'.split(' ')).map(function(item){return String.fromCharCode(item)})).join('')
块数据
适合块类型的数据字节(如果有)。该字段的长度可以为零。
CRC
一个四字节的CRC(Cyclic Redundancy Code)在chunk的前面的字节上计算,包括chunk type字段和chunk data字段,不包括length字段。CRC 可用于检查数据是否损坏。CRC 始终存在,即使对于不包含数据的块也是如此。
如IEND数据块,则为不包含数据的块。
循环冗余码算法(Cyclic Redundancy Code algorithm)
CRC 字段是使用标准化的 CRC 方法和预处理和后处理计算的,如 ISO 3309 ISO-3309和 ITU-T V.42 ITU-T-V42 所定义。使用的CRC多项式是
x 32 + x 26 + x 23 + x 22 + x 16 + x 12 + x 11 + x 10 + x 8 + x 7 + x 5 + x 4 + x 2 + x + 1
在 PNG 中,32 位 CRC 被初始化为全 1,然后每个字节的数据从最低有效位 (1) 到最高有效位 (128) 进行处理。在处理完所有数据字节后,CRC 被反转(取其补码)。该值首先传输(存储在数据流中)MSB。为分字节和排序,将32位CRC的最低有效位定义为x 31项的系数。
CRC 的实际计算通常采用预先计算的表格来加速计算。
示例循环冗余代码实现
ISO C code
unsigned long crc_table[256];
int crc_table_computed = 0;
void make_crc_table(void)
{
unsigned long c;
int n, k;
for (n = 0; n < 256; n++) {
c = (unsigned long) n;
for (k = 0; k < 8; k++) {
if (c & 1)
c = 0xedb88320L ^ (c >> 1);
else
c = c >> 1;
}
crc_table[n] = c;
}
crc_table_computed = 1;
}
unsigned long update_crc(unsigned long crc, unsigned char *buf,
int len)
{
unsigned long c = crc;
int n;
if (!crc_table_computed)
make_crc_table();
for (n = 0; n < len; n++) {
c = crc_table[(c ^ buf[n]) & 0xff] ^ (c >> 8);
}
return c;
}
unsigned long crc(unsigned char *buf, int len)
{
return update_crc(0xffffffffL, buf, len) ^ 0xffffffffL;
}