MediaWiki
REL1_24
|
00001 <?php 00034 class BitmapMetadataHandler { 00036 private $metadata = array(); 00037 00039 private $metaPriority = array( 00040 20 => array( 'other' ), 00041 40 => array( 'native' ), 00042 60 => array( 'iptc-good-hash', 'iptc-no-hash' ), 00043 70 => array( 'xmp-deprecated' ), 00044 80 => array( 'xmp-general' ), 00045 90 => array( 'xmp-exif' ), 00046 100 => array( 'iptc-bad-hash' ), 00047 120 => array( 'exif' ), 00048 ); 00049 00051 private $iptcType = 'iptc-no-hash'; 00052 00061 private function doApp13( $app13 ) { 00062 try { 00063 $this->iptcType = JpegMetadataExtractor::doPSIR( $app13 ); 00064 } catch ( MWException $e ) { 00065 // Error reading the iptc hash information. 00066 // This probably means the App13 segment is something other than what we expect. 00067 // However, still try to read it, and treat it as if the hash didn't exist. 00068 wfDebug( "Error parsing iptc data of file: " . $e->getMessage() . "\n" ); 00069 $this->iptcType = 'iptc-no-hash'; 00070 } 00071 00072 $iptc = IPTC::parse( $app13 ); 00073 $this->addMetadata( $iptc, $this->iptcType ); 00074 } 00075 00086 function getExif( $filename, $byteOrder ) { 00087 global $wgShowEXIF; 00088 if ( file_exists( $filename ) && $wgShowEXIF ) { 00089 $exif = new Exif( $filename, $byteOrder ); 00090 $data = $exif->getFilteredData(); 00091 if ( $data ) { 00092 $this->addMetadata( $data, 'exif' ); 00093 } 00094 } 00095 } 00096 00103 function addMetadata( $metaArray, $type = 'other' ) { 00104 if ( isset( $this->metadata[$type] ) ) { 00105 /* merge with old data */ 00106 $metaArray = $metaArray + $this->metadata[$type]; 00107 } 00108 00109 $this->metadata[$type] = $metaArray; 00110 } 00111 00121 function getMetadataArray() { 00122 // this seems a bit ugly... This is all so its merged in right order 00123 // based on the MWG recomendation. 00124 $temp = array(); 00125 krsort( $this->metaPriority ); 00126 foreach ( $this->metaPriority as $pri ) { 00127 foreach ( $pri as $type ) { 00128 if ( isset( $this->metadata[$type] ) ) { 00129 // Do some special casing for multilingual values. 00130 // Don't discard translations if also as a simple value. 00131 foreach ( $this->metadata[$type] as $itemName => $item ) { 00132 if ( is_array( $item ) && isset( $item['_type'] ) && $item['_type'] === 'lang' ) { 00133 if ( isset( $temp[$itemName] ) && !is_array( $temp[$itemName] ) ) { 00134 $default = $temp[$itemName]; 00135 $temp[$itemName] = $item; 00136 $temp[$itemName]['x-default'] = $default; 00137 unset( $this->metadata[$type][$itemName] ); 00138 } 00139 } 00140 } 00141 00142 $temp = $temp + $this->metadata[$type]; 00143 } 00144 } 00145 } 00146 00147 return $temp; 00148 } 00149 00156 static function Jpeg( $filename ) { 00157 $showXMP = function_exists( 'xml_parser_create_ns' ); 00158 $meta = new self(); 00159 00160 $seg = JpegMetadataExtractor::segmentSplitter( $filename ); 00161 if ( isset( $seg['COM'] ) && isset( $seg['COM'][0] ) ) { 00162 $meta->addMetadata( array( 'JPEGFileComment' => $seg['COM'] ), 'native' ); 00163 } 00164 if ( isset( $seg['PSIR'] ) && count( $seg['PSIR'] ) > 0 ) { 00165 foreach ( $seg['PSIR'] as $curPSIRValue ) { 00166 $meta->doApp13( $curPSIRValue ); 00167 } 00168 } 00169 if ( isset( $seg['XMP'] ) && $showXMP ) { 00170 $xmp = new XMPReader(); 00171 $xmp->parse( $seg['XMP'] ); 00172 foreach ( $seg['XMP_ext'] as $xmpExt ) { 00173 /* Support for extended xmp in jpeg files 00174 * is not well tested and a bit fragile. 00175 */ 00176 $xmp->parseExtended( $xmpExt ); 00177 } 00178 $res = $xmp->getResults(); 00179 foreach ( $res as $type => $array ) { 00180 $meta->addMetadata( $array, $type ); 00181 } 00182 } 00183 if ( isset( $seg['byteOrder'] ) ) { 00184 $meta->getExif( $filename, $seg['byteOrder'] ); 00185 } 00186 00187 return $meta->getMetadataArray(); 00188 } 00189 00198 public static function PNG( $filename ) { 00199 $showXMP = function_exists( 'xml_parser_create_ns' ); 00200 00201 $meta = new self(); 00202 $array = PNGMetadataExtractor::getMetadata( $filename ); 00203 if ( isset( $array['text']['xmp']['x-default'] ) 00204 && $array['text']['xmp']['x-default'] !== '' && $showXMP 00205 ) { 00206 $xmp = new XMPReader(); 00207 $xmp->parse( $array['text']['xmp']['x-default'] ); 00208 $xmpRes = $xmp->getResults(); 00209 foreach ( $xmpRes as $type => $xmpSection ) { 00210 $meta->addMetadata( $xmpSection, $type ); 00211 } 00212 } 00213 unset( $array['text']['xmp'] ); 00214 $meta->addMetadata( $array['text'], 'native' ); 00215 unset( $array['text'] ); 00216 $array['metadata'] = $meta->getMetadataArray(); 00217 $array['metadata']['_MW_PNG_VERSION'] = PNGMetadataExtractor::VERSION; 00218 00219 return $array; 00220 } 00221 00230 public static function GIF( $filename ) { 00231 00232 $meta = new self(); 00233 $baseArray = GIFMetadataExtractor::getMetadata( $filename ); 00234 00235 if ( count( $baseArray['comment'] ) > 0 ) { 00236 $meta->addMetadata( array( 'GIFFileComment' => $baseArray['comment'] ), 'native' ); 00237 } 00238 00239 if ( $baseArray['xmp'] !== '' && function_exists( 'xml_parser_create_ns' ) ) { 00240 $xmp = new XMPReader(); 00241 $xmp->parse( $baseArray['xmp'] ); 00242 $xmpRes = $xmp->getResults(); 00243 foreach ( $xmpRes as $type => $xmpSection ) { 00244 $meta->addMetadata( $xmpSection, $type ); 00245 } 00246 } 00247 00248 unset( $baseArray['comment'] ); 00249 unset( $baseArray['xmp'] ); 00250 00251 $baseArray['metadata'] = $meta->getMetadataArray(); 00252 $baseArray['metadata']['_MW_GIF_VERSION'] = GIFMetadataExtractor::VERSION; 00253 00254 return $baseArray; 00255 } 00256 00270 public static function Tiff( $filename ) { 00271 if ( file_exists( $filename ) ) { 00272 $byteOrder = self::getTiffByteOrder( $filename ); 00273 if ( !$byteOrder ) { 00274 throw new MWException( "Error determining byte order of $filename" ); 00275 } 00276 $exif = new Exif( $filename, $byteOrder ); 00277 $data = $exif->getFilteredData(); 00278 if ( $data ) { 00279 $data['MEDIAWIKI_EXIF_VERSION'] = Exif::version(); 00280 00281 return $data; 00282 } else { 00283 throw new MWException( "Could not extract data from tiff file $filename" ); 00284 } 00285 } else { 00286 throw new MWException( "File doesn't exist - $filename" ); 00287 } 00288 } 00289 00297 static function getTiffByteOrder( $filename ) { 00298 $fh = fopen( $filename, 'rb' ); 00299 if ( !$fh ) { 00300 return false; 00301 } 00302 $head = fread( $fh, 2 ); 00303 fclose( $fh ); 00304 00305 switch ( $head ) { 00306 case 'II': 00307 return 'LE'; // II for intel. 00308 case 'MM': 00309 return 'BE'; // MM for motorla. 00310 default: 00311 return false; // Something went wrong. 00312 00313 } 00314 } 00315 }