2017-09-07 36 views
0

我有一个PNG文件问题。PHP Imagick使每次更改特定二进制文件的PNG文件 - 从相同的图像文件

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

当我比较这两个文件时,结果表明它只有几个字节是不同的,而其余的字节完全相同,并且这些字节偏移也都是时间相同的。

我真的不知道怎么来的这些字节可能是所有的时间不同(好像它存储时间戳或还有什么呢?)

这里是高燃点二进制PNG文件的二进制,有人帮助我要弄清楚究竟发生了什么这个二进制文件:

enter image description here

我还附上了PNG文件:

enter image description here

谢谢。

+1

在上面一行中,您突出显示的是'tIME'块的开始,这应该是最后一次修改时间([请参阅此处的规格](https://www.w3.org/TR/PNG/# 11tIME))。你也可以找到[这个Unix SE问题](https://unix.stackexchange.com/questions/255252/create-the-same-png-with-imagemagick-2-times-binaries-differ)有帮助。 –

+0

@JoshH为什么只在Linux操作系统中添加?那么,如何使用Imagick(PHP)保存PNG时如何排除此块? – Codemole

+1

由于不同的字节每次都处于已知的偏移量,因此可以选择添加后处理步骤来清零这些字节? – GeorgeQ

回答

1

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

时间块给出了最后一次图像修改的时间(不是初始图像创建时的 时间)。

另一件要注意的规范是,第一个字母是小写(t),这意味着该块不是必需的。所以,彻底删除它应该可以解决你的问题。

我没有使用Imagick,但通过PHP documentation,它看起来像它提供了一种方法来从创建的PNG文件中删除tIME块。 0123'方法可让您更好地控制Imagick对图像所做的操作(list of available options)。 png:exclude-chunk选项可能是你正在寻找的。

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

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

非常感谢您提供2种解决方案,我为他们两个都赞不绝口,并且接受这一点,因为这样做很好! – Codemole

1

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

看着突出显示的行之前的行,我可以看到tIME在那里,所以它似乎是这种情况。

1

如果你正试图从那些已经被创建,或者如果你没有访问Imagick库图像删除tIME块,我测试了一些代码,可以从小型十岁上下的* 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尝试走了过来PHP_INT_MAX。但是,我可以让这段代码处理你在问题中提供的图像。