【问题标题】:What's wrong with my PNG IDAT chunk?我的 PNG IDAT 块有什么问题?
【发布时间】:2018-08-07 06:04:35
【问题描述】:

我正在尝试手动构建一个简单的 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, sec. 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 数据,以便我可以对其进行逆向工程?

更新 2

感谢 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

【问题讨论】:

  • 字节序呢?
  • 不错的想法 - 但即使是错误的方法,我也应该得到 一些 输出 ;-) 不?
  • 不知道,只是问...顺便说一句,您期望什么输出,来自什么软件?
  • 4x1 像素 PNG 红、绿、蓝、透明。

标签: image png zlib


【解决方案1】:

这个:

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

错了。 LENNLEN 都是 16 位,而不是 8 位。所以这需要:

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

您还需要一个围绕 deflate 数据的 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 向图像添加多行。不幸的是,这失败了。
  • IDAT 块的序列必须包含一个 single zlib 流。不幸的是,您不能只在 zlib 流的中间插入数据。至少在不更新 zlib 流的开始和结束的情况下是这样。
  • 啊哈!所以我需要把整个图像放在一个块中?
  • 不,您需要将整个图像放入单个 zlib 流。您可以将 zlib 流分解为多个块,或将其全部放入一个块中。
  • @Dycey 你能解释一下你是如何设法添加额外的行的吗? (因为你没有更新你的问题)
猜你喜欢
  • 2017-09-19
  • 1970-01-01
  • 2014-11-26
  • 2011-11-09
  • 2015-06-13
  • 2017-05-22
  • 1970-01-01
  • 2014-05-05
  • 1970-01-01
相关资源
最近更新 更多