* (bug 26484) add a lltitles param to prop=langlinks
[lhc/web/wiklou.git] / includes / media / PNGMetadataExtractor.php
1 <?php
2 /**
3 * PNG frame counter.
4 * Slightly derived from GIFMetadataExtractor.php
5 * Deliberately not using MWExceptions to avoid external dependencies, encouraging
6 * redistribution.
7 *
8 * @file
9 * @ingroup Media
10 */
11
12 /**
13 * PNG frame counter.
14 *
15 * @ingroup Media
16 */
17 class PNGMetadataExtractor {
18 static $png_sig;
19 static $CRC_size;
20
21 static function getMetadata( $filename ) {
22 self::$png_sig = pack( "C8", 137, 80, 78, 71, 13, 10, 26, 10 );
23 self::$CRC_size = 4;
24
25 $frameCount = 0;
26 $loopCount = 1;
27 $duration = 0.0;
28
29 if (!$filename)
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" );
33
34 $fh = fopen( $filename, 'r' );
35
36 if (!$fh) {
37 throw new Exception( __METHOD__ . ": Unable to open file $filename" );
38 }
39
40 // Check for the PNG header
41 $buf = fread( $fh, 8 );
42 if ( $buf != self::$png_sig ) {
43 throw new Exception( __METHOD__ . ": Not a valid PNG file; header: $buf" );
44 }
45
46 // Read chunks
47 while( !feof( $fh ) ) {
48 $buf = fread( $fh, 4 );
49 if( !$buf ) {
50 throw new Exception( __METHOD__ . ": Read error" );
51 }
52 $chunk_size = unpack( "N", $buf);
53 $chunk_size = $chunk_size[1];
54
55 $chunk_type = fread( $fh, 4 );
56 if( !$chunk_type ) {
57 throw new Exception( __METHOD__ . ": Read error" );
58 }
59
60 if ( $chunk_type == "acTL" ) {
61 $buf = fread( $fh, $chunk_size );
62 if( !$buf ) {
63 throw new Exception( __METHOD__ . ": Read error" );
64 }
65
66 $actl = unpack( "Nframes/Nplays", $buf );
67 $frameCount = $actl['frames'];
68 $loopCount = $actl['plays'];
69 } elseif ( $chunk_type == "fcTL" ) {
70 $buf = fread( $fh, $chunk_size );
71 if( !$buf ) {
72 throw new Exception( __METHOD__ . ": Read error" );
73 }
74 $buf = substr( $buf, 20 );
75
76 $fctldur = unpack( "ndelay_num/ndelay_den", $buf );
77 if( $fctldur['delay_den'] == 0 ) $fctldur['delay_den'] = 100;
78 if( $fctldur['delay_num'] ) {
79 $duration += $fctldur['delay_num'] / $fctldur['delay_den'];
80 }
81 } elseif ( ( $chunk_type == "IDAT" || $chunk_type == "IEND" ) && $frameCount == 0 ) {
82 // Not a valid animated image. No point in continuing.
83 break;
84 } elseif ( $chunk_type == "IEND" ) {
85 break;
86 } else {
87 fseek( $fh, $chunk_size, SEEK_CUR );
88 }
89 fseek( $fh, self::$CRC_size, SEEK_CUR );
90 }
91 fclose( $fh );
92
93 if( $loopCount > 1 ) {
94 $duration *= $loopCount;
95 }
96
97 return array(
98 'frameCount' => $frameCount,
99 'loopCount' => $loopCount,
100 'duration' => $duration
101 );
102
103 }
104 }