我有一个php代码,可以将动画PNG图像(APNG)拆分为帧,但是存在某种错误。该函数创建的图像无效(PHP 不会在 PHP imagecreatefrompng() 函数中返回图像资源(也不会显示在 Firefox 浏览器中)。
引用该函数来自 如何用 PHP 拆分动画 PNG?,作者:James Holderness
function splitapng($data) {
$parts = array();
// Save the PNG signature
$signature = substr($data, 0, 8);
$offset = 8;
$size = strlen($data);
while ($offset < $size) {
// Read the chunk length
$length = substr($data, $offset, 4);
$offset += 4;
// Read the chunk type
$type = substr($data, $offset, 4);
$offset += 4;
// Unpack the length and read the chunk data including 4 byte CRC
$ilength = unpack('Nlength', $length);
$ilength = $ilength['length'];
$chunk = substr($data, $offset, $ilength+4);
$offset += $ilength+4;
if ($type == 'IHDR')
$header = $length . $type . $chunk; // save the header chunk
else if ($type == 'IEND')
$end = $length . $type . $chunk; // save the end chunk
else if ($type == 'IDAT')
$parts[] = $length . $type . $chunk; // save the first frame
else if ($type == 'fdAT') {
// Animation frames need a bit of tweaking.
// We need to drop the first 4 bytes and set the correct type.
$length = pack('N', $ilength-4);
$type = 'IDAT';
$chunk = substr($chunk,4);
$parts[] = $length . $type . $chunk;
}
}
// Now we just add the signature, header, and end chunks to every part.
for ($i = 0; $i < count($parts); $i++) {
$parts[$i] = $signature . $header . $parts[$i] . $end;
}
return $parts;
}
保存零件的操作如下
$filename = 'example.png';
$handle = fopen($filename, 'rb');
$filesize = filesize($filename);
$data = fread($handle, $filesize);
fclose($handle);
$parts = splitapng($data);
for ($i = 0; $i < count($parts); $i++) {
$handle = fopen("part-$i.png",'wb');
fwrite($handle,$parts[$i]);
fclose($handle);
}
我尝试修改标题但没有运气。请帮忙!
当您将块名称从 fdAT 更改为 IDAT 并删除 4 个数据字节时,需要重新计算 CRC,以考虑新的块名称和数据。
我重写了splitapng()
,因为必须重新计算crc32。现在工作。
function splitapng($data) {
$parts = array();
// Save the PNG signature
$signature = substr($data, 0, 8);
$offset = 8;
$size = strlen($data);
while ($offset < $size) {
// Read the chunk length
$length = substr($data, $offset, 4);
$offset += 4;
// Read the chunk type
$type = substr($data, $offset, 4);
$offset += 4;
// Unpack the length and read the chunk data including 4 byte CRC
$ilength = unpack('Nlength', $length);
$ilength = $ilength['length'];
$chunk = substr($data, $offset, $ilength+4);
$offset += $ilength+4;
if ($type == 'IHDR')
$header = $length . $type . $chunk; // save the header chunk
else if ($type == 'IEND')
$end = $length . $type . $chunk; // save the end chunk
else if ($type == 'IDAT')
$parts[] = $length . $type . $chunk; // save the first frame
else if ($type == 'fdAT') {
// Animation frames need a bit of tweaking.
// We need to drop the first 4 bytes and set the correct type.
$length = pack('N', $ilength-4);
$type = 'IDAT';
// re-calc crc
$chunk = substr($chunk,4,-4);
$chunk .= hash('crc32b',$type.$chunk,true);
$parts[] = $length . $type . $chunk;
}
}
// Now we just add the signature, header, and end chunks to every part.
for ($i = 0; $i < count($parts); $i++) {
$parts[$i] = $signature . $header . $parts[$i] . $end;
}
return $parts;
}