发布于 2010-12-24 00:46:28
APNG图像被设计成“伪装”为PNG,供那些不支持它们的读者使用。也就是说,如果读取器不支持它们,它只会假设它是一个普通的PNG文件,并且只显示第一个帧。这意味着它们与PNG (image/png)具有相同的MIME类型,它们具有相同的魔术号(89 50 4e 47 0d 0a 1a 0a
),并且通常保存时具有相同的扩展名(尽管这并不是检查文件类型的好方法)。
那么,你如何区分它们呢?APNG中有一个"acTL“块。因此,如果您搜索字符串acTL
(或者,以十六进制表示,61 63 54 4C
(块标记之前的4个字节(即00 00 00 08
)是大端格式的块的大小,而不包括字段末尾的大小、标记或CRC32 ),那么您应该是很好的。为了得到更好的结果,请检查这个块是否出现在第一次出现"IDAT“块之前(只需查找IDAT
)。
这段代码(取自apng.php )将完成以下任务:
<?php
# Identifies APNGs
# Written by Coda, functionified by Foone/Popcorn Mariachi#!9i78bPeIxI
# This code is in the public domain
# identify_apng returns:
# true if the file is an APNG
# false if it is any other sort of file (it is not checked for PNG validity)
# takes on argument, a filename.
function identify_apng($filename)
{
$img_bytes = file_get_contents($filename);
if ($img_bytes)
{
if(strpos(substr($img_bytes, 0, strpos($img_bytes, 'IDAT')),
'acTL')!==false)
{
return true;
}
}
return false;
}
?>
发布于 2010-12-24 00:41:24
AFAIK,不支持APNG的库将只使用PNG的第一个框架。在您的示例中,您只需从APNG (或PNG、JPEG等)创建一个新的图像。把它重新保存为PNG。如果使用GD,它应该删除动画数据,除非库已经更新以支持APNG。
发布于 2018-10-07 03:17:20
我想建议一个更优化的版本,它不会读取整个文件,因为这些文件可能相当大,并且仍然依赖于IDAT规则之前的acTL:
function identify_apng($filepath) {
$apng = false;
$fh = fopen($filepath, 'r');
$previousdata = '';
while (!feof($fh)) {
$data = fread($fh, 1024);
if (strpos($data, 'acTL') !== false) {
$apng = true;
break;
} elseif (strpos($previousdata.$data, 'acTL') !== false) {
$apng = true;
break;
} elseif (strpos($data, 'IDAT') !== false) {
break;
} elseif (strpos($previousdata.$data, 'IDAT') !== false) {
break;
}
$previousdata = $data;
}
fclose($fh);
return $apng;
}
速度从5倍提高到10倍或更高,这取决于文件的大小,而且它使用的内存也要少得多。
注意:这可能会随着fread的大小或者与当前块的连接而被更多的调整。顺便说一句,我们需要这种连接,因为acTL/IDAT字可能被分成两个读块。
https://stackoverflow.com/questions/4525152
复制相似问题