PageRenderTime 60ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/assets/a8ca4cd2/plugins/images/connector/php/exifReader.php

https://bitbucket.org/graaaf/erso
PHP | 1703 lines | 1090 code | 196 blank | 417 comment | 141 complexity | 9cf98776969b7fad3ff869f4c9f7cd60 MD5 | raw file
Possible License(s): GPL-3.0, LGPL-3.0, LGPL-2.1, BSD-3-Clause, BSD-2-Clause

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 (vinayRas) < vinay@sanisoft.com >
  9. * http://www.sanisoft.com/phpexifrw/
  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_LATITUDE_REF","0x0001"); //
  207. define("TAG_GPS_LATITUDE","0x0002"); //
  208. define("TAG_GPS_LONGITUDE_REF","0x0003"); //
  209. define("TAG_GPS_LONGITUDE","0x0004"); //
  210. define("TAG_GPS_TrackRef","0x000E"); //
  211. define("TAG_GPS_GPSTrack","0x000F"); //
  212. define("TAG_GPS_GPSImgDirectionRef","0x0010"); //
  213. define("TAG_GPS_GPSImgDirection","0x0011"); //
  214. define("TAG_GPS_GPSMapDatum","0x0012"); //
  215. define("TAG_GPS_GPSDestLatitudeRef","0x0013"); //
  216. define("TAG_GPS_GPSDestLatitude","0x0014"); //
  217. define("TAG_GPS_GPSDestLongitudeRef","0x0015"); //
  218. define("TAG_GPS_GPSDestLongitude","0x0016"); //
  219. define("TAG_GPS_GPSDestBearingRef","0x0017"); //
  220. define("TAG_GPS_GPSDestBearing","0x0018"); //
  221. define("TAG_GPS_GPSDestDistanceRef","0x0019"); //
  222. define("TAG_GPS_GPSDestDistance","0x001A"); //
  223. define("TAG_GPS_GPSProcessingMethod","0x001B"); //
  224. define("TAG_GPS_GPSAreaInformation","0x001C"); //
  225. define("TAG_GPS_GPSDateStamp","0x001D"); //
  226. define("TAG_GPS_GPSDifferential","0x001E"); //
  227. define("TAG_AUDIO_IMA_ADPCM_DESC","0x0028"); // IMA-ADPCM Audio File Description Example - 40
  228. define("TAG_AUDIO_MU_LAW_DESC","0x0032"); // µ-Law Audio File Description Sample - 50
  229. define("TAG_AUDIO_MU_LAW","0x0086"); // (This File µ-LAW Sample) - 134
  230. define("TAG_EXPOSURE_INDEX","0xA215"); // Exposure index
  231. define("TAG_SENSING_METHOD","0xA217"); // SensingMethod
  232. define("TAG_SOUCE_TYPE","0xA300"); // FileSource
  233. define("TAG_SCENE_TYPE","0xA301"); // SceneType
  234. define("TAG_CFA_PATTERN","0xA302"); // CFA Pattern
  235. /** Tags in EXIF 2.2 Only */
  236. define("TAG_COMPRESS_SCHEME","0x0103"); //
  237. define("TAG_CUSTOM_RENDERED","0xA401"); // CustomRendered
  238. define("TAG_EXPOSURE_MODE","0xA402"); // Exposure mode ExposureMode
  239. define("TAG_WHITE_BALANCE","0xA403"); // White balance WhiteBalance
  240. define("TAG_DIGITAL_ZOOM_RATIO","0xA404"); // Digital zoom ratio DigitalZoomRatio
  241. define("TAG_FLENGTH_IN35MM","0xA405"); // Focal length in 35 mm film FocalLengthIn35mmFilm
  242. define("TAG_SCREEN_CAP_TYPE","0xA406"); // Scene capture type SceneCaptureType
  243. define("TAG_GAIN_CONTROL","0xA407"); //Gain control
  244. define("TAG_CONTRAST","0xA408"); // Contrast
  245. define("TAG_SATURATION","0xA409"); // Saturation
  246. define("TAG_SHARPNESS","0xA40A"); // Sharpness
  247. define("TAG_DEVICE_SETTING_DESC","0xA40B"); // SDevice settings description DeviceSettingDescription
  248. define("TAG_DIST_RANGE","0xA40C"); //Subject distance range SubjectDistanceRange
  249. define("TAG_FOCALPLANE_YRESOL","0xA20F");; //FocalPlaneYResolution
  250. define("TAG_BRIGHTNESS","0x9203");; //Brightness
  251. //--------------------------------
  252. /** error Description */
  253. /**
  254. 1 - File does not exists!
  255. 2 -
  256. 3 - Filename not provided
  257. 10 - too many padding bytes
  258. 11 - "invalid marker"
  259. 12 - Premature end of file?
  260. 51 - "Illegal subdirectory link"
  261. 52 - "NOT EXIF FORMAT"
  262. 53 - "Invalid Exif alignment marker.\n"
  263. 54 - "Invalid Exif start (1)"
  264. */
  265. /**
  266. * PHP Class to read, write and transfer EXIF information
  267. * that most of the digital camera produces
  268. * Currenty it can only read JPEG file.
  269. */
  270. /**
  271. * @author Vinay Yadav (vinayRas) < vinay@sanisoft.com >
  272. *
  273. * @todo Writing exif information to the file.
  274. * @todo Add EXIF audio reading methods (I think it exists!)
  275. * @todo Support of additional tags.
  276. * @todo Handling Unicode character in UserComment tag of EXif Information.
  277. *
  278. * @version 0.5
  279. * @licence http://opensource.org/licenses/lgpl-license.php GNU LGPL
  280. */
  281. class phpExifReader {
  282. /***
  283. * Array containg all Exif and JPEG image attributes
  284. * into regular expressions for themselves.
  285. * $ImageInfo[TAG] = TAG_VALUE;
  286. *
  287. * @var array
  288. * @access private
  289. *
  290. */
  291. var $ImageInfo = array();
  292. var $MotorolaOrder = 0;
  293. var $ExifImageWidth = 0; //
  294. var $FocalplaneXRes = 0; //
  295. var $FocalplaneUnits = 0; //
  296. var $sections = array();
  297. var $currSection = 0; /** Stores total number fo Sections */
  298. var $BytesPerFormat = array(0,1,1,2,4,8,1,1,2,4,8,4,8);
  299. var $ReadMode = array(
  300. "READ_EXIF" => 1,
  301. "READ_IMAGE" => 2,
  302. "READ_ALL" => 3
  303. );
  304. var $ImageReadMode = 3; /** related to $RealMode arrays values */
  305. var $file = ""; /** JPEG file to parse for EXIF data */
  306. var $newFile = 1; /** flag to check if the current file has been parsed or not. */
  307. var $thumbnail = ""; /* Name of thumbnail */
  308. var $thumbnailURL = ""; /* */
  309. var $exifSection = -1; // market the exif section index oout of all sections
  310. var $errno = 0;
  311. var $errstr = "";
  312. var $debug = false;
  313. // Caching ralated variables
  314. var $caching = false; /* Should cacheing of image thumnails be allowed? */
  315. var $cacheDir = ""; /* Checkout constructor for default path. */
  316. /**
  317. * Constructor
  318. * @param string File name to be parsed.
  319. *
  320. */
  321. function phpExifReader($file = "") {
  322. $this->timeStart = $this->getmicrotime();
  323. if(!empty($file)) {
  324. $this->file = $file;
  325. }
  326. /**
  327. * Initialize some variables. Avoid lots of errors with fulll error_reporting
  328. */
  329. $this->ExifImageLength = 0;
  330. $this->ImageInfo['h']["resolutionUnit"] = 0;
  331. $this->ImageInfo[TAG_MAXAPERTURE] = 0;
  332. $this->ImageInfo[TAG_ISO_EQUIVALENT] = 0;
  333. $this->ImageInfo[TAG_ORIENTATION] = 0;
  334. $this->ThumbnailSize = 0;
  335. if($this->caching) {
  336. $this->cacheDir = dirname(__FILE__)."/.cache_thumbs";
  337. /**
  338. * If Cache directory does not exists then attempt to create it.
  339. */
  340. if(!is_dir($this->cacheDir)) {
  341. mkdir($this->cacheDir);
  342. }
  343. // Prepare the ame of thumbnail
  344. if(is_dir($this->cacheDir)) {
  345. $this->thumbnail = $this->cacheDir."/".basename($this->file);
  346. $this->thumbnailURL = ".cache_thumbs/".basename($this->file);
  347. }
  348. }
  349. /** check if file exists! */
  350. if(!file_exists($this->file)) {
  351. $this->errno = 1;
  352. $this->errstr = "File '".$this->file."' does not exists!";
  353. }
  354. $this->currSection = 0;
  355. $this->processFile();
  356. }
  357. /**
  358. * Show Debugging information
  359. *
  360. * @param string Debugging message to display
  361. * @param int Type of error (0 - Warning, 1 - Error)
  362. * @return void
  363. *
  364. */
  365. function debug($str,$TYPE = 0,$file="",$line=0) {
  366. if($this->debug) {
  367. echo "<br>[$file:$line:".($this->getDiffTime())."]$str";
  368. flush();
  369. if($TYPE == 1) {
  370. exit;
  371. }
  372. }
  373. }
  374. /**
  375. * Processes the whole file.
  376. *
  377. */
  378. function processFile() {
  379. /** dont reparse the whole file. */
  380. if(!$this->newFile) return true;
  381. if(!file_exists($this->file)) {
  382. echo "<br>Error: File ".($this->file)."does not exists!";
  383. exit;
  384. }
  385. $this->debug("Stating Processing of ".$this->newFile,0,__FILE__,__LINE__);
  386. $i = 0; $exitAll = 0;
  387. /** Open the JPEG in binary safe reading mode */
  388. $fp = fopen($this->file,"rb");
  389. $this->ImageInfo["h"]["FileName"] = $this->file;
  390. $this->ImageInfo["h"]["FileSize"] = filesize($this->file); /** Size of the File */
  391. $this->ImageInfo["h"]["FileDateTime"] = filectime($this->file); /** File node change time */
  392. /** check whether jped image or not */
  393. $a = fgetc($fp);
  394. if (ord($a) != 0xff || ord(fgetc($fp)) != M_SOI){
  395. $this->debug("Not a JPEG FILE",1);
  396. $this->errorno = 1;
  397. $this->errorstr = "File '".$this->file."' is not a JPEG File!";
  398. }
  399. $tmpTestLevel = 0;
  400. /** Examines each byte one-by-one */
  401. while(!feof($fp)) {
  402. $data = array();
  403. for ($a=0;$a<7;$a++){
  404. $marker = fgetc($fp);
  405. if (ord($marker) != 0xff) break;
  406. if ($a >= 6){
  407. $this->errno = 10;
  408. $this->errstr = "too many padding bytes!";
  409. $this->debug($this->errstr,1);
  410. return false;
  411. }
  412. }
  413. if (ord($marker) == 0xff){
  414. // 0xff is legal padding, but if we get that many, something's wrong.
  415. $this->errno = 10;
  416. $this->errstr = "too many padding bytes!";
  417. $this->debug($this->errstr,1);
  418. }
  419. $marker = ord($marker);
  420. $this->sections[$this->currSection]["type"] = $marker;
  421. // Read the length of the section.
  422. $lh = ord(fgetc($fp));
  423. $ll = ord(fgetc($fp));
  424. $itemlen = ($lh << 8) | $ll;
  425. if ($itemlen < 2){
  426. $this->errno = 11;
  427. $this->errstr = "invalid marker";
  428. $this->debug($this->errstr,1);
  429. }
  430. $this->sections[$this->currSection]["size"] = $itemlen;
  431. $tmpDataArr = array(); /** Temporary Array */
  432. $tmpStr = fread($fp,$itemlen-2);
  433. /*
  434. $tmpDataArr[] = chr($lh);
  435. $tmpDataArr[] = chr($ll);
  436. $chars = preg_split('//', $tmpStr, -1, PREG_SPLIT_NO_EMPTY);
  437. $tmpDataArr = array_merge($tmpDataArr,$chars);
  438. $data = $tmpDataArr;
  439. */
  440. $data = chr($lh).chr($ll).$tmpStr;
  441. //$this->sections[$this->currSection]["data"] = $data;
  442. $this->debug("<hr><h1>".$this->currSection.":</h1>");
  443. //print_r($data);
  444. $this->debug("<hr>");
  445. //if(count($data) != $itemlen) {
  446. if(strlen($data) != $itemlen) {
  447. $this->errno = 12;
  448. $this->errstr = "Premature end of file?";
  449. $this->debug($this->errstr,1);
  450. }
  451. $this->currSection++; /** */
  452. switch($marker) {
  453. case M_SOS:
  454. $this->debug("<br>Found '".M_SOS."' Section, Prcessing it... <br>");;
  455. // If reading entire image is requested, read the rest of the data.
  456. if ($this->ImageReadMode & $this->ReadMode["READ_IMAGE"]){
  457. // Determine how much file is left.
  458. $cp = ftell($fp);
  459. fseek($fp,0, SEEK_END);
  460. $ep = ftell($fp);
  461. fseek($fp, $cp, SEEK_SET);
  462. $size = $ep-$cp;
  463. $got = fread($fp, $size);
  464. $this->sections[$this->currSection]["data"] = $got;
  465. $this->sections[$this->currSection]["size"] = $size;
  466. $this->sections[$this->currSection]["type"] = PSEUDO_IMAGE_MARKER;
  467. $this->currSection++;
  468. $HaveAll = 1;
  469. $exitAll =1;
  470. }
  471. $this->debug("<br>'".M_SOS."' Section, PROCESSED<br>");
  472. break;
  473. case M_COM: // Comment section
  474. $this->debug("<br>Found '".M_COM."'(Comment) Section, Processing<br>");
  475. $this->process_COM($data, $itemlen);
  476. $this->debug("<br>'".M_COM."'(Comment) Section, PROCESSED<br>");
  477. $tmpTestLevel++;
  478. break;
  479. case M_SOI:
  480. $this->debug(" <br> === START OF IMAGE =====<br>");
  481. break;
  482. case M_EOI:
  483. $this->debug(" <br>=== END OF IMAGE =====<br> ");
  484. break;
  485. case M_JFIF:
  486. // Regular jpegs always have this tag, exif images have the exif
  487. // marker instead, althogh ACDsee will write images with both markers.
  488. // this program will re-create this marker on absence of exif marker.
  489. // hence no need to keep the copy from the file.
  490. //echo " <br> === M_JFIF =====<br>";
  491. $this->sections[--$this->currSection]["data"] = "";
  492. break;
  493. case M_EXIF:
  494. // Seen files from some 'U-lead' software with Vivitar scanner
  495. // that uses marker 31 for non exif stuff. Thus make sure
  496. // it says 'Exif' in the section before treating it as exif.
  497. $this->debug("<br>Found '".M_EXIF."'(Exif) Section, Proccessing<br>");
  498. $this->exifSection = $this->currSection-1;
  499. if (($this->ImageReadMode & $this->ReadMode["READ_EXIF"]) && ($data[2].$data[3].$data[4].$data[5]) == "Exif"){
  500. $this->process_EXIF($data, $itemlen);
  501. }else{
  502. // Discard this section.
  503. $this->sections[--$this->currSection]["data"] = "";
  504. }
  505. $this->debug("<br>'".M_EXIF."'(Exif) Section, PROCESSED<br>");
  506. $tmpTestLevel++;
  507. break;
  508. case M_SOF0:
  509. case M_SOF1:
  510. case M_SOF2:
  511. case M_SOF3:
  512. case M_SOF5:
  513. case M_SOF6:
  514. case M_SOF7:
  515. case M_SOF9:
  516. case M_SOF10:
  517. case M_SOF11:
  518. case M_SOF13:
  519. case M_SOF14:
  520. case M_SOF15:
  521. $this->debug("<br>Found M_SOFn Section, Processing<br>");
  522. $this->process_SOFn($data,$marker);
  523. $this->debug("<br>M_SOFn Section, PROCESSED<br>");
  524. break;
  525. case M_EXIF_EXT: // 226 - Exif Extended Data
  526. $this->debug("<br><b>Found 'Exif Extended Data' Section, Processing</b><br>-------------------------------<br>");
  527. $this->process_EXT_EXIF($data, $itemlen);
  528. $this->debug("<br>--------------------------PROCESSED<br>");
  529. break;
  530. case M_QUANTA: // 219 - Quantisation Table Definition
  531. $this->debug("<br><b>Found 'Quantisation Table Definition' Section, Processing</b><br>-------------------------------<br>");
  532. $this->debug("<br>--------------------------PROCESSED<br>");
  533. break;
  534. case M_HUFF: // Huffman Table
  535. $this->debug("<br><b>Found 'Huffman Table' Section, Processing</b><br>-------------------------------<br>");
  536. $this->debug("<br>--------------------------PROCESSED<br>");
  537. break;
  538. default:
  539. $this->debug("DEFAULT: Jpeg section marker 0x$marker x size $itemlen\n");
  540. }
  541. $i++;
  542. if($exitAll == 1) break;
  543. //if($tmpTestLevel == 2) break;
  544. }
  545. fclose($fp);
  546. $this->newFile = 0;
  547. }
  548. /**
  549. * Changing / Assiging new file
  550. * @param string JPEG file to process
  551. *
  552. */
  553. function assign($file) {
  554. if(!empty($file)) {
  555. $this->file = $file;
  556. }
  557. /** check for existance of file! */
  558. if(!file_exists($this->file)) {
  559. $this->errorno = 1;
  560. $this->errorstr = "File '".$this->file."' does not exists!";
  561. }
  562. $this->newFile = 1;
  563. }
  564. /**
  565. * Process SOFn section of Image
  566. * @param array An array containing whole section.
  567. * @param hex Marker to specify the type of section.
  568. *
  569. */
  570. function process_SOFn($data,$marker) {
  571. $data_precision = 0;
  572. $num_components = 0;
  573. $data_precision = ord($data[2]);
  574. if($this->debug) {
  575. print("Image Dimension Calculation:");
  576. print("((ord($data[3]) << 8) | ord($data[4]));");
  577. }
  578. $this->ImageInfo["h"]["Height"] = ((ord($data[3]) << 8) | ord($data[4]));
  579. $this->ImageInfo["h"]["Width"] = ((ord($data[5]) << 8) | ord($data[6]));
  580. $num_components = ord($data[7]);
  581. if ($num_components == 3){
  582. $this->ImageInfo["h"]["IsColor"] = 1;
  583. }else{
  584. $this->ImageInfo["h"]["IsColor"] = 0;
  585. }
  586. $this->ImageInfo["h"]["Process"] = $marker;
  587. $this->debug("JPEG image is ".$this->ImageInfo["h"]["Width"]." * ".$this->ImageInfo["h"]["Height"].", $num_components color components, $data_precision bits per sample\n");
  588. }
  589. /**
  590. * Process Comments
  591. * @param array Section data
  592. * @param int Length of the section
  593. *
  594. */
  595. function process_COM($data,$length) {
  596. if ($length > MAX_COMMENT) $length = MAX_COMMENT;
  597. /** Truncate if it won't fit in our structure. */
  598. $nch = 0; $Comment = "";
  599. for ($a=2;$a<$length;$a++){
  600. $ch = $data[$a];
  601. if ($ch == '\r' && $data[$a+1] == '\n') continue; // Remove cr followed by lf.
  602. $Comment .= $ch;
  603. }
  604. //$this->ImageInfo[M_COM] = $Comment;
  605. $this->ImageInfo["h"]["imageComment"] = $this->string_format($Comment);
  606. $this->debug("COM marker comment: $Comment\n");
  607. }
  608. /**
  609. * Process one of the nested EXIF directories.
  610. * @param string All directory information
  611. * @param string whole Section
  612. * @param int Length of exif section
  613. *
  614. */
  615. function ProcessExifDir($DirStart, $OffsetBase, $ExifLength) {
  616. $NumDirEntries = 0;
  617. $ValuePtr = array();
  618. $NumDirEntries = $this->Get16u($DirStart[0],$DirStart[1]);
  619. $this->debug("<br>Directory with $NumDirEntries entries\n");
  620. for ($de=0;$de<$NumDirEntries;$de++){
  621. //$DirEntry = array_slice($DirStart,2+12*$de);
  622. $DirEntry = substr($DirStart,2+12*$de);
  623. $Tag = $this->Get16u($DirEntry[0],$DirEntry[1]);
  624. $Format = $this->Get16u($DirEntry[2],$DirEntry[3]);
  625. $Components = $this->Get32u($DirEntry[4],$DirEntry[5],$DirEntry[6],$DirEntry[7]);
  626. /**
  627. if ((Format-1) >= NUM_FORMATS) {
  628. // (-1) catches illegal zero case as unsigned underflows to positive large.
  629. ErrNonfatal("Illegal number format %d for tag %04x", Format, Tag);
  630. continue;
  631. }
  632. */
  633. $ByteCount = $Components * $this->BytesPerFormat[$Format];
  634. if ($ByteCount > 4){
  635. $OffsetVal = $this->Get32u($DirEntry[8],$DirEntry[9],$DirEntry[10],$DirEntry[11]);
  636. if ($OffsetVal+$ByteCount > $ExifLength){
  637. $this->debug("Illegal value pointer($OffsetVal) for tag $Tag",1);
  638. }
  639. //$ValuePtr = array_slice($OffsetBase,$OffsetVal);
  640. $ValuePtr = substr($OffsetBase,$OffsetVal);
  641. } else {
  642. //$ValuePtr = array_slice($DirEntry,8);
  643. $ValuePtr = substr($DirEntry,8);
  644. }
  645. switch($Tag){
  646. case TAG_MAKE:
  647. $this->ImageInfo["h"]["make"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  648. break;
  649. case TAG_MODEL:
  650. $this->ImageInfo["h"]["model"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  651. break;
  652. case TAG_DATETIME_ORIGINAL:
  653. $this->ImageInfo[TAG_DATETIME_ORIGINAL] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  654. $this->ImageInfo["h"]["DateTime"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  655. break;
  656. case TAG_USERCOMMENT:
  657. // Olympus has this padded with trailing spaces. Remove these first.
  658. for ($a=$ByteCount;;){
  659. $a--;
  660. if ($ValuePtr[$a] == ' '){
  661. //$ValuePtr[$a] = '\0';
  662. } else {
  663. break;
  664. }
  665. if ($a == 0) break;
  666. }
  667. // Copy the comment
  668. if (($ValuePtr[0].$ValuePtr[1].$ValuePtr[2].$ValuePtr[3].$ValuePtr[4]) == "ASCII"){
  669. for ($a=5;$a<10;$a++){
  670. $c = $ValuePtr[$a];
  671. if ($c != '\0' && $c != ' '){
  672. $tmp = substr($ValuePtr,0,$ByteCount);
  673. break;
  674. }
  675. }
  676. } else if (($ValuePtr[0].$ValuePtr[1].$ValuePtr[2].$ValuePtr[3].$ValuePtr[4].$ValuePtr[5].$ValuePtr[6]) == "Unicode"){
  677. $tmp = substr($ValuePtr,0,$ByteCount);
  678. // * Handle Unicode characters here...
  679. } else {
  680. //$this->ImageInfo[TAG_USERCOMMENT] = implode("",array_slice($ValuePtr,0,$ByteCount));
  681. $tmp = substr($ValuePtr,0,$ByteCount);
  682. }
  683. $this->ImageInfo['h']["exifComment"] = $this->string_format($tmp);
  684. break;
  685. case TAG_ARTIST:
  686. $this->ImageInfo['h']["artist"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  687. break;
  688. case TAG_COPYRIGHT:
  689. $this->ImageInfo['h']["copyright"] = htmlentities(substr($ValuePtr,0,$ByteCount));
  690. break;
  691. case TAG_FNUMBER:
  692. // Simplest way of expressing aperture, so I trust it the most.
  693. // (overwrite previously computd value if there is one)
  694. $tmp = $this->ConvertAnyFormat(substr($ValuePtr,0), $Format);
  695. $this->ImageInfo['h']["fnumber"] = sprintf("f/%3.1f",(double)$tmp[0]);
  696. break;
  697. case TAG_APERTURE:
  698. case TAG_MAXAPERTURE:
  699. // More relevant info always comes earlier, so only use this field if we don't
  700. // have appropriate aperture information yet.
  701. if (!isset($this->ImageInfo['h']["aperture"])){
  702. $tmpArr = $this->ConvertAnyFormat($ValuePtr, $Format);
  703. $this->ImageInfo['h']["aperture"] = exp($tmpArr[0]*log(2)*0.5);
  704. }
  705. break;
  706. case TAG_FOCALLENGTH:
  707. // Nice digital cameras actually save the focal length as a function
  708. // of how farthey are zoomed in.
  709. $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
  710. $this->ImageInfo['h']["focalLength"] = sprintf("%4.2f (%d/%d)",(double)$tmp[0],$tmp[1][0],$tmp[1][1]);
  711. if (isset($this->ImageInfo['h']["CCDWidth"])){
  712. $this->ImageInfo['h']["focalLength"] .= sprintf("(35mm equivalent: %dmm)",(int)($tmp[0]/$this->ImageInfo['h']["CCDWidth"]*36 + 0.5));
  713. }
  714. break;
  715. case TAG_SUBJECT_DISTANCE:
  716. // Inidcates the distacne the autofocus camera is focused to.
  717. // Tends to be less accurate as distance increases.
  718. //$this->ImageInfo["h"]["Distance"] = $this->ConvertAnyFormat($ValuePtr, $Format);
  719. $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
  720. $this->ImageInfo['h']["Distance"] = sprintf("%4.2f (%d/%d)",(double)$tmp[0],$tmp[1][0],$tmp[1][1]);
  721. if ($this->ImageInfo['h']["Distance"] < 0){
  722. $this->ImageInfo['h']["focusDistance"] = "Infinite";
  723. } else {
  724. $this->ImageInfo['h']["focusDistance"] = sprintf("%4.2fm",(double)$this->ImageInfo['h']["Distance"]);
  725. }
  726. break;
  727. case TAG_EXPOSURETIME:
  728. // Simplest way of expressing exposure time, so I trust it most.
  729. // (overwrite previously computd value if there is one)
  730. $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
  731. $this->ImageInfo['h']["exposureTime"] = sprintf("%6.3f s (%d/%d)",(double)$tmp[0],$tmp[1][0],$tmp[1][1]);
  732. if ($tmp[0] <= 0.5){
  733. $this->ImageInfo['h']["exposureTime"] .= sprintf(" (1/%d)",(int)(0.5 + 1/$tmp[0]));
  734. }
  735. break;
  736. case TAG_SHUTTERSPEED:
  737. // More complicated way of expressing exposure time, so only use
  738. // this value if we don't already have it from somewhere else.
  739. if ($this->ImageInfo[TAG_EXPOSURETIME] == 0){
  740. $sp = $this->ConvertAnyFormat($ValuePtr, $Format);
  741. $this->ImageInfo[TAG_SHUTTERSPEED] = (1/exp($sp[0]*log(2)));
  742. }
  743. break;
  744. case TAG_FLASH:
  745. $this->ImageInfo["h"]["flashUsed"] = "No";
  746. if ($this->ConvertAnyFormat($ValuePtr, $Format) & 7){
  747. $this->ImageInfo["h"]["flashUsed"] = "Yes";
  748. }
  749. break;
  750. case TAG_ORIENTATION:
  751. $this->ImageInfo[TAG_ORIENTATION] = $this->ConvertAnyFormat($ValuePtr, $Format);
  752. if ($this->ImageInfo[TAG_ORIENTATION] < 1 || $this->ImageInfo[TAG_ORIENTATION] > 8){
  753. $this->debug(sprintf("Undefined rotation value %d", $this->ImageInfo[TAG_ORIENTATION], 0),1);
  754. $this->ImageInfo[TAG_ORIENTATION] = 0;
  755. }
  756. break;
  757. case TAG_EXIF_IMAGELENGTH:
  758. // * Image height
  759. $a = (int) $this->ConvertAnyFormat($ValuePtr, $Format);
  760. if ($this->ExifImageLength < $a) $this->ExifImageLength = $a;
  761. $this->ImageInfo[TAG_EXIF_IMAGELENGTH] = $this->ExifImageLength;
  762. $this->ImageInfo["h"]["Height"] = $this->ExifImageLength;
  763. break;
  764. case TAG_EXIF_IMAGEWIDTH:
  765. // Use largest of height and width to deal with images that have been
  766. // rotated to portrait format.
  767. $a = (int) $this->ConvertAnyFormat($ValuePtr, $Format);
  768. if ($this->ExifImageWidth < $a) $this->ExifImageWidth = $a;
  769. $this->ImageInfo[TAG_EXIF_IMAGEWIDTH] = $this->ExifImageWidth;
  770. $this->ImageInfo["h"]["Width"] = $this->ExifImageWidth;
  771. break;
  772. case TAG_FOCALPLANEXRES:
  773. $this->FocalplaneXRes = $this->ConvertAnyFormat($ValuePtr, $Format);
  774. $this->FocalplaneXRes = $this->FocalplaneXRes[0];
  775. $this->ImageInfo[TAG_FOCALPLANEXRES] = $this->FocalplaneXRes[0];
  776. break;
  777. case TAG_FOCALPLANEUNITS:
  778. switch($this->ConvertAnyFormat($ValuePtr, $Format)){
  779. case 1: $this->FocalplaneUnits = 25.4; break; // inch
  780. case 2:
  781. // According to the information I was using, 2 means meters.
  782. // But looking at the Cannon powershot's files, inches is the only
  783. // sensible value.
  784. $this->FocalplaneUnits = 25.4;
  785. break;
  786. case 3: $this->FocalplaneUnits = 10; break; // centimeter
  787. case 4: $this->FocalplaneUnits = 1; break; // milimeter
  788. case 5: $this->FocalplaneUnits = .001; break; // micrometer
  789. }
  790. $this->ImageInfo[TAG_FOCALPLANEUNITS] = $this->FocalplaneUnits;
  791. break;
  792. // Remaining cases contributed by: Volker C. Schoech (schoech@gmx.de)
  793. case TAG_EXPOSURE_BIAS:
  794. $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
  795. $this->ImageInfo['h']["exposureBias"] = sprintf("%4.2f (%d/%d)",(double)$tmp[0],$tmp[1][0],$tmp[1][1]);
  796. break;
  797. case TAG_WHITEBALANCE:
  798. $tmp = (int) $this->ConvertAnyFormat($ValuePtr, $Format);
  799. $tmpArr = array("1"=>"Sunny","2"=>"fluorescent","3"=>"incandescent");
  800. $this->ImageInfo['h']["whiteBalance"] =
  801. (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Cloudy");
  802. break;
  803. case TAG_METERING_MODE:
  804. $tmp = (int) $this->ConvertAnyFormat($ValuePtr, $Format);
  805. $tmpArr = array("2"=>"center weight","3"=>"spot","5"=>"matrix");
  806. $this->ImageInfo['h']["meteringMode"] =
  807. (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Reserved");
  808. break;
  809. case TAG_EXPOSURE_PROGRAM:
  810. $tmp = (int) $this->ConvertAnyFormat($ValuePtr, $Format);
  811. $tmpArr = array("2"=>"program (auto)","3"=>"aperture priority (semi-auto)","4"=>"shutter priority (semi-auto)");
  812. $this->ImageInfo['h']["exposure"] =
  813. (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Reserved");
  814. break;
  815. case TAG_ISO_EQUIVALENT:
  816. $tmp = (int) $this->ConvertAnyFormat($ValuePtr, $Format);
  817. if ( $tmp < 50 ) $tmp *= 200;
  818. $this->ImageInfo['h']["isoEquiv"] = sprintf("%2d",(int)$tmp);
  819. break;
  820. case TAG_COMPRESSION_LEVEL:
  821. $tmp = (int) $this->ConvertAnyFormat($ValuePtr, $Format);
  822. $tmpArr = array("1"=>"Basic","2"=>"Normal","4"=>"Fine");
  823. $this->ImageInfo['h']["jpegQuality"] =
  824. (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Reserved");
  825. break;
  826. case TAG_THUMBNAIL_OFFSET:
  827. //$this->ThumbnailOffset = $this->ConvertAnyFormat($ValuePtr, $Format);
  828. //$this->DirWithThumbnailPtrs = $DirStart;
  829. break;
  830. case TAG_THUMBNAIL_LENGTH:
  831. //$this->ThumbnailSize = $this->ConvertAnyFormat($ValuePtr, $Format);
  832. //$this->ImageInfo[TAG_THUMBNAIL_LENGTH] = $this->ThumbnailSize;
  833. break;
  834. //----------------------------------------------
  835. case TAG_IMAGE_DESC:
  836. $this->ImageInfo['h']["imageDesc"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  837. break;
  838. case TAG_X_RESOLUTION:
  839. $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
  840. $this->ImageInfo['h']["xResolution"] = sprintf("%4.2f (%d/%d) %s",(double)$tmp[0],$tmp[1][0],$tmp[1][1],$this->ImageInfo['h']["resolutionUnit"]);
  841. break;
  842. case TAG_Y_RESOLUTION:
  843. $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
  844. $this->ImageInfo['h']["yResolution"] = sprintf("%4.2f (%d/%d) %s",(double)$tmp[0],$tmp[1][0],$tmp[1][1],$this->ImageInfo['h']["resolutionUnit"]);
  845. break;
  846. case TAG_RESOLUTION_UNIT:
  847. $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
  848. $tmpArr = array("2"=>"Inches","3"=>"Centimeters");
  849. $this->ImageInfo['h']["resolutionUnit"] =
  850. (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Reserved");
  851. break;
  852. case TAG_SOFTWARE:
  853. $this->ImageInfo['h']["software"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  854. break;
  855. case TAG_FILE_MODDATE;
  856. $this->ImageInfo['h']["fileModifiedDate"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  857. break;
  858. case TAG_YCBCR_POSITIONING:
  859. $this->ImageInfo['h']["YCbCrPositioning"] = $this->ConvertAnyFormat($ValuePtr, $Format);
  860. break;
  861. case TAG_EXIF_VERSION:
  862. $this->ImageInfo['h']["exifVersion"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  863. break;
  864. case TAG_DATE_TIME_DIGITIZED:
  865. $this->ImageInfo['h']["dateTimeDigitized"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  866. break;
  867. case TAG_COMPONENT_CONFIG: // need more tests for this
  868. $tmp = (int)$this->ConvertAnyFormat($ValuePtr, $Format);
  869. $tmpArr = array("0"=>"Does Not Exists","1"=>"Y","2"=>"Cb","3"=>"Cr","4"=>"R","5"=>"G","6"=>"B");
  870. if(strlen($tmp) < 4 ) {
  871. $this->ImageInfo['h']["componentConfig"] = $tmpArr["0"];
  872. } else {
  873. for($i=0;$i<strlen($tmp);$i++) {
  874. if($tmp["$i"] != 0) {
  875. $this->ImageInfo['h']["componentConfig"] .= $tmpArr[$tmp["$i"]];
  876. }
  877. }
  878. }
  879. break;
  880. case TAG_MAKER_NOTE:
  881. //$this->ImageInfo['h']["makerNote"] = substr($ValuePtr,0,$ByteCount);
  882. $this->ImageInfo['h']["makerNote"] = "NOT IMPLEMENTED";
  883. break;
  884. case TAG_SUB_SEC_TIME:
  885. $this->ImageInfo['h']["subSectionTime"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  886. break;
  887. case TAG_SUB_SEC_TIME_ORIG:
  888. $this->ImageInfo['h']["subSectionTimeOriginal"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  889. break;
  890. case TAG_SUB_SEC_TIME_DIGITIZED:
  891. $this->ImageInfo['h']["subSectionTimeDigtized"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  892. break;
  893. case TAG_FLASHPIX_VER:
  894. $this->ImageInfo['h']["flashpixVersion"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  895. break;
  896. case TAG_COLOR_SPACE:
  897. $this->ImageInfo['h']["colorSpace"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  898. break;
  899. case TAG_RELATED_SOUND_FILE:
  900. $this->ImageInfo['h']["relatedSoundFile"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  901. break;
  902. case TAG_GPS_LATITUDE_REF:
  903. $this->ImageInfo['h']["GPSLatitudeRef"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  904. $this->ImageInfo['h']["GPSLatitudeRef"] = trim($this->ImageInfo['h']["GPSLatitudeRef"]);
  905. $tmp = substr($this->ImageInfo['h']["GPSLatitudeRef"],0,1);
  906. if($tmp == "S") {
  907. $this->ImageInfo['h']["GPSLatitudeRef"] = "South latitude";
  908. } else if($tmp == "N") {
  909. $this->ImageInfo['h']["GPSLatitudeRef"] = "North latitude";
  910. } else {
  911. $this->ImageInfo['h']["GPSLatitudeRef"] = "Reserved";
  912. }
  913. break;
  914. case TAG_GPS_LATITUDE:
  915. $tmp = substr($ValuePtr,0,$ByteCount);
  916. $this->ImageInfo['h']["GPSLatitude"]["Degrees"] = ord(substr($tmp,0,1));
  917. $this->ImageInfo['h']["GPSLatitude"]["Minutes"] = ord(substr($tmp,1,1));
  918. $this->ImageInfo['h']["GPSLatitude"]["Seconds"] = ord(substr($tmp,2,1));
  919. break;
  920. case TAG_GPS_LONGITUDE:
  921. $tmp = substr($ValuePtr,0,$ByteCount);
  922. $this->ImageInfo['h']["GPSLongitude"]["Degrees"] = ord(substr($tmp,0,1));
  923. $this->ImageInfo['h']["GPSLongitude"]["Minutes"] = ord(substr($tmp,1,1));
  924. $this->ImageInfo['h']["GPSLongitude"]["Seconds"] = ord(substr($tmp,2,1));
  925. break;
  926. case TAG_GPS_LONGITUDE_REF:
  927. $this->ImageInfo['h']["GPSLongitudeRef"] = substr($ValuePtr,0,$ByteCount);
  928. $this->ImageInfo['h']["GPSLongitudeRef"] = trim($this->ImageInfo['h']["GPSLongitudeRef"]);
  929. $tmp = substr($this->ImageInfo['h']["GPSLongitudeRef"],0,1);
  930. if($tmp == "E") {
  931. $this->ImageInfo['h']["GPSLongitudeRef"] = "East Longitude";
  932. } else if($tmp == "W") {
  933. $this->ImageInfo['h']["GPSLongitudeRef"] = "West Longitude";
  934. } else {
  935. $this->ImageInfo['h']["GPSLongitudeRef"] = "Reserved";
  936. }
  937. break;
  938. case TAG_GPS_TrackRef: /* Reference for direction of movement GPSTrackRef */
  939. $this->ImageInfo['h']["GPSTrackRef"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  940. break;
  941. case TAG_GPS_GPSTrack: /* Direction of movement GPSTrack */
  942. $this->ImageInfo['h']["GPSTrack"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  943. break;
  944. case TAG_GPS_GPSImgDirectionRef: /* Reference for direction of image GPSImgDirectionRef */
  945. $this->ImageInfo['h']["GPSImgDirectionRef"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  946. break;
  947. case TAG_GPS_GPSImgDirection: /* Direction of image GPSImgDirection */
  948. $this->ImageInfo['h']["GPSImgDirection"] = $this->ConvertAnyFormat($ValuePtr, $Format);
  949. break;
  950. case TAG_GPS_GPSMapDatum: /* Geodetic survey data used GPSMapDatum */
  951. $this->ImageInfo['h']["GPSMapDatum"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  952. break;
  953. case TAG_GPS_GPSDestLatitudeRef:/* Reference for latitude of destination GPSDestLatitudeRef */
  954. $this->ImageInfo['h']["GPSDestLatitudeRef"] = substr($ValuePtr,0,$ByteCount);
  955. $this->ImageInfo['h']["GPSDestLatitudeRef"] = trim($this->ImageInfo['h']["GPSDestLatitudeRef"]);
  956. $tmp = substr($this->ImageInfo['h']["GPSDestLatitudeRef"],0,1);
  957. if($tmp == "S") {
  958. $this->ImageInfo['h']["GPSDestLatitudeRef"] = "South latitude";
  959. } else if($tmp == "N") {
  960. $this->ImageInfo['h']["GPSDestLatitudeRef"] = "North latitude";
  961. } else {
  962. $this->ImageInfo['h']["GPSDestLatitudeRef"] = "Reserved";
  963. }
  964. break;
  965. case TAG_GPS_GPSDestLatitude:/* Latitude of destination GPSDestLatitude */
  966. $tmp = substr($ValuePtr,0,$ByteCount);
  967. $this->ImageInfo['h']["GPSDestLatitude"]["Degrees"] = ord(substr($tmp,0,1));
  968. $this->ImageInfo['h']["GPSDestLatitude"]["Minutes"] = ord(substr($tmp,1,1));
  969. $this->ImageInfo['h']["GPSDestLatitude"]["Seconds"] = ord(substr($tmp,2,1));
  970. break;
  971. case TAG_GPS_GPSDestLongitudeRef:/* Reference for longitude of destination GPSDestLongitudeRef 21 */
  972. $this->ImageInfo['h']["GPSDestLongitudeRef"] = substr($ValuePtr,0,$ByteCount);
  973. $this->ImageInfo['h']["GPSDestLongitudeRef"] = trim($this->ImageInfo['h']["GPSDestLongitudeRef"]);
  974. $tmp = substr($this->ImageInfo['h']["GPSDestLongitudeRef"],0,1);
  975. if($tmp == "E") {
  976. $this->ImageInfo['h']["GPSDestLongitudeRef"] = "East Longitude";
  977. } else if($tmp == "W") {
  978. $this->ImageInfo['h']["GPSDestLongitudeRef"] = "West Longitude";
  979. } else {
  980. $this->ImageInfo['h']["GPSDestLongitudeRef"] = "Reserved";
  981. }
  982. break;
  983. case TAG_GPS_GPSDestLongitude:/* Longitude of destination GPSDestLongitude 22 */
  984. $this->ImageInfo['h']["GPSDestLongitude"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  985. break;
  986. case TAG_GPS_GPSDestBearingRef:/* Reference for bearing of destination GPSDestBearingRef 23 */
  987. $this->ImageInfo['h']["GPSDestBearingRef"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  988. break;
  989. case TAG_GPS_GPSDestBearing: /* Bearing of destination GPSDestBearing 24 */
  990. $this->ImageInfo['h']["GPSDestBearing"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  991. break;
  992. case TAG_GPS_GPSDestDistanceRef:/* Reference for distance to destination GPSDestDistanceRef 25 */
  993. $this->ImageInfo['h']["GPSDestDistanceRef"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  994. break;
  995. case TAG_GPS_GPSDestDistance: /* Distance to destination GPSDestDistance 26 */
  996. //$this->ImageInfo['h']["GPSDestDistance"] = $this->ConvertAnyFormat($ValuePtr, $Format);
  997. $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
  998. $this->ImageInfo['h']["GPSDestDistance"] = sprintf("%4.2f (%d/%d)",(double)$tmp[0],$tmp[1][0],$tmp[1][1]);;
  999. break;
  1000. case TAG_GPS_GPSProcessingMethod: /* Name of GPS processing method GPSProcessingMethod 27 */
  1001. //$this->ImageInfo['h']["GPSProcessingMethod"] = $this->ConvertAnyFormat($ValuePtr, $Format);
  1002. $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
  1003. $this->ImageInfo['h']["GPSProcessingMethod"] = sprintf("%4.2f (%d/%d)",(double)$tmp[0],$tmp[1][0],$tmp[1][1]);;
  1004. break;
  1005. case TAG_GPS_GPSAreaInformation: /* Name of GPS area GPSAreaInformation 28 */
  1006. $this->ImageInfo['h']["GPSAreaInformation"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  1007. break;
  1008. case TAG_GPS_GPSDateStamp: /* GPS date GPSDateStamp 29 */
  1009. $this->ImageInfo['h']["GPSDateStamp"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  1010. break;
  1011. case TAG_GPS_GPSDifferential: /* GPS differential correction GPSDifferential 30 */
  1012. $this->ImageInfo['h']["GPSDifferential"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  1013. break;
  1014. case TAG_AUDIO_MU_LAW:
  1015. $this->ImageInfo['h']["AudioMuLaw"] = $this->ConvertAnyFormat($ValuePtr, $Format);
  1016. break;
  1017. case TAG_AUDIO_IMA_ADPCM_DESC: // IMA-ADPCM Audio File Description Example - 40
  1018. $this->ImageInfo['h']["AudioIMA-ADPCM-DESC"] = $this->ConvertAnyFormat($ValuePtr, $Format);
  1019. break;
  1020. case TAG_AUDIO_MU_LAW_DESC: // µ-Law Audio File Description Sample - 50
  1021. $this->ImageInfo['h']["AudioMuLawDesc"] = $this->ConvertAnyFormat($ValuePtr, $Format);
  1022. break;
  1023. case TAG_EXPOSURE_INDEX:
  1024. $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
  1025. $this->ImageInfo['h']["ExposureIndex"] = sprintf("%4.2f (%d/%d)",(double)$tmp[0],$tmp[1][0],$tmp[1][1]);;
  1026. break;
  1027. case TAG_SENSING_METHOD:
  1028. $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
  1029. $tmpArr = array("1"=>"Not Defined","2"=>"One-chip color area sensor","3"=>"Two-chip color area sensor",
  1030. "4"=>"Three -chip color area sensor","5"=>"Color sequential area sensor",
  1031. "6"=>"Trilinear sensor", "7"=>"Color sequential linear sensor"
  1032. );
  1033. $this->ImageInfo['h']["sensing"] =
  1034. (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Reserved");
  1035. break;
  1036. case TAG_SOUCE_TYPE:
  1037. $this->ImageInfo['h']["sourceType"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  1038. break;
  1039. case TAG_SCENE_TYPE:
  1040. $this->ImageInfo['h']["sceneType"] = $t

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