MediaWiki
REL1_22
|
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 00082 function getExif( $filename, $byteOrder ) { 00083 global $wgShowEXIF; 00084 if ( file_exists( $filename ) && $wgShowEXIF ) { 00085 $exif = new Exif( $filename, $byteOrder ); 00086 $data = $exif->getFilteredData(); 00087 if ( $data ) { 00088 $this->addMetadata( $data, 'exif' ); 00089 } 00090 } 00091 } 00098 function addMetadata( $metaArray, $type = 'other' ) { 00099 if ( isset( $this->metadata[$type] ) ) { 00100 /* merge with old data */ 00101 $metaArray = $metaArray + $this->metadata[$type]; 00102 } 00103 00104 $this->metadata[$type] = $metaArray; 00105 } 00106 00116 function getMetadataArray() { 00117 // this seems a bit ugly... This is all so its merged in right order 00118 // based on the MWG recomendation. 00119 $temp = Array(); 00120 krsort( $this->metaPriority ); 00121 foreach ( $this->metaPriority as $pri ) { 00122 foreach ( $pri as $type ) { 00123 if ( isset( $this->metadata[$type] ) ) { 00124 // Do some special casing for multilingual values. 00125 // Don't discard translations if also as a simple value. 00126 foreach ( $this->metadata[$type] as $itemName => $item ) { 00127 if ( is_array( $item ) && isset( $item['_type'] ) && $item['_type'] === 'lang' ) { 00128 if ( isset( $temp[$itemName] ) && !is_array( $temp[$itemName] ) ) { 00129 $default = $temp[$itemName]; 00130 $temp[$itemName] = $item; 00131 $temp[$itemName]['x-default'] = $default; 00132 unset( $this->metadata[$type][$itemName] ); 00133 } 00134 } 00135 } 00136 00137 $temp = $temp + $this->metadata[$type]; 00138 } 00139 } 00140 } 00141 return $temp; 00142 } 00143 00150 static function Jpeg( $filename ) { 00151 $showXMP = function_exists( 'xml_parser_create_ns' ); 00152 $meta = new self(); 00153 00154 $seg = JpegMetadataExtractor::segmentSplitter( $filename ); 00155 if ( isset( $seg['COM'] ) && isset( $seg['COM'][0] ) ) { 00156 $meta->addMetadata( Array( 'JPEGFileComment' => $seg['COM'] ), 'native' ); 00157 } 00158 if ( isset( $seg['PSIR'] ) && count( $seg['PSIR'] ) > 0 ) { 00159 foreach ( $seg['PSIR'] as $curPSIRValue ) { 00160 $meta->doApp13( $curPSIRValue ); 00161 } 00162 } 00163 if ( isset( $seg['XMP'] ) && $showXMP ) { 00164 $xmp = new XMPReader(); 00165 $xmp->parse( $seg['XMP'] ); 00166 foreach ( $seg['XMP_ext'] as $xmpExt ) { 00167 /* Support for extended xmp in jpeg files 00168 * is not well tested and a bit fragile. 00169 */ 00170 $xmp->parseExtended( $xmpExt ); 00171 00172 } 00173 $res = $xmp->getResults(); 00174 foreach ( $res as $type => $array ) { 00175 $meta->addMetadata( $array, $type ); 00176 } 00177 } 00178 if ( isset( $seg['byteOrder'] ) ) { 00179 $meta->getExif( $filename, $seg['byteOrder'] ); 00180 } 00181 return $meta->getMetadataArray(); 00182 } 00183 00192 public static function PNG( $filename ) { 00193 $showXMP = function_exists( 'xml_parser_create_ns' ); 00194 00195 $meta = new self(); 00196 $array = PNGMetadataExtractor::getMetadata( $filename ); 00197 if ( isset( $array['text']['xmp']['x-default'] ) && $array['text']['xmp']['x-default'] !== '' && $showXMP ) { 00198 $xmp = new XMPReader(); 00199 $xmp->parse( $array['text']['xmp']['x-default'] ); 00200 $xmpRes = $xmp->getResults(); 00201 foreach ( $xmpRes as $type => $xmpSection ) { 00202 $meta->addMetadata( $xmpSection, $type ); 00203 } 00204 } 00205 unset( $array['text']['xmp'] ); 00206 $meta->addMetadata( $array['text'], 'native' ); 00207 unset( $array['text'] ); 00208 $array['metadata'] = $meta->getMetadataArray(); 00209 $array['metadata']['_MW_PNG_VERSION'] = PNGMetadataExtractor::VERSION; 00210 return $array; 00211 } 00212 00221 public static function GIF( $filename ) { 00222 00223 $meta = new self(); 00224 $baseArray = GIFMetadataExtractor::getMetadata( $filename ); 00225 00226 if ( count( $baseArray['comment'] ) > 0 ) { 00227 $meta->addMetadata( array( 'GIFFileComment' => $baseArray['comment'] ), 'native' ); 00228 } 00229 00230 if ( $baseArray['xmp'] !== '' && function_exists( 'xml_parser_create_ns' ) ) { 00231 $xmp = new XMPReader(); 00232 $xmp->parse( $baseArray['xmp'] ); 00233 $xmpRes = $xmp->getResults(); 00234 foreach ( $xmpRes as $type => $xmpSection ) { 00235 $meta->addMetadata( $xmpSection, $type ); 00236 } 00237 00238 } 00239 00240 unset( $baseArray['comment'] ); 00241 unset( $baseArray['xmp'] ); 00242 00243 $baseArray['metadata'] = $meta->getMetadataArray(); 00244 $baseArray['metadata']['_MW_GIF_VERSION'] = GIFMetadataExtractor::VERSION; 00245 return $baseArray; 00246 } 00247 00262 public static 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 ) { 00290 return false; 00291 } 00292 $head = fread( $fh, 2 ); 00293 fclose( $fh ); 00294 00295 switch ( $head ) { 00296 case 'II': 00297 return 'LE'; // II for intel. 00298 case 'MM': 00299 return 'BE'; // MM for motorla. 00300 default: 00301 return false; // Something went wrong. 00302 00303 } 00304 } 00305 }