1*55efc227SAndreas Gohr<?php 2*55efc227SAndreas Gohr/** 3*55efc227SAndreas Gohr * JPEG metadata reader/writer 4*55efc227SAndreas Gohr * 5*55efc227SAndreas Gohr * @license PHP license 2.0 (http://www.php.net/license/2_02.txt) 6*55efc227SAndreas Gohr * @link 7*55efc227SAndreas Gohr * @author Sebastian Delmont <sdelmont@zonageek.com> 8*55efc227SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org> 9*55efc227SAndreas Gohr */ 10*55efc227SAndreas Gohr 11*55efc227SAndreas Gohr// This class is a modified and enhanced version of the JPEG class by 12*55efc227SAndreas Gohr// Sebastian Delmont. Original Copyright notice follows: 13*55efc227SAndreas Gohr// 14*55efc227SAndreas Gohr// +----------------------------------------------------------------------+ 15*55efc227SAndreas Gohr// | PHP version 4.0 | 16*55efc227SAndreas Gohr// +----------------------------------------------------------------------+ 17*55efc227SAndreas Gohr// | Copyright (c) 1997, 1998, 1999, 2000, 2001 The PHP Group | 18*55efc227SAndreas Gohr// +----------------------------------------------------------------------+ 19*55efc227SAndreas Gohr// | This source file is subject to version 2.0 of the PHP license, | 20*55efc227SAndreas Gohr// | that is bundled with this package in the file LICENSE, and is | 21*55efc227SAndreas Gohr// | available at through the world-wide-web at | 22*55efc227SAndreas Gohr// | http://www.php.net/license/2_02.txt. | 23*55efc227SAndreas Gohr// | If you did not receive a copy of the PHP license and are unable to | 24*55efc227SAndreas Gohr// | obtain it through the world-wide-web, please send a note to | 25*55efc227SAndreas Gohr// | license@php.net so we can mail you a copy immediately. | 26*55efc227SAndreas Gohr// +----------------------------------------------------------------------+ 27*55efc227SAndreas Gohr// | Authors: Sebastian Delmont <sdelmont@zonageek.com> | 28*55efc227SAndreas Gohr// +----------------------------------------------------------------------+ 29*55efc227SAndreas Gohr 30*55efc227SAndreas Gohrclass JpegMeta 31*55efc227SAndreas Gohr{ 32*55efc227SAndreas Gohr var $_fileName; 33*55efc227SAndreas Gohr var $_fp = null; 34*55efc227SAndreas Gohr var $_type = 'unknown'; 35*55efc227SAndreas Gohr 36*55efc227SAndreas Gohr var $_markers; 37*55efc227SAndreas Gohr var $_info; 38*55efc227SAndreas Gohr 39*55efc227SAndreas Gohr 40*55efc227SAndreas Gohr /** 41*55efc227SAndreas Gohr * Constructor 42*55efc227SAndreas Gohr * 43*55efc227SAndreas Gohr * @author Sebastian Delmont <sdelmont@zonageek.com> 44*55efc227SAndreas Gohr */ 45*55efc227SAndreas Gohr function JpegMeta($fileName) 46*55efc227SAndreas Gohr { 47*55efc227SAndreas Gohr 48*55efc227SAndreas Gohr $this->_fileName = $fileName; 49*55efc227SAndreas Gohr 50*55efc227SAndreas Gohr $this->_fp = null; 51*55efc227SAndreas Gohr $this->_type = 'unknown'; 52*55efc227SAndreas Gohr 53*55efc227SAndreas Gohr unset($this->_info); 54*55efc227SAndreas Gohr unset($this->_markers); 55*55efc227SAndreas Gohr } 56*55efc227SAndreas Gohr 57*55efc227SAndreas Gohr /** 58*55efc227SAndreas Gohr * Returns all gathered info as multidim array 59*55efc227SAndreas Gohr * 60*55efc227SAndreas Gohr * @author Sebastian Delmont <sdelmont@zonageek.com> 61*55efc227SAndreas Gohr */ 62*55efc227SAndreas Gohr function & getRawInfo() 63*55efc227SAndreas Gohr { 64*55efc227SAndreas Gohr $this->_parseAll(); 65*55efc227SAndreas Gohr 66*55efc227SAndreas Gohr if ($this->_markers == null) { 67*55efc227SAndreas Gohr return false; 68*55efc227SAndreas Gohr } 69*55efc227SAndreas Gohr 70*55efc227SAndreas Gohr return $this->_info; 71*55efc227SAndreas Gohr } 72*55efc227SAndreas Gohr 73*55efc227SAndreas Gohr /** 74*55efc227SAndreas Gohr * Returns basic image info 75*55efc227SAndreas Gohr * 76*55efc227SAndreas Gohr * @author Sebastian Delmont <sdelmont@zonageek.com> 77*55efc227SAndreas Gohr */ 78*55efc227SAndreas Gohr function & getBasicInfo() 79*55efc227SAndreas Gohr { 80*55efc227SAndreas Gohr $this->_parseAll(); 81*55efc227SAndreas Gohr 82*55efc227SAndreas Gohr $info = array(); 83*55efc227SAndreas Gohr 84*55efc227SAndreas Gohr if ($this->_markers == null) { 85*55efc227SAndreas Gohr return false; 86*55efc227SAndreas Gohr } 87*55efc227SAndreas Gohr 88*55efc227SAndreas Gohr $info['Name'] = $this->_info['file']['Name']; 89*55efc227SAndreas Gohr if (isset($this->_info['file']['Url'])) { 90*55efc227SAndreas Gohr $info['Url'] = $this->_info['file']['Url']; 91*55efc227SAndreas Gohr $info['NiceSize'] = "???KB"; 92*55efc227SAndreas Gohr } 93*55efc227SAndreas Gohr else { 94*55efc227SAndreas Gohr $info['Size'] = $this->_info['file']['Size']; 95*55efc227SAndreas Gohr $info['NiceSize'] = $this->_info['file']['NiceSize']; 96*55efc227SAndreas Gohr } 97*55efc227SAndreas Gohr 98*55efc227SAndreas Gohr if (@isset($this->_info['sof']['Format'])) { 99*55efc227SAndreas Gohr $info['Format'] = $this->_info['sof']['Format'] . " JPEG"; 100*55efc227SAndreas Gohr } 101*55efc227SAndreas Gohr else { 102*55efc227SAndreas Gohr $info['Format'] = $this->_info['sof']['Format'] . " JPEG"; 103*55efc227SAndreas Gohr } 104*55efc227SAndreas Gohr 105*55efc227SAndreas Gohr if (@isset($this->_info['sof']['ColorChannels'])) { 106*55efc227SAndreas Gohr $info['ColorMode'] = ($this->_info['sof']['ColorChannels'] > 1) ? "Color" : "B&W"; 107*55efc227SAndreas Gohr } 108*55efc227SAndreas Gohr 109*55efc227SAndreas Gohr $info['Width'] = $this->getWidth(); 110*55efc227SAndreas Gohr $info['Height'] = $this->getHeight(); 111*55efc227SAndreas Gohr $info['DimStr'] = $this->getDimStr(); 112*55efc227SAndreas Gohr 113*55efc227SAndreas Gohr $dates = $this->getDates(); 114*55efc227SAndreas Gohr 115*55efc227SAndreas Gohr $info['DateTime'] = $dates['EarliestTime']; 116*55efc227SAndreas Gohr $info['DateTimeStr'] = $dates['EarliestTimeStr']; 117*55efc227SAndreas Gohr 118*55efc227SAndreas Gohr $info['HasThumbnail'] = $this->hasThumbnail(); 119*55efc227SAndreas Gohr 120*55efc227SAndreas Gohr return $info; 121*55efc227SAndreas Gohr } 122*55efc227SAndreas Gohr 123*55efc227SAndreas Gohr 124*55efc227SAndreas Gohr /** 125*55efc227SAndreas Gohr * Convinience function to access nearly all available Data 126*55efc227SAndreas Gohr * through one function 127*55efc227SAndreas Gohr * 128*55efc227SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org> 129*55efc227SAndreas Gohr */ 130*55efc227SAndreas Gohr function getField($fields) 131*55efc227SAndreas Gohr { 132*55efc227SAndreas Gohr if(!is_array($fields)) $fields = array($fields); 133*55efc227SAndreas Gohr $info = false; 134*55efc227SAndreas Gohr foreach($fields as $field){ 135*55efc227SAndreas Gohr if(strtolower(substr($field,0,5)) == 'iptc.'){ 136*55efc227SAndreas Gohr $info = $this->getIPTCField(substr($field,5)); 137*55efc227SAndreas Gohr }elseif(strtolower(substr($field,0,5)) == 'exif.'){ 138*55efc227SAndreas Gohr $info = $this->getExifField(substr($field,5)); 139*55efc227SAndreas Gohr }elseif(strtolower(substr($field,0,5)) == 'file.'){ 140*55efc227SAndreas Gohr $info = $this->getFileField(substr($field,5)); 141*55efc227SAndreas Gohr }elseif(strtolower(substr($field,0,5)) == 'date.'){ 142*55efc227SAndreas Gohr $info = $this->getDateField(substr($field,5)); 143*55efc227SAndreas Gohr }elseif(strtolower($field) == 'simple.camera'){ 144*55efc227SAndreas Gohr $info = $this->getCamera(); 145*55efc227SAndreas Gohr }elseif(strtolower($field) == 'simple.raw'){ 146*55efc227SAndreas Gohr return $this->getRawInfo(); 147*55efc227SAndreas Gohr }elseif(strtolower($field) == 'simple.title'){ 148*55efc227SAndreas Gohr $info = $this->getTitle(); 149*55efc227SAndreas Gohr }else{ 150*55efc227SAndreas Gohr $info = $this->getExifField($field); 151*55efc227SAndreas Gohr } 152*55efc227SAndreas Gohr if($info != false) break; 153*55efc227SAndreas Gohr } 154*55efc227SAndreas Gohr 155*55efc227SAndreas Gohr if($info === false) $info = $alt; 156*55efc227SAndreas Gohr if(is_array($info)){ 157*55efc227SAndreas Gohr if(isset($info['val'])){ 158*55efc227SAndreas Gohr $info = $info['val']; 159*55efc227SAndreas Gohr }else{ 160*55efc227SAndreas Gohr $info = join(', ',$info); 161*55efc227SAndreas Gohr } 162*55efc227SAndreas Gohr } 163*55efc227SAndreas Gohr return trim($info); 164*55efc227SAndreas Gohr } 165*55efc227SAndreas Gohr 166*55efc227SAndreas Gohr /** 167*55efc227SAndreas Gohr * Return a date field 168*55efc227SAndreas Gohr * 169*55efc227SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org> 170*55efc227SAndreas Gohr */ 171*55efc227SAndreas Gohr function getDateField($field) 172*55efc227SAndreas Gohr { 173*55efc227SAndreas Gohr if (!isset($this->_info['dates'])) { 174*55efc227SAndreas Gohr $this->_info['dates'] = $this->getDates(); 175*55efc227SAndreas Gohr } 176*55efc227SAndreas Gohr 177*55efc227SAndreas Gohr if (isset($this->_info['dates'][$field])) { 178*55efc227SAndreas Gohr return $this->_info['dates'][$field]; 179*55efc227SAndreas Gohr } 180*55efc227SAndreas Gohr 181*55efc227SAndreas Gohr return false; 182*55efc227SAndreas Gohr } 183*55efc227SAndreas Gohr 184*55efc227SAndreas Gohr /** 185*55efc227SAndreas Gohr * Return a file info field 186*55efc227SAndreas Gohr * 187*55efc227SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org> 188*55efc227SAndreas Gohr */ 189*55efc227SAndreas Gohr function getFileField($field) 190*55efc227SAndreas Gohr { 191*55efc227SAndreas Gohr if (!isset($this->_info['file'])) { 192*55efc227SAndreas Gohr $this->_parseFileInfo(); 193*55efc227SAndreas Gohr } 194*55efc227SAndreas Gohr 195*55efc227SAndreas Gohr if (isset($this->_info['file'][$field])) { 196*55efc227SAndreas Gohr return $this->_info['file'][$field]; 197*55efc227SAndreas Gohr } 198*55efc227SAndreas Gohr 199*55efc227SAndreas Gohr return false; 200*55efc227SAndreas Gohr } 201*55efc227SAndreas Gohr 202*55efc227SAndreas Gohr /** 203*55efc227SAndreas Gohr * Return the camera info (Maker and Model) 204*55efc227SAndreas Gohr * 205*55efc227SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org> 206*55efc227SAndreas Gohr * @todo handle makernotes 207*55efc227SAndreas Gohr */ 208*55efc227SAndreas Gohr function getCamera(){ 209*55efc227SAndreas Gohr $make = $this->getField(array('Exif.Make','Exif.TIFFMake')); 210*55efc227SAndreas Gohr $model = $this->getField(array('Exif.Model','Exif.TIFFModel')); 211*55efc227SAndreas Gohr $cam = trim("$make $model"); 212*55efc227SAndreas Gohr if(empty($cam)) return false; 213*55efc227SAndreas Gohr return $cam; 214*55efc227SAndreas Gohr } 215*55efc227SAndreas Gohr 216*55efc227SAndreas Gohr /** 217*55efc227SAndreas Gohr * Return an EXIF field 218*55efc227SAndreas Gohr * 219*55efc227SAndreas Gohr * @author Sebastian Delmont <sdelmont@zonageek.com> 220*55efc227SAndreas Gohr */ 221*55efc227SAndreas Gohr function getExifField($field) 222*55efc227SAndreas Gohr { 223*55efc227SAndreas Gohr if (!isset($this->_info['exif'])) { 224*55efc227SAndreas Gohr $this->_parseMarkerExif(); 225*55efc227SAndreas Gohr } 226*55efc227SAndreas Gohr 227*55efc227SAndreas Gohr if ($this->_markers == null) { 228*55efc227SAndreas Gohr return false; 229*55efc227SAndreas Gohr } 230*55efc227SAndreas Gohr 231*55efc227SAndreas Gohr if (isset($this->_info['exif'][$field])) { 232*55efc227SAndreas Gohr return $this->_info['exif'][$field]; 233*55efc227SAndreas Gohr } 234*55efc227SAndreas Gohr 235*55efc227SAndreas Gohr return false; 236*55efc227SAndreas Gohr } 237*55efc227SAndreas Gohr 238*55efc227SAndreas Gohr /** 239*55efc227SAndreas Gohr * Return an Adobe Field 240*55efc227SAndreas Gohr * 241*55efc227SAndreas Gohr * @author Sebastian Delmont <sdelmont@zonageek.com> 242*55efc227SAndreas Gohr */ 243*55efc227SAndreas Gohr function getAdobeField($field) 244*55efc227SAndreas Gohr { 245*55efc227SAndreas Gohr if (!isset($this->_info['adobe'])) { 246*55efc227SAndreas Gohr $this->_parseMarkerAdobe(); 247*55efc227SAndreas Gohr } 248*55efc227SAndreas Gohr 249*55efc227SAndreas Gohr if ($this->_markers == null) { 250*55efc227SAndreas Gohr return false; 251*55efc227SAndreas Gohr } 252*55efc227SAndreas Gohr 253*55efc227SAndreas Gohr if (isset($this->_info['adobe'][$field])) { 254*55efc227SAndreas Gohr return $this->_info['adobe'][$field]; 255*55efc227SAndreas Gohr } 256*55efc227SAndreas Gohr 257*55efc227SAndreas Gohr return false; 258*55efc227SAndreas Gohr } 259*55efc227SAndreas Gohr 260*55efc227SAndreas Gohr /** 261*55efc227SAndreas Gohr * Return an IPTC field 262*55efc227SAndreas Gohr * 263*55efc227SAndreas Gohr * @author Sebastian Delmont <sdelmont@zonageek.com> 264*55efc227SAndreas Gohr */ 265*55efc227SAndreas Gohr function getIPTCField($field) 266*55efc227SAndreas Gohr { 267*55efc227SAndreas Gohr if (!isset($this->_info['iptc'])) { 268*55efc227SAndreas Gohr $this->_parseMarkerAdobe(); 269*55efc227SAndreas Gohr } 270*55efc227SAndreas Gohr 271*55efc227SAndreas Gohr if ($this->_markers == null) { 272*55efc227SAndreas Gohr return false; 273*55efc227SAndreas Gohr } 274*55efc227SAndreas Gohr 275*55efc227SAndreas Gohr if (isset($this->_info['iptc'][$field])) { 276*55efc227SAndreas Gohr return $this->_info['iptc'][$field]; 277*55efc227SAndreas Gohr } 278*55efc227SAndreas Gohr 279*55efc227SAndreas Gohr return false; 280*55efc227SAndreas Gohr } 281*55efc227SAndreas Gohr 282*55efc227SAndreas Gohr /** 283*55efc227SAndreas Gohr * Set an EXIF field 284*55efc227SAndreas Gohr * 285*55efc227SAndreas Gohr * @author Sebastian Delmont <sdelmont@zonageek.com> 286*55efc227SAndreas Gohr */ 287*55efc227SAndreas Gohr function setExifField($field, $value) 288*55efc227SAndreas Gohr { 289*55efc227SAndreas Gohr if (!isset($this->_info['exif'])) { 290*55efc227SAndreas Gohr $this->_parseMarkerExif(); 291*55efc227SAndreas Gohr } 292*55efc227SAndreas Gohr 293*55efc227SAndreas Gohr if ($this->_markers == null) { 294*55efc227SAndreas Gohr return false; 295*55efc227SAndreas Gohr } 296*55efc227SAndreas Gohr 297*55efc227SAndreas Gohr if ($this->_info['exif'] == false) { 298*55efc227SAndreas Gohr $this->_info['exif'] = array(); 299*55efc227SAndreas Gohr } 300*55efc227SAndreas Gohr 301*55efc227SAndreas Gohr $this->_info['exif'][$field] = $value; 302*55efc227SAndreas Gohr 303*55efc227SAndreas Gohr return true; 304*55efc227SAndreas Gohr } 305*55efc227SAndreas Gohr 306*55efc227SAndreas Gohr /** 307*55efc227SAndreas Gohr * Set an Adobe Field 308*55efc227SAndreas Gohr * 309*55efc227SAndreas Gohr * @author Sebastian Delmont <sdelmont@zonageek.com> 310*55efc227SAndreas Gohr */ 311*55efc227SAndreas Gohr function setAdobeField($field, $value) 312*55efc227SAndreas Gohr { 313*55efc227SAndreas Gohr if (!isset($this->_info['adobe'])) { 314*55efc227SAndreas Gohr $this->_parseMarkerAdobe(); 315*55efc227SAndreas Gohr } 316*55efc227SAndreas Gohr 317*55efc227SAndreas Gohr if ($this->_markers == null) { 318*55efc227SAndreas Gohr return false; 319*55efc227SAndreas Gohr } 320*55efc227SAndreas Gohr 321*55efc227SAndreas Gohr if ($this->_info['adobe'] == false) { 322*55efc227SAndreas Gohr $this->_info['adobe'] = array(); 323*55efc227SAndreas Gohr } 324*55efc227SAndreas Gohr 325*55efc227SAndreas Gohr $this->_info['adobe'][$field] = $value; 326*55efc227SAndreas Gohr 327*55efc227SAndreas Gohr return true; 328*55efc227SAndreas Gohr } 329*55efc227SAndreas Gohr 330*55efc227SAndreas Gohr /** 331*55efc227SAndreas Gohr * Set an IPTC field 332*55efc227SAndreas Gohr * 333*55efc227SAndreas Gohr * @author Sebastian Delmont <sdelmont@zonageek.com> 334*55efc227SAndreas Gohr */ 335*55efc227SAndreas Gohr function setIPTCField($field, $value) 336*55efc227SAndreas Gohr { 337*55efc227SAndreas Gohr if (!isset($this->_info['iptc'])) { 338*55efc227SAndreas Gohr $this->_parseMarkerAdobe(); 339*55efc227SAndreas Gohr } 340*55efc227SAndreas Gohr 341*55efc227SAndreas Gohr if ($this->_markers == null) { 342*55efc227SAndreas Gohr return false; 343*55efc227SAndreas Gohr } 344*55efc227SAndreas Gohr 345*55efc227SAndreas Gohr if ($this->_info['iptc'] == false) { 346*55efc227SAndreas Gohr $this->_info['iptc'] = array(); 347*55efc227SAndreas Gohr } 348*55efc227SAndreas Gohr 349*55efc227SAndreas Gohr $this->_info['iptc'][$field] = $value; 350*55efc227SAndreas Gohr 351*55efc227SAndreas Gohr return true; 352*55efc227SAndreas Gohr } 353*55efc227SAndreas Gohr 354*55efc227SAndreas Gohr /** 355*55efc227SAndreas Gohr * Delete an EXIF field 356*55efc227SAndreas Gohr * 357*55efc227SAndreas Gohr * @author Sebastian Delmont <sdelmont@zonageek.com> 358*55efc227SAndreas Gohr */ 359*55efc227SAndreas Gohr function deleteExifField($field) 360*55efc227SAndreas Gohr { 361*55efc227SAndreas Gohr if (!isset($this->_info['exif'])) { 362*55efc227SAndreas Gohr $this->_parseMarkerAdobe(); 363*55efc227SAndreas Gohr } 364*55efc227SAndreas Gohr 365*55efc227SAndreas Gohr if ($this->_markers == null) { 366*55efc227SAndreas Gohr return false; 367*55efc227SAndreas Gohr } 368*55efc227SAndreas Gohr 369*55efc227SAndreas Gohr if ($this->_info['exif'] != false) { 370*55efc227SAndreas Gohr unset($this->_info['exif'][$field]); 371*55efc227SAndreas Gohr } 372*55efc227SAndreas Gohr 373*55efc227SAndreas Gohr return true; 374*55efc227SAndreas Gohr } 375*55efc227SAndreas Gohr 376*55efc227SAndreas Gohr /** 377*55efc227SAndreas Gohr * Delete an Adobe field 378*55efc227SAndreas Gohr * 379*55efc227SAndreas Gohr * @author Sebastian Delmont <sdelmont@zonageek.com> 380*55efc227SAndreas Gohr */ 381*55efc227SAndreas Gohr function deleteAdobeField($field) 382*55efc227SAndreas Gohr { 383*55efc227SAndreas Gohr if (!isset($this->_info['adobe'])) { 384*55efc227SAndreas Gohr $this->_parseMarkerAdobe(); 385*55efc227SAndreas Gohr } 386*55efc227SAndreas Gohr 387*55efc227SAndreas Gohr if ($this->_markers == null) { 388*55efc227SAndreas Gohr return false; 389*55efc227SAndreas Gohr } 390*55efc227SAndreas Gohr 391*55efc227SAndreas Gohr if ($this->_info['adobe'] != false) { 392*55efc227SAndreas Gohr unset($this->_info['adobe'][$field]); 393*55efc227SAndreas Gohr } 394*55efc227SAndreas Gohr 395*55efc227SAndreas Gohr return true; 396*55efc227SAndreas Gohr } 397*55efc227SAndreas Gohr 398*55efc227SAndreas Gohr /** 399*55efc227SAndreas Gohr * Delete an IPTC field 400*55efc227SAndreas Gohr * 401*55efc227SAndreas Gohr * @author Sebastian Delmont <sdelmont@zonageek.com> 402*55efc227SAndreas Gohr */ 403*55efc227SAndreas Gohr function deleteIPTCField($field) 404*55efc227SAndreas Gohr { 405*55efc227SAndreas Gohr if (!isset($this->_info['iptc'])) { 406*55efc227SAndreas Gohr $this->_parseMarkerAdobe(); 407*55efc227SAndreas Gohr } 408*55efc227SAndreas Gohr 409*55efc227SAndreas Gohr if ($this->_markers == null) { 410*55efc227SAndreas Gohr return false; 411*55efc227SAndreas Gohr } 412*55efc227SAndreas Gohr 413*55efc227SAndreas Gohr if ($this->_info['iptc'] != false) { 414*55efc227SAndreas Gohr unset($this->_info['iptc'][$field]); 415*55efc227SAndreas Gohr } 416*55efc227SAndreas Gohr 417*55efc227SAndreas Gohr return true; 418*55efc227SAndreas Gohr } 419*55efc227SAndreas Gohr 420*55efc227SAndreas Gohr /** 421*55efc227SAndreas Gohr * Get the image's title, tries various fields 422*55efc227SAndreas Gohr * 423*55efc227SAndreas Gohr * @param int $max maximum number chars (keeps words) 424*55efc227SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org> 425*55efc227SAndreas Gohr */ 426*55efc227SAndreas Gohr function getTitle($max=80){ 427*55efc227SAndreas Gohr $cap = ''; 428*55efc227SAndreas Gohr 429*55efc227SAndreas Gohr // try various fields 430*55efc227SAndreas Gohr $cap = $this->getField(array('Iptc.Headline', 431*55efc227SAndreas Gohr 'Iptc.Caption', 432*55efc227SAndreas Gohr 'Exif.UserComment', 433*55efc227SAndreas Gohr 'Exif.TIFFUserComment', 434*55efc227SAndreas Gohr 'Exif.TIFFImageDescription')); 435*55efc227SAndreas Gohr if (empty($cap)) return false; 436*55efc227SAndreas Gohr 437*55efc227SAndreas Gohr if(!$max) return $cap; 438*55efc227SAndreas Gohr // Shorten to 80 chars (keeping words) 439*55efc227SAndreas Gohr $new = preg_replace('/\n.+$/','',wordwrap($cap, $max)); 440*55efc227SAndreas Gohr if($new != $cap) $new .= '...'; 441*55efc227SAndreas Gohr 442*55efc227SAndreas Gohr return $new; 443*55efc227SAndreas Gohr } 444*55efc227SAndreas Gohr 445*55efc227SAndreas Gohr /** 446*55efc227SAndreas Gohr * Gather various date fields 447*55efc227SAndreas Gohr * 448*55efc227SAndreas Gohr * @author Sebastian Delmont <sdelmont@zonageek.com> 449*55efc227SAndreas Gohr */ 450*55efc227SAndreas Gohr function getDates() 451*55efc227SAndreas Gohr { 452*55efc227SAndreas Gohr $this->_parseAll(); 453*55efc227SAndreas Gohr 454*55efc227SAndreas Gohr if ($this->_markers == null) { 455*55efc227SAndreas Gohr return false; 456*55efc227SAndreas Gohr } 457*55efc227SAndreas Gohr 458*55efc227SAndreas Gohr $dates = array(); 459*55efc227SAndreas Gohr 460*55efc227SAndreas Gohr $latestTime = 0; 461*55efc227SAndreas Gohr $latestTimeSource = ""; 462*55efc227SAndreas Gohr $earliestTime = time(); 463*55efc227SAndreas Gohr $earliestTimeSource = ""; 464*55efc227SAndreas Gohr 465*55efc227SAndreas Gohr if (@isset($this->_info['exif']['DateTime'])) { 466*55efc227SAndreas Gohr $dates['ExifDateTime'] = $this->_info['exif']['DateTime']; 467*55efc227SAndreas Gohr 468*55efc227SAndreas Gohr $aux = $this->_info['exif']['DateTime']; 469*55efc227SAndreas Gohr $aux{4} = "-"; 470*55efc227SAndreas Gohr $aux{7} = "-"; 471*55efc227SAndreas Gohr $t = strtotime($aux); 472*55efc227SAndreas Gohr 473*55efc227SAndreas Gohr if ($t > $latestTime) { 474*55efc227SAndreas Gohr $latestTime = $t; 475*55efc227SAndreas Gohr $latestTimeSource = "ExifDateTime"; 476*55efc227SAndreas Gohr } 477*55efc227SAndreas Gohr 478*55efc227SAndreas Gohr if ($t < $earliestTime) { 479*55efc227SAndreas Gohr $earliestTime = $t; 480*55efc227SAndreas Gohr $earliestTimeSource = "ExifDateTime"; 481*55efc227SAndreas Gohr } 482*55efc227SAndreas Gohr } 483*55efc227SAndreas Gohr 484*55efc227SAndreas Gohr if (@isset($this->_info['exif']['DateTimeOriginal'])) { 485*55efc227SAndreas Gohr $dates['ExifDateTimeOriginal'] = $this->_info['exif']['DateTime']; 486*55efc227SAndreas Gohr 487*55efc227SAndreas Gohr $aux = $this->_info['exif']['DateTimeOriginal']; 488*55efc227SAndreas Gohr $aux{4} = "-"; 489*55efc227SAndreas Gohr $aux{7} = "-"; 490*55efc227SAndreas Gohr $t = strtotime($aux); 491*55efc227SAndreas Gohr 492*55efc227SAndreas Gohr if ($t > $latestTime) { 493*55efc227SAndreas Gohr $latestTime = $t; 494*55efc227SAndreas Gohr $latestTimeSource = "ExifDateTimeOriginal"; 495*55efc227SAndreas Gohr } 496*55efc227SAndreas Gohr 497*55efc227SAndreas Gohr if ($t < $earliestTime) { 498*55efc227SAndreas Gohr $earliestTime = $t; 499*55efc227SAndreas Gohr $earliestTimeSource = "ExifDateTimeOriginal"; 500*55efc227SAndreas Gohr } 501*55efc227SAndreas Gohr } 502*55efc227SAndreas Gohr 503*55efc227SAndreas Gohr if (@isset($this->_info['exif']['DateTimeDigitized'])) { 504*55efc227SAndreas Gohr $dates['ExifDateTimeDigitized'] = $this->_info['exif']['DateTime']; 505*55efc227SAndreas Gohr 506*55efc227SAndreas Gohr $aux = $this->_info['exif']['DateTimeDigitized']; 507*55efc227SAndreas Gohr $aux{4} = "-"; 508*55efc227SAndreas Gohr $aux{7} = "-"; 509*55efc227SAndreas Gohr $t = strtotime($aux); 510*55efc227SAndreas Gohr 511*55efc227SAndreas Gohr if ($t > $latestTime) { 512*55efc227SAndreas Gohr $latestTime = $t; 513*55efc227SAndreas Gohr $latestTimeSource = "ExifDateTimeDigitized"; 514*55efc227SAndreas Gohr } 515*55efc227SAndreas Gohr 516*55efc227SAndreas Gohr if ($t < $earliestTime) { 517*55efc227SAndreas Gohr $earliestTime = $t; 518*55efc227SAndreas Gohr $earliestTimeSource = "ExifDateTimeDigitized"; 519*55efc227SAndreas Gohr } 520*55efc227SAndreas Gohr } 521*55efc227SAndreas Gohr 522*55efc227SAndreas Gohr if (@isset($this->_info['iptc']['DateCreated'])) { 523*55efc227SAndreas Gohr $dates['IPTCDateCreated'] = $this->_info['iptc']['DateCreated']; 524*55efc227SAndreas Gohr 525*55efc227SAndreas Gohr $aux = $this->_info['iptc']['DateCreated']; 526*55efc227SAndreas Gohr $aux = substr($aux, 0, 4) . "-" . substr($aux, 4, 2) . "-" . substr($aux, 6, 2); 527*55efc227SAndreas Gohr $t = strtotime($aux); 528*55efc227SAndreas Gohr 529*55efc227SAndreas Gohr if ($t > $latestTime) { 530*55efc227SAndreas Gohr $latestTime = $t; 531*55efc227SAndreas Gohr $latestTimeSource = "IPTCDateCreated"; 532*55efc227SAndreas Gohr } 533*55efc227SAndreas Gohr 534*55efc227SAndreas Gohr if ($t < $earliestTime) { 535*55efc227SAndreas Gohr $earliestTime = $t; 536*55efc227SAndreas Gohr $earliestTimeSource = "IPTCDateCreated"; 537*55efc227SAndreas Gohr } 538*55efc227SAndreas Gohr } 539*55efc227SAndreas Gohr 540*55efc227SAndreas Gohr if (@isset($this->_info['file']['UnixTime'])) { 541*55efc227SAndreas Gohr $dates['FileModified'] = $this->_info['file']['UnixTime']; 542*55efc227SAndreas Gohr 543*55efc227SAndreas Gohr $t = $this->_info['file']['UnixTime']; 544*55efc227SAndreas Gohr 545*55efc227SAndreas Gohr if ($t > $latestTime) { 546*55efc227SAndreas Gohr $latestTime = $t; 547*55efc227SAndreas Gohr $latestTimeSource = "FileModified"; 548*55efc227SAndreas Gohr } 549*55efc227SAndreas Gohr 550*55efc227SAndreas Gohr if ($t < $earliestTime) { 551*55efc227SAndreas Gohr $earliestTime = $t; 552*55efc227SAndreas Gohr $earliestTimeSource = "FileModified"; 553*55efc227SAndreas Gohr } 554*55efc227SAndreas Gohr } 555*55efc227SAndreas Gohr 556*55efc227SAndreas Gohr $dates['Time'] = $earliestTime; 557*55efc227SAndreas Gohr $dates['TimeSource'] = $earliestTimeSource; 558*55efc227SAndreas Gohr $dates['TimeStr'] = date("Y-m-d H:i:s", $earliestTime); 559*55efc227SAndreas Gohr $dates['EarliestTime'] = $earliestTime; 560*55efc227SAndreas Gohr $dates['EarliestTimeSource'] = $earliestTimeSource; 561*55efc227SAndreas Gohr $dates['EarliestTimeStr'] = date("Y-m-d H:i:s", $earliestTime); 562*55efc227SAndreas Gohr $dates['LatestTime'] = $latestTime; 563*55efc227SAndreas Gohr $dates['LatestTimeSource'] = $latestTimeSource; 564*55efc227SAndreas Gohr $dates['LatestTimeStr'] = date("Y-m-d H:i:s", $latestTime); 565*55efc227SAndreas Gohr 566*55efc227SAndreas Gohr return $dates; 567*55efc227SAndreas Gohr } 568*55efc227SAndreas Gohr 569*55efc227SAndreas Gohr /** 570*55efc227SAndreas Gohr * Get the image width, tries various fields 571*55efc227SAndreas Gohr * 572*55efc227SAndreas Gohr * @author Sebastian Delmont <sdelmont@zonageek.com> 573*55efc227SAndreas Gohr */ 574*55efc227SAndreas Gohr function getWidth() 575*55efc227SAndreas Gohr { 576*55efc227SAndreas Gohr if (!isset($this->_info['sof'])) { 577*55efc227SAndreas Gohr $this->_parseMarkerSOF(); 578*55efc227SAndreas Gohr } 579*55efc227SAndreas Gohr 580*55efc227SAndreas Gohr if ($this->_markers == null) { 581*55efc227SAndreas Gohr return false; 582*55efc227SAndreas Gohr } 583*55efc227SAndreas Gohr 584*55efc227SAndreas Gohr if (isset($this->_info['sof']['ImageWidth'])) { 585*55efc227SAndreas Gohr return $this->_info['sof']['ImageWidth']; 586*55efc227SAndreas Gohr } 587*55efc227SAndreas Gohr 588*55efc227SAndreas Gohr if (!isset($this->_info['exif'])) { 589*55efc227SAndreas Gohr $this->_parseMarkerExif(); 590*55efc227SAndreas Gohr } 591*55efc227SAndreas Gohr 592*55efc227SAndreas Gohr if (isset($this->_info['exif']['PixelXDimension'])) { 593*55efc227SAndreas Gohr return $this->_info['exif']['PixelXDimension']; 594*55efc227SAndreas Gohr } 595*55efc227SAndreas Gohr 596*55efc227SAndreas Gohr return false; 597*55efc227SAndreas Gohr } 598*55efc227SAndreas Gohr 599*55efc227SAndreas Gohr /** 600*55efc227SAndreas Gohr * Get the image height, tries various fields 601*55efc227SAndreas Gohr * 602*55efc227SAndreas Gohr * @author Sebastian Delmont <sdelmont@zonageek.com> 603*55efc227SAndreas Gohr */ 604*55efc227SAndreas Gohr function getHeight() 605*55efc227SAndreas Gohr { 606*55efc227SAndreas Gohr if (!isset($this->_info['sof'])) { 607*55efc227SAndreas Gohr $this->_parseMarkerSOF(); 608*55efc227SAndreas Gohr } 609*55efc227SAndreas Gohr 610*55efc227SAndreas Gohr if ($this->_markers == null) { 611*55efc227SAndreas Gohr return false; 612*55efc227SAndreas Gohr } 613*55efc227SAndreas Gohr 614*55efc227SAndreas Gohr if (isset($this->_info['sof']['ImageHeight'])) { 615*55efc227SAndreas Gohr return $this->_info['sof']['ImageHeight']; 616*55efc227SAndreas Gohr } 617*55efc227SAndreas Gohr 618*55efc227SAndreas Gohr if (!isset($this->_info['exif'])) { 619*55efc227SAndreas Gohr $this->_parseMarkerExif(); 620*55efc227SAndreas Gohr } 621*55efc227SAndreas Gohr 622*55efc227SAndreas Gohr if (isset($this->_info['exif']['PixelYDimension'])) { 623*55efc227SAndreas Gohr return $this->_info['exif']['PixelYDimension']; 624*55efc227SAndreas Gohr } 625*55efc227SAndreas Gohr 626*55efc227SAndreas Gohr return false; 627*55efc227SAndreas Gohr } 628*55efc227SAndreas Gohr 629*55efc227SAndreas Gohr /** 630*55efc227SAndreas Gohr * Get an dimension string for use in img tag 631*55efc227SAndreas Gohr * 632*55efc227SAndreas Gohr * @author Sebastian Delmont <sdelmont@zonageek.com> 633*55efc227SAndreas Gohr */ 634*55efc227SAndreas Gohr function getDimStr() 635*55efc227SAndreas Gohr { 636*55efc227SAndreas Gohr if ($this->_markers == null) { 637*55efc227SAndreas Gohr return false; 638*55efc227SAndreas Gohr } 639*55efc227SAndreas Gohr 640*55efc227SAndreas Gohr $w = $this->getWidth(); 641*55efc227SAndreas Gohr $h = $this->getHeight(); 642*55efc227SAndreas Gohr 643*55efc227SAndreas Gohr return "width='" . $w . "' height='" . $h . "'"; 644*55efc227SAndreas Gohr } 645*55efc227SAndreas Gohr 646*55efc227SAndreas Gohr /** 647*55efc227SAndreas Gohr * Checks for an embedded thumbnail 648*55efc227SAndreas Gohr * 649*55efc227SAndreas Gohr * @author Sebastian Delmont <sdelmont@zonageek.com> 650*55efc227SAndreas Gohr */ 651*55efc227SAndreas Gohr function hasThumbnail($which = 'any') 652*55efc227SAndreas Gohr { 653*55efc227SAndreas Gohr if (($which == 'any') || ($which == 'exif')) { 654*55efc227SAndreas Gohr if (!isset($this->_info['exif'])) { 655*55efc227SAndreas Gohr $this->_parseMarkerExif(); 656*55efc227SAndreas Gohr } 657*55efc227SAndreas Gohr 658*55efc227SAndreas Gohr if ($this->_markers == null) { 659*55efc227SAndreas Gohr return false; 660*55efc227SAndreas Gohr } 661*55efc227SAndreas Gohr 662*55efc227SAndreas Gohr if (isset($this->_info['exif']) && is_array($this->_info['exif'])) { 663*55efc227SAndreas Gohr if (isset($this->_info['exif']['JFIFThumbnail'])) { 664*55efc227SAndreas Gohr return 'exif'; 665*55efc227SAndreas Gohr } 666*55efc227SAndreas Gohr } 667*55efc227SAndreas Gohr } 668*55efc227SAndreas Gohr 669*55efc227SAndreas Gohr if ($which == 'adobe') { 670*55efc227SAndreas Gohr if (!isset($this->_info['adobe'])) { 671*55efc227SAndreas Gohr $this->_parseMarkerAdobe(); 672*55efc227SAndreas Gohr } 673*55efc227SAndreas Gohr 674*55efc227SAndreas Gohr if ($this->_markers == null) { 675*55efc227SAndreas Gohr return false; 676*55efc227SAndreas Gohr } 677*55efc227SAndreas Gohr 678*55efc227SAndreas Gohr if (isset($this->_info['adobe']) && is_array($this->_info['adobe'])) { 679*55efc227SAndreas Gohr if (isset($this->_info['adobe']['ThumbnailData'])) { 680*55efc227SAndreas Gohr return 'exif'; 681*55efc227SAndreas Gohr } 682*55efc227SAndreas Gohr } 683*55efc227SAndreas Gohr } 684*55efc227SAndreas Gohr 685*55efc227SAndreas Gohr return false; 686*55efc227SAndreas Gohr } 687*55efc227SAndreas Gohr 688*55efc227SAndreas Gohr /** 689*55efc227SAndreas Gohr * Send embedded thumbnail to browser 690*55efc227SAndreas Gohr * 691*55efc227SAndreas Gohr * @author Sebastian Delmont <sdelmont@zonageek.com> 692*55efc227SAndreas Gohr */ 693*55efc227SAndreas Gohr function sendThumbnail($which = 'any') 694*55efc227SAndreas Gohr { 695*55efc227SAndreas Gohr $data = null; 696*55efc227SAndreas Gohr 697*55efc227SAndreas Gohr if (($which == 'any') || ($which == 'exif')) { 698*55efc227SAndreas Gohr if (!isset($this->_info['exif'])) { 699*55efc227SAndreas Gohr $this->_parseMarkerExif(); 700*55efc227SAndreas Gohr } 701*55efc227SAndreas Gohr 702*55efc227SAndreas Gohr if ($this->_markers == null) { 703*55efc227SAndreas Gohr return false; 704*55efc227SAndreas Gohr } 705*55efc227SAndreas Gohr 706*55efc227SAndreas Gohr if (isset($this->_info['exif']) && is_array($this->_info['exif'])) { 707*55efc227SAndreas Gohr if (isset($this->_info['exif']['JFIFThumbnail'])) { 708*55efc227SAndreas Gohr $data =& $this->_info['exif']['JFIFThumbnail']; 709*55efc227SAndreas Gohr } 710*55efc227SAndreas Gohr } 711*55efc227SAndreas Gohr } 712*55efc227SAndreas Gohr 713*55efc227SAndreas Gohr if (($which == 'adobe') || ($data == null)){ 714*55efc227SAndreas Gohr if (!isset($this->_info['adobe'])) { 715*55efc227SAndreas Gohr $this->_parseMarkerAdobe(); 716*55efc227SAndreas Gohr } 717*55efc227SAndreas Gohr 718*55efc227SAndreas Gohr if ($this->_markers == null) { 719*55efc227SAndreas Gohr return false; 720*55efc227SAndreas Gohr } 721*55efc227SAndreas Gohr 722*55efc227SAndreas Gohr if (isset($this->_info['adobe']) && is_array($this->_info['adobe'])) { 723*55efc227SAndreas Gohr if (isset($this->_info['adobe']['ThumbnailData'])) { 724*55efc227SAndreas Gohr $data =& $this->_info['adobe']['ThumbnailData']; 725*55efc227SAndreas Gohr } 726*55efc227SAndreas Gohr } 727*55efc227SAndreas Gohr } 728*55efc227SAndreas Gohr 729*55efc227SAndreas Gohr if ($data != null) { 730*55efc227SAndreas Gohr header("Content-type: image/jpeg"); 731*55efc227SAndreas Gohr echo $data; 732*55efc227SAndreas Gohr return true; 733*55efc227SAndreas Gohr } 734*55efc227SAndreas Gohr 735*55efc227SAndreas Gohr return false; 736*55efc227SAndreas Gohr } 737*55efc227SAndreas Gohr 738*55efc227SAndreas Gohr /** 739*55efc227SAndreas Gohr * Save changed Metadata 740*55efc227SAndreas Gohr * 741*55efc227SAndreas Gohr * @author Sebastian Delmont <sdelmont@zonageek.com> 742*55efc227SAndreas Gohr */ 743*55efc227SAndreas Gohr function save($fileName = "") { 744*55efc227SAndreas Gohr if ($fileName == "") { 745*55efc227SAndreas Gohr $tmpName = $this->_fileName . ".tmp"; 746*55efc227SAndreas Gohr $this->_writeJPEG($tmpName); 747*55efc227SAndreas Gohr if (file_exists($tmpName)) { 748*55efc227SAndreas Gohr rename($tmpName, $this->_fileName); 749*55efc227SAndreas Gohr } 750*55efc227SAndreas Gohr } 751*55efc227SAndreas Gohr else { 752*55efc227SAndreas Gohr $this->_writeJPEG($fileName); 753*55efc227SAndreas Gohr } 754*55efc227SAndreas Gohr } 755*55efc227SAndreas Gohr 756*55efc227SAndreas Gohr /*************************************************************/ 757*55efc227SAndreas Gohr /* PRIVATE FUNCTIONS (Internal Use Only!) */ 758*55efc227SAndreas Gohr /*************************************************************/ 759*55efc227SAndreas Gohr 760*55efc227SAndreas Gohr /*************************************************************/ 761*55efc227SAndreas Gohr function _dispose() 762*55efc227SAndreas Gohr { 763*55efc227SAndreas Gohr $this->_fileName = $fileName; 764*55efc227SAndreas Gohr 765*55efc227SAndreas Gohr $this->_fp = null; 766*55efc227SAndreas Gohr $this->_type = 'unknown'; 767*55efc227SAndreas Gohr 768*55efc227SAndreas Gohr unset($this->_markers); 769*55efc227SAndreas Gohr unset($this->_info); 770*55efc227SAndreas Gohr } 771*55efc227SAndreas Gohr 772*55efc227SAndreas Gohr /*************************************************************/ 773*55efc227SAndreas Gohr function _readJPEG() 774*55efc227SAndreas Gohr { 775*55efc227SAndreas Gohr unset($this->_markers); 776*55efc227SAndreas Gohr unset($this->_info); 777*55efc227SAndreas Gohr $this->_markers = array(); 778*55efc227SAndreas Gohr $this->_info = array(); 779*55efc227SAndreas Gohr 780*55efc227SAndreas Gohr $this->_fp = @fopen($this->_fileName, 'rb'); 781*55efc227SAndreas Gohr if ($this->_fp) { 782*55efc227SAndreas Gohr if (file_exists($this->_fileName)) { 783*55efc227SAndreas Gohr $this->_type = 'file'; 784*55efc227SAndreas Gohr } 785*55efc227SAndreas Gohr else { 786*55efc227SAndreas Gohr $this->_type = 'url'; 787*55efc227SAndreas Gohr } 788*55efc227SAndreas Gohr } 789*55efc227SAndreas Gohr else { 790*55efc227SAndreas Gohr $this->_fp = null; 791*55efc227SAndreas Gohr return false; // ERROR: Can't open file 792*55efc227SAndreas Gohr } 793*55efc227SAndreas Gohr 794*55efc227SAndreas Gohr // Check for the JPEG signature 795*55efc227SAndreas Gohr $c1 = ord(fgetc($this->_fp)); 796*55efc227SAndreas Gohr $c2 = ord(fgetc($this->_fp)); 797*55efc227SAndreas Gohr 798*55efc227SAndreas Gohr if ($c1 != 0xFF || $c2 != 0xD8) { // (0xFF + SOI) 799*55efc227SAndreas Gohr $this->_markers = null; 800*55efc227SAndreas Gohr return false; // ERROR: File is not a JPEG 801*55efc227SAndreas Gohr } 802*55efc227SAndreas Gohr 803*55efc227SAndreas Gohr $count = 0; 804*55efc227SAndreas Gohr 805*55efc227SAndreas Gohr $done = false; 806*55efc227SAndreas Gohr $ok = true; 807*55efc227SAndreas Gohr 808*55efc227SAndreas Gohr while (!$done) { 809*55efc227SAndreas Gohr $capture = false; 810*55efc227SAndreas Gohr 811*55efc227SAndreas Gohr // First, skip any non 0xFF bytes 812*55efc227SAndreas Gohr $discarded = 0; 813*55efc227SAndreas Gohr $c = ord(fgetc($this->_fp)); 814*55efc227SAndreas Gohr while (!feof($this->_fp) && ($c != 0xFF)) { 815*55efc227SAndreas Gohr $discarded++; 816*55efc227SAndreas Gohr $c = ord(fgetc($this->_fp)); 817*55efc227SAndreas Gohr } 818*55efc227SAndreas Gohr // Then skip all 0xFF until the marker byte 819*55efc227SAndreas Gohr do { 820*55efc227SAndreas Gohr $marker = ord(fgetc($this->_fp)); 821*55efc227SAndreas Gohr } while (!feof($this->_fp) && ($marker == 0xFF)); 822*55efc227SAndreas Gohr 823*55efc227SAndreas Gohr if (feof($this->_fp)) { 824*55efc227SAndreas Gohr return false; // ERROR: Unexpected EOF 825*55efc227SAndreas Gohr } 826*55efc227SAndreas Gohr if ($discarded != 0) { 827*55efc227SAndreas Gohr return false; // ERROR: Extraneous data 828*55efc227SAndreas Gohr } 829*55efc227SAndreas Gohr 830*55efc227SAndreas Gohr $length = ord(fgetc($this->_fp)) * 256 + ord(fgetc($this->_fp)); 831*55efc227SAndreas Gohr if (feof($this->_fp)) { 832*55efc227SAndreas Gohr return false; // ERROR: Unexpected EOF 833*55efc227SAndreas Gohr } 834*55efc227SAndreas Gohr if ($length < 2) { 835*55efc227SAndreas Gohr return false; // ERROR: Extraneous data 836*55efc227SAndreas Gohr } 837*55efc227SAndreas Gohr $length = $length - 2; // The length we got counts itself 838*55efc227SAndreas Gohr 839*55efc227SAndreas Gohr switch ($marker) { 840*55efc227SAndreas Gohr case 0xC0: // SOF0 841*55efc227SAndreas Gohr case 0xC1: // SOF1 842*55efc227SAndreas Gohr case 0xC2: // SOF2 843*55efc227SAndreas Gohr case 0xC9: // SOF9 844*55efc227SAndreas Gohr case 0xE0: // APP0: JFIF data 845*55efc227SAndreas Gohr case 0xE1: // APP1: EXIF data 846*55efc227SAndreas Gohr case 0xED: // APP13: IPTC / Photoshop data 847*55efc227SAndreas Gohr $capture = true; 848*55efc227SAndreas Gohr break; 849*55efc227SAndreas Gohr case 0xDA: // SOS: Start of scan... the image itself and the last block on the file 850*55efc227SAndreas Gohr $capture = false; 851*55efc227SAndreas Gohr $length = -1; // This field has no length... it includes all data until EOF 852*55efc227SAndreas Gohr $done = true; 853*55efc227SAndreas Gohr break; 854*55efc227SAndreas Gohr default: 855*55efc227SAndreas Gohr $capture = true;//false; 856*55efc227SAndreas Gohr break; 857*55efc227SAndreas Gohr } 858*55efc227SAndreas Gohr 859*55efc227SAndreas Gohr $this->_markers[$count] = array(); 860*55efc227SAndreas Gohr $this->_markers[$count]['marker'] = $marker; 861*55efc227SAndreas Gohr $this->_markers[$count]['length'] = $length; 862*55efc227SAndreas Gohr 863*55efc227SAndreas Gohr if ($capture) { 864*55efc227SAndreas Gohr $this->_markers[$count]['data'] =& fread($this->_fp, $length); 865*55efc227SAndreas Gohr } 866*55efc227SAndreas Gohr elseif (!$done) { 867*55efc227SAndreas Gohr $result = @fseek($this->_fp, $length, SEEK_CUR); 868*55efc227SAndreas Gohr // fseek doesn't seem to like HTTP 'files', but fgetc has no problem 869*55efc227SAndreas Gohr if (!($result === 0)) { 870*55efc227SAndreas Gohr for ($i = 0; $i < $length; $i++) { 871*55efc227SAndreas Gohr fgetc($this->_fp); 872*55efc227SAndreas Gohr } 873*55efc227SAndreas Gohr } 874*55efc227SAndreas Gohr } 875*55efc227SAndreas Gohr $count++; 876*55efc227SAndreas Gohr } 877*55efc227SAndreas Gohr 878*55efc227SAndreas Gohr if ($this->_fp) { 879*55efc227SAndreas Gohr fclose($this->_fp); 880*55efc227SAndreas Gohr $this->_fp = null; 881*55efc227SAndreas Gohr } 882*55efc227SAndreas Gohr 883*55efc227SAndreas Gohr return $ok; 884*55efc227SAndreas Gohr } 885*55efc227SAndreas Gohr 886*55efc227SAndreas Gohr /*************************************************************/ 887*55efc227SAndreas Gohr function _parseAll() 888*55efc227SAndreas Gohr { 889*55efc227SAndreas Gohr if (!isset($this->_markers)) { 890*55efc227SAndreas Gohr $this->_readJPEG(); 891*55efc227SAndreas Gohr } 892*55efc227SAndreas Gohr 893*55efc227SAndreas Gohr if ($this->_markers == null) { 894*55efc227SAndreas Gohr return false; 895*55efc227SAndreas Gohr } 896*55efc227SAndreas Gohr 897*55efc227SAndreas Gohr if (!isset($this->_info['jfif'])) { 898*55efc227SAndreas Gohr $this->_parseMarkerJFIF(); 899*55efc227SAndreas Gohr } 900*55efc227SAndreas Gohr if (!isset($this->_info['jpeg'])) { 901*55efc227SAndreas Gohr $this->_parseMarkerSOF(); 902*55efc227SAndreas Gohr } 903*55efc227SAndreas Gohr if (!isset($this->_info['exif'])) { 904*55efc227SAndreas Gohr $this->_parseMarkerExif(); 905*55efc227SAndreas Gohr } 906*55efc227SAndreas Gohr if (!isset($this->_info['adobe'])) { 907*55efc227SAndreas Gohr $this->_parseMarkerAdobe(); 908*55efc227SAndreas Gohr } 909*55efc227SAndreas Gohr if (!isset($this->_info['file'])) { 910*55efc227SAndreas Gohr $this->_parseFileInfo(); 911*55efc227SAndreas Gohr } 912*55efc227SAndreas Gohr } 913*55efc227SAndreas Gohr 914*55efc227SAndreas Gohr /*************************************************************/ 915*55efc227SAndreas Gohr function _writeJPEG($outputName) 916*55efc227SAndreas Gohr { 917*55efc227SAndreas Gohr $this->_parseAll(); 918*55efc227SAndreas Gohr 919*55efc227SAndreas Gohr $wroteEXIF = false; 920*55efc227SAndreas Gohr $wroteAdobe = false; 921*55efc227SAndreas Gohr 922*55efc227SAndreas Gohr $this->_fp = @fopen($this->_fileName, 'r'); 923*55efc227SAndreas Gohr if ($this->_fp) { 924*55efc227SAndreas Gohr if (file_exists($this->_fileName)) { 925*55efc227SAndreas Gohr $this->_type = 'file'; 926*55efc227SAndreas Gohr } 927*55efc227SAndreas Gohr else { 928*55efc227SAndreas Gohr $this->_type = 'url'; 929*55efc227SAndreas Gohr } 930*55efc227SAndreas Gohr } 931*55efc227SAndreas Gohr else { 932*55efc227SAndreas Gohr $this->_fp = null; 933*55efc227SAndreas Gohr return false; // ERROR: Can't open file 934*55efc227SAndreas Gohr } 935*55efc227SAndreas Gohr 936*55efc227SAndreas Gohr $this->_fpout = fopen($outputName, 'wb'); 937*55efc227SAndreas Gohr if ($this->_fpout) { 938*55efc227SAndreas Gohr } 939*55efc227SAndreas Gohr else { 940*55efc227SAndreas Gohr $this->_fpout = null; 941*55efc227SAndreas Gohr fclose($this->_fp); 942*55efc227SAndreas Gohr $this->_fp = null; 943*55efc227SAndreas Gohr return false; // ERROR: Can't open output file 944*55efc227SAndreas Gohr } 945*55efc227SAndreas Gohr 946*55efc227SAndreas Gohr // Check for the JPEG signature 947*55efc227SAndreas Gohr $c1 = ord(fgetc($this->_fp)); 948*55efc227SAndreas Gohr $c2 = ord(fgetc($this->_fp)); 949*55efc227SAndreas Gohr 950*55efc227SAndreas Gohr if ($c1 != 0xFF || $c2 != 0xD8) { // (0xFF + SOI) 951*55efc227SAndreas Gohr return false; // ERROR: File is not a JPEG 952*55efc227SAndreas Gohr } 953*55efc227SAndreas Gohr 954*55efc227SAndreas Gohr fputs($this->_fpout, chr(0xFF), 1); 955*55efc227SAndreas Gohr fputs($this->_fpout, chr(0xD8), 1); // (0xFF + SOI) 956*55efc227SAndreas Gohr 957*55efc227SAndreas Gohr $count = 0; 958*55efc227SAndreas Gohr 959*55efc227SAndreas Gohr $done = false; 960*55efc227SAndreas Gohr $ok = true; 961*55efc227SAndreas Gohr 962*55efc227SAndreas Gohr while (!$done) { 963*55efc227SAndreas Gohr // First, skip any non 0xFF bytes 964*55efc227SAndreas Gohr $discarded = 0; 965*55efc227SAndreas Gohr $c = ord(fgetc($this->_fp)); 966*55efc227SAndreas Gohr while (!feof($this->_fp) && ($c != 0xFF)) { 967*55efc227SAndreas Gohr $discarded++; 968*55efc227SAndreas Gohr $c = ord(fgetc($this->_fp)); 969*55efc227SAndreas Gohr } 970*55efc227SAndreas Gohr // Then skip all 0xFF until the marker byte 971*55efc227SAndreas Gohr do { 972*55efc227SAndreas Gohr $marker = ord(fgetc($this->_fp)); 973*55efc227SAndreas Gohr } while (!feof($this->_fp) && ($marker == 0xFF)); 974*55efc227SAndreas Gohr 975*55efc227SAndreas Gohr if (feof($this->_fp)) { 976*55efc227SAndreas Gohr $ok = false; 977*55efc227SAndreas Gohr break; // ERROR: Unexpected EOF 978*55efc227SAndreas Gohr } 979*55efc227SAndreas Gohr if ($discarded != 0) { 980*55efc227SAndreas Gohr $ok = false; 981*55efc227SAndreas Gohr break; // ERROR: Extraneous data 982*55efc227SAndreas Gohr } 983*55efc227SAndreas Gohr 984*55efc227SAndreas Gohr $length = ord(fgetc($this->_fp)) * 256 + ord(fgetc($this->_fp)); 985*55efc227SAndreas Gohr if (feof($this->_fp)) { 986*55efc227SAndreas Gohr $ok = false; 987*55efc227SAndreas Gohr break; // ERROR: Unexpected EOF 988*55efc227SAndreas Gohr } 989*55efc227SAndreas Gohr if ($length < 2) { 990*55efc227SAndreas Gohr $ok = false; 991*55efc227SAndreas Gohr break; // ERROR: Extraneous data 992*55efc227SAndreas Gohr } 993*55efc227SAndreas Gohr $length = $length - 2; // The length we got counts itself 994*55efc227SAndreas Gohr 995*55efc227SAndreas Gohr unset($data); 996*55efc227SAndreas Gohr if ($marker == 0xE1) { // APP1: EXIF data 997*55efc227SAndreas Gohr $data =& $this->_createMarkerEXIF(); 998*55efc227SAndreas Gohr $wroteEXIF = true; 999*55efc227SAndreas Gohr } 1000*55efc227SAndreas Gohr elseif ($marker == 0xED) { // APP13: IPTC / Photoshop data 1001*55efc227SAndreas Gohr $data =& $this->_createMarkerAdobe(); 1002*55efc227SAndreas Gohr $wroteAdobe = true; 1003*55efc227SAndreas Gohr } 1004*55efc227SAndreas Gohr elseif ($marker == 0xDA) { // SOS: Start of scan... the image itself and the last block on the file 1005*55efc227SAndreas Gohr $done = true; 1006*55efc227SAndreas Gohr } 1007*55efc227SAndreas Gohr 1008*55efc227SAndreas Gohr if (!$wroteEXIF && (($marker < 0xE0) || ($marker > 0xEF))) { 1009*55efc227SAndreas Gohr if (isset($this->_info['exif']) && is_array($this->_info['exif'])) { 1010*55efc227SAndreas Gohr $exif =& $this->_createMarkerEXIF(); 1011*55efc227SAndreas Gohr $this->_writeJPEGMarker(0xE1, strlen($exif), $exif, 0); 1012*55efc227SAndreas Gohr unset($exif); 1013*55efc227SAndreas Gohr } 1014*55efc227SAndreas Gohr $wroteEXIF = true; 1015*55efc227SAndreas Gohr } 1016*55efc227SAndreas Gohr 1017*55efc227SAndreas Gohr if (!$wroteAdobe && (($marker < 0xE0) || ($marker > 0xEF))) { 1018*55efc227SAndreas Gohr if ((isset($this->_info['adobe']) && is_array($this->_info['adobe'])) 1019*55efc227SAndreas Gohr || (isset($this->_info['iptc']) && is_array($this->_info['iptc']))) { 1020*55efc227SAndreas Gohr $adobe =& $this->_createMarkerAdobe(); 1021*55efc227SAndreas Gohr $this->_writeJPEGMarker(0xED, strlen($adobe), $adobe, 0); 1022*55efc227SAndreas Gohr unset($adobe); 1023*55efc227SAndreas Gohr } 1024*55efc227SAndreas Gohr $wroteAdobe = true; 1025*55efc227SAndreas Gohr } 1026*55efc227SAndreas Gohr 1027*55efc227SAndreas Gohr $origLength = $length; 1028*55efc227SAndreas Gohr if (isset($data)) { 1029*55efc227SAndreas Gohr $length = strlen($data); 1030*55efc227SAndreas Gohr } 1031*55efc227SAndreas Gohr 1032*55efc227SAndreas Gohr if ($marker != -1) { 1033*55efc227SAndreas Gohr $this->_writeJPEGMarker($marker, $length, $data, $origLength); 1034*55efc227SAndreas Gohr } 1035*55efc227SAndreas Gohr } 1036*55efc227SAndreas Gohr 1037*55efc227SAndreas Gohr if ($this->_fp) { 1038*55efc227SAndreas Gohr fclose($this->_fp); 1039*55efc227SAndreas Gohr $this->_fp = null; 1040*55efc227SAndreas Gohr } 1041*55efc227SAndreas Gohr 1042*55efc227SAndreas Gohr if ($this->_fpout) { 1043*55efc227SAndreas Gohr fclose($this->_fpout); 1044*55efc227SAndreas Gohr $this->_fpout = null; 1045*55efc227SAndreas Gohr } 1046*55efc227SAndreas Gohr 1047*55efc227SAndreas Gohr return $ok; 1048*55efc227SAndreas Gohr } 1049*55efc227SAndreas Gohr 1050*55efc227SAndreas Gohr /*************************************************************/ 1051*55efc227SAndreas Gohr function _writeJPEGMarker($marker, $length, &$data, $origLength) 1052*55efc227SAndreas Gohr { 1053*55efc227SAndreas Gohr if ($length <= 0) { 1054*55efc227SAndreas Gohr return false; 1055*55efc227SAndreas Gohr } 1056*55efc227SAndreas Gohr 1057*55efc227SAndreas Gohr fputs($this->_fpout, chr(0xFF), 1); 1058*55efc227SAndreas Gohr fputs($this->_fpout, chr($marker), 1); 1059*55efc227SAndreas Gohr fputs($this->_fpout, chr((($length + 2) & 0x0000FF00) >> 8), 1); 1060*55efc227SAndreas Gohr fputs($this->_fpout, chr((($length + 2) & 0x000000FF) >> 0), 1); 1061*55efc227SAndreas Gohr 1062*55efc227SAndreas Gohr if (isset($data)) { 1063*55efc227SAndreas Gohr // Copy the generated data 1064*55efc227SAndreas Gohr fputs($this->_fpout, $data, $length); 1065*55efc227SAndreas Gohr 1066*55efc227SAndreas Gohr if ($origLength > 0) { // Skip the original data 1067*55efc227SAndreas Gohr $result = @fseek($this->_fp, $origLength, SEEK_CUR); 1068*55efc227SAndreas Gohr // fseek doesn't seem to like HTTP 'files', but fgetc has no problem 1069*55efc227SAndreas Gohr if ($result != 0) { 1070*55efc227SAndreas Gohr for ($i = 0; $i < $origLength; $i++) { 1071*55efc227SAndreas Gohr fgetc($this->_fp); 1072*55efc227SAndreas Gohr } 1073*55efc227SAndreas Gohr } 1074*55efc227SAndreas Gohr } 1075*55efc227SAndreas Gohr } 1076*55efc227SAndreas Gohr else { 1077*55efc227SAndreas Gohr if ($marker == 0xDA) { // Copy until EOF 1078*55efc227SAndreas Gohr while (!feof($this->_fp)) { 1079*55efc227SAndreas Gohr $data =& fread($this->_fp, 1024 * 16); 1080*55efc227SAndreas Gohr fputs($this->_fpout, $data, strlen($data)); 1081*55efc227SAndreas Gohr } 1082*55efc227SAndreas Gohr } 1083*55efc227SAndreas Gohr else { // Copy only $length bytes 1084*55efc227SAndreas Gohr $data =& fread($this->_fp, $length); 1085*55efc227SAndreas Gohr fputs($this->_fpout, $data, $length); 1086*55efc227SAndreas Gohr } 1087*55efc227SAndreas Gohr } 1088*55efc227SAndreas Gohr 1089*55efc227SAndreas Gohr return true; 1090*55efc227SAndreas Gohr } 1091*55efc227SAndreas Gohr 1092*55efc227SAndreas Gohr /*************************************************************/ 1093*55efc227SAndreas Gohr function _parseFileInfo() 1094*55efc227SAndreas Gohr { 1095*55efc227SAndreas Gohr if (file_exists($this->_fileName)) { 1096*55efc227SAndreas Gohr $this->_info['file'] = array(); 1097*55efc227SAndreas Gohr $this->_info['file']['Name'] = basename($this->_fileName); 1098*55efc227SAndreas Gohr $this->_info['file']['Size'] = filesize($this->_fileName); 1099*55efc227SAndreas Gohr if ($this->_info['file']['Size'] < 1024) { 1100*55efc227SAndreas Gohr $this->_info['file']['NiceSize'] = $this->_info['file']['Size'] . 'B'; 1101*55efc227SAndreas Gohr } 1102*55efc227SAndreas Gohr elseif ($this->_info['file']['Size'] < (1024 * 1024)) { 1103*55efc227SAndreas Gohr $this->_info['file']['NiceSize'] = round($this->_info['file']['Size'] / 1024) . 'KB'; 1104*55efc227SAndreas Gohr } 1105*55efc227SAndreas Gohr elseif ($this->_info['file']['Size'] < (1024 * 1024 * 1024)) { 1106*55efc227SAndreas Gohr $this->_info['file']['NiceSize'] = round($this->_info['file']['Size'] / 1024) . 'MB'; 1107*55efc227SAndreas Gohr } 1108*55efc227SAndreas Gohr else { 1109*55efc227SAndreas Gohr $this->_info['file']['NiceSize'] = $this->_info['file']['Size'] . 'B'; 1110*55efc227SAndreas Gohr } 1111*55efc227SAndreas Gohr $this->_info['file']['UnixTime'] = filemtime($this->_fileName); 1112*55efc227SAndreas Gohr 1113*55efc227SAndreas Gohr // Andreas Gohr <andi@splitbrain.org> 1114*55efc227SAndreas Gohr // get image size directly from file 1115*55efc227SAndreas Gohr $size = getimagesize($this->_fileName); 1116*55efc227SAndreas Gohr $this->_info['file']['Width'] = $size[0]; 1117*55efc227SAndreas Gohr $this->_info['file']['Height'] = $size[1]; 1118*55efc227SAndreas Gohr // set mime types and formats 1119*55efc227SAndreas Gohr // http://www.php.net/manual/en/function.getimagesize.php 1120*55efc227SAndreas Gohr // http://www.php.net/manual/en/function.image-type-to-mime-type.php 1121*55efc227SAndreas Gohr switch ($size[2]){ 1122*55efc227SAndreas Gohr case 1: 1123*55efc227SAndreas Gohr $this->_info['file']['Mime'] = 'image/gif'; 1124*55efc227SAndreas Gohr $this->_info['file']['Format'] = 'GIF'; 1125*55efc227SAndreas Gohr break; 1126*55efc227SAndreas Gohr case 2: 1127*55efc227SAndreas Gohr $this->_info['file']['Mime'] = 'image/jpeg'; 1128*55efc227SAndreas Gohr $this->_info['file']['Format'] = 'JPEG'; 1129*55efc227SAndreas Gohr break; 1130*55efc227SAndreas Gohr case 3: 1131*55efc227SAndreas Gohr $this->_info['file']['Mime'] = 'image/png'; 1132*55efc227SAndreas Gohr $this->_info['file']['Format'] = 'PNG'; 1133*55efc227SAndreas Gohr break; 1134*55efc227SAndreas Gohr case 4: 1135*55efc227SAndreas Gohr $this->_info['file']['Mime'] = 'application/x-shockwave-flash'; 1136*55efc227SAndreas Gohr $this->_info['file']['Format'] = 'SWF'; 1137*55efc227SAndreas Gohr break; 1138*55efc227SAndreas Gohr case 5: 1139*55efc227SAndreas Gohr $this->_info['file']['Mime'] = 'image/psd'; 1140*55efc227SAndreas Gohr $this->_info['file']['Format'] = 'PSD'; 1141*55efc227SAndreas Gohr break; 1142*55efc227SAndreas Gohr case 6: 1143*55efc227SAndreas Gohr $this->_info['file']['Mime'] = 'image/bmp'; 1144*55efc227SAndreas Gohr $this->_info['file']['Format'] = 'BMP'; 1145*55efc227SAndreas Gohr break; 1146*55efc227SAndreas Gohr case 7: 1147*55efc227SAndreas Gohr $this->_info['file']['Mime'] = 'image/tiff'; 1148*55efc227SAndreas Gohr $this->_info['file']['Format'] = 'TIFF (Intel)'; 1149*55efc227SAndreas Gohr break; 1150*55efc227SAndreas Gohr case 8: 1151*55efc227SAndreas Gohr $this->_info['file']['Mime'] = 'image/tiff'; 1152*55efc227SAndreas Gohr $this->_info['file']['Format'] = 'TIFF (Motorola)'; 1153*55efc227SAndreas Gohr break; 1154*55efc227SAndreas Gohr case 9: 1155*55efc227SAndreas Gohr $this->_info['file']['Mime'] = 'application/octet-stream'; 1156*55efc227SAndreas Gohr $this->_info['file']['Format'] = 'JPC'; 1157*55efc227SAndreas Gohr break; 1158*55efc227SAndreas Gohr case 10: 1159*55efc227SAndreas Gohr $this->_info['file']['Mime'] = 'image/jp2'; 1160*55efc227SAndreas Gohr $this->_info['file']['Format'] = 'JP2'; 1161*55efc227SAndreas Gohr break; 1162*55efc227SAndreas Gohr case 11: 1163*55efc227SAndreas Gohr $this->_info['file']['Mime'] = 'application/octet-stream'; 1164*55efc227SAndreas Gohr $this->_info['file']['Format'] = 'JPX'; 1165*55efc227SAndreas Gohr break; 1166*55efc227SAndreas Gohr case 12: 1167*55efc227SAndreas Gohr $this->_info['file']['Mime'] = 'application/octet-stream'; 1168*55efc227SAndreas Gohr $this->_info['file']['Format'] = 'JB2'; 1169*55efc227SAndreas Gohr break; 1170*55efc227SAndreas Gohr case 13: 1171*55efc227SAndreas Gohr $this->_info['file']['Mime'] = 'application/x-shockwave-flash'; 1172*55efc227SAndreas Gohr $this->_info['file']['Format'] = 'SWC'; 1173*55efc227SAndreas Gohr break; 1174*55efc227SAndreas Gohr case 14: 1175*55efc227SAndreas Gohr $this->_info['file']['Mime'] = 'image/iff'; 1176*55efc227SAndreas Gohr $this->_info['file']['Format'] = 'IFF'; 1177*55efc227SAndreas Gohr break; 1178*55efc227SAndreas Gohr case 15: 1179*55efc227SAndreas Gohr $this->_info['file']['Mime'] = 'image/vnd.wap.wbmp'; 1180*55efc227SAndreas Gohr $this->_info['file']['Format'] = 'WBMP'; 1181*55efc227SAndreas Gohr break; 1182*55efc227SAndreas Gohr case 16: 1183*55efc227SAndreas Gohr $this->_info['file']['Mime'] = 'image/xbm'; 1184*55efc227SAndreas Gohr $this->_info['file']['Format'] = 'XBM'; 1185*55efc227SAndreas Gohr break; 1186*55efc227SAndreas Gohr default: 1187*55efc227SAndreas Gohr $this->_info['file']['Mime'] = 'image/unknown'; 1188*55efc227SAndreas Gohr } 1189*55efc227SAndreas Gohr } 1190*55efc227SAndreas Gohr else { 1191*55efc227SAndreas Gohr $this->_info['file'] = array(); 1192*55efc227SAndreas Gohr $this->_info['file']['Name'] = basename($this->_fileName); 1193*55efc227SAndreas Gohr $this->_info['file']['Url'] = $this->_fileName; 1194*55efc227SAndreas Gohr } 1195*55efc227SAndreas Gohr 1196*55efc227SAndreas Gohr return true; 1197*55efc227SAndreas Gohr } 1198*55efc227SAndreas Gohr 1199*55efc227SAndreas Gohr /*************************************************************/ 1200*55efc227SAndreas Gohr function _parseMarkerJFIF() 1201*55efc227SAndreas Gohr { 1202*55efc227SAndreas Gohr if (!isset($this->_markers)) { 1203*55efc227SAndreas Gohr $this->_readJPEG(); 1204*55efc227SAndreas Gohr } 1205*55efc227SAndreas Gohr 1206*55efc227SAndreas Gohr if ($this->_markers == null) { 1207*55efc227SAndreas Gohr return false; 1208*55efc227SAndreas Gohr } 1209*55efc227SAndreas Gohr 1210*55efc227SAndreas Gohr $data = null; 1211*55efc227SAndreas Gohr $count = count($this->_markers); 1212*55efc227SAndreas Gohr for ($i = 0; $i < $count; $i++) { 1213*55efc227SAndreas Gohr if ($this->_markers[$i]['marker'] == 0xE0) { 1214*55efc227SAndreas Gohr $signature = $this->_getFixedString($this->_markers[$i]['data'], 0, 4); 1215*55efc227SAndreas Gohr if ($signature == 'JFIF') { 1216*55efc227SAndreas Gohr $data =& $this->_markers[$i]['data']; 1217*55efc227SAndreas Gohr break; 1218*55efc227SAndreas Gohr } 1219*55efc227SAndreas Gohr } 1220*55efc227SAndreas Gohr } 1221*55efc227SAndreas Gohr 1222*55efc227SAndreas Gohr if ($data == null) { 1223*55efc227SAndreas Gohr $this->_info['jfif'] = false; 1224*55efc227SAndreas Gohr return false; 1225*55efc227SAndreas Gohr } 1226*55efc227SAndreas Gohr 1227*55efc227SAndreas Gohr $pos = 0; 1228*55efc227SAndreas Gohr $this->_info['jfif'] = array(); 1229*55efc227SAndreas Gohr 1230*55efc227SAndreas Gohr 1231*55efc227SAndreas Gohr $vmaj = $this->_getByte($data, 5); 1232*55efc227SAndreas Gohr $vmin = $this->_getByte($data, 6); 1233*55efc227SAndreas Gohr 1234*55efc227SAndreas Gohr $this->_info['jfif']['Version'] = sprintf('%d.%02d', $vmaj, $vmin); 1235*55efc227SAndreas Gohr 1236*55efc227SAndreas Gohr $units = $this->_getByte($data, 7); 1237*55efc227SAndreas Gohr switch ($units) { 1238*55efc227SAndreas Gohr case 0: 1239*55efc227SAndreas Gohr $this->_info['jfif']['Units'] = 'pixels'; 1240*55efc227SAndreas Gohr break; 1241*55efc227SAndreas Gohr case 1: 1242*55efc227SAndreas Gohr $this->_info['jfif']['Units'] = 'dpi'; 1243*55efc227SAndreas Gohr break; 1244*55efc227SAndreas Gohr case 2: 1245*55efc227SAndreas Gohr $this->_info['jfif']['Units'] = 'dpcm'; 1246*55efc227SAndreas Gohr break; 1247*55efc227SAndreas Gohr default: 1248*55efc227SAndreas Gohr $this->_info['jfif']['Units'] = 'unknown'; 1249*55efc227SAndreas Gohr break; 1250*55efc227SAndreas Gohr } 1251*55efc227SAndreas Gohr 1252*55efc227SAndreas Gohr $xdens = $this->_getShort($data, 8); 1253*55efc227SAndreas Gohr $ydens = $this->_getShort($data, 10); 1254*55efc227SAndreas Gohr 1255*55efc227SAndreas Gohr $this->_info['jfif']['XDensity'] = $xdens; 1256*55efc227SAndreas Gohr $this->_info['jfif']['YDensity'] = $ydens; 1257*55efc227SAndreas Gohr 1258*55efc227SAndreas Gohr $thumbx = $this->_getByte($data, 12); 1259*55efc227SAndreas Gohr $thumby = $this->_getByte($data, 13); 1260*55efc227SAndreas Gohr 1261*55efc227SAndreas Gohr $this->_info['jfif']['ThumbnailWidth'] = $thumbx; 1262*55efc227SAndreas Gohr $this->_info['jfif']['ThumbnailHeight'] = $thumby; 1263*55efc227SAndreas Gohr 1264*55efc227SAndreas Gohr return true; 1265*55efc227SAndreas Gohr } 1266*55efc227SAndreas Gohr 1267*55efc227SAndreas Gohr /*************************************************************/ 1268*55efc227SAndreas Gohr function _parseMarkerSOF() 1269*55efc227SAndreas Gohr { 1270*55efc227SAndreas Gohr if (!isset($this->_markers)) { 1271*55efc227SAndreas Gohr $this->_readJPEG(); 1272*55efc227SAndreas Gohr } 1273*55efc227SAndreas Gohr 1274*55efc227SAndreas Gohr if ($this->_markers == null) { 1275*55efc227SAndreas Gohr return false; 1276*55efc227SAndreas Gohr } 1277*55efc227SAndreas Gohr 1278*55efc227SAndreas Gohr $data = null; 1279*55efc227SAndreas Gohr $count = count($this->_markers); 1280*55efc227SAndreas Gohr for ($i = 0; $i < $count; $i++) { 1281*55efc227SAndreas Gohr switch ($this->_markers[$i]['marker']) { 1282*55efc227SAndreas Gohr case 0xC0: // SOF0 1283*55efc227SAndreas Gohr case 0xC1: // SOF1 1284*55efc227SAndreas Gohr case 0xC2: // SOF2 1285*55efc227SAndreas Gohr case 0xC9: // SOF9 1286*55efc227SAndreas Gohr $data =& $this->_markers[$i]['data']; 1287*55efc227SAndreas Gohr $marker = $this->_markers[$i]['marker']; 1288*55efc227SAndreas Gohr break; 1289*55efc227SAndreas Gohr } 1290*55efc227SAndreas Gohr } 1291*55efc227SAndreas Gohr 1292*55efc227SAndreas Gohr if ($data == null) { 1293*55efc227SAndreas Gohr $this->_info['sof'] = false; 1294*55efc227SAndreas Gohr return false; 1295*55efc227SAndreas Gohr } 1296*55efc227SAndreas Gohr 1297*55efc227SAndreas Gohr $pos = 0; 1298*55efc227SAndreas Gohr $this->_info['sof'] = array(); 1299*55efc227SAndreas Gohr 1300*55efc227SAndreas Gohr 1301*55efc227SAndreas Gohr switch ($marker) { 1302*55efc227SAndreas Gohr case 0xC0: // SOF0 1303*55efc227SAndreas Gohr $format = 'Baseline'; 1304*55efc227SAndreas Gohr break; 1305*55efc227SAndreas Gohr case 0xC1: // SOF1 1306*55efc227SAndreas Gohr $format = 'Progessive'; 1307*55efc227SAndreas Gohr break; 1308*55efc227SAndreas Gohr case 0xC2: // SOF2 1309*55efc227SAndreas Gohr $format = 'Non-baseline'; 1310*55efc227SAndreas Gohr break; 1311*55efc227SAndreas Gohr case 0xC9: // SOF9 1312*55efc227SAndreas Gohr $format = 'Arithmetic'; 1313*55efc227SAndreas Gohr break; 1314*55efc227SAndreas Gohr default: 1315*55efc227SAndreas Gohr return false; 1316*55efc227SAndreas Gohr break; 1317*55efc227SAndreas Gohr } 1318*55efc227SAndreas Gohr 1319*55efc227SAndreas Gohr 1320*55efc227SAndreas Gohr $this->_info['sof']['Format'] = $format; 1321*55efc227SAndreas Gohr 1322*55efc227SAndreas Gohr $this->_info['sof']['SamplePrecision'] = $this->_getByte($data, $pos + 0); 1323*55efc227SAndreas Gohr $this->_info['sof']['ImageHeight'] = $this->_getShort($data, $pos + 1); 1324*55efc227SAndreas Gohr $this->_info['sof']['ImageWidth'] = $this->_getShort($data, $pos + 3); 1325*55efc227SAndreas Gohr $this->_info['sof']['ColorChannels'] = $this->_getByte($data, $pos + 5); 1326*55efc227SAndreas Gohr 1327*55efc227SAndreas Gohr return true; 1328*55efc227SAndreas Gohr } 1329*55efc227SAndreas Gohr 1330*55efc227SAndreas Gohr /*************************************************************/ 1331*55efc227SAndreas Gohr function _parseMarkerExif() 1332*55efc227SAndreas Gohr { 1333*55efc227SAndreas Gohr if (!isset($this->_markers)) { 1334*55efc227SAndreas Gohr $this->_readJPEG(); 1335*55efc227SAndreas Gohr } 1336*55efc227SAndreas Gohr 1337*55efc227SAndreas Gohr if ($this->_markers == null) { 1338*55efc227SAndreas Gohr return false; 1339*55efc227SAndreas Gohr } 1340*55efc227SAndreas Gohr 1341*55efc227SAndreas Gohr $data = null; 1342*55efc227SAndreas Gohr $count = count($this->_markers); 1343*55efc227SAndreas Gohr for ($i = 0; $i < $count; $i++) { 1344*55efc227SAndreas Gohr if ($this->_markers[$i]['marker'] == 0xE1) { 1345*55efc227SAndreas Gohr $signature = $this->_getFixedString($this->_markers[$i]['data'], 0, 6); 1346*55efc227SAndreas Gohr if ($signature == "Exif\0\0") { 1347*55efc227SAndreas Gohr $data =& $this->_markers[$i]['data']; 1348*55efc227SAndreas Gohr break; 1349*55efc227SAndreas Gohr } 1350*55efc227SAndreas Gohr } 1351*55efc227SAndreas Gohr } 1352*55efc227SAndreas Gohr 1353*55efc227SAndreas Gohr if ($data == null) { 1354*55efc227SAndreas Gohr $this->_info['exif'] = false; 1355*55efc227SAndreas Gohr return false; 1356*55efc227SAndreas Gohr } 1357*55efc227SAndreas Gohr $pos = 6; 1358*55efc227SAndreas Gohr $this->_info['exif'] = array(); 1359*55efc227SAndreas Gohr 1360*55efc227SAndreas Gohr // We don't increment $pos after this because Exif uses offsets relative to this point 1361*55efc227SAndreas Gohr 1362*55efc227SAndreas Gohr $byteAlign = $this->_getShort($data, $pos + 0); 1363*55efc227SAndreas Gohr 1364*55efc227SAndreas Gohr if ($byteAlign == 0x4949) { // "II" 1365*55efc227SAndreas Gohr $isBigEndian = false; 1366*55efc227SAndreas Gohr } 1367*55efc227SAndreas Gohr elseif ($byteAlign == 0x4D4D) { // "MM" 1368*55efc227SAndreas Gohr $isBigEndian = true; 1369*55efc227SAndreas Gohr } 1370*55efc227SAndreas Gohr else { 1371*55efc227SAndreas Gohr return false; // Unexpected data 1372*55efc227SAndreas Gohr } 1373*55efc227SAndreas Gohr 1374*55efc227SAndreas Gohr $alignCheck = $this->_getShort($data, $pos + 2, $isBigEndian); 1375*55efc227SAndreas Gohr if ($alignCheck != 0x002A) // That's the expected value 1376*55efc227SAndreas Gohr return false; // Unexpected data 1377*55efc227SAndreas Gohr 1378*55efc227SAndreas Gohr if ($isBigEndian) { 1379*55efc227SAndreas Gohr $this->_info['exif']['ByteAlign'] = "Big Endian"; 1380*55efc227SAndreas Gohr } 1381*55efc227SAndreas Gohr else { 1382*55efc227SAndreas Gohr $this->_info['exif']['ByteAlign'] = "Little Endian"; 1383*55efc227SAndreas Gohr } 1384*55efc227SAndreas Gohr 1385*55efc227SAndreas Gohr $offsetIFD0 = $this->_getLong($data, $pos + 4, $isBigEndian); 1386*55efc227SAndreas Gohr if ($offsetIFD0 < 8) 1387*55efc227SAndreas Gohr return false; // Unexpected data 1388*55efc227SAndreas Gohr 1389*55efc227SAndreas Gohr $offsetIFD1 = $this->_readIFD($data, $pos, $offsetIFD0, $isBigEndian, 'ifd0'); 1390*55efc227SAndreas Gohr if ($offsetIFD1 != 0) 1391*55efc227SAndreas Gohr $this->_readIFD($data, $pos, $offsetIFD1, $isBigEndian, 'ifd1'); 1392*55efc227SAndreas Gohr 1393*55efc227SAndreas Gohr return true; 1394*55efc227SAndreas Gohr } 1395*55efc227SAndreas Gohr 1396*55efc227SAndreas Gohr /*************************************************************/ 1397*55efc227SAndreas Gohr function _readIFD($data, $base, $offset, $isBigEndian, $mode) 1398*55efc227SAndreas Gohr { 1399*55efc227SAndreas Gohr $EXIFTags = $this->_exifTagNames($mode); 1400*55efc227SAndreas Gohr 1401*55efc227SAndreas Gohr $numEntries = $this->_getShort($data, $base + $offset, $isBigEndian); 1402*55efc227SAndreas Gohr $offset += 2; 1403*55efc227SAndreas Gohr 1404*55efc227SAndreas Gohr $exifTIFFOffset = 0; 1405*55efc227SAndreas Gohr $exifTIFFLength = 0; 1406*55efc227SAndreas Gohr $exifThumbnailOffset = 0; 1407*55efc227SAndreas Gohr $exifThumbnailLength = 0; 1408*55efc227SAndreas Gohr 1409*55efc227SAndreas Gohr for ($i = 0; $i < $numEntries; $i++) { 1410*55efc227SAndreas Gohr $tag = $this->_getShort($data, $base + $offset, $isBigEndian); 1411*55efc227SAndreas Gohr $offset += 2; 1412*55efc227SAndreas Gohr $type = $this->_getShort($data, $base + $offset, $isBigEndian); 1413*55efc227SAndreas Gohr $offset += 2; 1414*55efc227SAndreas Gohr $count = $this->_getLong($data, $base + $offset, $isBigEndian); 1415*55efc227SAndreas Gohr $offset += 4; 1416*55efc227SAndreas Gohr 1417*55efc227SAndreas Gohr if (($type < 1) || ($type > 12)) 1418*55efc227SAndreas Gohr return false; // Unexpected Type 1419*55efc227SAndreas Gohr 1420*55efc227SAndreas Gohr $typeLengths = array( -1, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8 ); 1421*55efc227SAndreas Gohr 1422*55efc227SAndreas Gohr $dataLength = $typeLengths[$type] * $count; 1423*55efc227SAndreas Gohr if ($dataLength > 4) { 1424*55efc227SAndreas Gohr $dataOffset = $this->_getLong($data, $base + $offset, $isBigEndian); 1425*55efc227SAndreas Gohr $rawValue = $this->_getFixedString($data, $base + $dataOffset, $dataLength); 1426*55efc227SAndreas Gohr } 1427*55efc227SAndreas Gohr else { 1428*55efc227SAndreas Gohr $rawValue = $this->_getFixedString($data, $base + $offset, $dataLength); 1429*55efc227SAndreas Gohr } 1430*55efc227SAndreas Gohr $offset += 4; 1431*55efc227SAndreas Gohr 1432*55efc227SAndreas Gohr switch ($type) { 1433*55efc227SAndreas Gohr case 1: // UBYTE 1434*55efc227SAndreas Gohr if ($count == 1) { 1435*55efc227SAndreas Gohr $value = $this->_getByte($rawValue, 0); 1436*55efc227SAndreas Gohr } 1437*55efc227SAndreas Gohr else { 1438*55efc227SAndreas Gohr $value = array(); 1439*55efc227SAndreas Gohr for ($j = 0; $j < $count; $j++) 1440*55efc227SAndreas Gohr $value[$j] = $this->_getByte($rawValue, $j); 1441*55efc227SAndreas Gohr } 1442*55efc227SAndreas Gohr break; 1443*55efc227SAndreas Gohr case 2: // ASCII 1444*55efc227SAndreas Gohr $value = $rawValue; 1445*55efc227SAndreas Gohr break; 1446*55efc227SAndreas Gohr case 3: // USHORT 1447*55efc227SAndreas Gohr if ($count == 1) { 1448*55efc227SAndreas Gohr $value = $this->_getShort($rawValue, 0, $isBigEndian); 1449*55efc227SAndreas Gohr } 1450*55efc227SAndreas Gohr else { 1451*55efc227SAndreas Gohr $value = array(); 1452*55efc227SAndreas Gohr for ($j = 0; $j < $count; $j++) 1453*55efc227SAndreas Gohr $value[$j] = $this->_getShort($rawValue, $j * 2, $isBigEndian); 1454*55efc227SAndreas Gohr } 1455*55efc227SAndreas Gohr break; 1456*55efc227SAndreas Gohr case 4: // ULONG 1457*55efc227SAndreas Gohr if ($count == 1) { 1458*55efc227SAndreas Gohr $value = $this->_getLong($rawValue, 0, $isBigEndian); 1459*55efc227SAndreas Gohr } 1460*55efc227SAndreas Gohr else { 1461*55efc227SAndreas Gohr $value = array(); 1462*55efc227SAndreas Gohr for ($j = 0; $j < $count; $j++) 1463*55efc227SAndreas Gohr $value[$j] = $this->_getLong($rawValue, $j * 4, $isBigEndian); 1464*55efc227SAndreas Gohr } 1465*55efc227SAndreas Gohr break; 1466*55efc227SAndreas Gohr case 5: // URATIONAL 1467*55efc227SAndreas Gohr if ($count == 1) { 1468*55efc227SAndreas Gohr $a = $this->_getLong($rawValue, 0, $isBigEndian); 1469*55efc227SAndreas Gohr $b = $this->_getLong($rawValue, 4, $isBigEndian); 1470*55efc227SAndreas Gohr $value = array(); 1471*55efc227SAndreas Gohr $value['val'] = 0; 1472*55efc227SAndreas Gohr $value['num'] = $a; 1473*55efc227SAndreas Gohr $value['den'] = $b; 1474*55efc227SAndreas Gohr if (($a != 0) && ($b != 0)) { 1475*55efc227SAndreas Gohr $value['val'] = $a / $b; 1476*55efc227SAndreas Gohr } 1477*55efc227SAndreas Gohr } 1478*55efc227SAndreas Gohr else { 1479*55efc227SAndreas Gohr $value = array(); 1480*55efc227SAndreas Gohr for ($j = 0; $j < $count; $j++) { 1481*55efc227SAndreas Gohr $a = $this->_getLong($rawValue, $j * 8, $isBigEndian); 1482*55efc227SAndreas Gohr $b = $this->_getLong($rawValue, ($j * 8) + 4, $isBigEndian); 1483*55efc227SAndreas Gohr $value = array(); 1484*55efc227SAndreas Gohr $value[$j]['val'] = 0; 1485*55efc227SAndreas Gohr $value[$j]['num'] = $a; 1486*55efc227SAndreas Gohr $value[$j]['den'] = $b; 1487*55efc227SAndreas Gohr if (($a != 0) && ($b != 0)) 1488*55efc227SAndreas Gohr $value[$j]['val'] = $a / $b; 1489*55efc227SAndreas Gohr } 1490*55efc227SAndreas Gohr } 1491*55efc227SAndreas Gohr break; 1492*55efc227SAndreas Gohr case 6: // SBYTE 1493*55efc227SAndreas Gohr if ($count == 1) { 1494*55efc227SAndreas Gohr $value = $this->_getByte($rawValue, 0); 1495*55efc227SAndreas Gohr } 1496*55efc227SAndreas Gohr else { 1497*55efc227SAndreas Gohr $value = array(); 1498*55efc227SAndreas Gohr for ($j = 0; $j < $count; $j++) 1499*55efc227SAndreas Gohr $value[$j] = $this->_getByte($rawValue, $j); 1500*55efc227SAndreas Gohr } 1501*55efc227SAndreas Gohr break; 1502*55efc227SAndreas Gohr case 7: // UNDEFINED 1503*55efc227SAndreas Gohr $value = $rawValue; 1504*55efc227SAndreas Gohr break; 1505*55efc227SAndreas Gohr case 8: // SSHORT 1506*55efc227SAndreas Gohr if ($count == 1) { 1507*55efc227SAndreas Gohr $value = $this->_getShort($rawValue, 0, $isBigEndian); 1508*55efc227SAndreas Gohr } 1509*55efc227SAndreas Gohr else { 1510*55efc227SAndreas Gohr $value = array(); 1511*55efc227SAndreas Gohr for ($j = 0; $j < $count; $j++) 1512*55efc227SAndreas Gohr $value[$j] = $this->_getShort($rawValue, $j * 2, $isBigEndian); 1513*55efc227SAndreas Gohr } 1514*55efc227SAndreas Gohr break; 1515*55efc227SAndreas Gohr case 9: // SLONG 1516*55efc227SAndreas Gohr if ($count == 1) { 1517*55efc227SAndreas Gohr $value = $this->_getLong($rawValue, 0, $isBigEndian); 1518*55efc227SAndreas Gohr } 1519*55efc227SAndreas Gohr else { 1520*55efc227SAndreas Gohr $value = array(); 1521*55efc227SAndreas Gohr for ($j = 0; $j < $count; $j++) 1522*55efc227SAndreas Gohr $value[$j] = $this->_getLong($rawValue, $j * 4, $isBigEndian); 1523*55efc227SAndreas Gohr } 1524*55efc227SAndreas Gohr break; 1525*55efc227SAndreas Gohr case 10: // SRATIONAL 1526*55efc227SAndreas Gohr if ($count == 1) { 1527*55efc227SAndreas Gohr $a = $this->_getLong($rawValue, 0, $isBigEndian); 1528*55efc227SAndreas Gohr $b = $this->_getLong($rawValue, 4, $isBigEndian); 1529*55efc227SAndreas Gohr $value = array(); 1530*55efc227SAndreas Gohr $value['val'] = 0; 1531*55efc227SAndreas Gohr $value['num'] = $a; 1532*55efc227SAndreas Gohr $value['den'] = $b; 1533*55efc227SAndreas Gohr if (($a != 0) && ($b != 0)) 1534*55efc227SAndreas Gohr $value['val'] = $a / $b; 1535*55efc227SAndreas Gohr } 1536*55efc227SAndreas Gohr else { 1537*55efc227SAndreas Gohr $value = array(); 1538*55efc227SAndreas Gohr for ($j = 0; $j < $count; $j++) { 1539*55efc227SAndreas Gohr $a = $this->_getLong($rawValue, $j * 8, $isBigEndian); 1540*55efc227SAndreas Gohr $b = $this->_getLong($rawValue, ($j * 8) + 4, $isBigEndian); 1541*55efc227SAndreas Gohr $value = array(); 1542*55efc227SAndreas Gohr $value[$j]['val'] = 0; 1543*55efc227SAndreas Gohr $value[$j]['num'] = $a; 1544*55efc227SAndreas Gohr $value[$j]['den'] = $b; 1545*55efc227SAndreas Gohr if (($a != 0) && ($b != 0)) 1546*55efc227SAndreas Gohr $value[$j]['val'] = $a / $b; 1547*55efc227SAndreas Gohr } 1548*55efc227SAndreas Gohr } 1549*55efc227SAndreas Gohr break; 1550*55efc227SAndreas Gohr case 11: // FLOAT 1551*55efc227SAndreas Gohr $value = $rawValue; 1552*55efc227SAndreas Gohr break; 1553*55efc227SAndreas Gohr 1554*55efc227SAndreas Gohr case 12: // DFLOAT 1555*55efc227SAndreas Gohr $value = $rawValue; 1556*55efc227SAndreas Gohr break; 1557*55efc227SAndreas Gohr default: 1558*55efc227SAndreas Gohr return false; // Unexpected Type 1559*55efc227SAndreas Gohr } 1560*55efc227SAndreas Gohr 1561*55efc227SAndreas Gohr $tagName = ''; 1562*55efc227SAndreas Gohr if (($mode == 'ifd0') && ($tag == 0x8769)) { // ExifIFDOffset 1563*55efc227SAndreas Gohr $this->_readIFD($data, $base, $value, $isBigEndian, 'exif'); 1564*55efc227SAndreas Gohr } 1565*55efc227SAndreas Gohr elseif (($mode == 'ifd0') && ($tag == 0x8825)) { // GPSIFDOffset 1566*55efc227SAndreas Gohr $this->_readIFD($data, $base, $value, $isBigEndian, 'gps'); 1567*55efc227SAndreas Gohr } 1568*55efc227SAndreas Gohr elseif (($mode == 'ifd1') && ($tag == 0x0111)) { // TIFFStripOffsets 1569*55efc227SAndreas Gohr $exifTIFFOffset = $value; 1570*55efc227SAndreas Gohr } 1571*55efc227SAndreas Gohr elseif (($mode == 'ifd1') && ($tag == 0x0117)) { // TIFFStripByteCounts 1572*55efc227SAndreas Gohr $exifTIFFLength = $value; 1573*55efc227SAndreas Gohr } 1574*55efc227SAndreas Gohr elseif (($mode == 'ifd1') && ($tag == 0x0201)) { // TIFFJFIFOffset 1575*55efc227SAndreas Gohr $exifThumbnailOffset = $value; 1576*55efc227SAndreas Gohr } 1577*55efc227SAndreas Gohr elseif (($mode == 'ifd1') && ($tag == 0x0202)) { // TIFFJFIFLength 1578*55efc227SAndreas Gohr $exifThumbnailLength = $value; 1579*55efc227SAndreas Gohr } 1580*55efc227SAndreas Gohr elseif (($mode == 'exif') && ($tag == 0xA005)) { // InteropIFDOffset 1581*55efc227SAndreas Gohr $this->_readIFD($data, $base, $value, $isBigEndian, 'interop'); 1582*55efc227SAndreas Gohr } 1583*55efc227SAndreas Gohr // elseif (($mode == 'exif') && ($tag == 0x927C)) { // MakerNote 1584*55efc227SAndreas Gohr // } 1585*55efc227SAndreas Gohr else { 1586*55efc227SAndreas Gohr if (isset($EXIFTags[$tag])) { 1587*55efc227SAndreas Gohr $tagName = $EXIFTags[$tag]; 1588*55efc227SAndreas Gohr if (isset($this->_info['exif'][$tagName])) { 1589*55efc227SAndreas Gohr if (!is_array($this->_info['exif'][$tagName])) { 1590*55efc227SAndreas Gohr $aux = array(); 1591*55efc227SAndreas Gohr $aux[0] = $this->_info['exif'][$tagName]; 1592*55efc227SAndreas Gohr $this->_info['exif'][$tagName] = $aux; 1593*55efc227SAndreas Gohr } 1594*55efc227SAndreas Gohr 1595*55efc227SAndreas Gohr $this->_info['exif'][$tagName][count($this->_info['exif'][$tagName])] = $value; 1596*55efc227SAndreas Gohr } 1597*55efc227SAndreas Gohr else { 1598*55efc227SAndreas Gohr $this->_info['exif'][$tagName] = $value; 1599*55efc227SAndreas Gohr } 1600*55efc227SAndreas Gohr } 1601*55efc227SAndreas Gohr else { 1602*55efc227SAndreas Gohr#echo sprintf("<h1>Unknown tag %02x (t: %d l: %d) %s in %s</h1>", $tag, $type, $count, $mode, $this->_fileName); 1603*55efc227SAndreas Gohr // Unknown Tags will be ignored!!! 1604*55efc227SAndreas Gohr // That's because the tag might be a pointer (like the Exif tag) 1605*55efc227SAndreas Gohr // and saving it without saving the data it points to might 1606*55efc227SAndreas Gohr // create an invalid file. 1607*55efc227SAndreas Gohr } 1608*55efc227SAndreas Gohr } 1609*55efc227SAndreas Gohr } 1610*55efc227SAndreas Gohr 1611*55efc227SAndreas Gohr if (($exifThumbnailOffset > 0) && ($exifThumbnailLength > 0)) { 1612*55efc227SAndreas Gohr $this->_info['exif']['JFIFThumbnail'] = $this->_getFixedString($data, $base + $exifThumbnailOffset, $exifThumbnailLength); 1613*55efc227SAndreas Gohr } 1614*55efc227SAndreas Gohr 1615*55efc227SAndreas Gohr if (($exifTIFFOffset > 0) && ($exifTIFFLength > 0)) { 1616*55efc227SAndreas Gohr $this->_info['exif']['TIFFStrips'] = $this->_getFixedString($data, $base + $exifTIFFOffset, $exifTIFFLength); 1617*55efc227SAndreas Gohr } 1618*55efc227SAndreas Gohr 1619*55efc227SAndreas Gohr $nextOffset = $this->_getLong($data, $base + $offset, $isBigEndian); 1620*55efc227SAndreas Gohr return $nextOffset; 1621*55efc227SAndreas Gohr } 1622*55efc227SAndreas Gohr 1623*55efc227SAndreas Gohr /*************************************************************/ 1624*55efc227SAndreas Gohr function & _createMarkerExif() 1625*55efc227SAndreas Gohr { 1626*55efc227SAndreas Gohr $data = null; 1627*55efc227SAndreas Gohr $count = count($this->_markers); 1628*55efc227SAndreas Gohr for ($i = 0; $i < $count; $i++) { 1629*55efc227SAndreas Gohr if ($this->_markers[$i]['marker'] == 0xE1) { 1630*55efc227SAndreas Gohr $signature = $this->_getFixedString($this->_markers[$i]['data'], 0, 6); 1631*55efc227SAndreas Gohr if ($signature == "Exif\0\0") { 1632*55efc227SAndreas Gohr $data =& $this->_markers[$i]['data']; 1633*55efc227SAndreas Gohr break; 1634*55efc227SAndreas Gohr } 1635*55efc227SAndreas Gohr } 1636*55efc227SAndreas Gohr } 1637*55efc227SAndreas Gohr 1638*55efc227SAndreas Gohr if (!isset($this->_info['exif'])) { 1639*55efc227SAndreas Gohr return false; 1640*55efc227SAndreas Gohr } 1641*55efc227SAndreas Gohr 1642*55efc227SAndreas Gohr $data = "Exif\0\0"; 1643*55efc227SAndreas Gohr $pos = 6; 1644*55efc227SAndreas Gohr $offsetBase = 6; 1645*55efc227SAndreas Gohr 1646*55efc227SAndreas Gohr if (isset($this->_info['exif']['ByteAlign']) && ($this->_info['exif']['ByteAlign'] == "Big Endian")) { 1647*55efc227SAndreas Gohr $isBigEndian = true; 1648*55efc227SAndreas Gohr $aux = "MM"; 1649*55efc227SAndreas Gohr $pos = $this->_putString($data, $pos, $aux); 1650*55efc227SAndreas Gohr } 1651*55efc227SAndreas Gohr else { 1652*55efc227SAndreas Gohr $isBigEndian = false; 1653*55efc227SAndreas Gohr $aux = "II"; 1654*55efc227SAndreas Gohr $pos = $this->_putString($data, $pos, $aux); 1655*55efc227SAndreas Gohr } 1656*55efc227SAndreas Gohr $pos = $this->_putShort($data, $pos, 0x002A, $isBigEndian); 1657*55efc227SAndreas Gohr $pos = $this->_putLong($data, $pos, 0x00000008, $isBigEndian); // IFD0 Offset is always 8 1658*55efc227SAndreas Gohr 1659*55efc227SAndreas Gohr $ifd0 =& $this->_getIFDEntries($isBigEndian, 'ifd0'); 1660*55efc227SAndreas Gohr $ifd1 =& $this->_getIFDEntries($isBigEndian, 'ifd1'); 1661*55efc227SAndreas Gohr 1662*55efc227SAndreas Gohr $pos = $this->_writeIFD($data, $pos, $offsetBase, $ifd0, $isBigEndian, true); 1663*55efc227SAndreas Gohr $pos = $this->_writeIFD($data, $pos, $offsetBase, $ifd1, $isBigEndian, false); 1664*55efc227SAndreas Gohr 1665*55efc227SAndreas Gohr return $data; 1666*55efc227SAndreas Gohr } 1667*55efc227SAndreas Gohr 1668*55efc227SAndreas Gohr /*************************************************************/ 1669*55efc227SAndreas Gohr function _writeIFD(&$data, $pos, $offsetBase, &$entries, $isBigEndian, $hasNext) 1670*55efc227SAndreas Gohr { 1671*55efc227SAndreas Gohr $tiffData = null; 1672*55efc227SAndreas Gohr $tiffDataOffsetPos = -1; 1673*55efc227SAndreas Gohr 1674*55efc227SAndreas Gohr $entryCount = count($entries); 1675*55efc227SAndreas Gohr 1676*55efc227SAndreas Gohr $dataPos = $pos + 2 + ($entryCount * 12) + 4; 1677*55efc227SAndreas Gohr $pos = $this->_putShort($data, $pos, $entryCount, $isBigEndian); 1678*55efc227SAndreas Gohr 1679*55efc227SAndreas Gohr for ($i = 0; $i < $entryCount; $i++) { 1680*55efc227SAndreas Gohr $tag = $entries[$i]['tag']; 1681*55efc227SAndreas Gohr $type = $entries[$i]['type']; 1682*55efc227SAndreas Gohr 1683*55efc227SAndreas Gohr if ($type == -99) { // SubIFD 1684*55efc227SAndreas Gohr $pos = $this->_putShort($data, $pos, $tag, $isBigEndian); 1685*55efc227SAndreas Gohr $pos = $this->_putShort($data, $pos, 0x04, $isBigEndian); // LONG 1686*55efc227SAndreas Gohr $pos = $this->_putLong($data, $pos, 0x01, $isBigEndian); // Count = 1 1687*55efc227SAndreas Gohr $pos = $this->_putLong($data, $pos, $dataPos - $offsetBase, $isBigEndian); 1688*55efc227SAndreas Gohr 1689*55efc227SAndreas Gohr $dataPos = $this->_writeIFD($data, $dataPos, $offsetBase, $entries[$i]['value'], $isBigEndian, false); 1690*55efc227SAndreas Gohr } 1691*55efc227SAndreas Gohr elseif ($type == -98) { // TIFF Data 1692*55efc227SAndreas Gohr $pos = $this->_putShort($data, $pos, $tag, $isBigEndian); 1693*55efc227SAndreas Gohr $pos = $this->_putShort($data, $pos, 0x04, $isBigEndian); // LONG 1694*55efc227SAndreas Gohr $pos = $this->_putLong($data, $pos, 0x01, $isBigEndian); // Count = 1 1695*55efc227SAndreas Gohr $tiffDataOffsetPos = $pos; 1696*55efc227SAndreas Gohr $pos = $this->_putLong($data, $pos, 0x00, $isBigEndian); // For Now 1697*55efc227SAndreas Gohr $tiffData =& $entries[$i]['value'] ; 1698*55efc227SAndreas Gohr } 1699*55efc227SAndreas Gohr else { // Regular Entry 1700*55efc227SAndreas Gohr $pos = $this->_putShort($data, $pos, $tag, $isBigEndian); 1701*55efc227SAndreas Gohr $pos = $this->_putShort($data, $pos, $type, $isBigEndian); 1702*55efc227SAndreas Gohr $pos = $this->_putLong($data, $pos, $entries[$i]['count'], $isBigEndian); 1703*55efc227SAndreas Gohr if (strlen($entries[$i]['value']) > 4) { 1704*55efc227SAndreas Gohr $pos = $this->_putLong($data, $pos, $dataPos - $offsetBase, $isBigEndian); 1705*55efc227SAndreas Gohr $dataPos = $this->_putString($data, $dataPos, $entries[$i]['value']); 1706*55efc227SAndreas Gohr } 1707*55efc227SAndreas Gohr else { 1708*55efc227SAndreas Gohr $val = str_pad($entries[$i]['value'], 4, "\0"); 1709*55efc227SAndreas Gohr $pos = $this->_putString($data, $pos, $val); 1710*55efc227SAndreas Gohr } 1711*55efc227SAndreas Gohr } 1712*55efc227SAndreas Gohr } 1713*55efc227SAndreas Gohr 1714*55efc227SAndreas Gohr if ($tiffData != null) { 1715*55efc227SAndreas Gohr $this->_putLong($data, $tiffDataOffsetPos, $dataPos - $offsetBase, $isBigEndian); 1716*55efc227SAndreas Gohr $dataPos = $this->_putString($data, $dataPos, $tiffData); 1717*55efc227SAndreas Gohr } 1718*55efc227SAndreas Gohr 1719*55efc227SAndreas Gohr if ($hasNext) { 1720*55efc227SAndreas Gohr $pos = $this->_putLong($data, $pos, $dataPos - $offsetBase, $isBigEndian); 1721*55efc227SAndreas Gohr } 1722*55efc227SAndreas Gohr else { 1723*55efc227SAndreas Gohr $pos = $this->_putLong($data, $pos, 0, $isBigEndian); 1724*55efc227SAndreas Gohr } 1725*55efc227SAndreas Gohr 1726*55efc227SAndreas Gohr return $dataPos; 1727*55efc227SAndreas Gohr } 1728*55efc227SAndreas Gohr 1729*55efc227SAndreas Gohr /*************************************************************/ 1730*55efc227SAndreas Gohr function & _getIFDEntries($isBigEndian, $mode) 1731*55efc227SAndreas Gohr { 1732*55efc227SAndreas Gohr $EXIFNames = $this->_exifTagNames($mode); 1733*55efc227SAndreas Gohr $EXIFTags = $this->_exifNameTags($mode); 1734*55efc227SAndreas Gohr $EXIFTypeInfo = $this->_exifTagTypes($mode); 1735*55efc227SAndreas Gohr 1736*55efc227SAndreas Gohr $ifdEntries = array(); 1737*55efc227SAndreas Gohr $entryCount = 0; 1738*55efc227SAndreas Gohr 1739*55efc227SAndreas Gohr reset($EXIFNames); 1740*55efc227SAndreas Gohr while (list($tag, $name) = each($EXIFNames)) { 1741*55efc227SAndreas Gohr $type = $EXIFTypeInfo[$tag][0]; 1742*55efc227SAndreas Gohr $count = $EXIFTypeInfo[$tag][1]; 1743*55efc227SAndreas Gohr $value = null; 1744*55efc227SAndreas Gohr 1745*55efc227SAndreas Gohr if (($mode == 'ifd0') && ($tag == 0x8769)) { // ExifIFDOffset 1746*55efc227SAndreas Gohr if (isset($this->_info['exif']['EXIFVersion'])) { 1747*55efc227SAndreas Gohr $value =& $this->_getIFDEntries($isBigEndian, "exif"); 1748*55efc227SAndreas Gohr $type = -99; 1749*55efc227SAndreas Gohr } 1750*55efc227SAndreas Gohr else { 1751*55efc227SAndreas Gohr $value = null; 1752*55efc227SAndreas Gohr } 1753*55efc227SAndreas Gohr } 1754*55efc227SAndreas Gohr elseif (($mode == 'ifd0') && ($tag == 0x8825)) { // GPSIFDOffset 1755*55efc227SAndreas Gohr if (isset($this->_info['exif']['GPSVersionID'])) { 1756*55efc227SAndreas Gohr $value =& $this->_getIFDEntries($isBigEndian, "gps"); 1757*55efc227SAndreas Gohr $type = -99; 1758*55efc227SAndreas Gohr } 1759*55efc227SAndreas Gohr else { 1760*55efc227SAndreas Gohr $value = null; 1761*55efc227SAndreas Gohr } 1762*55efc227SAndreas Gohr } 1763*55efc227SAndreas Gohr elseif (($mode == 'ifd1') && ($tag == 0x0111)) { // TIFFStripOffsets 1764*55efc227SAndreas Gohr if (isset($this->_info['exif']['TIFFStrips'])) { 1765*55efc227SAndreas Gohr $value =& $this->_info['exif']['TIFFStrips']; 1766*55efc227SAndreas Gohr $type = -98; 1767*55efc227SAndreas Gohr } 1768*55efc227SAndreas Gohr else { 1769*55efc227SAndreas Gohr $value = null; 1770*55efc227SAndreas Gohr } 1771*55efc227SAndreas Gohr } 1772*55efc227SAndreas Gohr elseif (($mode == 'ifd1') && ($tag == 0x0117)) { // TIFFStripByteCounts 1773*55efc227SAndreas Gohr if (isset($this->_info['exif']['TIFFStrips'])) { 1774*55efc227SAndreas Gohr $value = strlen($this->_info['exif']['TIFFStrips']); 1775*55efc227SAndreas Gohr } 1776*55efc227SAndreas Gohr else { 1777*55efc227SAndreas Gohr $value = null; 1778*55efc227SAndreas Gohr } 1779*55efc227SAndreas Gohr } 1780*55efc227SAndreas Gohr elseif (($mode == 'ifd1') && ($tag == 0x0201)) { // TIFFJFIFOffset 1781*55efc227SAndreas Gohr if (isset($this->_info['exif']['JFIFThumbnail'])) { 1782*55efc227SAndreas Gohr $value =& $this->_info['exif']['JFIFThumbnail']; 1783*55efc227SAndreas Gohr $type = -98; 1784*55efc227SAndreas Gohr } 1785*55efc227SAndreas Gohr else { 1786*55efc227SAndreas Gohr $value = null; 1787*55efc227SAndreas Gohr } 1788*55efc227SAndreas Gohr } 1789*55efc227SAndreas Gohr elseif (($mode == 'ifd1') && ($tag == 0x0202)) { // TIFFJFIFLength 1790*55efc227SAndreas Gohr if (isset($this->_info['exif']['JFIFThumbnail'])) { 1791*55efc227SAndreas Gohr $value = strlen($this->_info['exif']['JFIFThumbnail']); 1792*55efc227SAndreas Gohr } 1793*55efc227SAndreas Gohr else { 1794*55efc227SAndreas Gohr $value = null; 1795*55efc227SAndreas Gohr } 1796*55efc227SAndreas Gohr } 1797*55efc227SAndreas Gohr elseif (($mode == 'exif') && ($tag == 0xA005)) { // InteropIFDOffset 1798*55efc227SAndreas Gohr if (isset($this->_info['exif']['InteroperabilityIndex'])) { 1799*55efc227SAndreas Gohr $value =& $this->_getIFDEntries($isBigEndian, "interop"); 1800*55efc227SAndreas Gohr $type = -99; 1801*55efc227SAndreas Gohr } 1802*55efc227SAndreas Gohr else { 1803*55efc227SAndreas Gohr $value = null; 1804*55efc227SAndreas Gohr } 1805*55efc227SAndreas Gohr } 1806*55efc227SAndreas Gohr elseif (isset($this->_info['exif'][$name])) { 1807*55efc227SAndreas Gohr $origValue =& $this->_info['exif'][$name]; 1808*55efc227SAndreas Gohr 1809*55efc227SAndreas Gohr // This makes it easier to process variable size elements 1810*55efc227SAndreas Gohr if (!is_array($origValue) || isset($origValue['val'])) { 1811*55efc227SAndreas Gohr unset($origValue); // Break the reference 1812*55efc227SAndreas Gohr $origValue = array($this->_info['exif'][$name]); 1813*55efc227SAndreas Gohr } 1814*55efc227SAndreas Gohr $origCount = count($origValue); 1815*55efc227SAndreas Gohr 1816*55efc227SAndreas Gohr if ($origCount == 0 ) { 1817*55efc227SAndreas Gohr $type = -1; // To ignore this field 1818*55efc227SAndreas Gohr } 1819*55efc227SAndreas Gohr 1820*55efc227SAndreas Gohr $value = " "; 1821*55efc227SAndreas Gohr 1822*55efc227SAndreas Gohr switch ($type) { 1823*55efc227SAndreas Gohr case 1: // UBYTE 1824*55efc227SAndreas Gohr if ($count == 0) { 1825*55efc227SAndreas Gohr $count = $origCount; 1826*55efc227SAndreas Gohr } 1827*55efc227SAndreas Gohr 1828*55efc227SAndreas Gohr $j = 0; 1829*55efc227SAndreas Gohr while (($j < $count) && ($j < $origCount)) { 1830*55efc227SAndreas Gohr 1831*55efc227SAndreas Gohr $this->_putByte($value, $j, $origValue[$j]); 1832*55efc227SAndreas Gohr $j++; 1833*55efc227SAndreas Gohr } 1834*55efc227SAndreas Gohr 1835*55efc227SAndreas Gohr while ($j < $count) { 1836*55efc227SAndreas Gohr $this->_putByte($value, $j, 0); 1837*55efc227SAndreas Gohr $j++; 1838*55efc227SAndreas Gohr } 1839*55efc227SAndreas Gohr break; 1840*55efc227SAndreas Gohr case 2: // ASCII 1841*55efc227SAndreas Gohr $v = strval($origValue[0]); 1842*55efc227SAndreas Gohr if (($count != 0) && (strlen($v) > $count)) { 1843*55efc227SAndreas Gohr $v = substr($v, 0, $count); 1844*55efc227SAndreas Gohr } 1845*55efc227SAndreas Gohr elseif (($count > 0) && (strlen($v) < $count)) { 1846*55efc227SAndreas Gohr $v = str_pad($v, $count, "\0"); 1847*55efc227SAndreas Gohr } 1848*55efc227SAndreas Gohr 1849*55efc227SAndreas Gohr $count = strlen($v); 1850*55efc227SAndreas Gohr 1851*55efc227SAndreas Gohr $this->_putString($value, 0, $v); 1852*55efc227SAndreas Gohr break; 1853*55efc227SAndreas Gohr case 3: // USHORT 1854*55efc227SAndreas Gohr if ($count == 0) { 1855*55efc227SAndreas Gohr $count = $origCount; 1856*55efc227SAndreas Gohr } 1857*55efc227SAndreas Gohr 1858*55efc227SAndreas Gohr $j = 0; 1859*55efc227SAndreas Gohr while (($j < $count) && ($j < $origCount)) { 1860*55efc227SAndreas Gohr $this->_putShort($value, $j * 2, $origValue[$j], $isBigEndian); 1861*55efc227SAndreas Gohr $j++; 1862*55efc227SAndreas Gohr } 1863*55efc227SAndreas Gohr 1864*55efc227SAndreas Gohr while ($j < $count) { 1865*55efc227SAndreas Gohr $this->_putShort($value, $j * 2, 0, $isBigEndian); 1866*55efc227SAndreas Gohr $j++; 1867*55efc227SAndreas Gohr } 1868*55efc227SAndreas Gohr break; 1869*55efc227SAndreas Gohr case 4: // ULONG 1870*55efc227SAndreas Gohr if ($count == 0) { 1871*55efc227SAndreas Gohr $count = $origCount; 1872*55efc227SAndreas Gohr } 1873*55efc227SAndreas Gohr 1874*55efc227SAndreas Gohr $j = 0; 1875*55efc227SAndreas Gohr while (($j < $count) && ($j < $origCount)) { 1876*55efc227SAndreas Gohr $this->_putLong($value, $j * 4, $origValue[$j], $isBigEndian); 1877*55efc227SAndreas Gohr $j++; 1878*55efc227SAndreas Gohr } 1879*55efc227SAndreas Gohr 1880*55efc227SAndreas Gohr while ($j < $count) { 1881*55efc227SAndreas Gohr $this->_putLong($value, $j * 4, 0, $isBigEndian); 1882*55efc227SAndreas Gohr $j++; 1883*55efc227SAndreas Gohr } 1884*55efc227SAndreas Gohr break; 1885*55efc227SAndreas Gohr case 5: // URATIONAL 1886*55efc227SAndreas Gohr if ($count == 0) { 1887*55efc227SAndreas Gohr $count = $origCount; 1888*55efc227SAndreas Gohr } 1889*55efc227SAndreas Gohr 1890*55efc227SAndreas Gohr $j = 0; 1891*55efc227SAndreas Gohr while (($j < $count) && ($j < $origCount)) { 1892*55efc227SAndreas Gohr $v = $origValue[$j]; 1893*55efc227SAndreas Gohr if (is_array($v)) { 1894*55efc227SAndreas Gohr $a = $v['num']; 1895*55efc227SAndreas Gohr $b = $v['den']; 1896*55efc227SAndreas Gohr } 1897*55efc227SAndreas Gohr else { 1898*55efc227SAndreas Gohr $a = 0; 1899*55efc227SAndreas Gohr $b = 0; 1900*55efc227SAndreas Gohr // TODO: Allow other types and convert them 1901*55efc227SAndreas Gohr } 1902*55efc227SAndreas Gohr $this->_putLong($value, $j * 8, $a, $isBigEndian); 1903*55efc227SAndreas Gohr $this->_putLong($value, ($j * 8) + 4, $b, $isBigEndian); 1904*55efc227SAndreas Gohr $j++; 1905*55efc227SAndreas Gohr } 1906*55efc227SAndreas Gohr 1907*55efc227SAndreas Gohr while ($j < $count) { 1908*55efc227SAndreas Gohr $this->_putLong($value, $j * 8, 0, $isBigEndian); 1909*55efc227SAndreas Gohr $this->_putLong($value, ($j * 8) + 4, 0, $isBigEndian); 1910*55efc227SAndreas Gohr $j++; 1911*55efc227SAndreas Gohr } 1912*55efc227SAndreas Gohr break; 1913*55efc227SAndreas Gohr case 6: // SBYTE 1914*55efc227SAndreas Gohr if ($count == 0) { 1915*55efc227SAndreas Gohr $count = $origCount; 1916*55efc227SAndreas Gohr } 1917*55efc227SAndreas Gohr 1918*55efc227SAndreas Gohr $j = 0; 1919*55efc227SAndreas Gohr while (($j < $count) && ($j < $origCount)) { 1920*55efc227SAndreas Gohr $this->_putByte($value, $j, $origValue[$j]); 1921*55efc227SAndreas Gohr $j++; 1922*55efc227SAndreas Gohr } 1923*55efc227SAndreas Gohr 1924*55efc227SAndreas Gohr while ($j < $count) { 1925*55efc227SAndreas Gohr $this->_putByte($value, $j, 0); 1926*55efc227SAndreas Gohr $j++; 1927*55efc227SAndreas Gohr } 1928*55efc227SAndreas Gohr break; 1929*55efc227SAndreas Gohr case 7: // UNDEFINED 1930*55efc227SAndreas Gohr $v = strval($origValue[0]); 1931*55efc227SAndreas Gohr if (($count != 0) && (strlen($v) > $count)) { 1932*55efc227SAndreas Gohr $v = substr($v, 0, $count); 1933*55efc227SAndreas Gohr } 1934*55efc227SAndreas Gohr elseif (($count > 0) && (strlen($v) < $count)) { 1935*55efc227SAndreas Gohr $v = str_pad($v, $count, "\0"); 1936*55efc227SAndreas Gohr } 1937*55efc227SAndreas Gohr 1938*55efc227SAndreas Gohr $count = strlen($v); 1939*55efc227SAndreas Gohr 1940*55efc227SAndreas Gohr $this->_putString($value, 0, $v); 1941*55efc227SAndreas Gohr break; 1942*55efc227SAndreas Gohr case 8: // SSHORT 1943*55efc227SAndreas Gohr if ($count == 0) { 1944*55efc227SAndreas Gohr $count = $origCount; 1945*55efc227SAndreas Gohr } 1946*55efc227SAndreas Gohr 1947*55efc227SAndreas Gohr $j = 0; 1948*55efc227SAndreas Gohr while (($j < $count) && ($j < $origCount)) { 1949*55efc227SAndreas Gohr $this->_putShort($value, $j * 2, $origValue[$j], $isBigEndian); 1950*55efc227SAndreas Gohr $j++; 1951*55efc227SAndreas Gohr } 1952*55efc227SAndreas Gohr 1953*55efc227SAndreas Gohr while ($j < $count) { 1954*55efc227SAndreas Gohr $this->_putShort($value, $j * 2, 0, $isBigEndian); 1955*55efc227SAndreas Gohr $j++; 1956*55efc227SAndreas Gohr } 1957*55efc227SAndreas Gohr break; 1958*55efc227SAndreas Gohr case 9: // SLONG 1959*55efc227SAndreas Gohr if ($count == 0) { 1960*55efc227SAndreas Gohr $count = $origCount; 1961*55efc227SAndreas Gohr } 1962*55efc227SAndreas Gohr 1963*55efc227SAndreas Gohr $j = 0; 1964*55efc227SAndreas Gohr while (($j < $count) && ($j < $origCount)) { 1965*55efc227SAndreas Gohr $this->_putLong($value, $j * 4, $origValue[$j], $isBigEndian); 1966*55efc227SAndreas Gohr $j++; 1967*55efc227SAndreas Gohr } 1968*55efc227SAndreas Gohr 1969*55efc227SAndreas Gohr while ($j < $count) { 1970*55efc227SAndreas Gohr $this->_putLong($value, $j * 4, 0, $isBigEndian); 1971*55efc227SAndreas Gohr $j++; 1972*55efc227SAndreas Gohr } 1973*55efc227SAndreas Gohr break; 1974*55efc227SAndreas Gohr case 10: // SRATIONAL 1975*55efc227SAndreas Gohr if ($count == 0) { 1976*55efc227SAndreas Gohr $count = $origCount; 1977*55efc227SAndreas Gohr } 1978*55efc227SAndreas Gohr 1979*55efc227SAndreas Gohr $j = 0; 1980*55efc227SAndreas Gohr while (($j < $count) && ($j < $origCount)) { 1981*55efc227SAndreas Gohr $v = $origValue[$j]; 1982*55efc227SAndreas Gohr if (is_array($v)) { 1983*55efc227SAndreas Gohr $a = $v['num']; 1984*55efc227SAndreas Gohr $b = $v['den']; 1985*55efc227SAndreas Gohr } 1986*55efc227SAndreas Gohr else { 1987*55efc227SAndreas Gohr $a = 0; 1988*55efc227SAndreas Gohr $b = 0; 1989*55efc227SAndreas Gohr // TODO: Allow other types and convert them 1990*55efc227SAndreas Gohr } 1991*55efc227SAndreas Gohr 1992*55efc227SAndreas Gohr $this->_putLong($value, $j * 8, $a, $isBigEndian); 1993*55efc227SAndreas Gohr $this->_putLong($value, ($j * 8) + 4, $b, $isBigEndian); 1994*55efc227SAndreas Gohr $j++; 1995*55efc227SAndreas Gohr } 1996*55efc227SAndreas Gohr 1997*55efc227SAndreas Gohr while ($j < $count) { 1998*55efc227SAndreas Gohr $this->_putLong($value, $j * 8, 0, $isBigEndian); 1999*55efc227SAndreas Gohr $this->_putLong($value, ($j * 8) + 4, 0, $isBigEndian); 2000*55efc227SAndreas Gohr $j++; 2001*55efc227SAndreas Gohr } 2002*55efc227SAndreas Gohr break; 2003*55efc227SAndreas Gohr case 11: // FLOAT 2004*55efc227SAndreas Gohr if ($count == 0) { 2005*55efc227SAndreas Gohr $count = $origCount; 2006*55efc227SAndreas Gohr } 2007*55efc227SAndreas Gohr 2008*55efc227SAndreas Gohr $j = 0; 2009*55efc227SAndreas Gohr while (($j < $count) && ($j < $origCount)) { 2010*55efc227SAndreas Gohr $v = strval($origValue[$j]); 2011*55efc227SAndreas Gohr if (strlen($v) > 4) { 2012*55efc227SAndreas Gohr $v = substr($v, 0, 4); 2013*55efc227SAndreas Gohr } 2014*55efc227SAndreas Gohr elseif (strlen($v) < 4) { 2015*55efc227SAndreas Gohr $v = str_pad($v, 4, "\0"); 2016*55efc227SAndreas Gohr } 2017*55efc227SAndreas Gohr $this->_putString($value, $j * 4, $v); 2018*55efc227SAndreas Gohr $j++; 2019*55efc227SAndreas Gohr } 2020*55efc227SAndreas Gohr 2021*55efc227SAndreas Gohr while ($j < $count) { 2022*55efc227SAndreas Gohr $this->_putString($value, $j * 4, "\0\0\0\0"); 2023*55efc227SAndreas Gohr $j++; 2024*55efc227SAndreas Gohr } 2025*55efc227SAndreas Gohr break; 2026*55efc227SAndreas Gohr case 12: // DFLOAT 2027*55efc227SAndreas Gohr if ($count == 0) { 2028*55efc227SAndreas Gohr $count = $origCount; 2029*55efc227SAndreas Gohr } 2030*55efc227SAndreas Gohr 2031*55efc227SAndreas Gohr $j = 0; 2032*55efc227SAndreas Gohr while (($j < $count) && ($j < $origCount)) { 2033*55efc227SAndreas Gohr $v = strval($origValue[$j]); 2034*55efc227SAndreas Gohr if (strlen($v) > 8) { 2035*55efc227SAndreas Gohr $v = substr($v, 0, 8); 2036*55efc227SAndreas Gohr } 2037*55efc227SAndreas Gohr elseif (strlen($v) < 8) { 2038*55efc227SAndreas Gohr $v = str_pad($v, 8, "\0"); 2039*55efc227SAndreas Gohr } 2040*55efc227SAndreas Gohr $this->_putString($value, $j * 8, $v); 2041*55efc227SAndreas Gohr $j++; 2042*55efc227SAndreas Gohr } 2043*55efc227SAndreas Gohr 2044*55efc227SAndreas Gohr while ($j < $count) { 2045*55efc227SAndreas Gohr $this->_putString($value, $j * 8, "\0\0\0\0\0\0\0\0"); 2046*55efc227SAndreas Gohr $j++; 2047*55efc227SAndreas Gohr } 2048*55efc227SAndreas Gohr break; 2049*55efc227SAndreas Gohr default: 2050*55efc227SAndreas Gohr $value = null; 2051*55efc227SAndreas Gohr break; 2052*55efc227SAndreas Gohr } 2053*55efc227SAndreas Gohr } 2054*55efc227SAndreas Gohr 2055*55efc227SAndreas Gohr if ($value != null) { 2056*55efc227SAndreas Gohr $ifdEntries[$entryCount] = array(); 2057*55efc227SAndreas Gohr $ifdEntries[$entryCount]['tag'] = $tag; 2058*55efc227SAndreas Gohr $ifdEntries[$entryCount]['type'] = $type; 2059*55efc227SAndreas Gohr $ifdEntries[$entryCount]['count'] = $count; 2060*55efc227SAndreas Gohr $ifdEntries[$entryCount]['value'] = $value; 2061*55efc227SAndreas Gohr 2062*55efc227SAndreas Gohr $entryCount++; 2063*55efc227SAndreas Gohr } 2064*55efc227SAndreas Gohr } 2065*55efc227SAndreas Gohr 2066*55efc227SAndreas Gohr return $ifdEntries; 2067*55efc227SAndreas Gohr } 2068*55efc227SAndreas Gohr 2069*55efc227SAndreas Gohr /*************************************************************/ 2070*55efc227SAndreas Gohr function _parseMarkerAdobe() 2071*55efc227SAndreas Gohr { 2072*55efc227SAndreas Gohr if (!isset($this->_markers)) { 2073*55efc227SAndreas Gohr $this->_readJPEG(); 2074*55efc227SAndreas Gohr } 2075*55efc227SAndreas Gohr 2076*55efc227SAndreas Gohr if ($this->_markers == null) { 2077*55efc227SAndreas Gohr return false; 2078*55efc227SAndreas Gohr } 2079*55efc227SAndreas Gohr 2080*55efc227SAndreas Gohr $data = null; 2081*55efc227SAndreas Gohr $count = count($this->_markers); 2082*55efc227SAndreas Gohr for ($i = 0; $i < $count; $i++) { 2083*55efc227SAndreas Gohr if ($this->_markers[$i]['marker'] == 0xED) { 2084*55efc227SAndreas Gohr $signature = $this->_getFixedString($this->_markers[$i]['data'], 0, 14); 2085*55efc227SAndreas Gohr if ($signature == "Photoshop 3.0\0") { 2086*55efc227SAndreas Gohr $data =& $this->_markers[$i]['data']; 2087*55efc227SAndreas Gohr break; 2088*55efc227SAndreas Gohr } 2089*55efc227SAndreas Gohr } 2090*55efc227SAndreas Gohr } 2091*55efc227SAndreas Gohr 2092*55efc227SAndreas Gohr if ($data == null) { 2093*55efc227SAndreas Gohr $this->_info['adobe'] = false; 2094*55efc227SAndreas Gohr $this->_info['iptc'] = false; 2095*55efc227SAndreas Gohr return false; 2096*55efc227SAndreas Gohr } 2097*55efc227SAndreas Gohr $pos = 14; 2098*55efc227SAndreas Gohr $this->_info['adobe'] = array(); 2099*55efc227SAndreas Gohr $this->_info['adobe']['raw'] = array(); 2100*55efc227SAndreas Gohr $this->_info['iptc'] = array(); 2101*55efc227SAndreas Gohr 2102*55efc227SAndreas Gohr $datasize = strlen($data); 2103*55efc227SAndreas Gohr 2104*55efc227SAndreas Gohr while ($pos < $datasize) { 2105*55efc227SAndreas Gohr $signature = $this->_getFixedString($data, $pos, 4); 2106*55efc227SAndreas Gohr if ($signature != '8BIM') 2107*55efc227SAndreas Gohr return false; 2108*55efc227SAndreas Gohr $pos += 4; 2109*55efc227SAndreas Gohr 2110*55efc227SAndreas Gohr $type = $this->_getShort($data, $pos); 2111*55efc227SAndreas Gohr $pos += 2; 2112*55efc227SAndreas Gohr 2113*55efc227SAndreas Gohr $strlen = $this->_getByte($data, $pos); 2114*55efc227SAndreas Gohr $pos += 1; 2115*55efc227SAndreas Gohr $header = ''; 2116*55efc227SAndreas Gohr for ($i = 0; $i < $strlen; $i++) { 2117*55efc227SAndreas Gohr $header .= $data{$pos + $i}; 2118*55efc227SAndreas Gohr } 2119*55efc227SAndreas Gohr $pos += $strlen + 1 - ($strlen % 2); // The string is padded to even length, counting the length byte itself 2120*55efc227SAndreas Gohr 2121*55efc227SAndreas Gohr $length = $this->_getLong($data, $pos); 2122*55efc227SAndreas Gohr $pos += 4; 2123*55efc227SAndreas Gohr 2124*55efc227SAndreas Gohr $basePos = $pos; 2125*55efc227SAndreas Gohr 2126*55efc227SAndreas Gohr switch ($type) { 2127*55efc227SAndreas Gohr case 0x0404: // Caption (IPTC Data) 2128*55efc227SAndreas Gohr $pos = $this->_readIPTC($data, $pos); 2129*55efc227SAndreas Gohr if ($pos == false) 2130*55efc227SAndreas Gohr return false; 2131*55efc227SAndreas Gohr break; 2132*55efc227SAndreas Gohr case 0x040A: // CopyrightFlag 2133*55efc227SAndreas Gohr $this->_info['adobe']['CopyrightFlag'] = $this->_getByte($data, $pos); 2134*55efc227SAndreas Gohr $pos += $length; 2135*55efc227SAndreas Gohr break; 2136*55efc227SAndreas Gohr case 0x040B: // ImageURL 2137*55efc227SAndreas Gohr $this->_info['adobe']['ImageURL'] = $this->_getFixedString($data, $pos, $length); 2138*55efc227SAndreas Gohr $pos += $length; 2139*55efc227SAndreas Gohr break; 2140*55efc227SAndreas Gohr case 0x040C: // Thumbnail 2141*55efc227SAndreas Gohr $aux = $this->_getLong($data, $pos); 2142*55efc227SAndreas Gohr $pos += 4; 2143*55efc227SAndreas Gohr if ($aux == 1) { 2144*55efc227SAndreas Gohr $this->_info['adobe']['ThumbnailWidth'] = $this->_getLong($data, $pos); 2145*55efc227SAndreas Gohr $pos += 4; 2146*55efc227SAndreas Gohr $this->_info['adobe']['ThumbnailHeight'] = $this->_getLong($data, $pos); 2147*55efc227SAndreas Gohr $pos += 4; 2148*55efc227SAndreas Gohr 2149*55efc227SAndreas Gohr $pos += 16; // Skip some data 2150*55efc227SAndreas Gohr 2151*55efc227SAndreas Gohr $this->_info['adobe']['ThumbnailData'] = $this->_getFixedString($data, $pos, $length - 28); 2152*55efc227SAndreas Gohr $pos += $length - 28; 2153*55efc227SAndreas Gohr } 2154*55efc227SAndreas Gohr break; 2155*55efc227SAndreas Gohr default: 2156*55efc227SAndreas Gohr break; 2157*55efc227SAndreas Gohr } 2158*55efc227SAndreas Gohr 2159*55efc227SAndreas Gohr // We save all blocks, even those we recognized 2160*55efc227SAndreas Gohr $label = sprintf('8BIM_0x%04x', $type); 2161*55efc227SAndreas Gohr $this->_info['adobe']['raw'][$label] = array(); 2162*55efc227SAndreas Gohr $this->_info['adobe']['raw'][$label]['type'] = $type; 2163*55efc227SAndreas Gohr $this->_info['adobe']['raw'][$label]['header'] = $header; 2164*55efc227SAndreas Gohr $this->_info['adobe']['raw'][$label]['data'] =& $this->_getFixedString($data, $basePos, $length); 2165*55efc227SAndreas Gohr 2166*55efc227SAndreas Gohr $pos = $basePos + $length + ($length % 2); // Even padding 2167*55efc227SAndreas Gohr } 2168*55efc227SAndreas Gohr 2169*55efc227SAndreas Gohr } 2170*55efc227SAndreas Gohr 2171*55efc227SAndreas Gohr /*************************************************************/ 2172*55efc227SAndreas Gohr function _readIPTC(&$data, $pos = 0) 2173*55efc227SAndreas Gohr { 2174*55efc227SAndreas Gohr $totalLength = strlen($data); 2175*55efc227SAndreas Gohr 2176*55efc227SAndreas Gohr $IPTCTags =& $this->_iptcTagNames(); 2177*55efc227SAndreas Gohr 2178*55efc227SAndreas Gohr while ($pos < ($totalLength - 5)) { 2179*55efc227SAndreas Gohr $signature = $this->_getShort($data, $pos); 2180*55efc227SAndreas Gohr if ($signature != 0x1C02) 2181*55efc227SAndreas Gohr return $pos; 2182*55efc227SAndreas Gohr $pos += 2; 2183*55efc227SAndreas Gohr 2184*55efc227SAndreas Gohr $type = $this->_getByte($data, $pos); 2185*55efc227SAndreas Gohr $pos += 1; 2186*55efc227SAndreas Gohr $length = $this->_getShort($data, $pos); 2187*55efc227SAndreas Gohr $pos += 2; 2188*55efc227SAndreas Gohr 2189*55efc227SAndreas Gohr $basePos = $pos; 2190*55efc227SAndreas Gohr $label = ''; 2191*55efc227SAndreas Gohr 2192*55efc227SAndreas Gohr if (isset($IPTCTags[$type])) { 2193*55efc227SAndreas Gohr $label = $IPTCTags[$type]; 2194*55efc227SAndreas Gohr } 2195*55efc227SAndreas Gohr else { 2196*55efc227SAndreas Gohr $label = sprintf('IPTC_0x%02x', $type); 2197*55efc227SAndreas Gohr } 2198*55efc227SAndreas Gohr 2199*55efc227SAndreas Gohr if ($label != '') { 2200*55efc227SAndreas Gohr if (isset($this->_info['iptc'][$label])) { 2201*55efc227SAndreas Gohr if (!is_array($this->_info['iptc'][$label])) { 2202*55efc227SAndreas Gohr $aux = array(); 2203*55efc227SAndreas Gohr $aux[0] = $this->_info['iptc'][$label]; 2204*55efc227SAndreas Gohr $this->_info['iptc'][$label] = $aux; 2205*55efc227SAndreas Gohr } 2206*55efc227SAndreas Gohr $this->_info['iptc'][$label][ count($this->_info['iptc'][$label]) ] = $this->_getFixedString($data, $pos, $length); 2207*55efc227SAndreas Gohr } 2208*55efc227SAndreas Gohr else { 2209*55efc227SAndreas Gohr $this->_info['iptc'][$label] = $this->_getFixedString($data, $pos, $length); 2210*55efc227SAndreas Gohr } 2211*55efc227SAndreas Gohr } 2212*55efc227SAndreas Gohr 2213*55efc227SAndreas Gohr $pos = $basePos + $length; // No padding 2214*55efc227SAndreas Gohr } 2215*55efc227SAndreas Gohr return $pos; 2216*55efc227SAndreas Gohr } 2217*55efc227SAndreas Gohr 2218*55efc227SAndreas Gohr /*************************************************************/ 2219*55efc227SAndreas Gohr function & _createMarkerAdobe() 2220*55efc227SAndreas Gohr { 2221*55efc227SAndreas Gohr if (isset($this->_info['iptc'])) { 2222*55efc227SAndreas Gohr if (!isset($this->_info['adobe'])) { 2223*55efc227SAndreas Gohr $this->_info['adobe'] = array(); 2224*55efc227SAndreas Gohr } 2225*55efc227SAndreas Gohr if (!isset($this->_info['adobe']['raw'])) { 2226*55efc227SAndreas Gohr $this->_info['adobe']['raw'] = array(); 2227*55efc227SAndreas Gohr } 2228*55efc227SAndreas Gohr if (!isset($this->_info['adobe']['raw']['8BIM_0x0404'])) { 2229*55efc227SAndreas Gohr $this->_info['adobe']['raw']['8BIM_0x0404'] = array(); 2230*55efc227SAndreas Gohr } 2231*55efc227SAndreas Gohr $this->_info['adobe']['raw']['8BIM_0x0404']['type'] = 0x0404; 2232*55efc227SAndreas Gohr $this->_info['adobe']['raw']['8BIM_0x0404']['header'] = "Caption"; 2233*55efc227SAndreas Gohr $this->_info['adobe']['raw']['8BIM_0x0404']['data'] =& $this->_writeIPTC(); 2234*55efc227SAndreas Gohr } 2235*55efc227SAndreas Gohr 2236*55efc227SAndreas Gohr if (isset($this->_info['adobe']['raw']) && (count($this->_info['adobe']['raw']) > 0)) { 2237*55efc227SAndreas Gohr $data = "Photoshop 3.0\0"; 2238*55efc227SAndreas Gohr $pos = 14; 2239*55efc227SAndreas Gohr 2240*55efc227SAndreas Gohr reset($this->_info['adobe']['raw']); 2241*55efc227SAndreas Gohr while (list($key) = each($this->_info['adobe']['raw'])) { 2242*55efc227SAndreas Gohr $pos = $this->_write8BIM( 2243*55efc227SAndreas Gohr $data, 2244*55efc227SAndreas Gohr $pos, 2245*55efc227SAndreas Gohr $this->_info['adobe']['raw'][$key]['type'], 2246*55efc227SAndreas Gohr $this->_info['adobe']['raw'][$key]['header'], 2247*55efc227SAndreas Gohr $this->_info['adobe']['raw'][$key]['data'] ); 2248*55efc227SAndreas Gohr } 2249*55efc227SAndreas Gohr } 2250*55efc227SAndreas Gohr 2251*55efc227SAndreas Gohr return $data; 2252*55efc227SAndreas Gohr } 2253*55efc227SAndreas Gohr 2254*55efc227SAndreas Gohr /*************************************************************/ 2255*55efc227SAndreas Gohr function _write8BIM(&$data, $pos, $type, $header, &$value) 2256*55efc227SAndreas Gohr { 2257*55efc227SAndreas Gohr $signature = "8BIM"; 2258*55efc227SAndreas Gohr 2259*55efc227SAndreas Gohr $pos = $this->_putString($data, $pos, $signature); 2260*55efc227SAndreas Gohr $pos = $this->_putShort($data, $pos, $type); 2261*55efc227SAndreas Gohr 2262*55efc227SAndreas Gohr $len = strlen($header); 2263*55efc227SAndreas Gohr 2264*55efc227SAndreas Gohr $pos = $this->_putByte($data, $pos, $len); 2265*55efc227SAndreas Gohr $pos = $this->_putString($data, $pos, $header); 2266*55efc227SAndreas Gohr if (($len % 2) == 0) { // Even padding, including the length byte 2267*55efc227SAndreas Gohr $pos = $this->_putByte($data, $pos, 0); 2268*55efc227SAndreas Gohr } 2269*55efc227SAndreas Gohr 2270*55efc227SAndreas Gohr $len = strlen($value); 2271*55efc227SAndreas Gohr $pos = $this->_putLong($data, $pos, $len); 2272*55efc227SAndreas Gohr $pos = $this->_putString($data, $pos, $value); 2273*55efc227SAndreas Gohr if (($len % 2) != 0) { // Even padding 2274*55efc227SAndreas Gohr $pos = $this->_putByte($data, $pos, 0); 2275*55efc227SAndreas Gohr } 2276*55efc227SAndreas Gohr return $pos; 2277*55efc227SAndreas Gohr } 2278*55efc227SAndreas Gohr 2279*55efc227SAndreas Gohr /*************************************************************/ 2280*55efc227SAndreas Gohr function & _writeIPTC() 2281*55efc227SAndreas Gohr { 2282*55efc227SAndreas Gohr $data = " "; 2283*55efc227SAndreas Gohr $pos = 0; 2284*55efc227SAndreas Gohr 2285*55efc227SAndreas Gohr $IPTCNames =& $this->_iptcNameTags(); 2286*55efc227SAndreas Gohr 2287*55efc227SAndreas Gohr reset($this->_info['iptc']); 2288*55efc227SAndreas Gohr 2289*55efc227SAndreas Gohr 2290*55efc227SAndreas Gohr while (list($label) = each($this->_info['iptc'])) { 2291*55efc227SAndreas Gohr $value =& $this->_info['iptc'][$label]; 2292*55efc227SAndreas Gohr $type = -1; 2293*55efc227SAndreas Gohr 2294*55efc227SAndreas Gohr if (isset($IPTCNames[$label])) { 2295*55efc227SAndreas Gohr $type = $IPTCNames[$label]; 2296*55efc227SAndreas Gohr } 2297*55efc227SAndreas Gohr elseif (substr($label, 0, 7) == "IPTC_0x") { 2298*55efc227SAndreas Gohr $type = hexdec(substr($label, 7, 2)); 2299*55efc227SAndreas Gohr } 2300*55efc227SAndreas Gohr 2301*55efc227SAndreas Gohr if ($type != -1) { 2302*55efc227SAndreas Gohr if (is_array($value)) { 2303*55efc227SAndreas Gohr for ($i = 0; $i < count($value); $i++) { 2304*55efc227SAndreas Gohr $pos = $this->_writeIPTCEntry($data, $pos, $type, $value[$i]); 2305*55efc227SAndreas Gohr } 2306*55efc227SAndreas Gohr } 2307*55efc227SAndreas Gohr else { 2308*55efc227SAndreas Gohr $pos = $this->_writeIPTCEntry($data, $pos, $type, $value); 2309*55efc227SAndreas Gohr } 2310*55efc227SAndreas Gohr } 2311*55efc227SAndreas Gohr } 2312*55efc227SAndreas Gohr 2313*55efc227SAndreas Gohr return $data; 2314*55efc227SAndreas Gohr } 2315*55efc227SAndreas Gohr 2316*55efc227SAndreas Gohr /*************************************************************/ 2317*55efc227SAndreas Gohr function _writeIPTCEntry(&$data, $pos, $type, &$value) 2318*55efc227SAndreas Gohr { 2319*55efc227SAndreas Gohr $pos = $this->_putShort($data, $pos, 0x1C02); 2320*55efc227SAndreas Gohr $pos = $this->_putByte($data, $pos, $type); 2321*55efc227SAndreas Gohr $pos = $this->_putShort($data, $pos, strlen($value)); 2322*55efc227SAndreas Gohr $pos = $this->_putString($data, $pos, $value); 2323*55efc227SAndreas Gohr 2324*55efc227SAndreas Gohr return $pos; 2325*55efc227SAndreas Gohr } 2326*55efc227SAndreas Gohr 2327*55efc227SAndreas Gohr /*************************************************************/ 2328*55efc227SAndreas Gohr function _exifTagNames($mode) 2329*55efc227SAndreas Gohr { 2330*55efc227SAndreas Gohr $tags = array(); 2331*55efc227SAndreas Gohr 2332*55efc227SAndreas Gohr if ($mode == 'ifd0') { 2333*55efc227SAndreas Gohr $tags[0x010E] = 'ImageDescription'; 2334*55efc227SAndreas Gohr $tags[0x010F] = 'Make'; 2335*55efc227SAndreas Gohr $tags[0x0110] = 'Model'; 2336*55efc227SAndreas Gohr $tags[0x0112] = 'Orientation'; 2337*55efc227SAndreas Gohr $tags[0x011A] = 'XResolution'; 2338*55efc227SAndreas Gohr $tags[0x011B] = 'YResolution'; 2339*55efc227SAndreas Gohr $tags[0x0128] = 'ResolutionUnit'; 2340*55efc227SAndreas Gohr $tags[0x0131] = 'Software'; 2341*55efc227SAndreas Gohr $tags[0x0132] = 'DateTime'; 2342*55efc227SAndreas Gohr $tags[0x013B] = 'Artist'; 2343*55efc227SAndreas Gohr $tags[0x013E] = 'WhitePoint'; 2344*55efc227SAndreas Gohr $tags[0x013F] = 'PrimaryChromaticities'; 2345*55efc227SAndreas Gohr $tags[0x0211] = 'YCbCrCoefficients'; 2346*55efc227SAndreas Gohr $tags[0x0212] = 'YCbCrSubSampling'; 2347*55efc227SAndreas Gohr $tags[0x0213] = 'YCbCrPositioning'; 2348*55efc227SAndreas Gohr $tags[0x0214] = 'ReferenceBlackWhite'; 2349*55efc227SAndreas Gohr $tags[0x8298] = 'Copyright'; 2350*55efc227SAndreas Gohr $tags[0x8769] = 'ExifIFDOffset'; 2351*55efc227SAndreas Gohr $tags[0x8825] = 'GPSIFDOffset'; 2352*55efc227SAndreas Gohr } 2353*55efc227SAndreas Gohr if ($mode == 'ifd1') { 2354*55efc227SAndreas Gohr $tags[0x00FE] = 'TIFFNewSubfileType'; 2355*55efc227SAndreas Gohr $tags[0x00FF] = 'TIFFSubfileType'; 2356*55efc227SAndreas Gohr $tags[0x0100] = 'TIFFImageWidth'; 2357*55efc227SAndreas Gohr $tags[0x0101] = 'TIFFImageHeight'; 2358*55efc227SAndreas Gohr $tags[0x0102] = 'TIFFBitsPerSample'; 2359*55efc227SAndreas Gohr $tags[0x0103] = 'TIFFCompression'; 2360*55efc227SAndreas Gohr $tags[0x0106] = 'TIFFPhotometricInterpretation'; 2361*55efc227SAndreas Gohr $tags[0x0107] = 'TIFFThreshholding'; 2362*55efc227SAndreas Gohr $tags[0x0108] = 'TIFFCellWidth'; 2363*55efc227SAndreas Gohr $tags[0x0109] = 'TIFFCellLength'; 2364*55efc227SAndreas Gohr $tags[0x010A] = 'TIFFFillOrder'; 2365*55efc227SAndreas Gohr $tags[0x010E] = 'TIFFImageDescription'; 2366*55efc227SAndreas Gohr $tags[0x010F] = 'TIFFMake'; 2367*55efc227SAndreas Gohr $tags[0x0110] = 'TIFFModel'; 2368*55efc227SAndreas Gohr $tags[0x0111] = 'TIFFStripOffsets'; 2369*55efc227SAndreas Gohr $tags[0x0112] = 'TIFFOrientation'; 2370*55efc227SAndreas Gohr $tags[0x0115] = 'TIFFSamplesPerPixel'; 2371*55efc227SAndreas Gohr $tags[0x0116] = 'TIFFRowsPerStrip'; 2372*55efc227SAndreas Gohr $tags[0x0117] = 'TIFFStripByteCounts'; 2373*55efc227SAndreas Gohr $tags[0x0118] = 'TIFFMinSampleValue'; 2374*55efc227SAndreas Gohr $tags[0x0119] = 'TIFFMaxSampleValue'; 2375*55efc227SAndreas Gohr $tags[0x011A] = 'TIFFXResolution'; 2376*55efc227SAndreas Gohr $tags[0x011B] = 'TIFFYResolution'; 2377*55efc227SAndreas Gohr $tags[0x011C] = 'TIFFPlanarConfiguration'; 2378*55efc227SAndreas Gohr $tags[0x0122] = 'TIFFGrayResponseUnit'; 2379*55efc227SAndreas Gohr $tags[0x0123] = 'TIFFGrayResponseCurve'; 2380*55efc227SAndreas Gohr $tags[0x0128] = 'TIFFResolutionUnit'; 2381*55efc227SAndreas Gohr $tags[0x0131] = 'TIFFSoftware'; 2382*55efc227SAndreas Gohr $tags[0x0132] = 'TIFFDateTime'; 2383*55efc227SAndreas Gohr $tags[0x013B] = 'TIFFArtist'; 2384*55efc227SAndreas Gohr $tags[0x013C] = 'TIFFHostComputer'; 2385*55efc227SAndreas Gohr $tags[0x0140] = 'TIFFColorMap'; 2386*55efc227SAndreas Gohr $tags[0x0152] = 'TIFFExtraSamples'; 2387*55efc227SAndreas Gohr $tags[0x0201] = 'TIFFJFIFOffset'; 2388*55efc227SAndreas Gohr $tags[0x0202] = 'TIFFJFIFLength'; 2389*55efc227SAndreas Gohr $tags[0x0211] = 'TIFFYCbCrCoefficients'; 2390*55efc227SAndreas Gohr $tags[0x0212] = 'TIFFYCbCrSubSampling'; 2391*55efc227SAndreas Gohr $tags[0x0213] = 'TIFFYCbCrPositioning'; 2392*55efc227SAndreas Gohr $tags[0x0214] = 'TIFFReferenceBlackWhite'; 2393*55efc227SAndreas Gohr $tags[0x8298] = 'TIFFCopyright'; 2394*55efc227SAndreas Gohr $tags[0x9286] = 'TIFFUserComment'; 2395*55efc227SAndreas Gohr } 2396*55efc227SAndreas Gohr elseif ($mode == 'exif') { 2397*55efc227SAndreas Gohr $tags[0x829A] = 'ExposureTime'; 2398*55efc227SAndreas Gohr $tags[0x829D] = 'FNumber'; 2399*55efc227SAndreas Gohr $tags[0x8822] = 'ExposureProgram'; 2400*55efc227SAndreas Gohr $tags[0x8824] = 'SpectralSensitivity'; 2401*55efc227SAndreas Gohr $tags[0x8827] = 'ISOSpeedRatings'; 2402*55efc227SAndreas Gohr $tags[0x8828] = 'OECF'; 2403*55efc227SAndreas Gohr $tags[0x9000] = 'EXIFVersion'; 2404*55efc227SAndreas Gohr $tags[0x9003] = 'DatetimeOriginal'; 2405*55efc227SAndreas Gohr $tags[0x9004] = 'DatetimeDigitized'; 2406*55efc227SAndreas Gohr $tags[0x9101] = 'ComponentsConfiguration'; 2407*55efc227SAndreas Gohr $tags[0x9102] = 'CompressedBitsPerPixel'; 2408*55efc227SAndreas Gohr $tags[0x9201] = 'ShutterSpeedValue'; 2409*55efc227SAndreas Gohr $tags[0x9202] = 'ApertureValue'; 2410*55efc227SAndreas Gohr $tags[0x9203] = 'BrightnessValue'; 2411*55efc227SAndreas Gohr $tags[0x9204] = 'ExposureBiasValue'; 2412*55efc227SAndreas Gohr $tags[0x9205] = 'MaxApertureValue'; 2413*55efc227SAndreas Gohr $tags[0x9206] = 'SubjectDistance'; 2414*55efc227SAndreas Gohr $tags[0x9207] = 'MeteringMode'; 2415*55efc227SAndreas Gohr $tags[0x9208] = 'LightSource'; 2416*55efc227SAndreas Gohr $tags[0x9209] = 'Flash'; 2417*55efc227SAndreas Gohr $tags[0x920A] = 'FocalLength'; 2418*55efc227SAndreas Gohr $tags[0x927C] = 'MakerNote'; 2419*55efc227SAndreas Gohr $tags[0x9286] = 'UserComment'; 2420*55efc227SAndreas Gohr $tags[0x9290] = 'SubSecTime'; 2421*55efc227SAndreas Gohr $tags[0x9291] = 'SubSecTimeOriginal'; 2422*55efc227SAndreas Gohr $tags[0x9292] = 'SubSecTimeDigitized'; 2423*55efc227SAndreas Gohr $tags[0xA000] = 'FlashPixVersion'; 2424*55efc227SAndreas Gohr $tags[0xA001] = 'ColorSpace'; 2425*55efc227SAndreas Gohr $tags[0xA002] = 'PixelXDimension'; 2426*55efc227SAndreas Gohr $tags[0xA003] = 'PixelYDimension'; 2427*55efc227SAndreas Gohr $tags[0xA004] = 'RelatedSoundFile'; 2428*55efc227SAndreas Gohr $tags[0xA005] = 'InteropIFDOffset'; 2429*55efc227SAndreas Gohr $tags[0xA20B] = 'FlashEnergy'; 2430*55efc227SAndreas Gohr $tags[0xA20C] = 'SpatialFrequencyResponse'; 2431*55efc227SAndreas Gohr $tags[0xA20E] = 'FocalPlaneXResolution'; 2432*55efc227SAndreas Gohr $tags[0xA20F] = 'FocalPlaneYResolution'; 2433*55efc227SAndreas Gohr $tags[0xA210] = 'FocalPlaneResolutionUnit'; 2434*55efc227SAndreas Gohr $tags[0xA214] = 'SubjectLocation'; 2435*55efc227SAndreas Gohr $tags[0xA215] = 'ExposureIndex'; 2436*55efc227SAndreas Gohr $tags[0xA217] = 'SensingMethod'; 2437*55efc227SAndreas Gohr $tags[0xA300] = 'FileSource'; 2438*55efc227SAndreas Gohr $tags[0xA301] = 'SceneType'; 2439*55efc227SAndreas Gohr $tags[0xA302] = 'CFAPattern'; 2440*55efc227SAndreas Gohr } 2441*55efc227SAndreas Gohr elseif ($mode == 'interop') { 2442*55efc227SAndreas Gohr $tags[0x0001] = 'InteroperabilityIndex'; 2443*55efc227SAndreas Gohr $tags[0x0002] = 'InteroperabilityVersion'; 2444*55efc227SAndreas Gohr $tags[0x1000] = 'RelatedImageFileFormat'; 2445*55efc227SAndreas Gohr $tags[0x1001] = 'RelatedImageWidth'; 2446*55efc227SAndreas Gohr $tags[0x1002] = 'RelatedImageLength'; 2447*55efc227SAndreas Gohr } 2448*55efc227SAndreas Gohr elseif ($mode == 'gps') { 2449*55efc227SAndreas Gohr $tags[0x0000] = 'GPSVersionID'; 2450*55efc227SAndreas Gohr $tags[0x0001] = 'GPSLatitudeRef'; 2451*55efc227SAndreas Gohr $tags[0x0002] = 'GPSLatitude'; 2452*55efc227SAndreas Gohr $tags[0x0003] = 'GPSLongitudeRef'; 2453*55efc227SAndreas Gohr $tags[0x0004] = 'GPSLongitude'; 2454*55efc227SAndreas Gohr $tags[0x0005] = 'GPSAltitudeRef'; 2455*55efc227SAndreas Gohr $tags[0x0006] = 'GPSAltitude'; 2456*55efc227SAndreas Gohr $tags[0x0007] = 'GPSTimeStamp'; 2457*55efc227SAndreas Gohr $tags[0x0008] = 'GPSSatellites'; 2458*55efc227SAndreas Gohr $tags[0x0009] = 'GPSStatus'; 2459*55efc227SAndreas Gohr $tags[0x000A] = 'GPSMeasureMode'; 2460*55efc227SAndreas Gohr $tags[0x000B] = 'GPSDOP'; 2461*55efc227SAndreas Gohr $tags[0x000C] = 'GPSSpeedRef'; 2462*55efc227SAndreas Gohr $tags[0x000D] = 'GPSSpeed'; 2463*55efc227SAndreas Gohr $tags[0x000E] = 'GPSTrackRef'; 2464*55efc227SAndreas Gohr $tags[0x000F] = 'GPSTrack'; 2465*55efc227SAndreas Gohr $tags[0x0010] = 'GPSImgDirectionRef'; 2466*55efc227SAndreas Gohr $tags[0x0011] = 'GPSImgDirection'; 2467*55efc227SAndreas Gohr $tags[0x0012] = 'GPSMapDatum'; 2468*55efc227SAndreas Gohr $tags[0x0013] = 'GPSDestLatitudeRef'; 2469*55efc227SAndreas Gohr $tags[0x0014] = 'GPSDestLatitude'; 2470*55efc227SAndreas Gohr $tags[0x0015] = 'GPSDestLongitudeRef'; 2471*55efc227SAndreas Gohr $tags[0x0016] = 'GPSDestLongitude'; 2472*55efc227SAndreas Gohr $tags[0x0017] = 'GPSDestBearingRef'; 2473*55efc227SAndreas Gohr $tags[0x0018] = 'GPSDestBearing'; 2474*55efc227SAndreas Gohr $tags[0x0019] = 'GPSDestDistanceRef'; 2475*55efc227SAndreas Gohr $tags[0x001A] = 'GPSDestDistance'; 2476*55efc227SAndreas Gohr } 2477*55efc227SAndreas Gohr 2478*55efc227SAndreas Gohr return $tags; 2479*55efc227SAndreas Gohr } 2480*55efc227SAndreas Gohr 2481*55efc227SAndreas Gohr /*************************************************************/ 2482*55efc227SAndreas Gohr function _exifTagTypes($mode) 2483*55efc227SAndreas Gohr { 2484*55efc227SAndreas Gohr $tags = array(); 2485*55efc227SAndreas Gohr 2486*55efc227SAndreas Gohr if ($mode == 'ifd0') { 2487*55efc227SAndreas Gohr $tags[0x010E] = array(2, 0); // ImageDescription -> ASCII, Any 2488*55efc227SAndreas Gohr $tags[0x010F] = array(2, 0); // Make -> ASCII, Any 2489*55efc227SAndreas Gohr $tags[0x0110] = array(2, 0); // Model -> ASCII, Any 2490*55efc227SAndreas Gohr $tags[0x0112] = array(3, 1); // Orientation -> SHORT, 1 2491*55efc227SAndreas Gohr $tags[0x011A] = array(5, 1); // XResolution -> RATIONAL, 1 2492*55efc227SAndreas Gohr $tags[0x011B] = array(5, 1); // YResolution -> RATIONAL, 1 2493*55efc227SAndreas Gohr $tags[0x0128] = array(3, 1); // ResolutionUnit -> SHORT 2494*55efc227SAndreas Gohr $tags[0x0131] = array(2, 0); // Software -> ASCII, Any 2495*55efc227SAndreas Gohr $tags[0x0132] = array(2, 20); // DateTime -> ASCII, 20 2496*55efc227SAndreas Gohr $tags[0x013B] = array(2, 0); // Artist -> ASCII, Any 2497*55efc227SAndreas Gohr $tags[0x013E] = array(5, 2); // WhitePoint -> RATIONAL, 2 2498*55efc227SAndreas Gohr $tags[0x013F] = array(5, 6); // PrimaryChromaticities -> RATIONAL, 6 2499*55efc227SAndreas Gohr $tags[0x0211] = array(5, 3); // YCbCrCoefficients -> RATIONAL, 3 2500*55efc227SAndreas Gohr $tags[0x0212] = array(3, 2); // YCbCrSubSampling -> SHORT, 2 2501*55efc227SAndreas Gohr $tags[0x0213] = array(3, 1); // YCbCrPositioning -> SHORT, 1 2502*55efc227SAndreas Gohr $tags[0x0214] = array(5, 6); // ReferenceBlackWhite -> RATIONAL, 6 2503*55efc227SAndreas Gohr $tags[0x8298] = array(2, 0); // Copyright -> ASCII, Any 2504*55efc227SAndreas Gohr $tags[0x8769] = array(4, 1); // ExifIFDOffset -> LONG, 1 2505*55efc227SAndreas Gohr $tags[0x8825] = array(4, 1); // GPSIFDOffset -> LONG, 1 2506*55efc227SAndreas Gohr } 2507*55efc227SAndreas Gohr if ($mode == 'ifd1') { 2508*55efc227SAndreas Gohr $tags[0x00FE] = array(4, 1); // TIFFNewSubfileType -> LONG, 1 2509*55efc227SAndreas Gohr $tags[0x00FF] = array(3, 1); // TIFFSubfileType -> SHORT, 1 2510*55efc227SAndreas Gohr $tags[0x0100] = array(4, 1); // TIFFImageWidth -> LONG (or SHORT), 1 2511*55efc227SAndreas Gohr $tags[0x0101] = array(4, 1); // TIFFImageHeight -> LONG (or SHORT), 1 2512*55efc227SAndreas Gohr $tags[0x0102] = array(3, 3); // TIFFBitsPerSample -> SHORT, 3 2513*55efc227SAndreas Gohr $tags[0x0103] = array(3, 1); // TIFFCompression -> SHORT, 1 2514*55efc227SAndreas Gohr $tags[0x0106] = array(3, 1); // TIFFPhotometricInterpretation -> SHORT, 1 2515*55efc227SAndreas Gohr $tags[0x0107] = array(3, 1); // TIFFThreshholding -> SHORT, 1 2516*55efc227SAndreas Gohr $tags[0x0108] = array(3, 1); // TIFFCellWidth -> SHORT, 1 2517*55efc227SAndreas Gohr $tags[0x0109] = array(3, 1); // TIFFCellLength -> SHORT, 1 2518*55efc227SAndreas Gohr $tags[0x010A] = array(3, 1); // TIFFFillOrder -> SHORT, 1 2519*55efc227SAndreas Gohr $tags[0x010E] = array(2, 0); // TIFFImageDescription -> ASCII, Any 2520*55efc227SAndreas Gohr $tags[0x010F] = array(2, 0); // TIFFMake -> ASCII, Any 2521*55efc227SAndreas Gohr $tags[0x0110] = array(2, 0); // TIFFModel -> ASCII, Any 2522*55efc227SAndreas Gohr $tags[0x0111] = array(4, 0); // TIFFStripOffsets -> LONG (or SHORT), Any (one per strip) 2523*55efc227SAndreas Gohr $tags[0x0112] = array(3, 1); // TIFFOrientation -> SHORT, 1 2524*55efc227SAndreas Gohr $tags[0x0115] = array(3, 1); // TIFFSamplesPerPixel -> SHORT, 1 2525*55efc227SAndreas Gohr $tags[0x0116] = array(4, 1); // TIFFRowsPerStrip -> LONG (or SHORT), 1 2526*55efc227SAndreas Gohr $tags[0x0117] = array(4, 0); // TIFFStripByteCounts -> LONG (or SHORT), Any (one per strip) 2527*55efc227SAndreas Gohr $tags[0x0118] = array(3, 0); // TIFFMinSampleValue -> SHORT, Any (SamplesPerPixel) 2528*55efc227SAndreas Gohr $tags[0x0119] = array(3, 0); // TIFFMaxSampleValue -> SHORT, Any (SamplesPerPixel) 2529*55efc227SAndreas Gohr $tags[0x011A] = array(5, 1); // TIFFXResolution -> RATIONAL, 1 2530*55efc227SAndreas Gohr $tags[0x011B] = array(5, 1); // TIFFYResolution -> RATIONAL, 1 2531*55efc227SAndreas Gohr $tags[0x011C] = array(3, 1); // TIFFPlanarConfiguration -> SHORT, 1 2532*55efc227SAndreas Gohr $tags[0x0122] = array(3, 1); // TIFFGrayResponseUnit -> SHORT, 1 2533*55efc227SAndreas Gohr $tags[0x0123] = array(3, 0); // TIFFGrayResponseCurve -> SHORT, Any (2^BitsPerSample) 2534*55efc227SAndreas Gohr $tags[0x0128] = array(3, 1); // TIFFResolutionUnit -> SHORT, 1 2535*55efc227SAndreas Gohr $tags[0x0131] = array(2, 0); // TIFFSoftware -> ASCII, Any 2536*55efc227SAndreas Gohr $tags[0x0132] = array(2, 20); // TIFFDateTime -> ASCII, 20 2537*55efc227SAndreas Gohr $tags[0x013B] = array(2, 0); // TIFFArtist -> ASCII, Any 2538*55efc227SAndreas Gohr $tags[0x013C] = array(2, 0); // TIFFHostComputer -> ASCII, Any 2539*55efc227SAndreas Gohr $tags[0x0140] = array(3, 0); // TIFFColorMap -> SHORT, Any (3 * 2^BitsPerSample) 2540*55efc227SAndreas Gohr $tags[0x0152] = array(3, 0); // TIFFExtraSamples -> SHORT, Any (SamplesPerPixel - 3) 2541*55efc227SAndreas Gohr $tags[0x0201] = array(4, 1); // TIFFJFIFOffset -> LONG, 1 2542*55efc227SAndreas Gohr $tags[0x0202] = array(4, 1); // TIFFJFIFLength -> LONG, 1 2543*55efc227SAndreas Gohr $tags[0x0211] = array(5, 3); // TIFFYCbCrCoefficients -> RATIONAL, 3 2544*55efc227SAndreas Gohr $tags[0x0212] = array(3, 2); // TIFFYCbCrSubSampling -> SHORT, 2 2545*55efc227SAndreas Gohr $tags[0x0213] = array(3, 1); // TIFFYCbCrPositioning -> SHORT, 1 2546*55efc227SAndreas Gohr $tags[0x0214] = array(5, 6); // TIFFReferenceBlackWhite -> RATIONAL, 6 2547*55efc227SAndreas Gohr $tags[0x8298] = array(2, 0); // TIFFCopyright -> ASCII, Any 2548*55efc227SAndreas Gohr $tags[0x9286] = array(2, 0); // TIFFUserComment -> ASCII, Any 2549*55efc227SAndreas Gohr } 2550*55efc227SAndreas Gohr elseif ($mode == 'exif') { 2551*55efc227SAndreas Gohr $tags[0x829A] = array(5, 1); // ExposureTime -> RATIONAL, 1 2552*55efc227SAndreas Gohr $tags[0x829D] = array(5, 1); // FNumber -> RATIONAL, 1 2553*55efc227SAndreas Gohr $tags[0x8822] = array(3, 1); // ExposureProgram -> SHORT, 1 2554*55efc227SAndreas Gohr $tags[0x8824] = array(2, 0); // SpectralSensitivity -> ASCII, Any 2555*55efc227SAndreas Gohr $tags[0x8827] = array(3, 0); // ISOSpeedRatings -> SHORT, Any 2556*55efc227SAndreas Gohr $tags[0x8828] = array(7, 0); // OECF -> UNDEFINED, Any 2557*55efc227SAndreas Gohr $tags[0x9000] = array(7, 4); // EXIFVersion -> UNDEFINED, 4 2558*55efc227SAndreas Gohr $tags[0x9003] = array(2, 20); // DatetimeOriginal -> ASCII, 20 2559*55efc227SAndreas Gohr $tags[0x9004] = array(2, 20); // DatetimeDigitized -> ASCII, 20 2560*55efc227SAndreas Gohr $tags[0x9101] = array(7, 4); // ComponentsConfiguration -> UNDEFINED, 4 2561*55efc227SAndreas Gohr $tags[0x9102] = array(5, 1); // CompressedBitsPerPixel -> RATIONAL, 1 2562*55efc227SAndreas Gohr $tags[0x9201] = array(10, 1); // ShutterSpeedValue -> SRATIONAL, 1 2563*55efc227SAndreas Gohr $tags[0x9202] = array(5, 1); // ApertureValue -> RATIONAL, 1 2564*55efc227SAndreas Gohr $tags[0x9203] = array(10, 1); // BrightnessValue -> SRATIONAL, 1 2565*55efc227SAndreas Gohr $tags[0x9204] = array(10, 1); // ExposureBiasValue -> SRATIONAL, 1 2566*55efc227SAndreas Gohr $tags[0x9205] = array(5, 1); // MaxApertureValue -> RATIONAL, 1 2567*55efc227SAndreas Gohr $tags[0x9206] = array(5, 1); // SubjectDistance -> RATIONAL, 1 2568*55efc227SAndreas Gohr $tags[0x9207] = array(3, 1); // MeteringMode -> SHORT, 1 2569*55efc227SAndreas Gohr $tags[0x9208] = array(3, 1); // LightSource -> SHORT, 1 2570*55efc227SAndreas Gohr $tags[0x9209] = array(3, 1); // Flash -> SHORT, 1 2571*55efc227SAndreas Gohr $tags[0x920A] = array(5, 1); // FocalLength -> RATIONAL, 1 2572*55efc227SAndreas Gohr $tags[0x927C] = array(7, 0); // MakerNote -> UNDEFINED, Any 2573*55efc227SAndreas Gohr $tags[0x9286] = array(7, 0); // UserComment -> UNDEFINED, Any 2574*55efc227SAndreas Gohr $tags[0x9290] = array(2, 0); // SubSecTime -> ASCII, Any 2575*55efc227SAndreas Gohr $tags[0x9291] = array(2, 0); // SubSecTimeOriginal -> ASCII, Any 2576*55efc227SAndreas Gohr $tags[0x9292] = array(2, 0); // SubSecTimeDigitized -> ASCII, Any 2577*55efc227SAndreas Gohr $tags[0xA000] = array(7, 4); // FlashPixVersion -> UNDEFINED, 4 2578*55efc227SAndreas Gohr $tags[0xA001] = array(3, 1); // ColorSpace -> SHORT, 1 2579*55efc227SAndreas Gohr $tags[0xA002] = array(4, 1); // PixelXDimension -> LONG (or SHORT), 1 2580*55efc227SAndreas Gohr $tags[0xA003] = array(4, 1); // PixelYDimension -> LONG (or SHORT), 1 2581*55efc227SAndreas Gohr $tags[0xA004] = array(2, 13); // RelatedSoundFile -> ASCII, 13 2582*55efc227SAndreas Gohr $tags[0xA005] = array(4, 1); // InteropIFDOffset -> LONG, 1 2583*55efc227SAndreas Gohr $tags[0xA20B] = array(5, 1); // FlashEnergy -> RATIONAL, 1 2584*55efc227SAndreas Gohr $tags[0xA20C] = array(7, 0); // SpatialFrequencyResponse -> UNDEFINED, Any 2585*55efc227SAndreas Gohr $tags[0xA20E] = array(5, 1); // FocalPlaneXResolution -> RATIONAL, 1 2586*55efc227SAndreas Gohr $tags[0xA20F] = array(5, 1); // FocalPlaneYResolution -> RATIONAL, 1 2587*55efc227SAndreas Gohr $tags[0xA210] = array(3, 1); // FocalPlaneResolutionUnit -> SHORT, 1 2588*55efc227SAndreas Gohr $tags[0xA214] = array(3, 2); // SubjectLocation -> SHORT, 2 2589*55efc227SAndreas Gohr $tags[0xA215] = array(5, 1); // ExposureIndex -> RATIONAL, 1 2590*55efc227SAndreas Gohr $tags[0xA217] = array(3, 1); // SensingMethod -> SHORT, 1 2591*55efc227SAndreas Gohr $tags[0xA300] = array(7, 1); // FileSource -> UNDEFINED, 1 2592*55efc227SAndreas Gohr $tags[0xA301] = array(7, 1); // SceneType -> UNDEFINED, 1 2593*55efc227SAndreas Gohr $tags[0xA302] = array(7, 0); // CFAPattern -> UNDEFINED, Any 2594*55efc227SAndreas Gohr } 2595*55efc227SAndreas Gohr elseif ($mode == 'interop') { 2596*55efc227SAndreas Gohr $tags[0x0001] = array(2, 0); // InteroperabilityIndex -> ASCII, Any 2597*55efc227SAndreas Gohr $tags[0x0002] = array(7, 4); // InteroperabilityVersion -> UNKNOWN, 4 2598*55efc227SAndreas Gohr $tags[0x1000] = array(2, 0); // RelatedImageFileFormat -> ASCII, Any 2599*55efc227SAndreas Gohr $tags[0x1001] = array(4, 1); // RelatedImageWidth -> LONG (or SHORT), 1 2600*55efc227SAndreas Gohr $tags[0x1002] = array(4, 1); // RelatedImageLength -> LONG (or SHORT), 1 2601*55efc227SAndreas Gohr } 2602*55efc227SAndreas Gohr elseif ($mode == 'gps') { 2603*55efc227SAndreas Gohr $tags[0x0000] = array(1, 4); // GPSVersionID -> BYTE, 4 2604*55efc227SAndreas Gohr $tags[0x0001] = array(2, 2); // GPSLatitudeRef -> ASCII, 2 2605*55efc227SAndreas Gohr $tags[0x0002] = array(5, 3); // GPSLatitude -> RATIONAL, 3 2606*55efc227SAndreas Gohr $tags[0x0003] = array(2, 2); // GPSLongitudeRef -> ASCII, 2 2607*55efc227SAndreas Gohr $tags[0x0004] = array(5, 3); // GPSLongitude -> RATIONAL, 3 2608*55efc227SAndreas Gohr $tags[0x0005] = array(2, 2); // GPSAltitudeRef -> ASCII, 2 2609*55efc227SAndreas Gohr $tags[0x0006] = array(5, 1); // GPSAltitude -> RATIONAL, 1 2610*55efc227SAndreas Gohr $tags[0x0007] = array(5, 3); // GPSTimeStamp -> RATIONAL, 3 2611*55efc227SAndreas Gohr $tags[0x0008] = array(2, 0); // GPSSatellites -> ASCII, Any 2612*55efc227SAndreas Gohr $tags[0x0009] = array(2, 2); // GPSStatus -> ASCII, 2 2613*55efc227SAndreas Gohr $tags[0x000A] = array(2, 2); // GPSMeasureMode -> ASCII, 2 2614*55efc227SAndreas Gohr $tags[0x000B] = array(5, 1); // GPSDOP -> RATIONAL, 1 2615*55efc227SAndreas Gohr $tags[0x000C] = array(2, 2); // GPSSpeedRef -> ASCII, 2 2616*55efc227SAndreas Gohr $tags[0x000D] = array(5, 1); // GPSSpeed -> RATIONAL, 1 2617*55efc227SAndreas Gohr $tags[0x000E] = array(2, 2); // GPSTrackRef -> ASCII, 2 2618*55efc227SAndreas Gohr $tags[0x000F] = array(5, 1); // GPSTrack -> RATIONAL, 1 2619*55efc227SAndreas Gohr $tags[0x0010] = array(2, 2); // GPSImgDirectionRef -> ASCII, 2 2620*55efc227SAndreas Gohr $tags[0x0011] = array(5, 1); // GPSImgDirection -> RATIONAL, 1 2621*55efc227SAndreas Gohr $tags[0x0012] = array(2, 0); // GPSMapDatum -> ASCII, Any 2622*55efc227SAndreas Gohr $tags[0x0013] = array(2, 2); // GPSDestLatitudeRef -> ASCII, 2 2623*55efc227SAndreas Gohr $tags[0x0014] = array(5, 3); // GPSDestLatitude -> RATIONAL, 3 2624*55efc227SAndreas Gohr $tags[0x0015] = array(2, 2); // GPSDestLongitudeRef -> ASCII, 2 2625*55efc227SAndreas Gohr $tags[0x0016] = array(5, 3); // GPSDestLongitude -> RATIONAL, 3 2626*55efc227SAndreas Gohr $tags[0x0017] = array(2, 2); // GPSDestBearingRef -> ASCII, 2 2627*55efc227SAndreas Gohr $tags[0x0018] = array(5, 1); // GPSDestBearing -> RATIONAL, 1 2628*55efc227SAndreas Gohr $tags[0x0019] = array(2, 2); // GPSDestDistanceRef -> ASCII, 2 2629*55efc227SAndreas Gohr $tags[0x001A] = array(5, 1); // GPSDestDistance -> RATIONAL, 1 2630*55efc227SAndreas Gohr } 2631*55efc227SAndreas Gohr 2632*55efc227SAndreas Gohr return $tags; 2633*55efc227SAndreas Gohr } 2634*55efc227SAndreas Gohr 2635*55efc227SAndreas Gohr /*************************************************************/ 2636*55efc227SAndreas Gohr function _exifNameTags($mode) 2637*55efc227SAndreas Gohr { 2638*55efc227SAndreas Gohr $tags = $this->_exifTagNames($mode); 2639*55efc227SAndreas Gohr return $this->_names2Tags($tags); 2640*55efc227SAndreas Gohr } 2641*55efc227SAndreas Gohr 2642*55efc227SAndreas Gohr /*************************************************************/ 2643*55efc227SAndreas Gohr function _iptcTagNames() 2644*55efc227SAndreas Gohr { 2645*55efc227SAndreas Gohr $tags = array(); 2646*55efc227SAndreas Gohr $tags[0x14] = 'SuplementalCategories'; 2647*55efc227SAndreas Gohr $tags[0x19] = 'Keywords'; 2648*55efc227SAndreas Gohr $tags[0x78] = 'Caption'; 2649*55efc227SAndreas Gohr $tags[0x7A] = 'CaptionWriter'; 2650*55efc227SAndreas Gohr $tags[0x69] = 'Headline'; 2651*55efc227SAndreas Gohr $tags[0x28] = 'SpecialInstructions'; 2652*55efc227SAndreas Gohr $tags[0x0F] = 'Category'; 2653*55efc227SAndreas Gohr $tags[0x50] = 'Byline'; 2654*55efc227SAndreas Gohr $tags[0x55] = 'BylineTitle'; 2655*55efc227SAndreas Gohr $tags[0x6E] = 'Credit'; 2656*55efc227SAndreas Gohr $tags[0x73] = 'Source'; 2657*55efc227SAndreas Gohr $tags[0x74] = 'CopyrightNotice'; 2658*55efc227SAndreas Gohr $tags[0x05] = 'ObjectName'; 2659*55efc227SAndreas Gohr $tags[0x5A] = 'City'; 2660*55efc227SAndreas Gohr $tags[0x5F] = 'ProvinceState'; 2661*55efc227SAndreas Gohr $tags[0x65] = 'CountryName'; 2662*55efc227SAndreas Gohr $tags[0x67] = 'OriginalTransmissionReference'; 2663*55efc227SAndreas Gohr $tags[0x37] = 'DateCreated'; 2664*55efc227SAndreas Gohr $tags[0x0A] = 'CopyrightFlag'; 2665*55efc227SAndreas Gohr 2666*55efc227SAndreas Gohr return $tags; 2667*55efc227SAndreas Gohr } 2668*55efc227SAndreas Gohr 2669*55efc227SAndreas Gohr /*************************************************************/ 2670*55efc227SAndreas Gohr function & _iptcNameTags() 2671*55efc227SAndreas Gohr { 2672*55efc227SAndreas Gohr $tags = $this->_iptcTagNames(); 2673*55efc227SAndreas Gohr return $this->_names2Tags($tags); 2674*55efc227SAndreas Gohr } 2675*55efc227SAndreas Gohr 2676*55efc227SAndreas Gohr /*************************************************************/ 2677*55efc227SAndreas Gohr function _names2Tags($tags2Names) 2678*55efc227SAndreas Gohr { 2679*55efc227SAndreas Gohr $names2Tags = array(); 2680*55efc227SAndreas Gohr reset($tags2Names); 2681*55efc227SAndreas Gohr while (list($tag, $name) = each($tags2Names)) { 2682*55efc227SAndreas Gohr $names2Tags[$name] = $tag; 2683*55efc227SAndreas Gohr } 2684*55efc227SAndreas Gohr 2685*55efc227SAndreas Gohr return $names2Tags; 2686*55efc227SAndreas Gohr } 2687*55efc227SAndreas Gohr 2688*55efc227SAndreas Gohr /*************************************************************/ 2689*55efc227SAndreas Gohr function _getByte(&$data, $pos) 2690*55efc227SAndreas Gohr { 2691*55efc227SAndreas Gohr return ord($data{$pos}); 2692*55efc227SAndreas Gohr } 2693*55efc227SAndreas Gohr 2694*55efc227SAndreas Gohr /*************************************************************/ 2695*55efc227SAndreas Gohr function _putByte(&$data, $pos, $val) 2696*55efc227SAndreas Gohr { 2697*55efc227SAndreas Gohr $val = intval($val); 2698*55efc227SAndreas Gohr 2699*55efc227SAndreas Gohr $data{$pos} = chr($val); 2700*55efc227SAndreas Gohr 2701*55efc227SAndreas Gohr return $pos + 1; 2702*55efc227SAndreas Gohr } 2703*55efc227SAndreas Gohr 2704*55efc227SAndreas Gohr /*************************************************************/ 2705*55efc227SAndreas Gohr function _getShort(&$data, $pos, $bigEndian = true) 2706*55efc227SAndreas Gohr { 2707*55efc227SAndreas Gohr if ($bigEndian) { 2708*55efc227SAndreas Gohr return (ord($data{$pos}) << 8) 2709*55efc227SAndreas Gohr + ord($data{$pos + 1}); 2710*55efc227SAndreas Gohr } 2711*55efc227SAndreas Gohr else { 2712*55efc227SAndreas Gohr return ord($data{$pos}) 2713*55efc227SAndreas Gohr + (ord($data{$pos + 1}) << 8); 2714*55efc227SAndreas Gohr } 2715*55efc227SAndreas Gohr } 2716*55efc227SAndreas Gohr 2717*55efc227SAndreas Gohr /*************************************************************/ 2718*55efc227SAndreas Gohr function _putShort(&$data, $pos = 0, $val, $bigEndian = true) 2719*55efc227SAndreas Gohr { 2720*55efc227SAndreas Gohr $val = intval($val); 2721*55efc227SAndreas Gohr 2722*55efc227SAndreas Gohr if ($bigEndian) { 2723*55efc227SAndreas Gohr $data{$pos + 0} = chr(($val & 0x0000FF00) >> 8); 2724*55efc227SAndreas Gohr $data{$pos + 1} = chr(($val & 0x000000FF) >> 0); 2725*55efc227SAndreas Gohr } 2726*55efc227SAndreas Gohr else { 2727*55efc227SAndreas Gohr $data{$pos + 0} = chr(($val & 0x00FF) >> 0); 2728*55efc227SAndreas Gohr $data{$pos + 1} = chr(($val & 0xFF00) >> 8); 2729*55efc227SAndreas Gohr } 2730*55efc227SAndreas Gohr 2731*55efc227SAndreas Gohr return $pos + 2; 2732*55efc227SAndreas Gohr } 2733*55efc227SAndreas Gohr 2734*55efc227SAndreas Gohr /*************************************************************/ 2735*55efc227SAndreas Gohr function _getLong(&$data, $pos, $bigEndian = true) 2736*55efc227SAndreas Gohr { 2737*55efc227SAndreas Gohr if ($bigEndian) { 2738*55efc227SAndreas Gohr return (ord($data{$pos}) << 24) 2739*55efc227SAndreas Gohr + (ord($data{$pos + 1}) << 16) 2740*55efc227SAndreas Gohr + (ord($data{$pos + 2}) << 8) 2741*55efc227SAndreas Gohr + ord($data{$pos + 3}); 2742*55efc227SAndreas Gohr } 2743*55efc227SAndreas Gohr else { 2744*55efc227SAndreas Gohr return ord($data{$pos}) 2745*55efc227SAndreas Gohr + (ord($data{$pos + 1}) << 8) 2746*55efc227SAndreas Gohr + (ord($data{$pos + 2}) << 16) 2747*55efc227SAndreas Gohr + (ord($data{$pos + 3}) << 24); 2748*55efc227SAndreas Gohr } 2749*55efc227SAndreas Gohr } 2750*55efc227SAndreas Gohr 2751*55efc227SAndreas Gohr /*************************************************************/ 2752*55efc227SAndreas Gohr function _putLong(&$data, $pos, $val, $bigEndian = true) 2753*55efc227SAndreas Gohr { 2754*55efc227SAndreas Gohr $val = intval($val); 2755*55efc227SAndreas Gohr 2756*55efc227SAndreas Gohr if ($bigEndian) { 2757*55efc227SAndreas Gohr $data{$pos + 0} = chr(($val & 0xFF000000) >> 24); 2758*55efc227SAndreas Gohr $data{$pos + 1} = chr(($val & 0x00FF0000) >> 16); 2759*55efc227SAndreas Gohr $data{$pos + 2} = chr(($val & 0x0000FF00) >> 8); 2760*55efc227SAndreas Gohr $data{$pos + 3} = chr(($val & 0x000000FF) >> 0); 2761*55efc227SAndreas Gohr } 2762*55efc227SAndreas Gohr else { 2763*55efc227SAndreas Gohr $data{$pos + 0} = chr(($val & 0x000000FF) >> 0); 2764*55efc227SAndreas Gohr $data{$pos + 1} = chr(($val & 0x0000FF00) >> 8); 2765*55efc227SAndreas Gohr $data{$pos + 2} = chr(($val & 0x00FF0000) >> 16); 2766*55efc227SAndreas Gohr $data{$pos + 3} = chr(($val & 0xFF000000) >> 24); 2767*55efc227SAndreas Gohr } 2768*55efc227SAndreas Gohr 2769*55efc227SAndreas Gohr return $pos + 4; 2770*55efc227SAndreas Gohr } 2771*55efc227SAndreas Gohr 2772*55efc227SAndreas Gohr /*************************************************************/ 2773*55efc227SAndreas Gohr function & _getNullString(&$data, $pos) 2774*55efc227SAndreas Gohr { 2775*55efc227SAndreas Gohr $str = ''; 2776*55efc227SAndreas Gohr $max = strlen($data); 2777*55efc227SAndreas Gohr 2778*55efc227SAndreas Gohr while ($pos < $max) { 2779*55efc227SAndreas Gohr if (ord($data{$pos}) == 0) { 2780*55efc227SAndreas Gohr return $str; 2781*55efc227SAndreas Gohr } 2782*55efc227SAndreas Gohr else { 2783*55efc227SAndreas Gohr $str .= $data{$pos}; 2784*55efc227SAndreas Gohr } 2785*55efc227SAndreas Gohr $pos++; 2786*55efc227SAndreas Gohr } 2787*55efc227SAndreas Gohr 2788*55efc227SAndreas Gohr return $str; 2789*55efc227SAndreas Gohr } 2790*55efc227SAndreas Gohr 2791*55efc227SAndreas Gohr /*************************************************************/ 2792*55efc227SAndreas Gohr function & _getFixedString(&$data, $pos, $length = -1) 2793*55efc227SAndreas Gohr { 2794*55efc227SAndreas Gohr if ($length == -1) { 2795*55efc227SAndreas Gohr $length = strlen($data) - $pos; 2796*55efc227SAndreas Gohr } 2797*55efc227SAndreas Gohr 2798*55efc227SAndreas Gohr return substr($data, $pos, $length); 2799*55efc227SAndreas Gohr } 2800*55efc227SAndreas Gohr 2801*55efc227SAndreas Gohr /*************************************************************/ 2802*55efc227SAndreas Gohr function _putString(&$data, $pos, &$str) 2803*55efc227SAndreas Gohr { 2804*55efc227SAndreas Gohr $len = strlen($str); 2805*55efc227SAndreas Gohr for ($i = 0; $i < $len; $i++) { 2806*55efc227SAndreas Gohr $data{$pos + $i} = $str{$i}; 2807*55efc227SAndreas Gohr } 2808*55efc227SAndreas Gohr 2809*55efc227SAndreas Gohr return $pos + $len; 2810*55efc227SAndreas Gohr } 2811*55efc227SAndreas Gohr 2812*55efc227SAndreas Gohr /*************************************************************/ 2813*55efc227SAndreas Gohr function _hexDump(&$data, $start = 0, $length = -1) 2814*55efc227SAndreas Gohr { 2815*55efc227SAndreas Gohr if (($length == -1) || (($length + $start) > strlen($data))) { 2816*55efc227SAndreas Gohr $end = strlen($data); 2817*55efc227SAndreas Gohr } 2818*55efc227SAndreas Gohr else { 2819*55efc227SAndreas Gohr $end = $start + $length; 2820*55efc227SAndreas Gohr } 2821*55efc227SAndreas Gohr 2822*55efc227SAndreas Gohr $ascii = ''; 2823*55efc227SAndreas Gohr $count = 0; 2824*55efc227SAndreas Gohr 2825*55efc227SAndreas Gohr echo "<tt>\n"; 2826*55efc227SAndreas Gohr 2827*55efc227SAndreas Gohr while ($start < $end) { 2828*55efc227SAndreas Gohr if (($count % 16) == 0) { 2829*55efc227SAndreas Gohr echo sprintf('%04d', $count) . ': '; 2830*55efc227SAndreas Gohr } 2831*55efc227SAndreas Gohr 2832*55efc227SAndreas Gohr $c = ord($data{$start}); 2833*55efc227SAndreas Gohr $count++; 2834*55efc227SAndreas Gohr $start++; 2835*55efc227SAndreas Gohr 2836*55efc227SAndreas Gohr $aux = dechex($c); 2837*55efc227SAndreas Gohr if (strlen($aux) == 1) 2838*55efc227SAndreas Gohr echo '0'; 2839*55efc227SAndreas Gohr echo $aux . ' '; 2840*55efc227SAndreas Gohr 2841*55efc227SAndreas Gohr if ($c == 60) 2842*55efc227SAndreas Gohr $ascii .= '<'; 2843*55efc227SAndreas Gohr elseif ($c == 62) 2844*55efc227SAndreas Gohr $ascii .= '>'; 2845*55efc227SAndreas Gohr elseif ($c == 32) 2846*55efc227SAndreas Gohr $ascii .= ' '; 2847*55efc227SAndreas Gohr elseif ($c > 32) 2848*55efc227SAndreas Gohr $ascii .= chr($c); 2849*55efc227SAndreas Gohr else 2850*55efc227SAndreas Gohr $ascii .= '.'; 2851*55efc227SAndreas Gohr 2852*55efc227SAndreas Gohr if (($count % 4) == 0) { 2853*55efc227SAndreas Gohr echo ' - '; 2854*55efc227SAndreas Gohr } 2855*55efc227SAndreas Gohr 2856*55efc227SAndreas Gohr if (($count % 16) == 0) { 2857*55efc227SAndreas Gohr echo ': ' . $ascii . "<br>\n"; 2858*55efc227SAndreas Gohr $ascii = ''; 2859*55efc227SAndreas Gohr } 2860*55efc227SAndreas Gohr } 2861*55efc227SAndreas Gohr 2862*55efc227SAndreas Gohr if ($ascii != '') { 2863*55efc227SAndreas Gohr while (($count % 16) != 0) { 2864*55efc227SAndreas Gohr echo '-- '; 2865*55efc227SAndreas Gohr $count++; 2866*55efc227SAndreas Gohr if (($count % 4) == 0) { 2867*55efc227SAndreas Gohr echo ' - '; 2868*55efc227SAndreas Gohr } 2869*55efc227SAndreas Gohr } 2870*55efc227SAndreas Gohr echo ': ' . $ascii . "<br>\n"; 2871*55efc227SAndreas Gohr } 2872*55efc227SAndreas Gohr 2873*55efc227SAndreas Gohr echo "</tt>\n"; 2874*55efc227SAndreas Gohr } 2875*55efc227SAndreas Gohr 2876*55efc227SAndreas Gohr/*****************************************************************/ 2877*55efc227SAndreas Gohr} 2878*55efc227SAndreas Gohr 2879*55efc227SAndreas Gohr/* vim: set expandtab tabstop=4 shiftwidth=4: */ 2880*55efc227SAndreas Gohr 2881