Merge "(bug 43915) Implement deleteEqualMessages.php"
[lhc/web/wiklou.git] / includes / media / BitmapMetadataHandler.php
index 2a512f7..55deef0 100644 (file)
@@ -1,13 +1,36 @@
 <?php
 /**
-Class to deal with reconciling and extracting metadata from bitmap images.
-This is meant to comply with http://www.metadataworkinggroup.org/pdf/mwg_guidance.pdf
+ * Extraction of metadata from different bitmap image types.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Media
+ */
 
-This sort of acts as an intermediary between MediaHandler::getMetadata
-and the various metadata extractors.
-
-@todo other image formats.
-*/
+/**
+ * Class to deal with reconciling and extracting metadata from bitmap images.
+ * This is meant to comply with http://www.metadataworkinggroup.org/pdf/mwg_guidance.pdf
+ *
+ * This sort of acts as an intermediary between MediaHandler::getMetadata
+ * and the various metadata extractors.
+ *
+ * @todo other image formats.
+ * @ingroup Media
+ */
 class BitmapMetadataHandler {
 
        private $metadata = array();
@@ -32,7 +55,15 @@ class BitmapMetadataHandler {
        * @param String $app13 String containing app13 block from jpeg file
        */
        private function doApp13 ( $app13 ) {
-               $this->iptcType = JpegMetadataExtractor::doPSIR( $app13 );
+               try {
+                       $this->iptcType = JpegMetadataExtractor::doPSIR( $app13 );
+               } catch ( MWException $e ) {
+                       // Error reading the iptc hash information.
+                       // This probably means the App13 segment is something other than what we expect.
+                       // However, still try to read it, and treat it as if the hash didn't exist.
+                       wfDebug( "Error parsing iptc data of file: " . $e->getMessage() . "\n" );
+                       $this->iptcType = 'iptc-no-hash';
+               }
 
                $iptc = IPTC::parse( $app13 );
                $this->addMetadata( $iptc, $this->iptcType );
@@ -40,16 +71,19 @@ class BitmapMetadataHandler {
 
 
        /**
-        *
-        * get exif info using exif class.
+        * Get exif info using exif class.
         * Basically what used to be in BitmapHandler::getMetadata().
         * Just calls stuff in the Exif class.
         *
+        * Parameters are passed to the Exif class.
+        *
         * @param $filename string
+        * @param $byteOrder string
         */
-       function getExif ( $filename ) {
-               if ( file_exists( $filename ) ) {
-                       $exif = new Exif( $filename );
+       function getExif ( $filename, $byteOrder ) {
+               global $wgShowEXIF;
+               if ( file_exists( $filename ) && $wgShowEXIF ) {
+                       $exif = new Exif( $filename, $byteOrder );
                        $data = $exif->getFilteredData();
                        if ( $data ) {
                                $this->addMetadata( $data, 'exif' );
@@ -109,22 +143,23 @@ class BitmapMetadataHandler {
        }
 
        /** Main entry point for jpeg's.
-       *
-       * @param string $file filename (with full path)
-       * @return metadata result array.
-       * @throws MWException on invalid file.
-       */
+        *
+        * @param $filename string filename (with full path)
+        * @return array metadata result array.
+        * @throws MWException on invalid file.
+        */
        static function Jpeg ( $filename ) {
                $showXMP = function_exists( 'xml_parser_create_ns' );
                $meta = new self();
-               $meta->getExif( $filename );
 
                $seg = JpegMetadataExtractor::segmentSplitter( $filename );
                if ( isset( $seg['COM'] ) && isset( $seg['COM'][0] ) ) {
                        $meta->addMetadata( Array( 'JPEGFileComment' => $seg['COM'] ), 'native' );
                }
-               if ( isset( $seg['PSIR'] ) ) {
-                       $meta->doApp13( $seg['PSIR'] );
+               if ( isset( $seg['PSIR'] ) && count( $seg['PSIR'] ) > 0 ) {
+                       foreach( $seg['PSIR'] as $curPSIRValue ) {
+                               $meta->doApp13( $curPSIRValue );
+                       }
                }
                if ( isset( $seg['XMP'] ) && $showXMP ) {
                        $xmp = new XMPReader();
@@ -141,17 +176,21 @@ class BitmapMetadataHandler {
                                $meta->addMetadata( $array, $type );
                        }
                }
+               if ( isset( $seg['byteOrder'] ) ) {
+                       $meta->getExif( $filename, $seg['byteOrder'] );
+               }
                return $meta->getMetadataArray();
        }
+
        /** Entry point for png
-       * At some point in the future this might
-       * merge the png various tEXt chunks to that
-       * are interesting, but for now it only does XMP
-       *
-       * @param $filename String full path to file
-       * @return Array Array for storage in img_metadata.
-       */
-       static public function PNG ( $filename ) {
+        * At some point in the future this might
+        * merge the png various tEXt chunks to that
+        * are interesting, but for now it only does XMP
+        *
+        * @param $filename String full path to file
+        * @return Array Array for storage in img_metadata.
+        */
+       public static function PNG ( $filename ) {
                $showXMP = function_exists( 'xml_parser_create_ns' );
 
                $meta = new self();
@@ -177,10 +216,10 @@ class BitmapMetadataHandler {
         * They don't really have native metadata, so just merges together
         * XMP and image comment.
         *
-        * @param $filename full path to file
+        * @param $filename string full path to file
         * @return Array metadata array
         */
-       static public function GIF ( $filename ) {
+       public static function GIF ( $filename ) {
 
                $meta = new self();
                $baseArray = GIFMetadataExtractor::getMetadata( $filename );
@@ -201,10 +240,67 @@ class BitmapMetadataHandler {
 
                unset( $baseArray['comment'] );
                unset( $baseArray['xmp'] );
-       
+
                $baseArray['metadata'] = $meta->getMetadataArray();
                $baseArray['metadata']['_MW_GIF_VERSION'] = GIFMetadataExtractor::VERSION;
                return $baseArray;
        }
 
+       /**
+        * This doesn't do much yet, but eventually I plan to add
+        * XMP support for Tiff. (PHP's exif support already extracts
+        * but needs some further processing because PHP's exif support
+        * is stupid...)
+        *
+        * @todo Add XMP support, so this function actually makes
+        * sense to put here.
+        *
+        * The various exceptions this throws are caught later.
+        * @param $filename String
+        * @throws MWException
+        * @return Array The metadata.
+        */
+       public static function Tiff ( $filename ) {
+               if ( file_exists( $filename ) ) {
+                       $byteOrder = self::getTiffByteOrder( $filename );
+                       if ( !$byteOrder ) {
+                               throw new MWException( "Error determining byte order of $filename" );
+                       }
+                       $exif = new Exif( $filename, $byteOrder );
+                       $data = $exif->getFilteredData();
+                       if ( $data ) {
+                               $data['MEDIAWIKI_EXIF_VERSION'] = Exif::version();
+                               return $data;
+                       } else {
+                               throw new MWException( "Could not extract data from tiff file $filename" );
+                       }
+               } else {
+                       throw new MWException( "File doesn't exist - $filename" );
+               }
+       }
+       /**
+        * Read the first 2 bytes of a tiff file to figure out
+        * Little Endian or Big Endian. Needed for exif stuff.
+        *
+        * @param $filename String The filename
+        * @return String 'BE' or 'LE' or false
+        */
+       static function getTiffByteOrder( $filename ) {
+               $fh = fopen( $filename, 'rb' );
+               if ( !$fh ) return false;
+               $head = fread( $fh, 2 );
+               fclose( $fh );
+
+               switch( $head ) {
+                       case 'II':
+                               return 'LE'; // II for intel.
+                       case 'MM':
+                               return 'BE'; // MM for motorla.
+                       default:
+                               return false; // Something went wrong.
+
+               }
+       }
+
+
 }