Splitting APNG into png images with PHP

倖福魔咒の 提交于 2019-12-24 11:55:25

问题


I have a php code that splits an animated PNG image (APNG) into frames, but there is some kind of error. The images that are created by the function are not valid (PHP does not return an image resource in PHP imagecreatefrompng() function (neither it's displayed in Firefox browser).

Quoting the function from How can I split animated PNG with PHP? by 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;
}

Saving the parts is performed as follows

$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);
}

I tried modifying headers but no luck. Please, help!


回答1:


The CRC needs to be recomputed when you change a chunk name from fdAT to IDAT, and remove 4 data bytes, to account for the new chunk name and data.



来源:https://stackoverflow.com/questions/18746811/splitting-apng-into-png-images-with-php

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!