如何使PHP zlib库输出PNG兼容压缩



情况

我目前正在制作一个从用户id创建图像的函数。我已经成功地生成了原始RGBA像素,并成功地过滤了它们,如下所示:

图像宽度为22像素,高度为2像素。

用户id:a308193d1eff2f15df7bedb4cb992bcf25cee012ca41751c35ce1d5500497063,如果太短无法生成像素,则会对其进行填充。

过滤后的原始像素:

01a30819ff000000009a16e60000000000f2f7e000000000004cd8d5000000000050ac770000000000048ca3000000000011edfc00000000006163520000000000f45901000000000020322c00000000001b63b600000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

我还成功地从用户id生成了一个可工作的SVG,但SVG不是我想要的。

问题

PHP zlib库似乎无法正确压缩数据。它总是输出与PNG格式不兼容的压缩数据,即使zlib最初是为PNG设计的。每个zlib库函数都会生成错误的压缩,如:

78da 635ccc21f99f010866893d03510c9fbe3f00d33e37ae82e98035e5609aa5673198167cfb074c27260781e92f918c605ac148074c4b276f03d34c0c340200 54f010d5

(我用空格把ZLIB头、压缩数据和adler32分开(。

它应该输出什么(或者至少类似于(:

0899 B5C1210A83500000D0E730582D03B1780093E730C8DAE2F0105EC213587F357B13C168B259646011B653F85E1492EC07C37303C7B9827A9941337620EE0348F70B7CDA17F8BE23505425C8DB093CDCE40F 54F010D5

(对于PNG,压缩字符串应始终以0x08字节开头(

每次只有Adler32校验和是正确的。

我尝试过每一个zlib压缩函数,它们中的每一个都会生成无用的数据。它们中大多数可配置的函数是deflate_init((+deflate_add((,但它们和其他函数一样无用。

例如:

$filtered_pixels = "01a30819ff000000009a16e60000000000f2f7e000000000004cd8d5000000000050ac770000000000048ca3000000000011edfc00000000006163520000000000f45901000000000020322c00000000001b63b600000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
$options = array(
"level" => 9, // Best compression
"memory" => 1, // No need to use much memory for such small image
"window" => 8, // 256-bit window size
"strategy" => ZLIB_RLE, // Especially good for PNG compression
"dictionary" => "", // No dictionary
);
$context = deflate_init(ZLIB_ENCODING_DEFLATE , $options);
$deflate = deflate_add($context, hex2bin($filtered_pixels));
// Outputs "1819 625ccc21f99f010866893d6300814fdf1f308080cf8dab0c2010b0a69c0104587a16338080e0db3f0c2090981cc400025f2219194040c148870104a493b731800013038d00000000ffff" without adler32 checksum
echo bin2hex($deflate);

我已经为这个问题挣扎了一周了,我尝试的函数和每个函数尝试的参数都不起作用。我是不是错过了一些显而易见的东西?我也知道如何从其他部分编码PNG,我已经做到了。只有IDAT块压缩才会让我失去理智。

不,它不应该总是以0x08开头。我不知道你从哪里得到的。78da0899都是有效的zlib标头。以78da开头的zlib流没有任何问题。这两个流都是有效的,并且都解压缩到您的数据中。两者都可以在PNG图像的IDAT块中使用。

尽管我确实对你认为的";应该";是输出。这一个压缩得相当差,在本应使用固定标头的情况下浪费了动态块标头上的空间,并且没有压缩多次零。因此,deflate流比zlib生成的流大32%。我想知道是什么造成了这个压缩不好的。

最新更新