PHP Imagick 使用每次更改的特定二进制文件生成 PNG 文件 - 来自同一图像文件

PHP Imagick makes PNG file with every-time changing specific binaries - from same image file

我有一个 PNG 文件问题。

当我使用 PHP Imagick 库转换图像时,尽管我多次尝试使用相同的图像文件,但每次都得到不同的二进制集。

当我比较这 2 个文件时,发现它只有几个字节不同,而其余字节完全相同,而且那些字节偏移量也都相同。

我真的不确定这些字节怎么会一直不同(好像它存储了时间戳或其他什么?)

这是带有高亮二进制文件的 PNG 文件的二进制文件,有人帮我弄清楚这个二进制文件到底是什么:

我也附上png文件:

谢谢。

这很可能是由于图片的元数据造成的?即文件被修改时的时间戳?

查看突出显示的行之前的行,我可以在其中看到 tIME,因此情况似乎就是这样。

PNG 文件是 "chunked",这意味着它们具有定义不同数据的不同命名部分。在 PNG file format specification 中,您可以找到有关 PNG 文件中 tIME 块的信息。

The tIME chunk gives the time of the last image modification (not the time of initial image creation).

规范中要注意的另一件事是第一个字母是小写的 (t),这意味着块不是必需的。因此,完全删除它应该可以解决您的问题。

我没有用过 Imagick,但通过 PHP documentation, it looks like it provides a way way to remove the tIME chunk from the created PNG file. The setOption method gives you more control over what Imagick does with the image (list of available options)。 png:exclude-chunk 选项可能就是您要找的。

此代码未经测试,因为我目前无法访问带有 Imagick 库的服务器。

$im = new Imagick();
$im->setOption('png:exclude-chunk', 'tIME'); // comma separated list of chunks

如果您尝试从已创建的图像中删除 tIME 块,或者如果您无权访问 Imagick 库,我测试了一些可以从小型图像中删除块的代码* PNG 文件。

PNG 文件具有 specific format:

  • PNG 签名 [8 字节]
  • 块数据 - 以 IHDR 开始,以 IEND 块结束,中间有其他块。每个块具有以下内容:
    • 长度 [4 字节]
    • 键入 [4 字节]
    • 数据 [长度字节](如果长度为 0,则可能为空)
    • CRC(循环冗余码)[4 字节]

使用这些信息,我们可以一个一个地读取块以找到我们想要删除的那个。

// read the PNG file's contents into a string
$str = file_get_contents('hD0aZ.png');

// how far into the string we are currently
$offset = 0;

// offset for the PNG signature (8 bytes)
$offset += 8;

// what we will replace in the original string once it is found
$timechunk = '';

while($offset < strlen($str)){
    // get the current chunk information
    list($length,$chunk,$name) = readchunk(substr($str,$offset));
    if($name == 'tIME'){
        $timechunk = $chunk;
        break;
    }
    // move to the next chunk
    $offset += $length;
}

header("Content-Type:image/png");
print str_replace($timechunk,'',$str);

function readchunk($str){
    $length = hexdec(bin2hex(substr($str,0,4)));
    // 4 bytes for length, 4 bytes for chunk name, 4 bytes for CRC = 12 bytes
    return array(
        12+$length,                 // total length of chunk
        substr($str,0,12+$length),  // full chunk data
        substr($str,4,4)            // chunk name
    );
}

*如果您的 PNG 文件太大并且 tIME 块在字符串中不够早,如果您的 $offset 试图超过 [=14],您可能会遇到问题=].但是,我能够让这段代码处理您在问题中提供的图像。