]> scripts.mit.edu Git - autoinstallsdev/mediawiki.git/blobdiff - includes/media/PNGMetadataExtractor.php
MediaWiki 1.17.0
[autoinstallsdev/mediawiki.git] / includes / media / PNGMetadataExtractor.php
diff --git a/includes/media/PNGMetadataExtractor.php b/includes/media/PNGMetadataExtractor.php
new file mode 100644 (file)
index 0000000..6a931e6
--- /dev/null
@@ -0,0 +1,104 @@
+<?php
+/**
+ * PNG frame counter.
+ * Slightly derived from GIFMetadataExtractor.php
+ * Deliberately not using MWExceptions to avoid external dependencies, encouraging
+ * redistribution.
+ *
+ * @file
+ * @ingroup Media
+ */
+
+/**
+ * PNG frame counter.
+ *
+ * @ingroup Media
+ */
+class PNGMetadataExtractor {
+       static $png_sig;
+       static $CRC_size;
+
+       static function getMetadata( $filename ) {
+               self::$png_sig = pack( "C8", 137, 80, 78, 71, 13, 10, 26, 10 );
+               self::$CRC_size = 4;
+               
+               $frameCount = 0;
+               $loopCount = 1;
+               $duration = 0.0;
+
+               if (!$filename)
+                       throw new Exception( __METHOD__ . ": No file name specified" );
+               elseif ( !file_exists($filename) || is_dir($filename) )
+                       throw new Exception( __METHOD__ . ": File $filename does not exist" );
+               
+               $fh = fopen( $filename, 'r' );
+               
+               if (!$fh) {
+                       throw new Exception( __METHOD__ . ": Unable to open file $filename" );
+               }
+               
+               // Check for the PNG header
+               $buf = fread( $fh, 8 );
+               if ( $buf != self::$png_sig ) {
+                       throw new Exception( __METHOD__ . ": Not a valid PNG file; header: $buf" );
+               }
+
+               // Read chunks
+               while( !feof( $fh ) ) {
+                       $buf = fread( $fh, 4 );
+                       if( !$buf ) {
+                               throw new Exception( __METHOD__ . ": Read error" );
+                       }
+                       $chunk_size = unpack( "N", $buf);
+                       $chunk_size = $chunk_size[1];
+
+                       $chunk_type = fread( $fh, 4 );
+                       if( !$chunk_type ) {
+                               throw new Exception( __METHOD__ . ": Read error" );
+                       }
+
+                       if ( $chunk_type == "acTL" ) {
+                               $buf = fread( $fh, $chunk_size );
+                               if( !$buf ) {
+                                       throw new Exception( __METHOD__ . ": Read error" );
+                               }
+
+                               $actl = unpack( "Nframes/Nplays", $buf );
+                               $frameCount = $actl['frames'];
+                               $loopCount = $actl['plays'];
+                       } elseif ( $chunk_type == "fcTL" ) {
+                               $buf = fread( $fh, $chunk_size );
+                               if( !$buf ) {
+                                       throw new Exception( __METHOD__ . ": Read error" );
+                               }
+                               $buf = substr( $buf, 20 );      
+
+                               $fctldur = unpack( "ndelay_num/ndelay_den", $buf );
+                               if( $fctldur['delay_den'] == 0 ) $fctldur['delay_den'] = 100;
+                               if( $fctldur['delay_num'] ) {
+                                       $duration += $fctldur['delay_num'] / $fctldur['delay_den'];
+                               }
+                       } elseif ( ( $chunk_type == "IDAT" || $chunk_type == "IEND" ) && $frameCount == 0 ) {
+                               // Not a valid animated image. No point in continuing.
+                               break;
+                       } elseif ( $chunk_type == "IEND" ) {
+                               break;
+                       } else {
+                               fseek( $fh, $chunk_size, SEEK_CUR );
+                       }
+                       fseek( $fh, self::$CRC_size, SEEK_CUR );
+               }
+               fclose( $fh );
+
+               if( $loopCount > 1 ) {
+                       $duration *= $loopCount;
+               }
+
+               return array(
+                       'frameCount' => $frameCount,
+                       'loopCount' => $loopCount,
+                       'duration' => $duration
+               );
+               
+       }
+}