[ Index ]

PHP Cross Reference of DokuWiki

title

Body

[close]

/inc/ -> JpegMeta.php (source)

   1  <?php
   2  /**
   3   * JPEG metadata reader/writer
   4   *
   5   * @license    PHP license 2.0 (http://www.php.net/license/2_02.txt)
   6   * @link       http://www.zonageek.com/software/php/jpeg/index.php
   7   * @author     Sebastian Delmont <sdelmont@zonageek.com>
   8   * @author     Andreas Gohr <andi@splitbrain.org>
   9   * @author Hakan Sandell <hakan.sandell@mydata.se>
  10   * @todo       Add support for Maker Notes, Extend for GIF and PNG metadata
  11   */
  12  
  13  // This class is a modified and enhanced version of the JPEG class by
  14  // Sebastian Delmont. Original Copyright notice follows:
  15  //
  16  // +----------------------------------------------------------------------+
  17  // | PHP version 4.0                                                      |
  18  // +----------------------------------------------------------------------+
  19  // | Copyright (c) 1997, 1998, 1999, 2000, 2001 The PHP Group             |
  20  // +----------------------------------------------------------------------+
  21  // | This source file is subject to version 2.0 of the PHP license,       |
  22  // | that is bundled with this package in the file LICENSE, and is        |
  23  // | available at through the world-wide-web at                           |
  24  // | http://www.php.net/license/2_02.txt.                                 |
  25  // | If you did not receive a copy of the PHP license and are unable to   |
  26  // | obtain it through the world-wide-web, please send a note to          |
  27  // | license@php.net so we can mail you a copy immediately.               |
  28  // +----------------------------------------------------------------------+
  29  // | Authors: Sebastian Delmont <sdelmont@zonageek.com>                   |
  30  // +----------------------------------------------------------------------+
  31  
  32  class JpegMeta
  33  {
  34      var $_fileName;
  35      var $_fp = null;
  36      var $_type = 'unknown';
  37  
  38      var $_markers;
  39      var $_info;
  40  
  41  
  42      /**
  43       * Constructor
  44       *
  45       * @author Sebastian Delmont <sdelmont@zonageek.com>
  46       */
  47      function JpegMeta($fileName)
  48      {
  49  
  50          $this->_fileName = $fileName;
  51  
  52          $this->_fp = null;
  53          $this->_type = 'unknown';
  54  
  55          unset($this->_info);
  56          unset($this->_markers);
  57      }
  58  
  59      /**
  60       * Returns all gathered info as multidim array
  61       *
  62       * @author Sebastian Delmont <sdelmont@zonageek.com>
  63       */
  64      function & getRawInfo()
  65      {
  66          $this->_parseAll();
  67  
  68          if ($this->_markers == null) {
  69              return false;
  70          }
  71  
  72          return $this->_info;
  73      }
  74  
  75      /**
  76       * Returns basic image info
  77       *
  78       * @author Sebastian Delmont <sdelmont@zonageek.com>
  79       */
  80      function & getBasicInfo()
  81      {
  82          $this->_parseAll();
  83  
  84          $info = array();
  85  
  86          if ($this->_markers == null) {
  87              return false;
  88          }
  89  
  90          $info['Name'] = $this->_info['file']['Name'];
  91          if (isset($this->_info['file']['Url'])) {
  92              $info['Url'] = $this->_info['file']['Url'];
  93              $info['NiceSize'] = "???KB";
  94          }
  95          else {
  96              $info['Size'] = $this->_info['file']['Size'];
  97              $info['NiceSize'] = $this->_info['file']['NiceSize'];
  98          }
  99  
 100          if (@isset($this->_info['sof']['Format'])) {
 101              $info['Format'] = $this->_info['sof']['Format'] . " JPEG";
 102          }
 103          else {
 104              $info['Format'] = $this->_info['sof']['Format'] . " JPEG";
 105          }
 106  
 107          if (@isset($this->_info['sof']['ColorChannels'])) {
 108              $info['ColorMode'] = ($this->_info['sof']['ColorChannels'] > 1) ? "Color" : "B&W";
 109          }
 110  
 111          $info['Width'] = $this->getWidth();
 112          $info['Height'] = $this->getHeight();
 113          $info['DimStr'] = $this->getDimStr();
 114  
 115          $dates = $this->getDates();
 116  
 117          $info['DateTime'] = $dates['EarliestTime'];
 118          $info['DateTimeStr'] = $dates['EarliestTimeStr'];
 119  
 120          $info['HasThumbnail'] = $this->hasThumbnail();
 121  
 122          return $info;
 123      }
 124  
 125  
 126      /**
 127       * Convinience function to access nearly all available Data
 128       * through one function
 129       *
 130       * @author Andreas Gohr <andi@splitbrain.org>
 131       */
 132      function getField($fields)
 133      {
 134          if(!is_array($fields)) $fields = array($fields);
 135          $info = false;
 136          foreach($fields as $field){
 137              if(strtolower(substr($field,0,5)) == 'iptc.'){
 138                  $info = $this->getIPTCField(substr($field,5));
 139              }elseif(strtolower(substr($field,0,5)) == 'exif.'){
 140                  $info = $this->getExifField(substr($field,5));
 141              }elseif(strtolower(substr($field,0,4)) == 'xmp.'){
 142                  $info = $this->getXmpField(substr($field,4));
 143              }elseif(strtolower(substr($field,0,5)) == 'file.'){
 144                  $info = $this->getFileField(substr($field,5));
 145              }elseif(strtolower(substr($field,0,5)) == 'date.'){
 146                  $info = $this->getDateField(substr($field,5));
 147              }elseif(strtolower($field) == 'simple.camera'){
 148                  $info = $this->getCamera();
 149              }elseif(strtolower($field) == 'simple.raw'){
 150                  return $this->getRawInfo();
 151              }elseif(strtolower($field) == 'simple.title'){
 152                  $info = $this->getTitle();
 153              }elseif(strtolower($field) == 'simple.shutterspeed'){
 154                  $info = $this->getShutterSpeed();
 155              }else{
 156                  $info = $this->getExifField($field);
 157              }
 158              if($info != false) break;
 159          }
 160  
 161          if($info === false)  $info = $alt;
 162          if(is_array($info)){
 163              if(isset($info['val'])){
 164                  $info = $info['val'];
 165              }else{
 166                  $info = join(', ',$info);
 167              }
 168          }
 169          return trim($info);
 170      }
 171  
 172      /**
 173       * Convinience function to set nearly all available Data
 174       * through one function
 175       *
 176       * @author Andreas Gohr <andi@splitbrain.org>
 177       */
 178      function setField($field, $value)
 179      {
 180          if(strtolower(substr($field,0,5)) == 'iptc.'){
 181              return $this->setIPTCField(substr($field,5),$value);
 182          }elseif(strtolower(substr($field,0,5)) == 'exif.'){
 183              return $this->setExifField(substr($field,5),$value);
 184          }else{
 185              return $this->setExifField($field,$value);
 186          }
 187      }
 188  
 189      /**
 190       * Convinience function to delete nearly all available Data
 191       * through one function
 192       *
 193       * @author Andreas Gohr <andi@splitbrain.org>
 194       */
 195      function deleteField($field)
 196      {
 197          if(strtolower(substr($field,0,5)) == 'iptc.'){
 198              return $this->deleteIPTCField(substr($field,5));
 199          }elseif(strtolower(substr($field,0,5)) == 'exif.'){
 200              return $this->deleteExifField(substr($field,5));
 201          }else{
 202              return $this->deleteExifField($field);
 203          }
 204      }
 205  
 206      /**
 207       * Return a date field
 208       *
 209       * @author Andreas Gohr <andi@splitbrain.org>
 210       */
 211      function getDateField($field)
 212      {
 213          if (!isset($this->_info['dates'])) {
 214              $this->_info['dates'] = $this->getDates();
 215          }
 216  
 217          if (isset($this->_info['dates'][$field])) {
 218              return $this->_info['dates'][$field];
 219          }
 220  
 221          return false;
 222      }
 223  
 224      /**
 225       * Return a file info field
 226       *
 227       * @author Andreas Gohr <andi@splitbrain.org>
 228       */
 229      function getFileField($field)
 230      {
 231          if (!isset($this->_info['file'])) {
 232              $this->_parseFileInfo();
 233          }
 234  
 235          if (isset($this->_info['file'][$field])) {
 236              return $this->_info['file'][$field];
 237          }
 238  
 239          return false;
 240      }
 241  
 242      /**
 243       * Return the camera info (Maker and Model)
 244       *
 245       * @author Andreas Gohr <andi@splitbrain.org>
 246       * @todo   handle makernotes
 247       */
 248      function getCamera(){
 249          $make  = $this->getField(array('Exif.Make','Exif.TIFFMake'));
 250          $model = $this->getField(array('Exif.Model','Exif.TIFFModel'));
 251          $cam = trim("$make $model");
 252          if(empty($cam)) return false;
 253          return $cam;
 254      }
 255  
 256      /**
 257       * Return shutter speed as a ratio
 258       *
 259       * @author Joe Lapp <joe.lapp@pobox.com>
 260       */
 261      function getShutterSpeed()
 262      {
 263          if (!isset($this->_info['exif'])) {
 264              $this->_parseMarkerExif();
 265          }
 266          if(!isset($this->_info['exif']['ExposureTime'])){
 267              return '';
 268          }
 269  
 270          $field = $this->_info['exif']['ExposureTime'];
 271          if($field['den'] == 1) return $field['num'];
 272          return $field['num'].'/'.$field['den'];
 273      }
 274  
 275      /**
 276       * Return an EXIF field
 277       *
 278       * @author Sebastian Delmont <sdelmont@zonageek.com>
 279       */
 280      function getExifField($field)
 281      {
 282          if (!isset($this->_info['exif'])) {
 283              $this->_parseMarkerExif();
 284          }
 285  
 286          if ($this->_markers == null) {
 287              return false;
 288          }
 289  
 290          if (isset($this->_info['exif'][$field])) {
 291              return $this->_info['exif'][$field];
 292          }
 293  
 294          return false;
 295      }
 296  
 297      /**
 298       * Return an XMP field
 299       *
 300       * @author Hakan Sandell <hakan.sandell@mydata.se>
 301       */
 302      function getXmpField($field)
 303      {
 304          if (!isset($this->_info['xmp'])) {
 305              $this->_parseMarkerXmp();
 306          }
 307  
 308          if ($this->_markers == null) {
 309              return false;
 310          }
 311  
 312          if (isset($this->_info['xmp'][$field])) {
 313              return $this->_info['xmp'][$field];
 314          }
 315  
 316          return false;
 317      }
 318  
 319      /**
 320       * Return an Adobe Field
 321       *
 322       * @author Sebastian Delmont <sdelmont@zonageek.com>
 323       */
 324      function getAdobeField($field)
 325      {
 326          if (!isset($this->_info['adobe'])) {
 327              $this->_parseMarkerAdobe();
 328          }
 329  
 330          if ($this->_markers == null) {
 331              return false;
 332          }
 333  
 334          if (isset($this->_info['adobe'][$field])) {
 335              return $this->_info['adobe'][$field];
 336          }
 337  
 338          return false;
 339      }
 340  
 341      /**
 342       * Return an IPTC field
 343       *
 344       * @author Sebastian Delmont <sdelmont@zonageek.com>
 345       */
 346      function getIPTCField($field)
 347      {
 348          if (!isset($this->_info['iptc'])) {
 349              $this->_parseMarkerAdobe();
 350          }
 351  
 352          if ($this->_markers == null) {
 353              return false;
 354          }
 355  
 356          if (isset($this->_info['iptc'][$field])) {
 357              return $this->_info['iptc'][$field];
 358          }
 359  
 360          return false;
 361      }
 362  
 363      /**
 364       * Set an EXIF field
 365       *
 366       * @author Sebastian Delmont <sdelmont@zonageek.com>
 367       * @author Joe Lapp <joe.lapp@pobox.com>
 368       */
 369      function setExifField($field, $value)
 370      {
 371          if (!isset($this->_info['exif'])) {
 372              $this->_parseMarkerExif();
 373          }
 374  
 375          if ($this->_markers == null) {
 376              return false;
 377          }
 378  
 379          if ($this->_info['exif'] == false) {
 380              $this->_info['exif'] = array();
 381          }
 382  
 383          // make sure datetimes are in correct format
 384          if(strlen($field) >= 8 && strtolower(substr($field, 0, 8)) == 'datetime') {
 385              if(strlen($value) < 8 || $value{4} != ':' || $value{7} != ':') {
 386                  $value = date('Y:m:d H:i:s', strtotime($value));
 387              }
 388          }
 389  
 390          $this->_info['exif'][$field] = $value;
 391  
 392          return true;
 393      }
 394  
 395      /**
 396       * Set an Adobe Field
 397       *
 398       * @author Sebastian Delmont <sdelmont@zonageek.com>
 399       */
 400      function setAdobeField($field, $value)
 401      {
 402          if (!isset($this->_info['adobe'])) {
 403              $this->_parseMarkerAdobe();
 404          }
 405  
 406          if ($this->_markers == null) {
 407              return false;
 408          }
 409  
 410          if ($this->_info['adobe'] == false) {
 411              $this->_info['adobe'] = array();
 412          }
 413  
 414          $this->_info['adobe'][$field] = $value;
 415  
 416          return true;
 417      }
 418  
 419      /**
 420       * Calculates the multiplier needed to resize the image to the given
 421       * dimensions
 422       *
 423       * @author Andreas Gohr <andi@splitbrain.org>
 424       */
 425      function getResizeRatio($maxwidth,$maxheight=0){
 426          if(!$maxheight) $maxheight = $maxwidth;
 427  
 428          $w = $this->getField('File.Width');
 429          $h = $this->getField('File.Height');
 430  
 431          $ratio = 1;
 432          if($w >= $h){
 433              if($w >= $maxwidth){
 434                  $ratio = $maxwidth/$w;
 435              }elseif($h > $maxheight){
 436                  $ratio = $maxheight/$h;
 437              }
 438          }else{
 439              if($h >= $maxheight){
 440                  $ratio = $maxheight/$h;
 441              }elseif($w > $maxwidth){
 442                  $ratio = $maxwidth/$w;
 443              }
 444          }
 445          return $ratio;
 446      }
 447  
 448  
 449      /**
 450       * Set an IPTC field
 451       *
 452       * @author Sebastian Delmont <sdelmont@zonageek.com>
 453       */
 454      function setIPTCField($field, $value)
 455      {
 456          if (!isset($this->_info['iptc'])) {
 457              $this->_parseMarkerAdobe();
 458          }
 459  
 460          if ($this->_markers == null) {
 461              return false;
 462          }
 463  
 464          if ($this->_info['iptc'] == false) {
 465              $this->_info['iptc'] = array();
 466          }
 467  
 468          $this->_info['iptc'][$field] = $value;
 469  
 470          return true;
 471      }
 472  
 473      /**
 474       * Delete an EXIF field
 475       *
 476       * @author Sebastian Delmont <sdelmont@zonageek.com>
 477       */
 478      function deleteExifField($field)
 479      {
 480          if (!isset($this->_info['exif'])) {
 481              $this->_parseMarkerAdobe();
 482          }
 483  
 484          if ($this->_markers == null) {
 485              return false;
 486          }
 487  
 488          if ($this->_info['exif'] != false) {
 489              unset($this->_info['exif'][$field]);
 490          }
 491  
 492          return true;
 493      }
 494  
 495      /**
 496       * Delete an Adobe field
 497       *
 498       * @author Sebastian Delmont <sdelmont@zonageek.com>
 499       */
 500      function deleteAdobeField($field)
 501      {
 502          if (!isset($this->_info['adobe'])) {
 503              $this->_parseMarkerAdobe();
 504          }
 505  
 506          if ($this->_markers == null) {
 507              return false;
 508          }
 509  
 510          if ($this->_info['adobe'] != false) {
 511              unset($this->_info['adobe'][$field]);
 512          }
 513  
 514          return true;
 515      }
 516  
 517      /**
 518       * Delete an IPTC field
 519       *
 520       * @author Sebastian Delmont <sdelmont@zonageek.com>
 521       */
 522      function deleteIPTCField($field)
 523      {
 524          if (!isset($this->_info['iptc'])) {
 525              $this->_parseMarkerAdobe();
 526          }
 527  
 528          if ($this->_markers == null) {
 529              return false;
 530          }
 531  
 532          if ($this->_info['iptc'] != false) {
 533              unset($this->_info['iptc'][$field]);
 534          }
 535  
 536          return true;
 537      }
 538  
 539      /**
 540       * Get the image's title, tries various fields
 541       *
 542       * @param int $max  maximum number chars (keeps words)
 543       * @author Andreas Gohr <andi@splitbrain.org>
 544       */
 545      function getTitle($max=80){
 546          $cap = '';
 547  
 548          // try various fields
 549          $cap = $this->getField(array('Iptc.Headline',
 550                                       'Iptc.Caption',
 551                                       'Xmp.dc:title',
 552                                       'Exif.UserComment',
 553                                       'Exif.TIFFUserComment',
 554                                       'Exif.TIFFImageDescription',
 555                                       'File.Name'));
 556          if (empty($cap)) return false;
 557  
 558          if(!$max) return $cap;
 559          // Shorten to 80 chars (keeping words)
 560          $new = preg_replace('/\n.+$/','',wordwrap($cap, $max));
 561          if($new != $cap) $new .= '...';
 562  
 563          return $new;
 564      }
 565  
 566      /**
 567       * Gather various date fields
 568       *
 569       * @author Sebastian Delmont <sdelmont@zonageek.com>
 570       */
 571      function getDates()
 572      {
 573          $this->_parseAll();
 574  
 575          if ($this->_markers == null) {
 576              return false;
 577          }
 578  
 579          $dates = array();
 580  
 581          $latestTime = 0;
 582          $latestTimeSource = "";
 583          $earliestTime = time();
 584          $earliestTimeSource = "";
 585  
 586          if (@isset($this->_info['exif']['DateTime'])) {
 587              $dates['ExifDateTime'] = $this->_info['exif']['DateTime'];
 588  
 589              $aux = $this->_info['exif']['DateTime'];
 590              $aux{4} = "-";
 591              $aux{7} = "-";
 592              $t = strtotime($aux);
 593  
 594              if ($t > $latestTime) {
 595                  $latestTime = $t;
 596                  $latestTimeSource = "ExifDateTime";
 597              }
 598  
 599              if ($t < $earliestTime) {
 600                  $earliestTime = $t;
 601                  $earliestTimeSource = "ExifDateTime";
 602              }
 603          }
 604  
 605          if (@isset($this->_info['exif']['DateTimeOriginal'])) {
 606              $dates['ExifDateTimeOriginal'] = $this->_info['exif']['DateTime'];
 607  
 608