PageRenderTime 93ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/wp-content/plugins/yet-another-photoblog/lib/phpExifRW-1.1/exifReader.inc

https://github.com/Mercedes/ratonesytortillas
PHP | 1718 lines | 1125 code | 197 blank | 396 comment | 152 complexity | 72dd73ae670ce088e5e13285ea3133dd MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /**
  3. * PHP Class to read EXIF information
  4. * that most of the digital camera produce
  5. *
  6. * This class is based on jhead (in C) by Matthias Wandel
  7. *
  8. * Vinay Yadav (vinay@vinayras.com)
  9. * http://open.vinayras.com/phpexifrw_exif_reader_writer
  10. *
  11. * For more information on EXIF
  12. * http://www.exif.org/
  13. *
  14. * Features:
  15. * - Read Exif Information
  16. * - Extract and display emdedded thumbnails
  17. *
  18. * Tested With
  19. - Sony
  20. - Cybershot (Sony)
  21. - DSC-D700
  22. - PowerShotA5
  23. - Sony P71
  24. - SANYO Electric Co.,Ltd
  25. - SR6
  26. - SX113
  27. - OLYMPUS OPTICAL CO.,LTD
  28. - C960Z, D460Z
  29. - C3000Z
  30. - Canon
  31. PowerShot A40 (Canon)
  32. Canon DIGITAL IXUS
  33. Canon 300D
  34. - RICOH
  35. - Caplio RR30
  36. - RDC-5300
  37. - NIKON
  38. - D100 (NIKON CORPORATION)
  39. - E5700 (NIKON)
  40. - E950
  41. - CASIO QV-8000SX
  42. - KODAK
  43. - DC290 Zoom Digital Camera (V01.00) [Eastman Kodak Company]
  44. - DC210 Zoom (V05.00) [Eastman Kodak Company]
  45. - KODAK DC240 ZOOM DIGITAL CAMERA
  46. - FujiFilm
  47. DX10
  48. FinePix40i
  49. MX-1700ZOOM
  50. *
  51. *
  52. */
  53. /** * Start Of Frame N */
  54. define("M_SOF0",0xC0);
  55. /** * N indicates which compression process */
  56. define("M_SOF1",0xC1);
  57. /** * Only SOF0-SOF2 are now in common use */
  58. define("M_SOF2",0xC2);
  59. /** * */
  60. define("M_SOF3",0xC3);
  61. /** * NB: codes C4 and CC are NOT SOF markers */
  62. define("M_SOF5",0xC5);
  63. /** * */
  64. define("M_SOF6",0xC6);
  65. /** * */
  66. define("M_SOF7",0xC7);
  67. /** * */
  68. define("M_SOF9",0xC9);
  69. /** * */
  70. define("M_SOF10",0xCA);
  71. /** * */
  72. define("M_SOF11",0xCB);
  73. /** * */
  74. define("M_SOF13",0xCD);
  75. /** * */
  76. define("M_SOF14",0xCE);
  77. /** * */
  78. define("M_SOF15",0xCF);
  79. /** * Start Of Image (beginning of datastream) */
  80. define("M_SOI",0xD8);
  81. /** * End Of Image (end of datastream) */
  82. define("M_EOI",0xD9);
  83. /** * Start Of Scan (begins compressed data) */
  84. define("M_SOS",0xDA);
  85. /** * Jfif marker */
  86. define("M_JFIF",0xE0);
  87. /** * Exif marker */
  88. define("M_EXIF",0xE1);
  89. define("M_EXIF_EXT",0xE2); // 226 - Exif Extended Data
  90. define("M_QUANTA",0xDB); // 219 - Quantisation Table Definition
  91. define("M_HUFF",0xC4); // (DEC=196) - Huffman Table Definition
  92. /** * Image Title -- */
  93. define("M_COM",0xFE);
  94. define("NUM_FORMATS","12");
  95. /** * Tag Data Format */
  96. define("FMT_BYTE","1");
  97. /** * ASCII */
  98. define("FMT_STRING","2");
  99. /** * Short */
  100. define("FMT_USHORT","3");
  101. /** * Long */
  102. define("FMT_ULONG","4");
  103. /** * Rational */
  104. define("FMT_URATIONAL","5");
  105. /** * Byte */
  106. define("FMT_SBYTE","6");
  107. /** * Undefined */
  108. define("FMT_UNDEFINED","7");
  109. /** * Short */
  110. define("FMT_SSHORT","8");
  111. /** * Long */
  112. define("FMT_SLONG","9");
  113. /** * Rational */
  114. define("FMT_SRATIONAL","10");
  115. /** * Single */
  116. define("FMT_SINGLE","11");
  117. /** * Double */
  118. define("FMT_DOUBLE","12");
  119. /** * Exif IFD */
  120. define("TAG_EXIF_OFFSET","0x8769");
  121. /** * Interoperability tag */
  122. define("TAG_INTEROP_OFFSET","0xa005");
  123. /** * Image input equipment manufacturer */
  124. define("TAG_MAKE","0x010F");
  125. /** * Image input equipment model */
  126. define("TAG_MODEL","0x0110");
  127. /** * Orientation of image */
  128. define("TAG_ORIENTATION","0x0112");
  129. /** * Exposure Time */
  130. define("TAG_EXPOSURETIME","0x829A");
  131. /** * F Number */
  132. define("TAG_FNUMBER","0x829D");
  133. /** * Shutter Speed */
  134. define("TAG_SHUTTERSPEED","0x9201");
  135. /** * Aperture */
  136. define("TAG_APERTURE","0x9202");
  137. /** * Aperture */
  138. define("TAG_MAXAPERTURE","0x9205");
  139. /** * Lens Focal Length */
  140. define("TAG_FOCALLENGTH","0x920A");
  141. /** * The date and time when the original image data was generated. */
  142. define("TAG_DATETIME_ORIGINAL","0x9003");
  143. /** * User Comments */
  144. define("TAG_USERCOMMENT","0x9286");
  145. /** * subject Location */
  146. define("TAG_SUBJECT_DISTANCE","0x9206");
  147. /** * Flash */
  148. define("TAG_FLASH","0x9209");
  149. /** * Focal Plane X Resolution */
  150. define("TAG_FOCALPLANEXRES","0xa20E");
  151. /** * Focal Plane Resolution Units */
  152. define("TAG_FOCALPLANEUNITS","0xa210");
  153. /** * Image Width */
  154. define("TAG_EXIF_IMAGEWIDTH","0xA002");
  155. /** * Image Height */
  156. define("TAG_EXIF_IMAGELENGTH","0xA003");
  157. /** * Exposure Bias */
  158. define("TAG_EXPOSURE_BIAS","0x9204");
  159. /** * Light Source */
  160. define("TAG_WHITEBALANCE","0x9208");
  161. /** * Metering Mode */
  162. define("TAG_METERING_MODE","0x9207");
  163. /** * Exposure Program */
  164. define("TAG_EXPOSURE_PROGRAM","0x8822");
  165. /** * ISO Equivalent Speed Rating */
  166. define("TAG_ISO_EQUIVALENT","0x8827");
  167. /** * Compressed Bits Per Pixel */
  168. define("TAG_COMPRESSION_LEVEL","0x9102");
  169. /** * Thumbnail Start Offset */
  170. define("TAG_THUMBNAIL_OFFSET","0x0201");
  171. /** * Thumbnail Length */
  172. define("TAG_THUMBNAIL_LENGTH","0x0202");
  173. /** * Image Marker */
  174. define("PSEUDO_IMAGE_MARKER",0x123);
  175. /** * Max Image Title Length */
  176. define("MAX_COMMENT",2000);
  177. define("TAG_ARTIST","0x013B");
  178. define("TAG_COPYRIGHT","0x8298");
  179. //--------------------------------
  180. define("TAG_IMAGE_WD","0x0100"); // image width
  181. define("TAG_IMAGE_HT","0x0101"); // image height
  182. define("TAG_IMAGE_BPS","0x0102"); // Bits Per sample
  183. define("TAG_IMAGE_PHOTO_INT","0x0106"); // photometricinterpretation
  184. define("TAG_IMAGE_SOFFSET","0x0111"); // stripoffsets
  185. define("TAG_IMAGE_SPP","0x0115"); // Samples per pixel - 277
  186. define("TAG_IMAGE_RPS","0x0116"); // RowsPerStrip - 278
  187. define("TAG_IMAGE_SBC","0x0117"); // StripByteCounts - 279
  188. define("TAG_IMAGE_P_CONFIG","0x011C"); // Planar Configuration - 284
  189. define("TAG_IMAGE_DESC","0x010E"); // image title
  190. define("TAG_X_RESOLUTION","0x011A"); // Image resolution in width direction
  191. define("TAG_Y_RESOLUTION","0x011B"); // Image resolution in height direction
  192. define("TAG_RESOLUTION_UNIT","0x0128"); // Unit of X and Y resolution
  193. define("TAG_SOFTWARE","0x0131"); // Software used
  194. define("TAG_FILE_MODDATE","0x0132"); // DateTime File change date and time
  195. define("TAG_YCBCR_POSITIONING","0x0213"); // Y and C positioning
  196. define("TAG_EXIF_VERSION","0x9000"); // Exif version
  197. define("TAG_DATE_TIME_DIGITIZED","0x9004"); // Date and time of digital data
  198. define("TAG_COMPONENT_CONFIG","0x9101"); // Component configuration
  199. define("TAG_MAKER_NOTE","0x927C");
  200. define("TAG_SUB_SEC_TIME","0x9290");
  201. define("TAG_SUB_SEC_TIME_ORIG","0x9291");
  202. define("TAG_SUB_SEC_TIME_DIGITIZED","0x9292");
  203. define("TAG_FLASHPIX_VER","0xA000"); //FlashPixVersion
  204. define("TAG_COLOR_SPACE","0xA001"); //ColorSpace
  205. define("TAG_RELATED_SOUND_FILE","0xA004"); //Related audio file
  206. define("TAG_GPS_IFD" , "0x8825"); // GPS IFD
  207. define("TAG_GPS_LATITUDE_REF","0x0001"); //
  208. define("TAG_GPS_LATITUDE","0x0002"); //
  209. define("TAG_GPS_LONGITUDE_REF","0x0003"); //
  210. define("TAG_GPS_LONGITUDE","0x0004"); //
  211. define("TAG_GPS_TrackRef","0x000E"); //
  212. define("TAG_GPS_GPSTrack","0x000F"); //
  213. define("TAG_GPS_GPSImgDirectionRef","0x0010"); //
  214. define("TAG_GPS_GPSImgDirection","0x0011"); //
  215. define("TAG_GPS_GPSMapDatum","0x0012"); //
  216. define("TAG_GPS_GPSDestLatitudeRef","0x0013"); //
  217. define("TAG_GPS_GPSDestLatitude","0x0014"); //
  218. define("TAG_GPS_GPSDestLongitudeRef","0x0015"); //
  219. define("TAG_GPS_GPSDestLongitude","0x0016"); //
  220. define("TAG_GPS_GPSDestBearingRef","0x0017"); //
  221. define("TAG_GPS_GPSDestBearing","0x0018"); //
  222. define("TAG_GPS_GPSDestDistanceRef","0x0019"); //
  223. define("TAG_GPS_GPSDestDistance","0x001A"); //
  224. define("TAG_GPS_GPSProcessingMethod","0x001B"); //
  225. define("TAG_GPS_GPSAreaInformation","0x001C"); //
  226. define("TAG_GPS_GPSDateStamp","0x001D"); //
  227. define("TAG_GPS_GPSDifferential","0x001E"); //
  228. define("TAG_AUDIO_IMA_ADPCM_DESC","0x0028"); // IMA-ADPCM Audio File Description Example - 40
  229. define("TAG_AUDIO_MU_LAW_DESC","0x0032"); // µ-Law Audio File Description Sample - 50
  230. define("TAG_AUDIO_MU_LAW","0x0086"); // (This File µ-LAW Sample) - 134
  231. define("TAG_EXPOSURE_INDEX","0xA215"); // Exposure index
  232. define("TAG_SENSING_METHOD","0xA217"); // SensingMethod
  233. define("TAG_SOUCE_TYPE","0xA300"); // FileSource
  234. define("TAG_SCENE_TYPE","0xA301"); // SceneType
  235. define("TAG_CFA_PATTERN","0xA302"); // CFA Pattern
  236. /** Tags in EXIF 2.2 Only */
  237. define("TAG_COMPRESS_SCHEME","0x0103"); //
  238. define("TAG_CUSTOM_RENDERED","0xA401"); // CustomRendered
  239. define("TAG_EXPOSURE_MODE","0xA402"); // Exposure mode ExposureMode
  240. define("TAG_WHITE_BALANCE","0xA403"); // White balance WhiteBalance
  241. define("TAG_DIGITAL_ZOOM_RATIO","0xA404"); // Digital zoom ratio DigitalZoomRatio
  242. define("TAG_FLENGTH_IN35MM","0xA405"); // Focal length in 35 mm film FocalLengthIn35mmFilm
  243. define("TAG_SCREEN_CAP_TYPE","0xA406"); // Scene capture type SceneCaptureType
  244. define("TAG_GAIN_CONTROL","0xA407"); //Gain control
  245. define("TAG_CONTRAST","0xA408"); // Contrast
  246. define("TAG_SATURATION","0xA409"); // Saturation
  247. define("TAG_SHARPNESS","0xA40A"); // Sharpness
  248. define("TAG_DEVICE_SETTING_DESC","0xA40B"); // SDevice settings description DeviceSettingDescription
  249. define("TAG_DIST_RANGE","0xA40C"); //Subject distance range SubjectDistanceRange
  250. define("TAG_FOCALPLANE_YRESOL","0xA20F");; //FocalPlaneYResolution
  251. define("TAG_BRIGHTNESS","0x9203");; //Brightness
  252. //--------------------------------
  253. /** error Description */
  254. /**
  255. 1 - File does not exists!
  256. 2 -
  257. 3 - Filename not provided
  258. 10 - too many padding bytes
  259. 11 - "invalid marker"
  260. 12 - Premature end of file?
  261. 51 - "Illegal subdirectory link"
  262. 52 - "NOT EXIF FORMAT"
  263. 53 - "Invalid Exif alignment marker.\n"
  264. 54 - "Invalid Exif start (1)"
  265. */
  266. /**
  267. * PHP Class to read, write and transfer EXIF information
  268. * that most of the digital camera produces
  269. * Currenty it can only read JPEG file.
  270. */
  271. /**
  272. * @author Vinay Yadav (vinayRas) < vinay@sanisoft.com >
  273. *
  274. * @todo Writing exif information to the file.
  275. * @todo Add EXIF audio reading methods (I think it exists!)
  276. * @todo Support of additional tags.
  277. * @todo Handling Unicode character in UserComment tag of EXif Information.
  278. *
  279. * @version 0.5
  280. * @licence http://opensource.org/licenses/lgpl-license.php GNU LGPL
  281. */
  282. class phpExifReader {
  283. /***
  284. * Array containg all Exif and JPEG image attributes
  285. * into regular expressions for themselves.
  286. * $ImageInfo[TAG] = TAG_VALUE;
  287. *
  288. * @var array
  289. * @access private
  290. *
  291. */
  292. var $ImageInfo = array();
  293. var $MotorolaOrder = 0;
  294. var $ExifImageWidth = 0; //
  295. var $FocalplaneXRes = 0; //
  296. var $FocalplaneUnits = 0; //
  297. var $sections = array();
  298. var $currSection = 0; /** Stores total number fo Sections */
  299. var $BytesPerFormat = array(0,1,1,2,4,8,1,1,2,4,8,4,8);
  300. var $ReadMode = array(
  301. "READ_EXIF" => 1,
  302. "READ_IMAGE" => 2,
  303. "READ_ALL" => 3
  304. );
  305. var $ImageReadMode = 3; /** related to $RealMode arrays values */
  306. var $file = ""; /** JPEG file to parse for EXIF data */
  307. var $newFile = 1; /** flag to check if the current file has been parsed or not. */
  308. var $thumbnail = ""; /* Name of thumbnail */
  309. var $thumbnailURL = ""; /* */
  310. var $exifSection = -1; // market the exif section index oout of all sections
  311. var $errno = 0;
  312. var $errstr = "";
  313. var $debug = false;
  314. // Caching ralated variables
  315. var $caching = false; /* Should cacheing of image thumnails be allowed? */
  316. var $cacheDir = ""; /* Checkout constructor for default path. */
  317. /**
  318. * Constructor
  319. * @param string File name to be parsed.
  320. *
  321. */
  322. function phpExifReader($file = "") {
  323. $this->timeStart = $this->getmicrotime();
  324. if(!empty($file)) {
  325. $this->file = $file;
  326. }
  327. /**
  328. * Initialize some variables. Avoid lots of errors with fulll error_reporting
  329. */
  330. $this->ExifImageLength = 0;
  331. $this->ImageInfo['h']["resolutionUnit"] = 0;
  332. $this->ImageInfo[TAG_MAXAPERTURE] = 0;
  333. $this->ImageInfo[TAG_ISO_EQUIVALENT] = 0;
  334. $this->ImageInfo[TAG_ORIENTATION] = 0;
  335. $this->ThumbnailSize = 0;
  336. if($this->caching) {
  337. $this->cacheDir = dirname(__FILE__)."/.cache_thumbs";
  338. /**
  339. * If Cache directory does not exists then attempt to create it.
  340. */
  341. if(!is_dir($this->cacheDir)) {
  342. mkdir($this->cacheDir);
  343. }
  344. // Prepare the ame of thumbnail
  345. if(is_dir($this->cacheDir)) {
  346. $this->thumbnail = $this->cacheDir."/".basename($this->file);
  347. $this->thumbnailURL = ".cache_thumbs/".basename($this->file);
  348. }
  349. }
  350. /** check if file exists! */
  351. if(!file_exists($this->file)) {
  352. $this->errno = 1;
  353. $this->errstr = "File '".$this->file."' does not exists!";
  354. }
  355. $this->currSection = 0;
  356. $this->processFile();
  357. }
  358. /**
  359. * Show Debugging information
  360. *
  361. * @param string Debugging message to display
  362. * @param int Type of error (0 - Warning, 1 - Error)
  363. * @return void
  364. *
  365. */
  366. function debug($str,$TYPE = 0,$file="",$line=0) {
  367. if($this->debug) {
  368. echo "<br>[$file:$line:".($this->getDiffTime())."]$str";
  369. flush();
  370. if($TYPE == 1) {
  371. exit;
  372. }
  373. }
  374. }
  375. /**
  376. * Processes the whole file.
  377. *
  378. */
  379. function processFile() {
  380. /** dont reparse the whole file. */
  381. if(!$this->newFile) return true;
  382. if(!file_exists($this->file)) {
  383. echo "<br>Error: File ".($this->file)."does not exists!";
  384. exit;
  385. }
  386. $this->debug("Stating Processing of ".$this->newFile,0,__FILE__,__LINE__);
  387. $i = 0; $exitAll = 0;
  388. /** Open the JPEG in binary safe reading mode */
  389. $fp = fopen($this->file,"rb");
  390. $this->ImageInfo["h"]["FileName"] = $this->file;
  391. $this->ImageInfo["h"]["FileSize"] = filesize($this->file); /** Size of the File */
  392. $this->ImageInfo["h"]["FileDateTime"] = filectime($this->file); /** File node change time */
  393. /** check whether jped image or not */
  394. $a = fgetc($fp);
  395. if (ord($a) != 0xff || ord(fgetc($fp)) != M_SOI){
  396. $this->debug("Not a JPEG FILE",1);
  397. $this->errorno = 1;
  398. $this->errorstr = "File '".$this->file."' is not a JPEG File!";
  399. }
  400. $tmpTestLevel = 0;
  401. /** Examines each byte one-by-one */
  402. while(!feof($fp)) {
  403. $data = array();
  404. for ($a=0;$a<7;$a++){
  405. $marker = fgetc($fp);
  406. if (ord($marker) != 0xff) break;
  407. if ($a >= 6){
  408. $this->errno = 10;
  409. $this->errstr = "too many padding bytes!";
  410. $this->debug($this->errstr,1);
  411. return false;
  412. }
  413. }
  414. if (ord($marker) == 0xff){
  415. // 0xff is legal padding, but if we get that many, something's wrong.
  416. $this->errno = 10;
  417. $this->errstr = "too many padding bytes!";
  418. $this->debug($this->errstr,1);
  419. }
  420. $marker = ord($marker);
  421. $this->sections[$this->currSection]["type"] = $marker;
  422. // Read the length of the section.
  423. $lh = ord(fgetc($fp));
  424. $ll = ord(fgetc($fp));
  425. $itemlen = ($lh << 8) | $ll;
  426. if ($itemlen < 2){
  427. $this->errno = 11;
  428. $this->errstr = "invalid marker";
  429. $this->debug($this->errstr,1);
  430. }
  431. $this->sections[$this->currSection]["size"] = $itemlen;
  432. $tmpDataArr = array(); /** Temporary Array */
  433. $tmpStr = fread($fp,$itemlen-2);
  434. /*
  435. $tmpDataArr[] = chr($lh);
  436. $tmpDataArr[] = chr($ll);
  437. $chars = preg_split('//', $tmpStr, -1, PREG_SPLIT_NO_EMPTY);
  438. $tmpDataArr = array_merge($tmpDataArr,$chars);
  439. $data = $tmpDataArr;
  440. */
  441. $data = chr($lh).chr($ll).$tmpStr;
  442. //$this->sections[$this->currSection]["data"] = $data;
  443. $this->debug("<hr><h1>".$this->currSection.":</h1>");
  444. //print_r($data);
  445. $this->debug("<hr>");
  446. //if(count($data) != $itemlen) {
  447. if(strlen($data) != $itemlen) {
  448. $this->errno = 12;
  449. $this->errstr = "Premature end of file?";
  450. $this->debug($this->errstr,1);
  451. }
  452. $this->currSection++; /** */
  453. switch($marker) {
  454. case M_SOS:
  455. $this->debug("<br>Found '".M_SOS."' Section, Prcessing it... <br>");;
  456. // If reading entire image is requested, read the rest of the data.
  457. if ($this->ImageReadMode & $this->ReadMode["READ_IMAGE"]){
  458. // Determine how much file is left.
  459. $cp = ftell($fp);
  460. fseek($fp,0, SEEK_END);
  461. $ep = ftell($fp);
  462. fseek($fp, $cp, SEEK_SET);
  463. $size = $ep-$cp;
  464. $got = fread($fp, $size);
  465. $this->sections[$this->currSection]["data"] = $got;
  466. $this->sections[$this->currSection]["size"] = $size;
  467. $this->sections[$this->currSection]["type"] = PSEUDO_IMAGE_MARKER;
  468. $this->currSection++;
  469. $HaveAll = 1;
  470. $exitAll =1;
  471. }
  472. $this->debug("<br>'".M_SOS."' Section, PROCESSED<br>");
  473. break;
  474. case M_COM: // Comment section
  475. $this->debug("<br>Found '".M_COM."'(Comment) Section, Processing<br>");
  476. $this->process_COM($data, $itemlen);
  477. $this->debug("<br>'".M_COM."'(Comment) Section, PROCESSED<br>");
  478. $tmpTestLevel++;
  479. break;
  480. case M_SOI:
  481. $this->debug(" <br> === START OF IMAGE =====<br>");
  482. break;
  483. case M_EOI:
  484. $this->debug(" <br>=== END OF IMAGE =====<br> ");
  485. break;
  486. case M_JFIF:
  487. // Regular jpegs always have this tag, exif images have the exif
  488. // marker instead, althogh ACDsee will write images with both markers.
  489. // this program will re-create this marker on absence of exif marker.
  490. // hence no need to keep the copy from the file.
  491. //echo " <br> === M_JFIF =====<br>";
  492. $this->sections[--$this->currSection]["data"] = "";
  493. break;
  494. case M_EXIF:
  495. // Seen files from some 'U-lead' software with Vivitar scanner
  496. // that uses marker 31 for non exif stuff. Thus make sure
  497. // it says 'Exif' in the section before treating it as exif.
  498. $this->debug("<br>Found '".M_EXIF."'(Exif) Section, Proccessing<br>");
  499. $this->exifSection = $this->currSection-1;
  500. if (($this->ImageReadMode & $this->ReadMode["READ_EXIF"]) && ($data[2].$data[3].$data[4].$data[5]) == "Exif"){
  501. $this->process_EXIF($data, $itemlen);
  502. }else{
  503. // Discard this section.
  504. $this->sections[--$this->currSection]["data"] = "";
  505. }
  506. $this->debug("<br>'".M_EXIF."'(Exif) Section, PROCESSED<br>");
  507. $tmpTestLevel++;
  508. break;
  509. case M_SOF0:
  510. case M_SOF1:
  511. case M_SOF2:
  512. case M_SOF3:
  513. case M_SOF5:
  514. case M_SOF6:
  515. case M_SOF7:
  516. case M_SOF9:
  517. case M_SOF10:
  518. case M_SOF11:
  519. case M_SOF13:
  520. case M_SOF14:
  521. case M_SOF15:
  522. $this->debug("<br>Found M_SOFn Section, Processing<br>");
  523. $this->process_SOFn($data,$marker);
  524. $this->debug("<br>M_SOFn Section, PROCESSED<br>");
  525. break;
  526. case M_EXIF_EXT: // 226 - Exif Extended Data
  527. $this->debug("<br><b>Found 'Exif Extended Data' Section, Processing</b><br>-------------------------------<br>");
  528. $this->process_EXT_EXIF($data, $itemlen);
  529. $this->debug("<br>--------------------------PROCESSED<br>");
  530. break;
  531. case M_QUANTA: // 219 - Quantisation Table Definition
  532. $this->debug("<br><b>Found 'Quantisation Table Definition' Section, Processing</b><br>-------------------------------<br>");
  533. $this->debug("<br>--------------------------PROCESSED<br>");
  534. break;
  535. case M_HUFF: // Huffman Table
  536. $this->debug("<br><b>Found 'Huffman Table' Section, Processing</b><br>-------------------------------<br>");
  537. $this->debug("<br>--------------------------PROCESSED<br>");
  538. break;
  539. default:
  540. $this->debug("DEFAULT: Jpeg section marker 0x$marker x size $itemlen\n");
  541. }
  542. $i++;
  543. if($exitAll == 1) break;
  544. //if($tmpTestLevel == 2) break;
  545. }
  546. fclose($fp);
  547. $this->newFile = 0;
  548. }
  549. /**
  550. * Changing / Assiging new file
  551. * @param string JPEG file to process
  552. *
  553. */
  554. function assign($file) {
  555. if(!empty($file)) {
  556. $this->file = $file;
  557. }
  558. /** check for existance of file! */
  559. if(!file_exists($this->file)) {
  560. $this->errorno = 1;
  561. $this->errorstr = "File '".$this->file."' does not exists!";
  562. }
  563. $this->newFile = 1;
  564. }
  565. /**
  566. * Process SOFn section of Image
  567. * @param array An array containing whole section.
  568. * @param hex Marker to specify the type of section.
  569. *
  570. */
  571. function process_SOFn($data,$marker) {
  572. $data_precision = 0;
  573. $num_components = 0;
  574. $data_precision = ord($data[2]);
  575. if($this->debug) {
  576. print("Image Dimension Calculation:");
  577. print("((ord($data[3]) << 8) | ord($data[4]));");
  578. }
  579. $this->ImageInfo["h"]["Height"] = ((ord($data[3]) << 8) | ord($data[4]));
  580. $this->ImageInfo["h"]["Width"] = ((ord($data[5]) << 8) | ord($data[6]));
  581. $num_components = ord($data[7]);
  582. if ($num_components == 3){
  583. $this->ImageInfo["h"]["IsColor"] = 1;
  584. }else{
  585. $this->ImageInfo["h"]["IsColor"] = 0;
  586. }
  587. $this->ImageInfo["h"]["Process"] = $marker;
  588. $this->debug("JPEG image is ".$this->ImageInfo["h"]["Width"]." * ".$this->ImageInfo["h"]["Height"].", $num_components color components, $data_precision bits per sample\n");
  589. }
  590. /**
  591. * Process Comments
  592. * @param array Section data
  593. * @param int Length of the section
  594. *
  595. */
  596. function process_COM($data,$length) {
  597. if ($length > MAX_COMMENT) $length = MAX_COMMENT;
  598. /** Truncate if it won't fit in our structure. */
  599. $nch = 0; $Comment = "";
  600. for ($a=2;$a<$length;$a++){
  601. $ch = $data[$a];
  602. if ($ch == '\r' && $data[$a+1] == '\n') continue; // Remove cr followed by lf.
  603. $Comment .= $ch;
  604. }
  605. //$this->ImageInfo[M_COM] = $Comment;
  606. $this->ImageInfo["h"]["imageComment"] = $this->string_format($Comment);
  607. $this->debug("COM marker comment: $Comment\n");
  608. }
  609. /**
  610. * Process one of the nested EXIF directories.
  611. * @param string All directory information
  612. * @param string whole Section
  613. * @param int Length of exif section
  614. *
  615. */
  616. function ProcessExifDir($DirStart, $OffsetBase, $ExifLength) {
  617. $NumDirEntries = 0;
  618. $ValuePtr = array();
  619. $NumDirEntries = $this->Get16u($DirStart[0],$DirStart[1]);
  620. $this->debug("<br>Directory with $NumDirEntries entries\n");
  621. for ($de=0;$de<$NumDirEntries;$de++){
  622. //$DirEntry = array_slice($DirStart,2+12*$de);
  623. $DirEntry = substr($DirStart,2+12*$de);
  624. $Tag = $this->Get16u($DirEntry[0],$DirEntry[1]);
  625. $Format = $this->Get16u($DirEntry[2],$DirEntry[3]);
  626. $Components = $this->Get32u($DirEntry[4],$DirEntry[5],$DirEntry[6],$DirEntry[7]);
  627. /**
  628. if ((Format-1) >= NUM_FORMATS) {
  629. // (-1) catches illegal zero case as unsigned underflows to positive large.
  630. ErrNonfatal("Illegal number format %d for tag %04x", Format, Tag);
  631. continue;
  632. }
  633. */
  634. $ByteCount = $Components * $this->BytesPerFormat[$Format];
  635. if ($ByteCount > 4){
  636. $OffsetVal = $this->Get32u($DirEntry[8],$DirEntry[9],$DirEntry[10],$DirEntry[11]);
  637. if ($OffsetVal+$ByteCount > $ExifLength){
  638. $this->debug("Illegal value pointer($OffsetVal) for tag $Tag",1);
  639. }
  640. //$ValuePtr = array_slice($OffsetBase,$OffsetVal);
  641. $ValuePtr = substr($OffsetBase,$OffsetVal);
  642. } else {
  643. //$ValuePtr = array_slice($DirEntry,8);
  644. $ValuePtr = substr($DirEntry,8);
  645. }
  646. switch($Tag){
  647. case TAG_MAKE:
  648. $this->ImageInfo["h"]["make"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  649. break;
  650. case TAG_MODEL:
  651. $this->ImageInfo["h"]["model"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  652. break;
  653. case TAG_DATETIME_ORIGINAL:
  654. $this->ImageInfo[TAG_DATETIME_ORIGINAL] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  655. $this->ImageInfo["h"]["DateTime"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  656. break;
  657. case TAG_USERCOMMENT:
  658. // Olympus has this padded with trailing spaces. Remove these first.
  659. for ($a=$ByteCount;;){
  660. $a--;
  661. if ($ValuePtr[$a] == ' '){
  662. //$ValuePtr[$a] = '\0';
  663. } else {
  664. break;
  665. }
  666. if ($a == 0) break;
  667. }
  668. // Copy the comment
  669. if (($ValuePtr[0].$ValuePtr[1].$ValuePtr[2].$ValuePtr[3].$ValuePtr[4]) == "ASCII"){
  670. for ($a=5;$a<10;$a++){
  671. $c = $ValuePtr[$a];
  672. if ($c != '\0' && $c != ' '){
  673. $tmp = substr($ValuePtr,0,$ByteCount);
  674. break;
  675. }
  676. }
  677. } else if (($ValuePtr[0].$ValuePtr[1].$ValuePtr[2].$ValuePtr[3].$ValuePtr[4].$ValuePtr[5].$ValuePtr[6]) == "Unicode"){
  678. $tmp = substr($ValuePtr,0,$ByteCount);
  679. // * Handle Unicode characters here...
  680. } else {
  681. //$this->ImageInfo[TAG_USERCOMMENT] = implode("",array_slice($ValuePtr,0,$ByteCount));
  682. $tmp = substr($ValuePtr,0,$ByteCount);
  683. }
  684. $this->ImageInfo['h']["exifComment"] = $this->string_format($tmp);
  685. break;
  686. case TAG_ARTIST:
  687. $this->ImageInfo['h']["artist"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  688. break;
  689. case TAG_COPYRIGHT:
  690. $this->ImageInfo['h']["copyright"] = htmlentities(substr($ValuePtr,0,$ByteCount));
  691. break;
  692. case TAG_FNUMBER:
  693. // Simplest way of expressing aperture, so I trust it the most.
  694. // (overwrite previously computd value if there is one)
  695. $tmp = $this->ConvertAnyFormat(substr($ValuePtr,0), $Format);
  696. $this->ImageInfo['h']["fnumber"] = sprintf("f/%3.1f",(double)$tmp[0]);
  697. break;
  698. case TAG_APERTURE:
  699. case TAG_MAXAPERTURE:
  700. // More relevant info always comes earlier, so only use this field if we don't
  701. // have appropriate aperture information yet.
  702. if (!isset($this->ImageInfo['h']["aperture"])){
  703. $tmpArr = $this->ConvertAnyFormat($ValuePtr, $Format);
  704. $this->ImageInfo['h']["aperture"] = exp($tmpArr[0]*log(2)*0.5);
  705. }
  706. break;
  707. case TAG_FOCALLENGTH:
  708. // Nice digital cameras actually save the focal length as a function
  709. // of how farthey are zoomed in.
  710. $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
  711. $this->ImageInfo['h']["focalLength"] = sprintf("%4.2f (%d/%d)",(double)$tmp[0],$tmp[1][0],$tmp[1][1]);
  712. if (isset($this->ImageInfo['h']["CCDWidth"])){
  713. $this->ImageInfo['h']["focalLength"] .= sprintf("(35mm equivalent: %dmm)",(int)($tmp[0]/$this->ImageInfo['h']["CCDWidth"]*36 + 0.5));
  714. }
  715. break;
  716. case TAG_SUBJECT_DISTANCE:
  717. // Inidcates the distacne the autofocus camera is focused to.
  718. // Tends to be less accurate as distance increases.
  719. //$this->ImageInfo["h"]["Distance"] = $this->ConvertAnyFormat($ValuePtr, $Format);
  720. $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
  721. $this->ImageInfo['h']["Distance"] = sprintf("%4.2f (%d/%d)",(double)$tmp[0],$tmp[1][0],$tmp[1][1]);
  722. if ($this->ImageInfo['h']["Distance"] < 0){
  723. $this->ImageInfo['h']["focusDistance"] = "Infinite";
  724. } else {
  725. $this->ImageInfo['h']["focusDistance"] = sprintf("%4.2fm",(double)$this->ImageInfo['h']["Distance"]);
  726. }
  727. break;
  728. case TAG_EXPOSURETIME:
  729. // Simplest way of expressing exposure time, so I trust it most.
  730. // (overwrite previously computd value if there is one)
  731. $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
  732. $this->ImageInfo['h']["exposureTime"] = sprintf("%6.3f s (%d/%d)",(double)$tmp[0],$tmp[1][0],$tmp[1][1]);
  733. if ($tmp[0] <= 0.5){
  734. $this->ImageInfo['h']["exposureTime"] .= sprintf(" (1/%d)",(int)(0.5 + 1/$tmp[0]));
  735. }
  736. break;
  737. case TAG_SHUTTERSPEED:
  738. // More complicated way of expressing exposure time, so only use
  739. // this value if we don't already have it from somewhere else.
  740. if ($this->ImageInfo[TAG_EXPOSURETIME] == 0){
  741. $sp = $this->ConvertAnyFormat($ValuePtr, $Format);
  742. // Temporary Workaround for divizion by zero problem
  743. if (!empty($sp[0])) {
  744. $this->ImageInfo[TAG_SHUTTERSPEED] = (1/exp($sp[0]*log(2)));
  745. } else {
  746. $this->ImageInfo[TAG_SHUTTERSPEED] = 0;
  747. }
  748. }
  749. break;
  750. case TAG_FLASH:
  751. $this->ImageInfo["h"]["flashUsed"] = "No";
  752. if ($this->ConvertAnyFormat($ValuePtr, $Format) & 7){
  753. $this->ImageInfo["h"]["flashUsed"] = "Yes";
  754. }
  755. break;
  756. case TAG_ORIENTATION:
  757. $this->ImageInfo[TAG_ORIENTATION] = $this->ConvertAnyFormat($ValuePtr, $Format);
  758. if ($this->ImageInfo[TAG_ORIENTATION] < 1 || $this->ImageInfo[TAG_ORIENTATION] > 8){
  759. $this->debug(sprintf("Undefined rotation value %d", $this->ImageInfo[TAG_ORIENTATION], 0),1);
  760. $this->ImageInfo[TAG_ORIENTATION] = 0;
  761. }
  762. break;
  763. case TAG_EXIF_IMAGELENGTH:
  764. // * Image height
  765. $a = (int) $this->ConvertAnyFormat($ValuePtr, $Format);
  766. if ($this->ExifImageLength < $a) $this->ExifImageLength = $a;
  767. $this->ImageInfo[TAG_EXIF_IMAGELENGTH] = $this->ExifImageLength;
  768. $this->ImageInfo["h"]["Height"] = $this->ExifImageLength;
  769. break;
  770. case TAG_EXIF_IMAGEWIDTH:
  771. // Use largest of height and width to deal with images that have been
  772. // rotated to portrait format.
  773. $a = (int) $this->ConvertAnyFormat($ValuePtr, $Format);
  774. if ($this->ExifImageWidth < $a) $this->ExifImageWidth = $a;
  775. $this->ImageInfo[TAG_EXIF_IMAGEWIDTH] = $this->ExifImageWidth;
  776. $this->ImageInfo["h"]["Width"] = $this->ExifImageWidth;
  777. break;
  778. case TAG_FOCALPLANEXRES:
  779. $this->FocalplaneXRes = $this->ConvertAnyFormat($ValuePtr, $Format);
  780. $this->FocalplaneXRes = $this->FocalplaneXRes[0];
  781. $this->ImageInfo[TAG_FOCALPLANEXRES] = $this->FocalplaneXRes[0];
  782. break;
  783. case TAG_FOCALPLANEUNITS:
  784. switch($this->ConvertAnyFormat($ValuePtr, $Format)){
  785. case 1: $this->FocalplaneUnits = 25.4; break; // inch
  786. case 2:
  787. // According to the information I was using, 2 means meters.
  788. // But looking at the Cannon powershot's files, inches is the only
  789. // sensible value.
  790. $this->FocalplaneUnits = 25.4;
  791. break;
  792. case 3: $this->FocalplaneUnits = 10; break; // centimeter
  793. case 4: $this->FocalplaneUnits = 1; break; // milimeter
  794. case 5: $this->FocalplaneUnits = .001; break; // micrometer
  795. }
  796. $this->ImageInfo[TAG_FOCALPLANEUNITS] = $this->FocalplaneUnits;
  797. break;
  798. // Remaining cases contributed by: Volker C. Schoech (schoech@gmx.de)
  799. case TAG_EXPOSURE_BIAS:
  800. $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
  801. $this->ImageInfo['h']["exposureBias"] = sprintf("%4.2f (%d/%d)",(double)$tmp[0],$tmp[1][0],$tmp[1][1]);
  802. break;
  803. case TAG_WHITEBALANCE:
  804. $tmp = (int) $this->ConvertAnyFormat($ValuePtr, $Format);
  805. $tmpArr = array("1"=>"Sunny","2"=>"fluorescent","3"=>"incandescent");
  806. $this->ImageInfo['h']["whiteBalance"] =
  807. (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Cloudy");
  808. break;
  809. case TAG_METERING_MODE:
  810. $tmp = (int) $this->ConvertAnyFormat($ValuePtr, $Format);
  811. $tmpArr = array("2"=>"center weight","3"=>"spot","5"=>"matrix");
  812. $this->ImageInfo['h']["meteringMode"] =
  813. (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Reserved");
  814. break;
  815. case TAG_EXPOSURE_PROGRAM:
  816. $tmp = (int) $this->ConvertAnyFormat($ValuePtr, $Format);
  817. $tmpArr = array("2"=>"program (auto)","3"=>"aperture priority (semi-auto)","4"=>"shutter priority (semi-auto)");
  818. $this->ImageInfo['h']["exposure"] =
  819. (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Reserved");
  820. break;
  821. case TAG_ISO_EQUIVALENT:
  822. $tmp = (int) $this->ConvertAnyFormat($ValuePtr, $Format);
  823. if ( $tmp < 50 ) $tmp *= 200;
  824. $this->ImageInfo['h']["isoEquiv"] = sprintf("%2d",(int)$tmp);
  825. break;
  826. case TAG_COMPRESSION_LEVEL:
  827. $tmp = (int) $this->ConvertAnyFormat($ValuePtr, $Format);
  828. $tmpArr = array("1"=>"Basic","2"=>"Normal","4"=>"Fine");
  829. $this->ImageInfo['h']["jpegQuality"] =
  830. (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Reserved");
  831. break;
  832. case TAG_THUMBNAIL_OFFSET:
  833. $this->ThumbnailOffset = $this->ConvertAnyFormat($ValuePtr, $Format);
  834. $this->DirWithThumbnailPtrs = $DirStart;
  835. break;
  836. case TAG_THUMBNAIL_LENGTH:
  837. $this->ThumbnailSize = $this->ConvertAnyFormat($ValuePtr, $Format);
  838. $this->ImageInfo[TAG_THUMBNAIL_LENGTH] = $this->ThumbnailSize;
  839. break;
  840. //----------------------------------------------
  841. case TAG_IMAGE_DESC:
  842. $this->ImageInfo['h']["imageDesc"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  843. break;
  844. case TAG_X_RESOLUTION:
  845. $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
  846. $this->ImageInfo['h']["xResolution"] = sprintf("%4.2f (%d/%d) %s",(double)$tmp[0],$tmp[1][0],$tmp[1][1],$this->ImageInfo['h']["resolutionUnit"]);
  847. break;
  848. case TAG_Y_RESOLUTION:
  849. $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
  850. $this->ImageInfo['h']["yResolution"] = sprintf("%4.2f (%d/%d) %s",(double)$tmp[0],$tmp[1][0],$tmp[1][1],$this->ImageInfo['h']["resolutionUnit"]);
  851. break;
  852. case TAG_RESOLUTION_UNIT:
  853. $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
  854. $tmpArr = array("2"=>"Inches","3"=>"Centimeters");
  855. $this->ImageInfo['h']["resolutionUnit"] =
  856. (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Reserved");
  857. break;
  858. case TAG_SOFTWARE:
  859. $this->ImageInfo['h']["software"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  860. break;
  861. case TAG_FILE_MODDATE;
  862. $this->ImageInfo['h']["fileModifiedDate"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  863. break;
  864. case TAG_YCBCR_POSITIONING:
  865. $this->ImageInfo['h']["YCbCrPositioning"] = $this->ConvertAnyFormat($ValuePtr, $Format);
  866. break;
  867. case TAG_EXIF_VERSION:
  868. $this->ImageInfo['h']["exifVersion"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  869. break;
  870. case TAG_DATE_TIME_DIGITIZED:
  871. $this->ImageInfo['h']["dateTimeDigitized"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  872. break;
  873. case TAG_COMPONENT_CONFIG: // need more tests for this
  874. $tmp = (int)$this->ConvertAnyFormat($ValuePtr, $Format);
  875. $tmpArr = array("0"=>"Does Not Exists","1"=>"Y","2"=>"Cb","3"=>"Cr","4"=>"R","5"=>"G","6"=>"B");
  876. if(strlen($tmp) < 4 ) {
  877. $this->ImageInfo['h']["componentConfig"] = $tmpArr["0"];
  878. } else {
  879. for($i=0;$i<strlen($tmp);$i++) {
  880. if($tmp["$i"] != 0) {
  881. $this->ImageInfo['h']["componentConfig"] .= $tmpArr[$tmp["$i"]];
  882. }
  883. }
  884. }
  885. break;
  886. case TAG_MAKER_NOTE:
  887. //$this->ImageInfo['h']["makerNote"] = substr($ValuePtr,0,$ByteCount);
  888. $this->ImageInfo['h']["makerNote"] = "NOT IMPLEMENTED";
  889. break;
  890. case TAG_SUB_SEC_TIME:
  891. $this->ImageInfo['h']["subSectionTime"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  892. break;
  893. case TAG_SUB_SEC_TIME_ORIG:
  894. $this->ImageInfo['h']["subSectionTimeOriginal"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  895. break;
  896. case TAG_SUB_SEC_TIME_DIGITIZED:
  897. $this->ImageInfo['h']["subSectionTimeDigtized"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  898. break;
  899. case TAG_FLASHPIX_VER:
  900. $this->ImageInfo['h']["flashpixVersion"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  901. break;
  902. case TAG_COLOR_SPACE:
  903. $this->ImageInfo['h']["colorSpace"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  904. break;
  905. case TAG_RELATED_SOUND_FILE:
  906. $this->ImageInfo['h']["relatedSoundFile"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  907. break;
  908. case TAG_GPS_LATITUDE_REF:
  909. $this->ImageInfo['h']["GPSLatitudeRef"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  910. $this->ImageInfo['h']["GPSLatitudeRef"] = trim($this->ImageInfo['h']["GPSLatitudeRef"]);
  911. $tmp = substr($this->ImageInfo['h']["GPSLatitudeRef"],0,1);
  912. if($tmp == "S") {
  913. $this->ImageInfo['h']["GPSLatitudeRef"] = "South latitude";
  914. } else if($tmp == "N") {
  915. $this->ImageInfo['h']["GPSLatitudeRef"] = "North latitude";
  916. } else {
  917. $this->ImageInfo['h']["GPSLatitudeRef"] = "Reserved";
  918. }
  919. break;
  920. case TAG_GPS_LATITUDE:
  921. $degrees = $this->ConvertAnyFormat( substr($ValuePtr,0,8), FMT_URATIONAL);
  922. $degrees = $degrees[0];
  923. $minutes = $this->ConvertAnyFormat( substr($ValuePtr,8,8), FMT_URATIONAL);
  924. $minutes = $minutes[0];
  925. $seconds = $this->ConvertAnyFormat( substr($ValuePtr,16,8), FMT_URATIONAL);
  926. $seconds = $seconds[0];
  927. $this->ImageInfo['h']["GPSLatitude"]["Degrees"] = $degrees;
  928. $this->ImageInfo['h']["GPSLatitude"]["Minutes"] = $minutes;
  929. $this->ImageInfo['h']["GPSLatitude"]["Seconds"] = $seconds;
  930. break;
  931. case TAG_GPS_LONGITUDE:
  932. $degrees = $this->ConvertAnyFormat( substr($ValuePtr,0,8), FMT_URATIONAL);
  933. $degrees = $degrees[0];
  934. $minutes = $this->ConvertAnyFormat( substr($ValuePtr,8,8), FMT_URATIONAL);
  935. $minutes = $minutes[0];
  936. $seconds = $this->ConvertAnyFormat( substr($ValuePtr,16,8), FMT_URATIONAL);
  937. $seconds = $seconds[0];
  938. $this->ImageInfo['h']["GPSLongitude"]["Degrees"] = $degrees;
  939. $this->ImageInfo['h']["GPSLongitude"]["Minutes"] = $minutes;
  940. $this->ImageInfo['h']["GPSLongitude"]["Seconds"] = $seconds;
  941. break;
  942. case TAG_GPS_LONGITUDE_REF:
  943. $this->ImageInfo['h']["GPSLongitudeRef"] = substr($ValuePtr,0,$ByteCount);
  944. $this->ImageInfo['h']["GPSLongitudeRef"] = trim($this->ImageInfo['h']["GPSLongitudeRef"]);
  945. $tmp = substr($this->ImageInfo['h']["GPSLongitudeRef"],0,1);
  946. if($tmp == "E") {
  947. $this->ImageInfo['h']["GPSLongitudeRef"] = "East Longitude";
  948. } else if($tmp == "W") {
  949. $this->ImageInfo['h']["GPSLongitudeRef"] = "West Longitude";
  950. } else {
  951. $this->ImageInfo['h']["GPSLongitudeRef"] = "Reserved";
  952. }
  953. break;
  954. case TAG_GPS_TrackRef: /* Reference for direction of movement GPSTrackRef */
  955. $this->ImageInfo['h']["GPSTrackRef"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  956. break;
  957. case TAG_GPS_GPSTrack: /* Direction of movement GPSTrack */
  958. $this->ImageInfo['h']["GPSTrack"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  959. break;
  960. case TAG_GPS_GPSImgDirectionRef: /* Reference for direction of image GPSImgDirectionRef */
  961. $this->ImageInfo['h']["GPSImgDirectionRef"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  962. break;
  963. case TAG_GPS_GPSImgDirection: /* Direction of image GPSImgDirection */
  964. $this->ImageInfo['h']["GPSImgDirection"] = $this->ConvertAnyFormat($ValuePtr, $Format);
  965. break;
  966. case TAG_GPS_GPSMapDatum: /* Geodetic survey data used GPSMapDatum */
  967. $this->ImageInfo['h']["GPSMapDatum"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  968. break;
  969. case TAG_GPS_GPSDestLatitudeRef:/* Reference for latitude of destination GPSDestLatitudeRef */
  970. $this->ImageInfo['h']["GPSDestLatitudeRef"] = substr($ValuePtr,0,$ByteCount);
  971. $this->ImageInfo['h']["GPSDestLatitudeRef"] = trim($this->ImageInfo['h']["GPSDestLatitudeRef"]);
  972. $tmp = substr($this->ImageInfo['h']["GPSDestLatitudeRef"],0,1);
  973. if($tmp == "S") {
  974. $this->ImageInfo['h']["GPSDestLatitudeRef"] = "South latitude";
  975. } else if($tmp == "N") {
  976. $this->ImageInfo['h']["GPSDestLatitudeRef"] = "North latitude";
  977. } else {
  978. $this->ImageInfo['h']["GPSDestLatitudeRef"] = "Reserved";
  979. }
  980. break;
  981. case TAG_GPS_GPSDestLatitude:/* Latitude of destination GPSDestLatitude */
  982. $tmp = substr($ValuePtr,0,$ByteCount);
  983. $this->ImageInfo['h']["GPSDestLatitude"]["Degrees"] = ord(substr($tmp,0,1));
  984. $this->ImageInfo['h']["GPSDestLatitude"]["Minutes"] = ord(substr($tmp,1,1));
  985. $this->ImageInfo['h']["GPSDestLatitude"]["Seconds"] = ord(substr($tmp,2,1));
  986. break;
  987. case TAG_GPS_GPSDestLongitudeRef:/* Reference for longitude of destination GPSDestLongitudeRef 21 */
  988. $this->ImageInfo['h']["GPSDestLongitudeRef"] = substr($ValuePtr,0,$ByteCount);
  989. $this->ImageInfo['h']["GPSDestLongitudeRef"] = trim($this->ImageInfo['h']["GPSDestLongitudeRef"]);
  990. $tmp = substr($this->ImageInfo['h']["GPSDestLongitudeRef"],0,1);
  991. if($tmp == "E") {
  992. $this->ImageInfo['h']["GPSDestLongitudeRef"] = "East Longitude";
  993. } else if($tmp == "W") {
  994. $this->ImageInfo['h']["GPSDestLongitudeRef"] = "West Longitude";
  995. } else {
  996. $this->ImageInfo['h']["GPSDestLongitudeRef"] = "Reserved";
  997. }
  998. break;
  999. case TAG_GPS_GPSDestLongitude:/* Longitude of destination GPSDestLongitude 22 */
  1000. $this->ImageInfo['h']["GPSDestLongitude"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  1001. break;
  1002. case TAG_GPS_GPSDestBearingRef:/* Reference for bearing of destination GPSDestBearingRef 23 */
  1003. $this->ImageInfo['h']["GPSDestBearingRef"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  1004. break;
  1005. case TAG_GPS_GPSDestBearing: /* Bearing of destination GPSDestBearing 24 */
  1006. $this->ImageInfo['h']["GPSDestBearing"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  1007. break;
  1008. case TAG_GPS_GPSDestDistanceRef:/* Reference for distance to destination GPSDestDistanceRef 25 */
  1009. $this->ImageInfo['h']["GPSDestDistanceRef"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  1010. break;
  1011. case TAG_GPS_GPSDestDistance: /* Distance to destination GPSDestDistance 26 */
  1012. //$this->ImageInfo['h']["GPSDestDistance"] = $this->ConvertAnyFormat($ValuePtr, $Format);
  1013. $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
  1014. $this->ImageInfo['h']["GPSDestDistance"] = sprintf("%4.2f (%d/%d)",(double)$tmp[0],$tmp[1][0],$tmp[1][1]);;
  1015. break;
  1016. case TAG_GPS_GPSProcessingMethod: /* Name of GPS processing method GPSProcessingMethod 27 */
  1017. //$this->ImageInfo['h']["GPSProcessingMethod"] = $this->ConvertAnyFormat($ValuePtr, $Format);
  1018. $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
  1019. $this->ImageInfo['h']["GPSProcessingMethod"] = sprintf("%4.2f (%d/%d)",(double)$tmp[0],$tmp[1][0],$tmp[1][1]);;
  1020. break;
  1021. case TAG_GPS_GPSAreaInformation: /* Name of GPS area GPSAreaInformation 28 */
  1022. $this->ImageInfo['h']["GPSAreaInformation"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  1023. break;
  1024. case TAG_GPS_GPSDateStamp: /* GPS date GPSDateStamp 29 */
  1025. $this->ImageInfo['h']["GPSDateStamp"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  1026. break;
  1027. case TAG_GPS_GPSDifferential: /* GPS differential correction GPSDifferential 30 */
  1028. $this->ImageInfo['h']["GPSDifferential"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  1029. break;
  1030. case TAG_AUDIO_MU_LAW:
  1031. $this->ImageInfo['h']["AudioMuLaw"] = $this->ConvertAnyFormat($ValuePtr, $Format);
  1032. break;
  1033. case TAG_AUDIO_IMA_ADPCM_DESC: // IMA-ADPCM Audio File Description Example - 40
  1034. $this->ImageInfo['h']["AudioIMA-ADPCM-DESC"] = $this->ConvertAnyFormat($ValuePtr, $Format);
  1035. break;
  1036. case TAG_AUDIO_MU_LAW_DESC: // µ-Law Audio File Description Sample - 50
  1037. $this->ImageInfo['h']["AudioMuLawDesc"] = $this->ConvertAnyFormat($ValuePtr, $Format);
  1038. break;
  1039. case TAG_EXPOSURE_INDEX:
  1040. $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
  1041. $this->ImageInfo['h']["ExposureIndex"] = sprintf("%4.2f (%d/%d)",(double)$tmp[0],$tmp[1][0],$tmp[1][1]);;
  1042. break;
  1043. case TAG_SENSING_METHOD:
  1044. $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
  1045. $tmpArr = array("1"=

Large files files are truncated, but you can click here to view the full file