4 * Slightly derived from GIFMetadataExtractor.php
5 * Deliberately not using MWExceptions to avoid external dependencies, encouraging
17 class PNGMetadataExtractor
{
21 static function getMetadata( $filename ) {
22 self
::$png_sig = pack( "C8", 137, 80, 78, 71, 13, 10, 26, 10 );
30 throw new Exception( __METHOD__
. ": No file name specified" );
31 elseif ( !file_exists($filename) ||
is_dir($filename) )
32 throw new Exception( __METHOD__
. ": File $filename does not exist" );
34 $fh = fopen( $filename, 'r' );
37 throw new Exception( __METHOD__
. ": Unable to open file $filename" );
39 // Check for the PNG header
40 $buf = fread( $fh, 8 );
41 if ( !($buf == self
::$png_sig) ) {
42 throw new Exception( __METHOD__
. ": Not a valid PNG file; header: $buf" );
46 while( !feof( $fh ) ) {
47 $buf = fread( $fh, 4 );
49 throw new Exception( __METHOD__
. ": Read error" );
51 $chunk_size = unpack( "N", $buf);
52 $chunk_size = $chunk_size[1];
54 $chunk_type = fread( $fh, 4 );
56 throw new Exception( __METHOD__
. ": Read error" );
59 if ( $chunk_type == "acTL" ) {
60 $buf = fread( $fh, $chunk_size );
62 throw new Exception( __METHOD__
. ": Read error" );
65 $actl = unpack( "Nframes/Nplays", $buf );
66 $frameCount = $actl['frames'];
67 $loopCount = $actl['plays'];
68 } elseif ( $chunk_type == "fcTL" ) {
69 $buf = fread( $fh, $chunk_size );
71 throw new Exception( __METHOD__
. ": Read error" );
73 $buf = substr( $buf, 20 );
75 $fctldur = unpack( "ndelay_num/ndelay_den", $buf );
76 if( $fctldur['delay_den'] == 0 ) $fctldur['delay_den'] = 100;
77 if( $fctldur['delay_num'] ) {
78 $duration +
= $fctldur['delay_num'] / $fctldur['delay_den'];
80 } elseif ( ( $chunk_type == "IDAT" ||
$chunk_type == "IEND" ) && $frameCount == 0 ) {
81 // Not a valid animated image. No point in continuing.
83 } elseif ( $chunk_type == "IEND" ) {
86 fseek( $fh, $chunk_size, SEEK_CUR
);
88 fseek( $fh, self
::$CRC_size, SEEK_CUR
);
92 if( $loopCount > 1 ) {
93 $duration *= $loopCount;
97 'frameCount' => $frameCount,
98 'loopCount' => $loopCount,
99 'duration' => $duration