【问题标题】:How can I make PHP zlib library output PNG compatible compression?如何使 PHP zlib 库输出 PNG 兼容压缩?
【发布时间】:2022-01-10 15:20:19
【问题描述】:

情况

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

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

用户id:a308193d1eff2f15df7bedb4cb992bcf25cee012ca41751c35ce1d5500497063,如果太短无法生成像素,将被填充。

过滤后的原始像素:

01a30819ff000000009a16e60000000000f2f7e000000000004cd8d5000000000050ac770000000000048ca3000000000011edfc00000000006163520000000000f45901000000000020322c00000000001b63b600000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

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

问题

PHP zlib 库似乎没有正确压缩数据。尽管 zlib 最初是为 PNG 设计的,但它始终输出与 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 块压缩是让我失去理智的原因。

【问题讨论】:

  • 这是一个非常有趣的话题,但我对此一无所知。阅读libpng.org/pub/png/spec/1.2/PNG-Compression.html 或许Note that the zlib compression method number is not the same as the PNG compression method number. 会提供有用的提示。

标签: php png zlib


【解决方案1】:

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

虽然我确实对你认为“应该”是输出的那个有一些小问题。那个压缩得相当差,在动态块头上浪费空间,而它应该使用固定头,并且没有压缩许多零运行。结果,该 deflate 流比 zlib 生成的流大 32%。我想知道是什么导致压缩效果不佳。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-07
    • 2016-12-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多