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

/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
  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"=>"Not Defined","2"=>"One-chip color area sensor","3"=>"Two-chip color area sensor",
  1046. "4"=>"Three -chip color area sensor","5"=>"Color sequential area sensor",
  1047. "6"=>"Trilinear sensor", "7"=>"Color sequential linear sensor"
  1048. );
  1049. $this->ImageInfo['h']["sensing"] =
  1050. (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Reserved");
  1051. break;
  1052. case TAG_SOUCE_TYPE:
  1053. $this->ImageInfo['h']["sourceType"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  1054. break;
  1055. case TAG_SCENE_TYPE:
  1056. $this->ImageInfo['h']["sceneType"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  1057. break;
  1058. case TAG_CFA_PATTERN:
  1059. $this->ImageInfo['h']["CFAPattern"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
  1060. break;
  1061. case TAG_CUSTOM_RENDERED:
  1062. $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
  1063. $this->ImageInfo['h']["customRendered"] = ($mp == 0) ? 'Normal Process' : ($mp == 1 ? 'Custom Process' : 'Reserved');
  1064. break;
  1065. case TAG_EXPOSURE_MODE:
  1066. $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
  1067. $tmpArr = array('Auto Exposure','Manual Exposure','Auto Bracket');
  1068. $this->ImageInfo['h']["exposureMode"] =
  1069. (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Reserved");
  1070. break;
  1071. case TAG_WHITE_BALANCE:
  1072. $this->ImageInfo['h']["whiteBalance"] = $this->ConvertAnyFormat($ValuePtr, $Format);
  1073. break;
  1074. case TAG_DIGITAL_ZOOM_RATIO:
  1075. $tmp = $this->ImageInfo['h']["zoomRatio"] = $this->ConvertAnyFormat($ValuePtr, $Format);
  1076. $this->ImageInfo['h']["zoomRatio"] = sprintf("%4.2f (%d/%d)",(double)$tmp[0],$tmp[1][0],$tmp[1][1]);
  1077. break;
  1078. case TAG_FLENGTH_IN35MM:
  1079. $this->ImageInfo['h']["flength35mm"] = $this->ConvertAnyFormat($ValuePtr, $Format);
  1080. break;
  1081. case TAG_SCREEN_CAP_TYPE:
  1082. $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
  1083. $tmpArr = array("Standard","Landscape","Portrait","Night Scene");
  1084. $this->ImageInfo['h']["screenCaptureType"] =
  1085. (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Reserved");
  1086. break;
  1087. case TAG_GAIN_CONTROL:
  1088. $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
  1089. $tmpArr = array("None","Low Gain Up","High Gain Up","Low Gain Down","High Gain Down");
  1090. $this->ImageInfo['h']["gainControl"] =
  1091. (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Reserved");
  1092. break;
  1093. case TAG_CONTRAST:
  1094. $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
  1095. $tmpArr = array("Normal","Soft","Hard");
  1096. $this->ImageInfo['h']["contrast"] =
  1097. (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Reserved");
  1098. break;
  1099. case TAG_SATURATION:
  1100. $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
  1101. $tmpArr = array("Normal","Low Saturation","High Saturation");
  1102. $this->ImageInfo['h']["saturation"] =
  1103. (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Reserved");
  1104. break;
  1105. case TAG_SHARPNESS:
  1106. $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
  1107. $tmpArr = array("Normal","Soft","Hard");
  1108. $this->ImageInfo['h']["sharpness"] =
  1109. (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Reserved");
  1110. break;
  1111. case TAG_DIST_RANGE:
  1112. $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
  1113. $tmpArr = array("Unknown","Macro","Close View","Distant View");
  1114. $this->ImageInfo['h']["distanceRange"] =
  1115. (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Reserved");
  1116. break;
  1117. case TAG_DEVICE_SETTING_DESC:
  1118. /*
  1119. $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
  1120. $tmpArr = array("Unknown","Macro","Close View","Distant View");
  1121. $this->ImageInfo['h']["distanceRange"] =
  1122. (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Reserved");
  1123. */
  1124. $this->ImageInfo['h']["deviceSettingDesc"] = "NOT IMPLEMENTED";
  1125. break;
  1126. case TAG_COMPRESS_SCHEME:
  1127. $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
  1128. $tmpArr = array("1"=>"Uncompressed","6"=>"JPEG compression (thumbnails only)");
  1129. $this->ImageInfo['h']["compressScheme"] =
  1130. (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Reserved");
  1131. break;
  1132. case TAG_IMAGE_WD:
  1133. $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
  1134. $this->ImageInfo['h']["jpegImageWidth"] = $tmp;
  1135. break;
  1136. case TAG_IMAGE_HT:
  1137. $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
  1138. $this->ImageInfo['h']["jpegImageHeight"] = $tmp;
  1139. break;
  1140. case TAG_IMAGE_BPS:
  1141. $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
  1142. $this->ImageInfo['h']["jpegBitsPerSample"] = $tmp;
  1143. break;
  1144. case TAG_IMAGE_PHOTO_INT:
  1145. $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
  1146. $this->ImageInfo['h']["jpegPhotometricInt"] = $tmp;
  1147. $tmpArr = array("2"=>"RGB","6"=>"YCbCr");
  1148. $this->ImageInfo['h']["jpegPhotometricInt"] =
  1149. (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Reserved");
  1150. break;
  1151. case TAG_IMAGE_SOFFSET:
  1152. $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
  1153. $this->ImageInfo['h']["jpegStripOffsets"] = $tmp;
  1154. break;
  1155. case TAG_IMAGE_SPP:
  1156. $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
  1157. $this->ImageInfo['h']["jpegSamplesPerPixel"] = $tmp;
  1158. break;
  1159. case TAG_IMAGE_RPS:
  1160. $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
  1161. $this->ImageInfo['h']["jpegRowsPerStrip"] = $tmp;
  1162. break;
  1163. case TAG_IMAGE_SBC:
  1164. $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
  1165. $this->ImageInfo['h']["jpegStripByteCounts"] = $tmp;
  1166. break;
  1167. case TAG_IMAGE_P_CONFIG:
  1168. $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
  1169. $tmpArr = array("1"=>"Chunky Format","2"=>"Planar Format");
  1170. $this->ImageInfo['h']["jpegPlanarConfig"] =
  1171. (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Reserved");
  1172. break;
  1173. case TAG_FOCALPLANE_YRESOL:
  1174. $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
  1175. $this->ImageInfo['h']["focalPlaneYResolution"] = sprintf("%4.2f (%d/%d)",(double)$tmp[0],$tmp[1][0],$tmp[1][1]);
  1176. break;
  1177. case TAG_BRIGHTNESS:
  1178. $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
  1179. $this->ImageInfo['h']["brightness"] = sprintf("%4.2f (%d/%d)",(double)$tmp[0],$tmp[1][0],$tmp[1][1]);
  1180. break;
  1181. //---------------------------------------------
  1182. case TAG_EXIF_OFFSET:
  1183. case TAG_INTEROP_OFFSET:
  1184. case TAG_GPS_IFD:
  1185. {
  1186. $SubdirStart = substr($OffsetBase,$this->Get32u($ValuePtr[0],$ValuePtr[1],$ValuePtr[2],$ValuePtr[3]));
  1187. //if ($SubdirStart < $OffsetBase || $SubdirStart > $OffsetBase+$ExifLength){
  1188. // debug("Illegal exif or interop ofset directory link",1);
  1189. //}else{
  1190. //echo "<h1>Calling sub-exif dir</h1>";
  1191. $this->ProcessExifDir($SubdirStart, $OffsetBase, $ExifLength);
  1192. //}
  1193. continue;
  1194. }
  1195. default: {
  1196. $this->debug("UNKNOWN TAG: $Tag");
  1197. }
  1198. }
  1199. }
  1200. {
  1201. // In addition to linking to subdirectories via exif tags,
  1202. // there's also a potential link to another directory at the end of each
  1203. // directory. this has got to be the result of a comitee!
  1204. $tmpDirStart = substr($DirStart,2+12*$NumDirEntries);
  1205. if (strlen($tmpDirStart) + 4 <= strlen($OffsetBase)+$ExifLength){
  1206. $Offset = $this->Get32u($tmpDirStart[0],$tmpDirStart[1],$tmpDirStart[2],$tmpDirStart[3]);
  1207. if ($Offset){
  1208. $SubdirStart = substr($OffsetBase,$Offset);
  1209. if (strlen($SubdirStart) > strlen($OffsetBase)+$ExifLength){
  1210. if (strlen($SubdirStart) < strlen($OffsetBase)+$ExifLength+20){
  1211. // Jhead 1.3 or earlier would crop the whole directory!
  1212. // As Jhead produces this form of format incorrectness,
  1213. // I'll just let it pass silently
  1214. } else {
  1215. $this->errno = 51;
  1216. $this->errstr = "Illegal subdirectory link";
  1217. $this->debug($this->errstr,1);
  1218. }
  1219. }else{
  1220. if (strlen($SubdirStart) <= strlen($OffsetBase)+$ExifLength){
  1221. $this->ProcessExifDir($SubdirStart, $OffsetBase, $ExifLength);
  1222. }
  1223. }
  1224. }
  1225. } else {
  1226. // The exif header ends before the last next directory pointer.
  1227. }
  1228. }
  1229. /**
  1230. * Check if thumbnail has been cached or not.
  1231. * If yes! then read the file.
  1232. */
  1233. if(file_exists($this->thumbnail) && $this->caching && (filemtime($this->thumbnail) == filemtime($this->file) )) {
  1234. $this->ImageInfo["h"]["Thumbnail"] = $this->thumbnail;
  1235. $this->ImageInfo["h"]["ThumbnailSize"] = sprintf("%d bytes",filesize($this->thumbnail));
  1236. } else{
  1237. if ($this->ThumbnailSize && $this->ThumbnailOffset){
  1238. if ($this->ThumbnailSize + $this->ThumbnailOffset <= $ExifLength){
  1239. // The thumbnail pointer appears to be valid. Store it.
  1240. $this->ImageInfo["h"]["Thumbnail"] = substr($OffsetBase,$this->ThumbnailOffset);
  1241. // Save the thumbnail /
  1242. if($this->caching && is_dir($this->cacheDir)) {
  1243. $this->saveThumbnail($this->thumbnail);
  1244. $this->ImageInfo["h"]["Thumbnail"] = $this->thumbnail;
  1245. }
  1246. $this->ImageInfo["h"]["ThumbnailSize"] = sprintf("%d bytes",strlen($this->ImageInfo["h"]["Thumbnail"]));
  1247. }
  1248. }
  1249. }
  1250. }
  1251. /**
  1252. * Process Exif data
  1253. * @param array Section data as an array
  1254. * @param int Length of the section (length of data array)
  1255. *
  1256. */
  1257. function process_EXT_EXIF($data,$length) {
  1258. //print_r($data);
  1259. }
  1260. /**
  1261. * Process Exif data
  1262. * @param array Section data as an array
  1263. * @param int Length of the section (length of data array)
  1264. *
  1265. */
  1266. function process_EXIF($data,$length) {
  1267. $this->debug("Exif header $length bytes long\n");
  1268. if(($data[2].$data[3].$data[4].$data[5]) != "Exif") {
  1269. $this->errno = 52;
  1270. $this->errstr = "NOT EXIF FORMAT";
  1271. $this->debug($this->errstr,1);
  1272. }
  1273. $this->ImageInfo["h"]["FlashUsed"] = 0;
  1274. /** If it s from a digicam, and it used flash, it says so. */
  1275. $this->FocalplaneXRes = 0;
  1276. $this->FocalplaneUnits = 0;
  1277. $this->ExifImageWidth = 0;
  1278. if(($data[8].$data[9]) == "II") {
  1279. $this->debug("Exif section in Intel order\n");
  1280. $this->MotorolaOrder = 0;
  1281. } else if(($data[8].$data[9]) == "MM") {
  1282. $this->debug("Exif section in Motorola order\n");
  1283. $this->MotorolaOrder = 1;
  1284. } else {
  1285. $this->errno = 53;
  1286. $this->errstr = "Invalid Exif alignment marker.\n";
  1287. $this->debug($this->errstr,1);
  1288. return;
  1289. }
  1290. if($this->Get16u($data[10],$data[11]) != 0x2A || $this->Get32s($data[12],$data[13],$data[14],$data[15]) != 0x08) {
  1291. $this->errno = 54;
  1292. $this->errstr = "Invalid Exif start (1)";
  1293. $this->debug($this->errstr,1);
  1294. }
  1295. $DirWithThumbnailPtrs = NULL;
  1296. //$this->ProcessExifDir(array_slice($data,16),array_slice($data,8),$length);
  1297. $this->ProcessExifDir(substr($data,16),substr($data,8),$length);
  1298. // Compute the CCD width, in milimeters. 2
  1299. if ($this->FocalplaneXRes != 0){
  1300. $this->ImageInfo["h"]["CCDWidth"] = sprintf("%4.2fmm",(float)($this->ExifImageWidth * $this->FocalplaneUnits / $this->FocalplaneXRes));
  1301. }
  1302. $this->debug("Non settings part of Exif header: ".$length." bytes\n");
  1303. } // end of function process_EXIF
  1304. /**
  1305. * Converts two byte number into its equivalent int integer
  1306. * @param int
  1307. * @param int
  1308. *
  1309. */
  1310. function Get16u($val,$by) {
  1311. if($this->MotorolaOrder){
  1312. return ((ord($val) << 8) | ord($by));
  1313. } else {
  1314. return ((ord($by) << 8) | ord($val));
  1315. }
  1316. }
  1317. /**
  1318. * Converts 4-byte number into its equivalent integer
  1319. *
  1320. * @param int
  1321. * @param int
  1322. * @param int
  1323. * @param int
  1324. *
  1325. * @return int
  1326. */
  1327. function Get32s($val1,$val2,$val3,$val4)
  1328. {
  1329. $val1 = ord($val1);
  1330. $val2 = ord($val2);
  1331. $val3 = ord($val3);
  1332. $val4 = ord($val4);
  1333. if ($this->MotorolaOrder){
  1334. return (($val1 << 24) | ($val2 << 16) | ($val3 << 8 ) | ($val4 << 0 ));
  1335. }else{
  1336. return (($val4 << 24) | ($val3 << 16) | ($val2 << 8 ) | ($val1 << 0 ));
  1337. }
  1338. }
  1339. /**
  1340. * Converts 4-byte number into its equivalent integer with the help of Get32s
  1341. *
  1342. * @param int
  1343. * @param int
  1344. * @param int
  1345. * @param int
  1346. *
  1347. * @return int
  1348. *
  1349. */
  1350. function get32u($val1,$val2,$val3,$val4) {
  1351. return ($this->Get32s($val1,$val2,$val3,$val4) & 0xffffffff);
  1352. }
  1353. //--------------------------------------------------------------------------
  1354. // Evaluate number, be it int, rational, or float from directory.
  1355. //--------------------------------------------------------------------------
  1356. function ConvertAnyFormat($ValuePtr, $Format)
  1357. {
  1358. $Value = 0;
  1359. switch($Format){
  1360. case FMT_SBYTE: $Value = $ValuePtr[0]; break;
  1361. case FMT_BYTE: $Value = $ValuePtr[0]; break;
  1362. case FMT_USHORT: $Value = $this->Get16u($ValuePtr[0],$ValuePtr[1]); break;
  1363. case FMT_ULONG: $Value = $this->Get32u($ValuePtr[0],$ValuePtr[1],$ValuePtr[2],$ValuePtr[3]); break;
  1364. case FMT_URATIONAL:
  1365. case FMT_SRATIONAL:
  1366. {
  1367. $Num = $this->Get32s($ValuePtr[0],$ValuePtr[1],$ValuePtr[2],$ValuePtr[3]);
  1368. $Den = $this->Get32s($ValuePtr[4],$ValuePtr[5],$ValuePtr[6],$ValuePtr[7]);
  1369. if ($Den == 0){
  1370. $Value = 0;
  1371. }else{
  1372. $Value = (double) ($Num/$Den);
  1373. }
  1374. return array($Value,array($Num,$Den));
  1375. break;
  1376. }
  1377. case FMT_SSHORT: $Value = $this->Get16u($ValuePtr[0],$ValuePtr[1]); break;
  1378. case FMT_SLONG: $Value = $this->Get32s($ValuePtr[0],$ValuePtr[1],$ValuePtr[2],$ValuePtr[3]); break;
  1379. // Not sure if this is correct (never seen float used in Exif format)
  1380. case FMT_SINGLE: $Value = $ValuePtr[0]; break;
  1381. case FMT_DOUBLE: $Value = $ValuePtr[0]; break;
  1382. }
  1383. return $Value;
  1384. }
  1385. /**
  1386. * Function to extract thumbnail from Exif data of the image.
  1387. * and store it in a filename given by $ThumbFile
  1388. *
  1389. * @param String Files name to store the thumbnail
  1390. *
  1391. */
  1392. function saveThumbnail($ThumbFile) {
  1393. $ThumbFile = trim($ThumbFile);
  1394. $file = basename($this->file);
  1395. if(empty($ThumbFile)) $ThumbFile = "th_$file";
  1396. if (!empty($this->ImageInfo["h"]["Thumbnail"])){
  1397. $tp = fopen($ThumbFile,"wb");
  1398. if(!$tp) {
  1399. $this->errno = 2;
  1400. $this->errstr = "Cannot Open file '$ThumbFile'";
  1401. }
  1402. fwrite($tp,$this->ImageInfo["h"]["Thumbnail"]);
  1403. fclose($tp);
  1404. touch($ThumbFile,filemtime($this->file));
  1405. }
  1406. //$this->thumbnailURL = $ThumbFile;
  1407. $this->ImageInfo["h"]["Thumbnail"] = $ThumbFile;
  1408. }
  1409. /**
  1410. * Returns thumbnail url along with parameter supplied.
  1411. * Should be called in src attribute of image
  1412. *
  1413. * @return string File URL
  1414. *
  1415. */
  1416. function showThumbnail() {
  1417. return "showThumbnail.php?file=".$this->file;
  1418. //$this->ImageInfo["h"]["Thumbnail"]
  1419. }
  1420. /**
  1421. * Function to give back thumbail image
  1422. * @return string full image
  1423. *
  1424. */
  1425. function getThumbnail() {
  1426. return $this->ImageInfo["h"]["Thumbnail"];
  1427. }
  1428. /**
  1429. *
  1430. */
  1431. function getImageInfo() {
  1432. $imgInfo = $this->ImageInfo["h"];
  1433. $retArr = $imgInfo;
  1434. $retArr["FileName"] = $imgInfo["FileName"];
  1435. $retArr["FileSize"] = $imgInfo["FileSize"]." bytes";
  1436. $retArr["FileDateTime"] = date("d-M-Y H:i:s",$imgInfo["FileDateTime"]);
  1437. $retArr["resolution"] = $imgInfo["Width"]."x".$imgInfo["Height"];
  1438. if ($this->ImageInfo[TAG_ORIENTATION] > 1){
  1439. // Only print orientation if one was supplied, and if its not 1 (normal orientation)
  1440. // 1 - "The 0th row is at the visual top of the image, and the 0th column is the visual left-hand side."
  1441. // 2 - "The 0th row is at the visual top of the image, and the 0th column is the visual right-hand side."
  1442. // 3 - "The 0th row is at the visual bottom of the image, and the 0th column is the visual right-hand side."
  1443. // 4 - "The 0th row is at the visual bottom of the image, and the 0th column is the visual left-hand side."
  1444. // 5 - "The 0th row is the visual left-hand side of of the image, and the 0th column is the visual top."
  1445. // 6 - "The 0th row is the visual right-hand side of of the image, and the 0th column is the visual top."
  1446. // 7 - "The 0th row is the visual right-hand side of of the image, and the 0th column is the visual bottom."
  1447. // 8 - "The 0th row is the visual left-hand side of of the image, and the 0th column is the visual bottom."
  1448. // Note: The descriptions here are the same as the name of the command line
  1449. // ption to pass to jpegtran to right the image
  1450. $OrientTab = array(
  1451. "Undefined",
  1452. "Normal", // 1
  1453. "flip horizontal", // left right reversed mirror
  1454. "rotate 180", // 3
  1455. "flip vertical", // upside down mirror
  1456. "transpose", // Flipped about top-left <--> bottom-right axis.
  1457. "rotate 90", // rotate 90 cw to right it.
  1458. "transverse", // flipped about top-right <--> bottom-left axis
  1459. "rotate 270", // rotate 270 to right it.
  1460. );
  1461. $retArr["orientation"] = $OrientTab[$this->ImageInfo[TAG_ORIENTATION]];
  1462. }
  1463. $retArr["color"] = ($imgInfo["IsColor"] == 0) ? "Black and white" : "Color";
  1464. if(isset($imgInfo["Process"])) {
  1465. switch($imgInfo["Process"]) {
  1466. case M_SOF0: $process = "Baseline";break;
  1467. case M_SOF1: $process = "Extended sequential";break;
  1468. case M_SOF2: $process = "Progressive";break;
  1469. case M_SOF3: $process = "Lossless";break;
  1470. case M_SOF5: $process = "Differential sequential";break;
  1471. case M_SOF6: $process = "Differential progressive";break;
  1472. case M_SOF7: $process = "Differential lossless";break;
  1473. case M_SOF9: $process = "Extended sequential, arithmetic coding";break;
  1474. case M_SOF10: $process = "Progressive, arithmetic coding";break;
  1475. case M_SOF11: $process = "Lossless, arithmetic coding";break;
  1476. case M_SOF13: $process = "Differential sequential, arithmetic coding";break;
  1477. case M_SOF14: $process = "Differential progressive, arithmetic coding";break;
  1478. case M_SOF15: $process = "Differential lossless, arithmetic coding";break;
  1479. default: $process = "Unknown";
  1480. }
  1481. $retArr["jpegProcess"] = $process;
  1482. }
  1483. if(file_exists($this->thumbnailURL)) {
  1484. $retArr["Thumbnail"] = "<a href='$this->thumbnailURL'>$this->thumbnailURL</a>";
  1485. }
  1486. return $retArr;
  1487. }
  1488. /**
  1489. *
  1490. */
  1491. function string_format($str) {
  1492. $tmpStr = "";
  1493. for($i=0;$i<strlen($str);$i++) {
  1494. if(ord($str[$i]) !=0) {
  1495. $tmpStr .= $str[$i];
  1496. }
  1497. }
  1498. return $tmpStr;
  1499. }
  1500. /**
  1501. * Returns time in microseconds
  1502. */
  1503. function getmicrotime(){
  1504. list($usec, $sec) = explode(" ",microtime());
  1505. return ((float)$usec + (float)$sec);
  1506. }
  1507. /**
  1508. * Get the time difference
  1509. */
  1510. function getDiffTime() {
  1511. return ($this->getmicrotime() - $this->timeStart);
  1512. }
  1513. } // end of class
  1514. ?>