MediaWiki
REL1_20
|
00001 <?php 00034 class BitmapMetadataHandler { 00035 00036 private $metadata = array(); 00037 private $metaPriority = array( 00038 20 => array( 'other' ), 00039 40 => array( 'native' ), 00040 60 => array( 'iptc-good-hash', 'iptc-no-hash' ), 00041 70 => array( 'xmp-deprecated' ), 00042 80 => array( 'xmp-general' ), 00043 90 => array( 'xmp-exif' ), 00044 100 => array( 'iptc-bad-hash' ), 00045 120 => array( 'exif' ), 00046 ); 00047 private $iptcType = 'iptc-no-hash'; 00048 00057 private function doApp13 ( $app13 ) { 00058 try { 00059 $this->iptcType = JpegMetadataExtractor::doPSIR( $app13 ); 00060 } catch ( MWException $e ) { 00061 // Error reading the iptc hash information. 00062 // This probably means the App13 segment is something other than what we expect. 00063 // However, still try to read it, and treat it as if the hash didn't exist. 00064 wfDebug( "Error parsing iptc data of file: " . $e->getMessage() . "\n" ); 00065 $this->iptcType = 'iptc-no-hash'; 00066 } 00067 00068 $iptc = IPTC::parse( $app13 ); 00069 $this->addMetadata( $iptc, $this->iptcType ); 00070 } 00071 00072 00083 function getExif ( $filename, $byteOrder ) { 00084 global $wgShowEXIF; 00085 if ( file_exists( $filename ) && $wgShowEXIF ) { 00086 $exif = new Exif( $filename, $byteOrder ); 00087 $data = $exif->getFilteredData(); 00088 if ( $data ) { 00089 $this->addMetadata( $data, 'exif' ); 00090 } 00091 } 00092 } 00099 function addMetadata ( $metaArray, $type = 'other' ) { 00100 if ( isset( $this->metadata[$type] ) ) { 00101 /* merge with old data */ 00102 $metaArray = $metaArray + $this->metadata[$type]; 00103 } 00104 00105 $this->metadata[$type] = $metaArray; 00106 } 00107 00117 function getMetadataArray () { 00118 // this seems a bit ugly... This is all so its merged in right order 00119 // based on the MWG recomendation. 00120 $temp = Array(); 00121 krsort( $this->metaPriority ); 00122 foreach ( $this->metaPriority as $pri ) { 00123 foreach ( $pri as $type ) { 00124 if ( isset( $this->metadata[$type] ) ) { 00125 // Do some special casing for multilingual values. 00126 // Don't discard translations if also as a simple value. 00127 foreach ( $this->metadata[$type] as $itemName => $item ) { 00128 if ( is_array( $item ) && isset( $item['_type'] ) && $item['_type'] === 'lang' ) { 00129 if ( isset( $temp[$itemName] ) && !is_array( $temp[$itemName] ) ) { 00130 $default = $temp[$itemName]; 00131 $temp[$itemName] = $item; 00132 $temp[$itemName]['x-default'] = $default; 00133 unset( $this->metadata[$type][$itemName] ); 00134 } 00135 } 00136 } 00137 00138 $temp = $temp + $this->metadata[$type]; 00139 } 00140 } 00141 } 00142 return $temp; 00143 } 00144 00151 static function Jpeg ( $filename ) { 00152 $showXMP = function_exists( 'xml_parser_create_ns' ); 00153 $meta = new self(); 00154 00155 $seg = JpegMetadataExtractor::segmentSplitter( $filename ); 00156 if ( isset( $seg['COM'] ) && isset( $seg['COM'][0] ) ) { 00157 $meta->addMetadata( Array( 'JPEGFileComment' => $seg['COM'] ), 'native' ); 00158 } 00159 if ( isset( $seg['PSIR'] ) && count( $seg['PSIR'] ) > 0 ) { 00160 foreach( $seg['PSIR'] as $curPSIRValue ) { 00161 $meta->doApp13( $curPSIRValue ); 00162 } 00163 } 00164 if ( isset( $seg['XMP'] ) && $showXMP ) { 00165 $xmp = new XMPReader(); 00166 $xmp->parse( $seg['XMP'] ); 00167 foreach ( $seg['XMP_ext'] as $xmpExt ) { 00168 /* Support for extended xmp in jpeg files 00169 * is not well tested and a bit fragile. 00170 */ 00171 $xmp->parseExtended( $xmpExt ); 00172 00173 } 00174 $res = $xmp->getResults(); 00175 foreach ( $res as $type => $array ) { 00176 $meta->addMetadata( $array, $type ); 00177 } 00178 } 00179 if ( isset( $seg['byteOrder'] ) ) { 00180 $meta->getExif( $filename, $seg['byteOrder'] ); 00181 } 00182 return $meta->getMetadataArray(); 00183 } 00184 00193 static public function PNG ( $filename ) { 00194 $showXMP = function_exists( 'xml_parser_create_ns' ); 00195 00196 $meta = new self(); 00197 $array = PNGMetadataExtractor::getMetadata( $filename ); 00198 if ( isset( $array['text']['xmp']['x-default'] ) && $array['text']['xmp']['x-default'] !== '' && $showXMP ) { 00199 $xmp = new XMPReader(); 00200 $xmp->parse( $array['text']['xmp']['x-default'] ); 00201 $xmpRes = $xmp->getResults(); 00202 foreach ( $xmpRes as $type => $xmpSection ) { 00203 $meta->addMetadata( $xmpSection, $type ); 00204 } 00205 } 00206 unset( $array['text']['xmp'] ); 00207 $meta->addMetadata( $array['text'], 'native' ); 00208 unset( $array['text'] ); 00209 $array['metadata'] = $meta->getMetadataArray(); 00210 $array['metadata']['_MW_PNG_VERSION'] = PNGMetadataExtractor::VERSION; 00211 return $array; 00212 } 00213 00222 static public function GIF ( $filename ) { 00223 00224 $meta = new self(); 00225 $baseArray = GIFMetadataExtractor::getMetadata( $filename ); 00226 00227 if ( count( $baseArray['comment'] ) > 0 ) { 00228 $meta->addMetadata( array( 'GIFFileComment' => $baseArray['comment'] ), 'native' ); 00229 } 00230 00231 if ( $baseArray['xmp'] !== '' && function_exists( 'xml_parser_create_ns' ) ) { 00232 $xmp = new XMPReader(); 00233 $xmp->parse( $baseArray['xmp'] ); 00234 $xmpRes = $xmp->getResults(); 00235 foreach ( $xmpRes as $type => $xmpSection ) { 00236 $meta->addMetadata( $xmpSection, $type ); 00237 } 00238 00239 } 00240 00241 unset( $baseArray['comment'] ); 00242 unset( $baseArray['xmp'] ); 00243 00244 $baseArray['metadata'] = $meta->getMetadataArray(); 00245 $baseArray['metadata']['_MW_GIF_VERSION'] = GIFMetadataExtractor::VERSION; 00246 return $baseArray; 00247 } 00248 00262 static public function Tiff ( $filename ) { 00263 if ( file_exists( $filename ) ) { 00264 $byteOrder = self::getTiffByteOrder( $filename ); 00265 if ( !$byteOrder ) { 00266 throw new MWException( "Error determining byte order of $filename" ); 00267 } 00268 $exif = new Exif( $filename, $byteOrder ); 00269 $data = $exif->getFilteredData(); 00270 if ( $data ) { 00271 $data['MEDIAWIKI_EXIF_VERSION'] = Exif::version(); 00272 return $data; 00273 } else { 00274 throw new MWException( "Could not extract data from tiff file $filename" ); 00275 } 00276 } else { 00277 throw new MWException( "File doesn't exist - $filename" ); 00278 } 00279 } 00287 static function getTiffByteOrder( $filename ) { 00288 $fh = fopen( $filename, 'rb' ); 00289 if ( !$fh ) return false; 00290 $head = fread( $fh, 2 ); 00291 fclose( $fh ); 00292 00293 switch( $head ) { 00294 case 'II': 00295 return 'LE'; // II for intel. 00296 case 'MM': 00297 return 'BE'; // MM for motorla. 00298 default: 00299 return false; // Something went wrong. 00300 00301 } 00302 } 00303 00304 00305 }