在 php 中附加一个 png pHYs 块

2022-01-09 00:00:00 binary png chunks php

我正在尝试添加一些有关物理尺寸的信息,以便在生成 PNG 之前打印它们.

I'm trying to tack on some information about the physical size for printing my PNGs just before they are generated.

阅读 libpng doc 和 pHYs 块规范很有帮助但我似乎无法破解它.

Reading the libpng doc and the pHYs chunk specifications has been helpful but I just can't seem to crack it.

我已尝试以最手动和最简单的方式添加此块,但是 .png 文件最终损坏.我错过了编码技巧吗?

I have tried adding this chunk in the most manual and simplest way possible, however, the .png file ends up corrupted. Am I missing an encoding trick?

对于 CRC 计算,我使用了 this site,已插入下面代码给我的块的 ASCII 值.

For the CRC computation I have used the 32-bit result of this site, having plugged in the ASCII values for the chunk that the code below gives me.

$encoded = $_POST['imgdata'];
$encoded = str_replace(' ', '+', $encoded);
$decoded=  base64_decode($encoded);

$test = explode('IDAT',$decoded);
$ppu='00000000000000000010111000100011';  //32-bit integer for the pixels per unit
$dppu=bindec($ppu);
$test[0].=sprintf("%c",bindec('00000000000000000000000000001001')) //length, also 32-bit
    .'pHYs'                                                      //type
    .  sprintf("%c",$dppu)                             //Pixels per unit, x axis
    . sprintf("%c",$dppu)                             //Pixels per unit, y axis
    .'1'                                                 //Units in metres (1 byte)
    .  sprintf("%c",  bindec(base_convert('0x0BFAAA7E', 16, 2))) //CRC (32-bit)
    .'IDAT';
$fintest=implode($test);

echo $fintest;

请让我知道像这样入侵它是否可行.我也不确定我的 32 位整数:当我正在做正确的方法使它们成为 32 位时,是否对它们进行了零填充?

Please let me know whether hacking it in like this is likely to work. I am also unsure about my 32-bit integers: is zero-padding them as I am doing the correct way to make them 32-bit?

推荐答案

花了一天的时间,我发现这样做的方法是逐字节翻译所有内容.按照文档,pHYs 块需要:

After having spent the day on this, I found that the way to do this was to translate everything byte by byte. Following the docs, the pHYs chunk takes:

  • 块(仅数据)长度为 4 个字节
  • 4 个字节用于块类型(字符pHYs")
  • 9 字节用于块数据:x 和 y 密度各 4 字节,单位选择 1 字节
  • 4 个字节用于 CRC

我将所有这些都写成二进制字符串,必要时用 0 填充字节.然后事实证明, chr() 函数正确编码了它以在 PNG 文件中使用,这与我使用的 sprintf("%c",$string) 方法不同在问题中.这是代码

I wrote all this as a binary string, padding the bytes with 0 as necessary. It then turns out that the chr() function correctly encodes this to be used in the PNG file, unlike the sprintf("%c",$string) method I use in the question. Here is the code

$encoded = $_POST['imgdata'];
$encoded = str_replace(' ', '+', $encoded);
$decoded=  base64_decode($encoded);

$binstring='00000000000000000000000000001001' //4-byte length
        . '01110000010010000101100101110011' //4-byte type or 'pHYs'
        . '000000000000000000101110001000110000000000000000001011100010001100000001' //9-byte data
        . base_convert('0x0BFAAA7E', 16, 2); //4-byte CRC
foreach (str_split($binstring,8) as $b) {
    $on.=chr(bindec($b));
}

然后将 $on 变量附加到 IDAT 块长度的 4 个字节之前的位置.

The $on variable is then appended to the position just before the 4 bytes of the IDAT chunk length.

相关文章