我的PNG IDAT块有什么问题?

3

我正在尝试手动构建一个简单的、4x1的未压缩PNG。

到目前为止,我已经完成了以下步骤:

89504E47  // PNG Header
0D0A1A0A

0000000D  // byte length of IHDR chunk contents, 4 bytes, value 13
49484452  // IHDR start - 4 bytes
00000004  // Width                        4 bytes }
00000001  // Height                       4 bytes }
08        // bit depth 8 = 24/32 bit      1 byte  }
06        // color type, 6 - RGBa         1 byte  }
00        // compression, 0 = Deflate     1 byte  }
00        // filter, 0 = no filter        1 byte  }
00        // interlace, 0 = no interlace  1 byte  } Total, 13 Bytes
F93C0FCD  // CRC of IHDR chunk, 4 bytes         

00000013  // byte length of IDAT chunk contents, 4 bytes, value 19
49444154  // IDAT start - 4 bytes
0000      // ZLib 0 compression,          2 bytes }
00        // Filter = 0,                  1 bytes }
CC0000FF  // Pixel 1, Red-ish,            4 bytes }
00CC00FF  // Pixel 2, Green-ish,          4 bytes }
0000CCFF  // Pixel 3, Blue-ish,           4 bytes }
CCCCCCCC  // Pixel 4, transclucent grey,  4 bytes } Total, 19 Bytes
6464C2B0  // CRC of IHDR chunk, 4 bytes

00000000  // byte length of IEND chunk, 4 bytes (value: 0)
49454E44  // IEND start - 4 bytes
AE426082  // CRC of IEND chunk, 4 bytes

更新

我认为我遇到的问题与ZLib / Deflate排序有关。

我认为我必须包括来自RFC 1951,第3.2.4节的“非压缩块格式”详细信息,但我有点不确定交互作用。我能找到的唯一示例是针对压缩块的(可以理解!)

所以我现在尝试了:

49444154  // IDAT start - 4 bytes
01        // BFINAL = 1, BTYPE = 00       1 byte  }
11EE      // LEN & NLEN of data           2 bytes }
00        // Filter = 0,                  1 byte  }
CC0000FF  // Pixel 1, Red-ish,            4 bytes }
00CC00FF  // Pixel 2, Green-ish,          4 bytes }
0000CCFF  // Pixel 3, Blue-ish,           4 bytes }
CCCCCCCC  // Pixel 4, transclucent grey,  4 bytes } Total, 19 Bytes
6464C2B0  // CRC of IHDR chunk, 4 bytes

整个PNG文件如下:

89504E47    // PNG Block
0d0a1a0A

0000000D    // IHDR Block
49484452
00000004
00000001
08060000
00
F93C0FCD

00000014    // IDAT Block
49444154
0111EE00
CC0000FF
00CC00FF
0000CCFF
CCCCCCCC
6464C2B0

00000000    // IEND Block
49454E44
AE426082

我希望你能给出一些指针,让我知道问题出在哪里......或者一个工作文件的PNG数据,这样我就可以反向工程它?感谢Mark Adler,我已经纠正了我的新手错误,现在有了可以复制他下面回答中显示的结果的功能代码,即4x1像素图像。从这里,我现在可以愉快地生成100x1的图像!然而,作为最后一步,我希望通过调整IHDR中的高度字段并添加额外的非终端IDAT来将其扩展到4 x 2图像。不幸的是,这似乎不像我期望的那样工作。现在我有了类似于...
89504E47 // PNG Header
0D0A1A0A

0000000D // re calc'ed IHDR with 2 rows
49484452
00000004
00000002 // changed - now 2 rows
08
06
00
00
00
7FA87D63 // CRC of IHDR updated

0000001C // row 1 IDAT, non-terminal
49444154
7801
00       // BFINAL = 0, BTYPE = 00 
1100EEFF
00
CC0000FF
00CC00FF
0000CCFF
CCCCCCCC
3D3A0892
5D19A623


0000001C // row 2, terminal IDAT, as Mark Adler's answer
49444154
7801
01       // BFINAL = 1, BTYPE = 00 
1100EEFF
00
CC0000FF
00CC00FF
0000CCFF
CCCCCCCC
3D3A0892
BA0400B4

00000000
49454E44
AE426082

字节序是怎么样的? - Usagi Miyamoto
好的想法 - 但即使是反过来,我也应该得到一些输出吧;-)? - Dycey
不知道,只是在问一下... 顺便问一下,你希望得到什么输出结果,以及使用哪个软件? - Usagi Miyamoto
4x1像素的PNG图片,分别为红色、绿色、蓝色和透明。 - Dycey
1个回答

6

This:

11EE      // LEN & NLEN of data           2 bytes }

有误。 LENNLEN 都是16位,而不是8位。因此需要这样更正:

1100EEFF  // LEN & NLEN of data           4 bytes }

你还需要对压缩数据进行zlib包装。请参考RFC 1950。
最后,你需要更新块的CRC。(顺便说一下,它有错误的注释——它应该是IDAT块的CRC。)
修复后如下:
89504E47  // PNG Header
0D0A1A0A

0000000D  // byte length of IHDR chunk contents, 4 bytes, value 13
49484452  // IHDR start - 4 bytes
00000004  // Width                        4 bytes }
00000001  // Height                       4 bytes }
08        // bit depth 8 = 24/32 bit      1 byte  }
06        // color type, 6 - RGBa         1 byte  }
00        // compression, 0 = Deflate     1 byte  }
00        // filter, 0 = no filter        1 byte  }
00        // interlace, 0 = no interlace  1 byte  } Total, 13 Bytes
F93C0FCD  // CRC of IHDR chunk, 4 bytes         

0000001C  // byte length of IDAT chunk contents, 4 bytes, value 28
49444154  // IDAT start - 4 bytes
7801      // zlib Header                  2 bytes }
01        // BFINAL = 1, BTYPE = 00       1 byte  }
1100EEFF  // LEN & NLEN of data           4 bytes }
00        // Filter = 0,                  1 byte  }
CC0000FF  // Pixel 1, Red-ish,            4 bytes }
00CC00FF  // Pixel 2, Green-ish,          4 bytes }
0000CCFF  // Pixel 3, Blue-ish,           4 bytes }
CCCCCCCC  // Pixel 4, transclucent grey,  4 bytes }
3d3a0892  // Adler-32 check               4 bytes }
ba0400b4  // CRC of IDAT chunk, 4 bytes

00000000  // byte length of IEND chunk, 4 bytes (value: 0)
49454E44  // IEND start - 4 bytes
AE426082  // CRC of IEND chunk, 4 bytes

马克 - 很荣幸你能回答这个问题!谢谢。我已经重新编写了我的代码(请参见上文),现在它产生的代码与您提供的完全相同,这太棒了!然而,我的意图是使用额外的非终端IDAT来添加多行到图像中。不幸的是,这种方法失败了。 - Dycey
1
IDAT块的序列必须包含一个_zlib流。不幸的是,您不能在zlib流的中间插入数据。至少不更新zlib流的开头和结尾是不行的。 - Mark Adler
或者...你的意思是我可以将整个图像的LEN和NLEN放在第一个数据块中,然后在块之间分配行...我会尝试一下。再次感谢。 - Dycey
1
不,你需要将整个图像放入一个_zlib流_中。你可以将zlib流分成多个块,或将其全部放入单个块中。 - Mark Adler
1
@Dycey 你能解释一下你是如何添加额外的行的吗?(因为你没有更新你的问题) - creativecreatorormaybenot
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接