Пример #1
0
 function getMetadata($image, $filename)
 {
     if (!isset($image->parsedGIFMetadata)) {
         try {
             $image->parsedGIFMetadata = GIFMetadataExtractor::getMetadata($filename);
         } catch (Exception $e) {
             // Broken file?
             wfDebug(__METHOD__ . ': ' . $e->getMessage() . "\n");
             return '0';
         }
     }
     return serialize($image->parsedGIFMetadata);
 }
 /**
  * Put in a file, and see if the metadata coming out is as expected.
  * @param $filename String
  * @param $expected Array The extracted metadata.
  * @dataProvider provideGetMetadata
  */
 public function testGetMetadata($filename, $expected)
 {
     $actual = GIFMetadataExtractor::getMetadata($this->mediaPath . $filename);
     $this->assertEquals($expected, $actual);
 }
Пример #3
0
 static function getMetadata($filename)
 {
     self::$gif_frame_sep = pack("C", ord(","));
     self::$gif_extension_sep = pack("C", ord("!"));
     self::$gif_term = pack("C", ord(";"));
     $frameCount = 0;
     $duration = 0.0;
     $isLooped = false;
     if (!$filename) {
         throw new Exception("No file name specified");
     } elseif (!file_exists($filename) || is_dir($filename)) {
         throw new Exception("File {$filename} does not exist");
     }
     $fh = fopen($filename, 'r');
     if (!$fh) {
         throw new Exception("Unable to open file {$filename}");
     }
     // Check for the GIF header
     $buf = fread($fh, 6);
     if (!($buf == 'GIF87a' || $buf == 'GIF89a')) {
         throw new Exception("Not a valid GIF file; header: {$buf}");
     }
     // Skip over width and height.
     fread($fh, 4);
     // Read BPP
     $buf = fread($fh, 1);
     $bpp = self::decodeBPP($buf);
     // Skip over background and aspect ratio
     fread($fh, 2);
     // Skip over the GCT
     self::readGCT($fh, $bpp);
     while (!feof($fh)) {
         $buf = fread($fh, 1);
         if ($buf == self::$gif_frame_sep) {
             // Found a frame
             $frameCount++;
             ## Skip bounding box
             fread($fh, 8);
             ## Read BPP
             $buf = fread($fh, 1);
             $bpp = self::decodeBPP($buf);
             ## Read GCT
             self::readGCT($fh, $bpp);
             fread($fh, 1);
             self::skipBlock($fh);
         } elseif ($buf == self::$gif_extension_sep) {
             $buf = fread($fh, 1);
             $extension_code = unpack('C', $buf);
             $extension_code = $extension_code[1];
             if ($extension_code == 0xf9) {
                 // Graphics Control Extension.
                 fread($fh, 1);
                 // Block size
                 fread($fh, 1);
                 // Transparency, disposal method, user input
                 $buf = fread($fh, 2);
                 // Delay, in hundredths of seconds.
                 $delay = unpack('v', $buf);
                 $delay = $delay[1];
                 $duration += $delay * 0.01;
                 fread($fh, 1);
                 // Transparent colour index
                 $term = fread($fh, 1);
                 // Should be a terminator
                 $term = unpack('C', $term);
                 $term = $term[1];
                 if ($term != 0) {
                     throw new Exception("Malformed Graphics Control Extension block");
                 }
             } elseif ($extension_code == 0xff) {
                 // Application extension (Netscape info about the animated gif)
                 $blockLength = fread($fh, 1);
                 $blockLength = unpack('C', $blockLength);
                 $blockLength = $blockLength[1];
                 $data = fread($fh, $blockLength);
                 // NETSCAPE2.0 (application name)
                 if ($blockLength != 11 || $data != 'NETSCAPE2.0') {
                     fseek($fh, -($blockLength + 1), SEEK_CUR);
                     self::skipBlock($fh);
                     continue;
                 }
                 $data = fread($fh, 2);
                 // Block length and introduction, should be 03 01
                 if ($data != "") {
                     throw new Exception("Expected , got {$data}");
                 }
                 // Unsigned little-endian integer, loop count or zero for "forever"
                 $loopData = fread($fh, 2);
                 $loopData = unpack('v', $loopData);
                 $loopCount = $loopData[1];
                 if ($loopCount != 1) {
                     $isLooped = true;
                 }
                 // Read out terminator byte
                 fread($fh, 1);
             } else {
                 self::skipBlock($fh);
             }
         } elseif ($buf == self::$gif_term) {
             break;
         } else {
             $byte = unpack('C', $buf);
             $byte = $byte[1];
             throw new Exception("At position: " . ftell($fh) . ", Unknown byte " . $byte);
         }
     }
     return array('frameCount' => $frameCount, 'looped' => $isLooped, 'duration' => $duration);
 }
Пример #4
0
 /** function for gif images.
  *
  * They don't really have native metadata, so just merges together
  * XMP and image comment.
  *
  * @param string $filename full path to file
  * @return Array metadata array
  */
 public static function GIF($filename)
 {
     $meta = new self();
     $baseArray = GIFMetadataExtractor::getMetadata($filename);
     if (count($baseArray['comment']) > 0) {
         $meta->addMetadata(array('GIFFileComment' => $baseArray['comment']), 'native');
     }
     if ($baseArray['xmp'] !== '' && function_exists('xml_parser_create_ns')) {
         $xmp = new XMPReader();
         $xmp->parse($baseArray['xmp']);
         $xmpRes = $xmp->getResults();
         foreach ($xmpRes as $type => $xmpSection) {
             $meta->addMetadata($xmpSection, $type);
         }
     }
     unset($baseArray['comment']);
     unset($baseArray['xmp']);
     $baseArray['metadata'] = $meta->getMetadataArray();
     $baseArray['metadata']['_MW_GIF_VERSION'] = GIFMetadataExtractor::VERSION;
     return $baseArray;
 }
 /**
  * @throws Exception
  * @param $filename string
  * @return array
  */
 static function getMetadata($filename)
 {
     self::$gif_frame_sep = pack("C", ord(","));
     self::$gif_extension_sep = pack("C", ord("!"));
     self::$gif_term = pack("C", ord(";"));
     $frameCount = 0;
     $duration = 0.0;
     $isLooped = false;
     $xmp = "";
     $comment = array();
     if (!$filename) {
         throw new Exception("No file name specified");
     } elseif (!file_exists($filename) || is_dir($filename)) {
         throw new Exception("File {$filename} does not exist");
     }
     $fh = fopen($filename, 'rb');
     if (!$fh) {
         throw new Exception("Unable to open file {$filename}");
     }
     // Check for the GIF header
     $buf = fread($fh, 6);
     if (!($buf == 'GIF87a' || $buf == 'GIF89a')) {
         throw new Exception("Not a valid GIF file; header: {$buf}");
     }
     // Skip over width and height.
     fread($fh, 4);
     // Read BPP
     $buf = fread($fh, 1);
     $bpp = self::decodeBPP($buf);
     // Skip over background and aspect ratio
     fread($fh, 2);
     // Skip over the GCT
     self::readGCT($fh, $bpp);
     while (!feof($fh)) {
         $buf = fread($fh, 1);
         if ($buf == self::$gif_frame_sep) {
             // Found a frame
             $frameCount++;
             ## Skip bounding box
             fread($fh, 8);
             ## Read BPP
             $buf = fread($fh, 1);
             $bpp = self::decodeBPP($buf);
             ## Read GCT
             self::readGCT($fh, $bpp);
             fread($fh, 1);
             self::skipBlock($fh);
         } elseif ($buf == self::$gif_extension_sep) {
             $buf = fread($fh, 1);
             if (strlen($buf) < 1) {
                 throw new Exception("Ran out of input");
             }
             $extension_code = unpack('C', $buf);
             $extension_code = $extension_code[1];
             if ($extension_code == 0xf9) {
                 // Graphics Control Extension.
                 fread($fh, 1);
                 // Block size
                 fread($fh, 1);
                 // Transparency, disposal method, user input
                 $buf = fread($fh, 2);
                 // Delay, in hundredths of seconds.
                 if (strlen($buf) < 2) {
                     throw new Exception("Ran out of input");
                 }
                 $delay = unpack('v', $buf);
                 $delay = $delay[1];
                 $duration += $delay * 0.01;
                 fread($fh, 1);
                 // Transparent colour index
                 $term = fread($fh, 1);
                 // Should be a terminator
                 if (strlen($term) < 1) {
                     throw new Exception("Ran out of input");
                 }
                 $term = unpack('C', $term);
                 $term = $term[1];
                 if ($term != 0) {
                     throw new Exception("Malformed Graphics Control Extension block");
                 }
             } elseif ($extension_code == 0xfe) {
                 // Comment block(s).
                 $data = self::readBlock($fh);
                 if ($data === "") {
                     throw new Exception('Read error, zero-length comment block');
                 }
                 // The standard says this should be ASCII, however its unclear if
                 // thats true in practise. Check to see if its valid utf-8, if so
                 // assume its that, otherwise assume its windows-1252 (iso-8859-1)
                 $dataCopy = $data;
                 // quickIsNFCVerify has the side effect of replacing any invalid characters
                 UtfNormal::quickIsNFCVerify($dataCopy);
                 if ($dataCopy !== $data) {
                     wfSuppressWarnings();
                     $data = iconv('windows-1252', 'UTF-8', $data);
                     wfRestoreWarnings();
                 }
                 $commentCount = count($comment);
                 if ($commentCount === 0 || $comment[$commentCount - 1] !== $data) {
                     // Some applications repeat the same comment on each
                     // frame of an animated GIF image, so if this comment
                     // is identical to the last, only extract once.
                     $comment[] = $data;
                 }
             } elseif ($extension_code == 0xff) {
                 // Application extension (Netscape info about the animated gif)
                 // or XMP (or theoretically any other type of extension block)
                 $blockLength = fread($fh, 1);
                 if (strlen($blockLength) < 1) {
                     throw new Exception("Ran out of input");
                 }
                 $blockLength = unpack('C', $blockLength);
                 $blockLength = $blockLength[1];
                 $data = fread($fh, $blockLength);
                 if ($blockLength != 11) {
                     wfDebug(__METHOD__ . ' GIF application block with wrong length');
                     fseek($fh, -($blockLength + 1), SEEK_CUR);
                     self::skipBlock($fh);
                     continue;
                 }
                 // NETSCAPE2.0 (application name for animated gif)
                 if ($data == 'NETSCAPE2.0') {
                     $data = fread($fh, 2);
                     // Block length and introduction, should be 03 01
                     if ($data != "") {
                         throw new Exception("Expected , got {$data}");
                     }
                     // Unsigned little-endian integer, loop count or zero for "forever"
                     $loopData = fread($fh, 2);
                     if (strlen($loopData) < 2) {
                         throw new Exception("Ran out of input");
                     }
                     $loopData = unpack('v', $loopData);
                     $loopCount = $loopData[1];
                     if ($loopCount != 1) {
                         $isLooped = true;
                     }
                     // Read out terminator byte
                     fread($fh, 1);
                 } elseif ($data == 'XMP DataXMP') {
                     // application name for XMP data.
                     // see pg 18 of XMP spec part 3.
                     $xmp = self::readBlock($fh, true);
                     if (substr($xmp, -257, 3) !== "ÿþ" || substr($xmp, -4) !== "") {
                         // this is just a sanity check.
                         throw new Exception("XMP does not have magic trailer!");
                     }
                     // strip out trailer.
                     $xmp = substr($xmp, 0, -257);
                 } else {
                     // unrecognized extension block
                     fseek($fh, -($blockLength + 1), SEEK_CUR);
                     self::skipBlock($fh);
                     continue;
                 }
             } else {
                 self::skipBlock($fh);
             }
         } elseif ($buf == self::$gif_term) {
             break;
         } else {
             if (strlen($buf) < 1) {
                 throw new Exception("Ran out of input");
             }
             $byte = unpack('C', $buf);
             $byte = $byte[1];
             throw new Exception("At position: " . ftell($fh) . ", Unknown byte " . $byte);
         }
     }
     return array('frameCount' => $frameCount, 'looped' => $isLooped, 'duration' => $duration, 'xmp' => $xmp, 'comment' => $comment);
 }
 /** function for gif images.
  *
  * They don't really have native metadata, so just merges together
  * XMP and image comment.
  *
  * @param string $filename Full path to file
  * @return array Metadata array
  */
 public static function GIF($filename)
 {
     $meta = new self();
     $baseArray = GIFMetadataExtractor::getMetadata($filename);
     if (count($baseArray['comment']) > 0) {
         $meta->addMetadata(['GIFFileComment' => $baseArray['comment']], 'native');
     }
     if ($baseArray['xmp'] !== '' && XMPReader::isSupported()) {
         $xmp = new XMPReader(LoggerFactory::getInstance('XMP'));
         $xmp->parse($baseArray['xmp']);
         $xmpRes = $xmp->getResults();
         foreach ($xmpRes as $type => $xmpSection) {
             $meta->addMetadata($xmpSection, $type);
         }
     }
     unset($baseArray['comment']);
     unset($baseArray['xmp']);
     $baseArray['metadata'] = $meta->getMetadataArray();
     $baseArray['metadata']['_MW_GIF_VERSION'] = GIFMetadataExtractor::VERSION;
     return $baseArray;
 }