MediaWiki
REL1_19
|
00001 <?php 00011 class BitmapMetadataHandler { 00012 00013 private $metadata = array(); 00014 private $metaPriority = array( 00015 20 => array( 'other' ), 00016 40 => array( 'native' ), 00017 60 => array( 'iptc-good-hash', 'iptc-no-hash' ), 00018 70 => array( 'xmp-deprecated' ), 00019 80 => array( 'xmp-general' ), 00020 90 => array( 'xmp-exif' ), 00021 100 => array( 'iptc-bad-hash' ), 00022 120 => array( 'exif' ), 00023 ); 00024 private $iptcType = 'iptc-no-hash'; 00025 00034 private function doApp13 ( $app13 ) { 00035 try { 00036 $this->iptcType = JpegMetadataExtractor::doPSIR( $app13 ); 00037 } catch ( MWException $e ) { 00038 // Error reading the iptc hash information. 00039 // This probably means the App13 segment is something other than what we expect. 00040 // However, still try to read it, and treat it as if the hash didn't exist. 00041 wfDebug( "Error parsing iptc data of file: " . $e->getMessage() . "\n" ); 00042 $this->iptcType = 'iptc-no-hash'; 00043 } 00044 00045 $iptc = IPTC::parse( $app13 ); 00046 $this->addMetadata( $iptc, $this->iptcType ); 00047 } 00048 00049 00060 function getExif ( $filename, $byteOrder ) { 00061 global $wgShowEXIF; 00062 if ( file_exists( $filename ) && $wgShowEXIF ) { 00063 $exif = new Exif( $filename, $byteOrder ); 00064 $data = $exif->getFilteredData(); 00065 if ( $data ) { 00066 $this->addMetadata( $data, 'exif' ); 00067 } 00068 } 00069 } 00076 function addMetadata ( $metaArray, $type = 'other' ) { 00077 if ( isset( $this->metadata[$type] ) ) { 00078 /* merge with old data */ 00079 $metaArray = $metaArray + $this->metadata[$type]; 00080 } 00081 00082 $this->metadata[$type] = $metaArray; 00083 } 00084 00094 function getMetadataArray () { 00095 // this seems a bit ugly... This is all so its merged in right order 00096 // based on the MWG recomendation. 00097 $temp = Array(); 00098 krsort( $this->metaPriority ); 00099 foreach ( $this->metaPriority as $pri ) { 00100 foreach ( $pri as $type ) { 00101 if ( isset( $this->metadata[$type] ) ) { 00102 // Do some special casing for multilingual values. 00103 // Don't discard translations if also as a simple value. 00104 foreach ( $this->metadata[$type] as $itemName => $item ) { 00105 if ( is_array( $item ) && isset( $item['_type'] ) && $item['_type'] === 'lang' ) { 00106 if ( isset( $temp[$itemName] ) && !is_array( $temp[$itemName] ) ) { 00107 $default = $temp[$itemName]; 00108 $temp[$itemName] = $item; 00109 $temp[$itemName]['x-default'] = $default; 00110 unset( $this->metadata[$type][$itemName] ); 00111 } 00112 } 00113 } 00114 00115 $temp = $temp + $this->metadata[$type]; 00116 } 00117 } 00118 } 00119 return $temp; 00120 } 00121 00128 static function Jpeg ( $filename ) { 00129 $showXMP = function_exists( 'xml_parser_create_ns' ); 00130 $meta = new self(); 00131 00132 $seg = JpegMetadataExtractor::segmentSplitter( $filename ); 00133 if ( isset( $seg['COM'] ) && isset( $seg['COM'][0] ) ) { 00134 $meta->addMetadata( Array( 'JPEGFileComment' => $seg['COM'] ), 'native' ); 00135 } 00136 if ( isset( $seg['PSIR'] ) && count( $seg['PSIR'] ) > 0 ) { 00137 foreach( $seg['PSIR'] as $curPSIRValue ) { 00138 $meta->doApp13( $curPSIRValue ); 00139 } 00140 } 00141 if ( isset( $seg['XMP'] ) && $showXMP ) { 00142 $xmp = new XMPReader(); 00143 $xmp->parse( $seg['XMP'] ); 00144 foreach ( $seg['XMP_ext'] as $xmpExt ) { 00145 /* Support for extended xmp in jpeg files 00146 * is not well tested and a bit fragile. 00147 */ 00148 $xmp->parseExtended( $xmpExt ); 00149 00150 } 00151 $res = $xmp->getResults(); 00152 foreach ( $res as $type => $array ) { 00153 $meta->addMetadata( $array, $type ); 00154 } 00155 } 00156 if ( isset( $seg['byteOrder'] ) ) { 00157 $meta->getExif( $filename, $seg['byteOrder'] ); 00158 } 00159 return $meta->getMetadataArray(); 00160 } 00161 00170 static public function PNG ( $filename ) { 00171 $showXMP = function_exists( 'xml_parser_create_ns' ); 00172 00173 $meta = new self(); 00174 $array = PNGMetadataExtractor::getMetadata( $filename ); 00175 if ( isset( $array['text']['xmp']['x-default'] ) && $array['text']['xmp']['x-default'] !== '' && $showXMP ) { 00176 $xmp = new XMPReader(); 00177 $xmp->parse( $array['text']['xmp']['x-default'] ); 00178 $xmpRes = $xmp->getResults(); 00179 foreach ( $xmpRes as $type => $xmpSection ) { 00180 $meta->addMetadata( $xmpSection, $type ); 00181 } 00182 } 00183 unset( $array['text']['xmp'] ); 00184 $meta->addMetadata( $array['text'], 'native' ); 00185 unset( $array['text'] ); 00186 $array['metadata'] = $meta->getMetadataArray(); 00187 $array['metadata']['_MW_PNG_VERSION'] = PNGMetadataExtractor::VERSION; 00188 return $array; 00189 } 00190 00199 static public function GIF ( $filename ) { 00200 00201 $meta = new self(); 00202 $baseArray = GIFMetadataExtractor::getMetadata( $filename ); 00203 00204 if ( count( $baseArray['comment'] ) > 0 ) { 00205 $meta->addMetadata( array( 'GIFFileComment' => $baseArray['comment'] ), 'native' ); 00206 } 00207 00208 if ( $baseArray['xmp'] !== '' && function_exists( 'xml_parser_create_ns' ) ) { 00209 $xmp = new XMPReader(); 00210 $xmp->parse( $baseArray['xmp'] ); 00211 $xmpRes = $xmp->getResults(); 00212 foreach ( $xmpRes as $type => $xmpSection ) { 00213 $meta->addMetadata( $xmpSection, $type ); 00214 } 00215 00216 } 00217 00218 unset( $baseArray['comment'] ); 00219 unset( $baseArray['xmp'] ); 00220 00221 $baseArray['metadata'] = $meta->getMetadataArray(); 00222 $baseArray['metadata']['_MW_GIF_VERSION'] = GIFMetadataExtractor::VERSION; 00223 return $baseArray; 00224 } 00225 00239 static public function Tiff ( $filename ) { 00240 if ( file_exists( $filename ) ) { 00241 $byteOrder = self::getTiffByteOrder( $filename ); 00242 if ( !$byteOrder ) { 00243 throw new MWException( "Error determining byte order of $filename" ); 00244 } 00245 $exif = new Exif( $filename, $byteOrder ); 00246 $data = $exif->getFilteredData(); 00247 if ( $data ) { 00248 $data['MEDIAWIKI_EXIF_VERSION'] = Exif::version(); 00249 return $data; 00250 } else { 00251 throw new MWException( "Could not extract data from tiff file $filename" ); 00252 } 00253 } else { 00254 throw new MWException( "File doesn't exist - $filename" ); 00255 } 00256 } 00264 static function getTiffByteOrder( $filename ) { 00265 $fh = fopen( $filename, 'rb' ); 00266 if ( !$fh ) return false; 00267 $head = fread( $fh, 2 ); 00268 fclose( $fh ); 00269 00270 switch( $head ) { 00271 case 'II': 00272 return 'LE'; // II for intel. 00273 case 'MM': 00274 return 'BE'; // MM for motorla. 00275 default: 00276 return false; // Something went wrong. 00277 00278 } 00279 } 00280 00281 00282 }