Splitting APNG into png images with PHP

后端 未结 2 1970
遥遥无期
遥遥无期 2021-01-26 19:05

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

相关标签:
2条回答
  • 2021-01-26 19:15

    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.

    0 讨论(0)
  • 2021-01-26 19:27

    I rewrite the splitapng() because crc32 has to be re-calculated. Works now.

    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;
    }
    
    
    0 讨论(0)
提交回复
热议问题