source: spip-zone/_plugins_/metadonnees_photo/inc/exifReader.php @ 34889

Last change on this file since 34889 was 34889, checked in by arno@…, 11 years ago

Suppression des ereg.

File size: 74.0 KB
Line 
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
20        - Sony
21            - Cybershot (Sony)
22            - DSC-D700
23            - PowerShotA5
24                        - Sony P71
25        - SANYO Electric Co.,Ltd
26            - SR6
27            - SX113
28        - OLYMPUS OPTICAL CO.,LTD
29            - C960Z, D460Z
30                        - C3000Z
31        - Canon
32            PowerShot A40 (Canon)
33            Canon DIGITAL IXUS
34                        Canon 300D
35        - RICOH
36            - Caplio RR30
37            - RDC-5300
38        - NIKON
39            - D100 (NIKON CORPORATION)
40            - E5700 (NIKON)
41            - E950
42        - CASIO QV-8000SX
43        - KODAK
44            - DC290 Zoom Digital Camera (V01.00) [Eastman Kodak Company]
45            - DC210 Zoom (V05.00) [Eastman Kodak Company]
46            - KODAK DC240 ZOOM DIGITAL CAMERA
47        - FujiFilm
48            DX10
49            FinePix40i
50            MX-1700ZOOM
51 *
52 *
53 */
54
55/** * Start Of Frame N */
56define("M_SOF0",0xC0);
57/** * N indicates which compression process */
58define("M_SOF1",0xC1);
59/** * Only SOF0-SOF2 are now in common use */
60define("M_SOF2",0xC2);
61/** *  */
62define("M_SOF3",0xC3);
63/** * NB: codes C4 and CC are NOT SOF markers */
64define("M_SOF5",0xC5);
65/** *  */
66define("M_SOF6",0xC6);
67/** *  */
68define("M_SOF7",0xC7);
69/** *  */
70define("M_SOF9",0xC9);
71/** *  */
72define("M_SOF10",0xCA);
73/** *  */
74define("M_SOF11",0xCB);
75/** *  */
76define("M_SOF13",0xCD);
77/** *  */
78define("M_SOF14",0xCE);
79/** *  */
80define("M_SOF15",0xCF);
81/** * Start Of Image (beginning of datastream) */
82define("M_SOI",0xD8);
83/** * End Of Image (end of datastream) */
84define("M_EOI",0xD9);
85/** * Start Of Scan (begins compressed data) */
86define("M_SOS",0xDA);
87/** * Jfif marker */
88define("M_JFIF",0xE0);
89/** * Exif marker */
90define("M_EXIF",0xE1);
91
92define("M_EXIF_EXT",0xE2); // 226 - Exif Extended Data
93define("M_QUANTA",0xDB); // 219 - Quantisation Table Definition
94define("M_HUFF",0xC4); // (DEC=196) - Huffman Table Definition
95/** * Image Title -- */
96define("M_COM",0xFE);
97
98define("NUM_FORMATS","12");
99
100/** * Tag Data Format */
101define("FMT_BYTE","1");
102/** * ASCII */
103define("FMT_STRING","2");
104/** * Short */
105define("FMT_USHORT","3");
106/** * Long */
107define("FMT_ULONG","4");
108/** * Rational */
109define("FMT_URATIONAL","5");
110/** * Byte */
111define("FMT_SBYTE","6");
112/** * Undefined */
113define("FMT_UNDEFINED","7");
114/** * Short */
115define("FMT_SSHORT","8");
116/** * Long */
117define("FMT_SLONG","9");
118/** * Rational */
119define("FMT_SRATIONAL","10");
120/** * Single */
121define("FMT_SINGLE","11");
122/** * Double */
123define("FMT_DOUBLE","12");
124
125/** * Exif IFD */
126define("TAG_EXIF_OFFSET","0x8769");
127/** * Interoperability tag */
128define("TAG_INTEROP_OFFSET","0xa005");
129/** * Image input equipment manufacturer */
130define("TAG_MAKE","0x010F");
131/** * Image input equipment model */
132define("TAG_MODEL","0x0110");
133/** * Orientation of image */
134define("TAG_ORIENTATION","0x0112");
135/** * Exposure Time */
136define("TAG_EXPOSURETIME","0x829A");
137/** * F Number */
138define("TAG_FNUMBER","0x829D");
139/** * Shutter Speed */
140define("TAG_SHUTTERSPEED","0x9201");
141/** * Aperture */
142define("TAG_APERTURE","0x9202");
143/** * Aperture */
144define("TAG_MAXAPERTURE","0x9205");
145/** * Lens Focal Length */
146define("TAG_FOCALLENGTH","0x920A");
147/** * The date and time when the original image data was generated. */
148define("TAG_DATETIME_ORIGINAL","0x9003");
149/** * User Comments */
150define("TAG_USERCOMMENT","0x9286");
151/** * subject Location */
152define("TAG_SUBJECT_DISTANCE","0x9206");
153/** * Flash */
154define("TAG_FLASH","0x9209");
155/** * Focal Plane X Resolution */
156define("TAG_FOCALPLANEXRES","0xa20E");
157/** * Focal Plane Resolution Units */
158define("TAG_FOCALPLANEUNITS","0xa210");
159/** * Image Width */
160define("TAG_EXIF_IMAGEWIDTH","0xA002");
161/** * Image Height */
162define("TAG_EXIF_IMAGELENGTH","0xA003");
163/** * Exposure Bias */
164define("TAG_EXPOSURE_BIAS","0x9204");
165/** * Light Source */
166define("TAG_WHITEBALANCE","0x9208");
167/** * Metering Mode */
168define("TAG_METERING_MODE","0x9207");
169/** * Exposure Program */
170define("TAG_EXPOSURE_PROGRAM","0x8822");
171/** * ISO Equivalent Speed Rating */
172define("TAG_ISO_EQUIVALENT","0x8827");
173/** * Compressed Bits Per Pixel */
174define("TAG_COMPRESSION_LEVEL","0x9102");
175/** * Thumbnail Start Offset */
176define("TAG_THUMBNAIL_OFFSET","0x0201");
177/** * Thumbnail Length */
178define("TAG_THUMBNAIL_LENGTH","0x0202");
179/** * Image Marker */
180define("PSEUDO_IMAGE_MARKER",0x123);
181/** * Max Image Title Length */
182define("MAX_COMMENT",2000);
183
184define("TAG_ARTIST","0x013B");
185define("TAG_COPYRIGHT","0x8298");
186
187//--------------------------------
188
189define("TAG_IMAGE_WD","0x0100"); // image width
190define("TAG_IMAGE_HT","0x0101"); // image height
191define("TAG_IMAGE_BPS","0x0102"); // Bits Per sample
192
193define("TAG_IMAGE_PHOTO_INT","0x0106"); // photometricinterpretation
194define("TAG_IMAGE_SOFFSET","0x0111"); // stripoffsets
195
196define("TAG_IMAGE_SPP","0x0115"); // Samples per pixel - 277
197define("TAG_IMAGE_RPS","0x0116"); // RowsPerStrip - 278
198define("TAG_IMAGE_SBC","0x0117"); // StripByteCounts - 279
199
200define("TAG_IMAGE_P_CONFIG","0x011C"); // Planar Configuration - 284
201
202define("TAG_IMAGE_DESC","0x010E"); // image title
203define("TAG_X_RESOLUTION","0x011A"); // Image resolution in width direction
204define("TAG_Y_RESOLUTION","0x011B"); // Image resolution in height direction
205define("TAG_RESOLUTION_UNIT","0x0128"); // Unit of X and Y resolution
206define("TAG_SOFTWARE","0x0131"); // Software used
207define("TAG_FILE_MODDATE","0x0132"); // DateTime File change date and time
208define("TAG_YCBCR_POSITIONING","0x0213"); // Y and C positioning
209define("TAG_EXIF_VERSION","0x9000"); // Exif version
210define("TAG_DATE_TIME_DIGITIZED","0x9004"); // Date and time of digital data
211define("TAG_COMPONENT_CONFIG","0x9101"); // Component configuration
212define("TAG_MAKER_NOTE","0x927C");
213define("TAG_SUB_SEC_TIME","0x9290");
214define("TAG_SUB_SEC_TIME_ORIG","0x9291");
215define("TAG_SUB_SEC_TIME_DIGITIZED","0x9292");
216define("TAG_FLASHPIX_VER","0xA000"); //FlashPixVersion
217define("TAG_COLOR_SPACE","0xA001"); //ColorSpace
218define("TAG_RELATED_SOUND_FILE","0xA004"); //Related audio file
219
220define("TAG_GPS_LATITUDE_REF","0x0001"); //
221define("TAG_GPS_LATITUDE","0x0002"); //
222
223define("TAG_GPS_LONGITUDE_REF","0x0003"); //
224define("TAG_GPS_LONGITUDE","0x0004"); //
225
226define("TAG_GPS_TrackRef","0x000E"); //
227define("TAG_GPS_GPSTrack","0x000F"); //
228define("TAG_GPS_GPSImgDirectionRef","0x0010"); //
229define("TAG_GPS_GPSImgDirection","0x0011"); //
230define("TAG_GPS_GPSMapDatum","0x0012"); //
231define("TAG_GPS_GPSDestLatitudeRef","0x0013"); //
232define("TAG_GPS_GPSDestLatitude","0x0014"); //
233define("TAG_GPS_GPSDestLongitudeRef","0x0015"); //
234define("TAG_GPS_GPSDestLongitude","0x0016"); //
235define("TAG_GPS_GPSDestBearingRef","0x0017"); //
236define("TAG_GPS_GPSDestBearing","0x0018"); //
237define("TAG_GPS_GPSDestDistanceRef","0x0019"); //
238define("TAG_GPS_GPSDestDistance","0x001A"); //
239define("TAG_GPS_GPSProcessingMethod","0x001B"); //
240define("TAG_GPS_GPSAreaInformation","0x001C"); //
241define("TAG_GPS_GPSDateStamp","0x001D"); //
242define("TAG_GPS_GPSDifferential","0x001E"); //
243
244define("TAG_AUDIO_IMA_ADPCM_DESC","0x0028"); //  IMA-ADPCM Audio File Description Example - 40
245define("TAG_AUDIO_MU_LAW_DESC","0x0032"); //  µ-Law Audio File Description Sample - 50
246
247define("TAG_AUDIO_MU_LAW","0x0086"); // (This File µ-LAW Sample) - 134
248
249
250define("TAG_EXPOSURE_INDEX","0xA215"); // Exposure index
251
252define("TAG_SENSING_METHOD","0xA217"); // SensingMethod
253
254define("TAG_SOUCE_TYPE","0xA300"); // FileSource
255define("TAG_SCENE_TYPE","0xA301"); // SceneType
256
257define("TAG_CFA_PATTERN","0xA302"); // CFA Pattern
258
259/** Tags in EXIF 2.2 Only */
260define("TAG_COMPRESS_SCHEME","0x0103"); //
261define("TAG_CUSTOM_RENDERED","0xA401"); //  CustomRendered
262define("TAG_EXPOSURE_MODE","0xA402"); // Exposure mode      ExposureMode
263define("TAG_WHITE_BALANCE","0xA403"); // White balance      WhiteBalance
264define("TAG_DIGITAL_ZOOM_RATIO","0xA404"); // Digital zoom ratio      DigitalZoomRatio
265define("TAG_FLENGTH_IN35MM","0xA405"); // Focal length in 35 mm film      FocalLengthIn35mmFilm
266define("TAG_SCREEN_CAP_TYPE","0xA406"); // Scene capture type      SceneCaptureType
267define("TAG_GAIN_CONTROL","0xA407"); //Gain control
268define("TAG_CONTRAST","0xA408"); // Contrast
269define("TAG_SATURATION","0xA409"); // Saturation
270define("TAG_SHARPNESS","0xA40A"); // Sharpness
271define("TAG_DEVICE_SETTING_DESC","0xA40B"); // SDevice settings description      DeviceSettingDescription
272define("TAG_DIST_RANGE","0xA40C"); //Subject distance range SubjectDistanceRange
273
274define("TAG_FOCALPLANE_YRESOL","0xA20F");; //FocalPlaneYResolution
275define("TAG_BRIGHTNESS","0x9203");; //Brightness
276
277define("TAG_EXTEND_LENS","0xFDEA"); // Extend lens model
278
279
280//--------------------------------
281/** error Description  */
282/**
283  1 - File does not exists!
284  2 -
285  3 - Filename not provided
286
287  10 - too many padding bytes
288  11 - "invalid marker"
289  12 - Premature end of file?
290
291
292  51 - "Illegal subdirectory link"
293  52 - "NOT EXIF FORMAT"
294  53 - "Invalid Exif alignment marker.\n"
295  54 - "Invalid Exif start (1)"
296
297*/
298
299
300/**
301 * PHP Class to read, write and transfer EXIF information
302 * that most of the digital camera produces
303 * Currenty it can only read JPEG file.
304 */
305 /**
306 * @author Vinay Yadav (vinayRas) < vinay@sanisoft.com >
307 *
308 * @todo Writing exif information to the file.
309 * @todo Add EXIF audio reading methods (I think it exists!)
310 * @todo Support of additional tags.
311 * @todo Handling Unicode character in UserComment tag of EXif Information.
312 *
313 * @version 0.5
314 * @licence http://opensource.org/licenses/lgpl-license.php GNU LGPL
315 */
316class phpExifReader {
317
318    /***
319    * Array containg all Exif and JPEG image attributes
320    * into regular expressions for themselves.
321    * $ImageInfo[TAG] = TAG_VALUE;
322    *
323    * @var       array
324    * @access    private
325    *
326    */
327    var $ImageInfo = array();
328
329    var $MotorolaOrder = 0;
330    var $ExifImageWidth = 0; //
331    var $FocalplaneXRes = 0; //
332    var $FocalplaneUnits = 0; //
333    var $sections = array();
334    var $currSection = 0;  /** Stores total number fo Sections */
335
336    var $BytesPerFormat = array(0,1,1,2,4,8,1,1,2,4,8,4,8);
337
338    var $ReadMode = array(
339                            "READ_EXIF" => 1,
340                            "READ_IMAGE" => 2,
341                            "READ_ALL" => 3
342                        );
343
344    var $ImageReadMode = 3; /** related to $RealMode arrays values */
345    var $file =  "";     /** JPEG file to parse for EXIF data */
346    var $newFile = 1;   /** flag to check if the current file has been parsed or not. */
347
348    var $thumbnail = ""; /* Name of thumbnail */
349    var $thumbnailURL = ""; /* */
350
351    var $exifSection = -1;   // market the exif section index oout of all sections
352
353    var $errno = 0;
354    var $errstr = "";
355
356    var $debug = false;
357
358    // Caching ralated variables
359    var $caching = false; /* Should cacheing of image thumnails be allowed? */
360    var $cacheDir = ""; /* Checkout constructor for default path. */
361
362    /**
363     * Constructor
364     * @param string File name to be parsed.
365     *
366     */
367    function phpExifReader($file = "") {
368      $this->timeStart = $this->getmicrotime();
369      if(!empty($file)) {
370        $this->file = $file;
371      }
372
373      /**
374      * Initialize some variables. Avoid lots of errors with fulll error_reporting
375      */
376      $this->ExifImageLength       = 0;
377      $this->ImageInfo['h']["resolutionUnit"] = 0;
378
379      $this->ImageInfo[TAG_MAXAPERTURE] = 0;
380      $this->ImageInfo[TAG_ISO_EQUIVALENT] = 0;
381      $this->ImageInfo[TAG_ORIENTATION] = 0;
382
383      $this->ThumbnailSize = 0;
384
385      if($this->caching) {
386        $this->cacheDir = dirname(__FILE__)."/.cache_thumbs";
387
388        /**
389        * If Cache directory does not exists then attempt to create it.
390        */
391        if(!is_dir($this->cacheDir)) {
392             mkdir($this->cacheDir);
393        }
394
395          // Prepare the ame of thumbnail
396          if(is_dir($this->cacheDir)) {
397            $this->thumbnail = $this->cacheDir."/".basename($this->file);
398            $this->thumbnailURL = ".cache_thumbs/".basename($this->file);
399          }
400      }
401
402      /** check if file exists! */
403      if(!file_exists($this->file)) {
404         $this->errno = 1;
405         $this->errstr = "File '".$this->file."' does not exists!";
406      }
407      $this->currSection = 0;
408
409      $this->processFile();
410    }
411
412    /**
413     * Show Debugging information
414     *
415     * @param   string     Debugging message to display
416     * @param   int   Type of error (0 - Warning, 1 - Error)
417     * @return    void
418     *
419     */
420    function debug($str,$TYPE = 0,$file="",$line=0) {
421       if($this->debug) {
422        echo "<br>[$file:$line:".($this->getDiffTime())."]$str";
423        flush();
424        if($TYPE == 1) {
425           exit;
426        }
427       }
428    }
429
430    /**
431     * Processes the whole file.
432     *
433     */
434    function processFile() {
435        /** dont reparse the whole file. */
436        if(!$this->newFile) return true;
437       
438        if(!file_exists($this->file)) {
439            echo "<br>Error: File ".($this->file)."does not exists!";
440            exit;
441        }
442
443        $this->debug("Stating Processing of ".$this->newFile,0,__FILE__,__LINE__);
444
445        $i = 0; $exitAll = 0;
446        /** Open the JPEG in binary safe reading mode */
447        $fp = fopen($this->file,"rb");
448
449        $this->ImageInfo["h"]["FileName"] = $this->file;
450        $this->ImageInfo["h"]["FileSize"] = filesize($this->file); /** Size of the File */
451        $this->ImageInfo["h"]["FileDateTime"] = filectime($this->file); /** File node change time */
452
453        /** check whether jped image or not */
454        $a = fgetc($fp);
455        if (ord($a) != 0xff || ord(fgetc($fp)) != M_SOI){
456                $this->debug("Not a JPEG FILE",1);
457                $this->errorno = 1;
458                $this->errorstr = "File '".$this->file."' is not a JPEG File!";
459        }
460        $tmpTestLevel = 0;
461        /** Examines each byte one-by-one */
462        while(!feof($fp)) {
463            $data = array();
464                for ($a=0;$a<7;$a++){
465                        $marker = fgetc($fp);
466                        if (ord($marker) != 0xff) break;
467                        if ($a >= 6){
468                                $this->errno = 10;
469                                $this->errstr = "too many padding bytes!";
470                                $this->debug($this->errstr,1);
471                                return false;
472                        }
473                }
474
475                if (ord($marker) == 0xff){
476                    // 0xff is legal padding, but if we get that many, something's wrong.
477                    $this->errno = 10;
478                    $this->errstr = "too many padding bytes!";
479                    $this->debug($this->errstr,1);
480                }
481
482        $marker = ord($marker);
483        $this->sections[$this->currSection]["type"] = $marker;
484
485        // Read the length of the section.
486        $lh = ord(fgetc($fp));
487        $ll = ord(fgetc($fp));
488
489        $itemlen = ($lh << 8) | $ll;
490
491        if ($itemlen < 2){
492                $this->errno = 11;
493                $this->errstr = "invalid marker";
494                $this->debug($this->errstr,1);
495        }
496        $this->sections[$this->currSection]["size"] = $itemlen;
497
498        $tmpDataArr = array();  /** Temporary Array */
499
500        $tmpStr = fread($fp,$itemlen-2);
501        /*
502        $tmpDataArr[] = chr($lh);
503        $tmpDataArr[] = chr($ll);
504
505        $chars = preg_split('//', $tmpStr, -1, PREG_SPLIT_NO_EMPTY);
506        $tmpDataArr = array_merge($tmpDataArr,$chars);
507
508        $data = $tmpDataArr;
509        */
510        $data = chr($lh).chr($ll).$tmpStr;
511
512        //$this->sections[$this->currSection]["data"] = $data;
513
514        $this->debug("<hr><h1>".$this->currSection.":</h1>");
515        //print_r($data);
516        $this->debug("<hr>");
517
518        //if(count($data) != $itemlen) {
519        if(strlen($data) != $itemlen) {
520            $this->errno = 12;
521            $this->errstr = "Premature end of file?";
522            $this->debug($this->errstr,1);
523        }
524
525        $this->currSection++; /** */
526               
527        switch($marker) {
528                case M_SOS:
529                    $this->debug("<br>Found '".M_SOS."' Section, Prcessing it... <br>");;
530                        // If reading entire image is requested, read the rest of the data.
531                        if ($this->ImageReadMode & $this->ReadMode["READ_IMAGE"]){
532                        // Determine how much file is left.
533                                $cp = ftell($fp);
534                                fseek($fp,0, SEEK_END);
535                                $ep = ftell($fp);
536                                fseek($fp, $cp, SEEK_SET);
537
538                        $size = $ep-$cp;
539                        $got = fread($fp, $size);
540
541                        $this->sections[$this->currSection]["data"] = $got;
542                        $this->sections[$this->currSection]["size"] = $size;
543                        $this->sections[$this->currSection]["type"] = PSEUDO_IMAGE_MARKER;
544                        $this->currSection++;
545                        $HaveAll = 1;
546                        $exitAll =1;
547                        }
548                        $this->debug("<br>'".M_SOS."' Section, PROCESSED<br>");
549                    break;
550                case M_COM: // Comment section
551                        $this->debug("<br>Found '".M_COM."'(Comment) Section, Processing<br>");
552                        $this->process_COM($data, $itemlen);
553                        $this->debug("<br>'".M_COM."'(Comment) Section, PROCESSED<br>");
554
555                        $tmpTestLevel++;
556                    break;
557                case M_SOI:
558                        $this->debug(" <br> === START OF IMAGE =====<br>");
559                break;
560                case M_EOI:
561                        $this->debug(" <br>=== END OF IMAGE =====<br> ");
562                break;
563                case M_JFIF:
564                        // Regular jpegs always have this tag, exif images have the exif
565                        // marker instead, althogh ACDsee will write images with both markers.
566                        // this program will re-create this marker on absence of exif marker.
567                        // hence no need to keep the copy from the file.
568                        //echo " <br> === M_JFIF =====<br>";
569                        $this->sections[--$this->currSection]["data"] = "";
570                        break;
571                case M_EXIF:
572                        // Seen files from some 'U-lead' software with Vivitar scanner
573                        // that uses marker 31 for non exif stuff.  Thus make sure
574                        // it says 'Exif' in the section before treating it as exif.
575                        $this->debug("<br>Found '".M_EXIF."'(Exif) Section, Proccessing<br>");
576                        $this->exifSection = $this->currSection-1;
577                        if (($this->ImageReadMode & $this->ReadMode["READ_EXIF"]) && ($data[2].$data[3].$data[4].$data[5]) == "Exif"){
578                                $this->process_EXIF($data, $itemlen);
579                        }else{
580                                // Discard this section.
581                                $this->sections[--$this->currSection]["data"] = "";
582                        }
583                        $this->debug("<br>'".M_EXIF."'(Exif) Section, PROCESSED<br>");
584                        $tmpTestLevel++;
585                break;
586                case M_SOF0:
587                case M_SOF1:
588                case M_SOF2:
589                case M_SOF3:
590                case M_SOF5:
591                case M_SOF6:
592                case M_SOF7:
593                case M_SOF9:
594                case M_SOF10:
595                case M_SOF11:
596                case M_SOF13:
597                case M_SOF14:
598                case M_SOF15:
599                        $this->debug("<br>Found M_SOFn Section, Processing<br>");
600                        $this->process_SOFn($data,$marker);
601                        $this->debug("<br>M_SOFn Section, PROCESSED<br>");
602                break;
603                                case M_EXIF_EXT: // 226 - Exif Extended Data
604                                    $this->debug("<br><b>Found 'Exif Extended Data' Section, Processing</b><br>-------------------------------<br>");
605                    $this->process_EXT_EXIF($data, $itemlen);
606                                        $this->debug("<br>--------------------------PROCESSED<br>");
607                                        break;
608
609                                case M_QUANTA: // 219 - Quantisation Table Definition
610                                    $this->debug("<br><b>Found 'Quantisation Table Definition' Section, Processing</b><br>-------------------------------<br>");
611                                        $this->debug("<br>--------------------------PROCESSED<br>");
612                                        break;
613
614                                case M_HUFF: // Huffman Table
615                                    $this->debug("<br><b>Found 'Huffman Table' Section, Processing</b><br>-------------------------------<br>");
616                                        $this->debug("<br>--------------------------PROCESSED<br>");
617                                        break;
618
619                default:
620                        $this->debug("DEFAULT: Jpeg section marker 0x$marker x size $itemlen\n");
621        }
622        $i++;
623        if($exitAll == 1)  break;
624            //if($tmpTestLevel == 2)  break;
625        }
626        fclose($fp);
627        $this->newFile = 0;
628    }
629
630    /**
631     * Changing / Assiging new file
632     * @param   string    JPEG file to process
633     *
634     */
635    function assign($file) {
636
637      if(!empty($file)) {
638        $this->file = $file;
639      }
640
641      /** check for existance of file! */
642      if(!file_exists($this->file)) {
643         $this->errorno = 1;
644         $this->errorstr = "File '".$this->file."' does not exists!";
645      }
646      $this->newFile = 1;
647    }
648
649    /**
650     * Process SOFn section of Image
651     * @param  array    An array containing whole section.
652     * @param   hex  Marker to specify the type of section.
653     *
654     */
655    function process_SOFn($data,$marker) {
656        $data_precision = 0;
657        $num_components = 0;
658
659        $data_precision = ord($data[2]);
660
661        if($this->debug) {
662          print("Image Dimension Calculation:");
663          print("((ord($data[3]) << 8) | ord($data[4]));");
664        }
665        $this->ImageInfo["h"]["Height"] = ((ord($data[3]) << 8) | ord($data[4]));
666        $this->ImageInfo["h"]["Width"] = ((ord($data[5]) << 8) | ord($data[6]));
667
668        $num_components = ord($data[7]);
669
670        if ($num_components == 3){
671            $this->ImageInfo["h"]["IsColor"] = 1;
672        }else{
673            $this->ImageInfo["h"]["IsColor"] = 0;
674        }
675
676        $this->ImageInfo["h"]["Process"] = $marker;
677        $this->debug("JPEG image is ".$this->ImageInfo["h"]["Width"]." * ".$this->ImageInfo["h"]["Height"].", $num_components color components, $data_precision bits per sample\n");
678    }
679
680    /**
681     * Process Comments
682     * @param   array    Section data
683     * @param   int  Length of the section
684     *
685     */
686    function process_COM($data,$length) {
687        if ($length > MAX_COMMENT) $length = MAX_COMMENT;
688            /** Truncate if it won't fit in our structure. */
689
690        $nch = 0; $Comment = "";
691        for ($a=2;$a<$length;$a++){
692            $ch = $data[$a];
693            if ($ch == '\r' && $data[$a+1] == '\n') continue; // Remove cr followed by lf.
694
695            $Comment .= $ch;
696        }
697        //$this->ImageInfo[M_COM] = $Comment;
698        $this->ImageInfo["h"]["imageComment"] = $this->string_format($Comment);
699        $this->debug("COM marker comment: $Comment\n");
700    }
701    /**
702     * Process one of the nested EXIF directories.
703     * @param   string        All directory information
704     * @param   string     whole Section
705     * @param   int  Length of exif section
706     *
707    */
708    function ProcessExifDir($DirStart, $OffsetBase, $ExifLength) {
709
710        $NumDirEntries = 0;
711        $ValuePtr = array();
712
713        $NumDirEntries = $this->Get16u($DirStart[0],$DirStart[1]);
714
715
716        $this->debug("<br>Directory with $NumDirEntries entries\n");
717
718        for ($de=0;$de<$NumDirEntries;$de++){
719            //$DirEntry = array_slice($DirStart,2+12*$de);
720            $DirEntry = substr($DirStart,2+12*$de);
721
722            $Tag = $this->Get16u($DirEntry[0],$DirEntry[1]);
723            $Format = $this->Get16u($DirEntry[2],$DirEntry[3]);
724            $Components = $this->Get32u($DirEntry[4],$DirEntry[5],$DirEntry[6],$DirEntry[7]);
725
726            /**
727            if ((Format-1) >= NUM_FORMATS) {
728                // (-1) catches illegal zero case as unsigned underflows to positive large.
729                ErrNonfatal("Illegal number format %d for tag %04x", Format, Tag);
730                continue;
731            }
732            */
733
734            $ByteCount = $Components * $this->BytesPerFormat[$Format];
735
736            if ($ByteCount > 4){
737                $OffsetVal = $this->Get32u($DirEntry[8],$DirEntry[9],$DirEntry[10],$DirEntry[11]);
738                if ($OffsetVal+$ByteCount > $ExifLength){
739                    $this->debug("Illegal value pointer($OffsetVal) for tag $Tag",1);
740                }
741                //$ValuePtr = array_slice($OffsetBase,$OffsetVal);
742                $ValuePtr = substr($OffsetBase,$OffsetVal);
743            } else {
744                //$ValuePtr = array_slice($DirEntry,8);
745                $ValuePtr = substr($DirEntry,8);
746            }
747                       
748
749            switch($Tag){
750                case TAG_MAKE:
751
752                    $this->ImageInfo["h"]["make"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
753                                        $this->ImageInfo['h']["make"] = trim(strtoupper($this->ImageInfo['h']["make"]));
754                        $this->ImageInfo["h"]["make"] = str_replace("NIKON CORPORATION", "NIKON", $this->ImageInfo["h"]["make"]);
755                        $this->ImageInfo["h"]["make"] = str_replace("OLYMPUS IMAGING CORP.", "OLYMPUS", $this->ImageInfo["h"]["make"]);
756                        $this->ImageInfo["h"]["make"] = str_replace("OLYMPUS OPTICAL CO.,LTD", "OLYMPUS", $this->ImageInfo["h"]["make"]);
757                        $this->ImageInfo["h"]["make"] = str_replace("OLYMPUS CORPORATION", "OLYMPUS", $this->ImageInfo["h"]["make"]);
758                        $this->ImageInfo["h"]["make"] = str_replace("PENTAX CORPORATION", "PENTAX", $this->ImageInfo["h"]["make"]);
759                        $this->ImageInfo["h"]["make"] = str_replace("SANYO ELECTRIC CO.,Ltd.", "SANYO", $this->ImageInfo["h"]["make"]);
760                        $this->ImageInfo["h"]["make"] = str_replace("CASIO COMPUTER CO.,LTD", "CASIO", $this->ImageInfo["h"]["make"]);
761                        $this->ImageInfo["h"]["make"] = str_replace("CASIO.", "CASIO", $this->ImageInfo["h"]["make"]);
762                        $this->ImageInfo["h"]["make"] = str_replace("KONICA MINOLTA CAMERA, INC.", "KONICA MINOLTA", $this->ImageInfo["h"]["make"]);
763                        $this->ImageInfo["h"]["make"] = str_replace("EASTMAN KODAK COMPANY", "KODAK", $this->ImageInfo["h"]["make"]);
764                        $this->ImageInfo["h"]["make"] = str_replace("PHASE ONE A/S", "PHASE ONE", $this->ImageInfo["h"]["make"]);
765                        $this->ImageInfo["h"]["make"] = str_replace("HASSELBLAD/IMACON", "HASSELBLAD", $this->ImageInfo["h"]["make"]);
766                        $this->ImageInfo["h"]["make"] = str_replace("SONY COMPUTER ENTERTAINMENT INC.", "SONY", $this->ImageInfo["h"]["make"]);
767                        $this->ImageInfo["h"]["make"] = str_replace("SAMSUNG TECHWIN CO.", "SAMSUNG", $this->ImageInfo["h"]["make"]);
768                        $this->ImageInfo["h"]["make"] = str_replace("SAMSUNG TECHWIN", "SAMSUNG", $this->ImageInfo["h"]["make"]);
769               
770                        break;
771
772                case TAG_MODEL:
773                    $this->ImageInfo["h"]["model"] = strtoupper($this->string_format(substr($ValuePtr,0,$ByteCount)));
774                    break;
775                   
776                case TAG_EXTEND_LENS:
777                        break;
778
779
780                case TAG_DATETIME_ORIGINAL:
781                    $this->ImageInfo[TAG_DATETIME_ORIGINAL] =  $this->string_format(substr($ValuePtr,0,$ByteCount));
782                    $this->ImageInfo["h"]["DateTime"]  = $this->string_format(substr($ValuePtr,0,$ByteCount));
783                    break;
784
785                case TAG_USERCOMMENT:
786                    // Olympus has this padded with trailing spaces.  Remove these first.
787                    for ($a=$ByteCount;;){
788                        $a--;
789                        if ($ValuePtr[$a] == ' '){
790                            //$ValuePtr[$a] = '\0';
791                        } else {
792                            break;
793                        }
794                        if ($a == 0) break;
795                    }
796
797                    // Copy the comment
798                    if (($ValuePtr[0].$ValuePtr[1].$ValuePtr[2].$ValuePtr[3].$ValuePtr[4]) == "ASCII"){
799                        for ($a=5;$a<10;$a++){
800                            $c = $ValuePtr[$a];
801                            if ($c != '\0' && $c != ' '){
802                                $tmp = substr($ValuePtr,0,$ByteCount);
803                                    break;
804                            }
805                        }
806                    } else if (($ValuePtr[0].$ValuePtr[1].$ValuePtr[2].$ValuePtr[3].$ValuePtr[4].$ValuePtr[5].$ValuePtr[6]) == "Unicode"){
807                        $tmp = substr($ValuePtr,0,$ByteCount);
808                        //  * Handle Unicode characters here...
809                    } else {
810                        //$this->ImageInfo[TAG_USERCOMMENT] = implode("",array_slice($ValuePtr,0,$ByteCount));
811                        $tmp = substr($ValuePtr,0,$ByteCount);
812                    }
813                    $this->ImageInfo['h']["exifComment"] = $this->string_format($tmp);
814                    break;
815
816                                case TAG_ARTIST:
817                    $this->ImageInfo['h']["artist"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
818                                        break;
819
820                                case TAG_COPYRIGHT:
821                    $this->ImageInfo['h']["copyright"] = htmlentities(substr($ValuePtr,0,$ByteCount));
822                                        break;
823
824                case TAG_FNUMBER:
825                    // Simplest way of expressing aperture, so I trust it the most.
826                    // (overwrite previously computd value if there is one)
827                    $tmp = $this->ConvertAnyFormat(substr($ValuePtr,0), $Format);
828                    $this->ImageInfo['h']["fnumber"] = round(10 * sprintf("%3.1f",(double)$tmp[0])) / 10;
829                    break;
830
831//                case TAG_APERTURE:
832                case TAG_MAXAPERTURE:
833                    // More relevant info always comes earlier, so only use this field if we don't
834                    // have appropriate aperture information yet.
835                    if (!isset($this->ImageInfo['h']["aperture"])){
836                        $tmpArr =  $this->ConvertAnyFormat($ValuePtr, $Format);
837                        $this->ImageInfo['h']["maxAperture"] = round(10 * exp($tmpArr[0]*log(2)*0.5)) / 10;
838                    }
839                    break;
840
841                case TAG_FOCALLENGTH:
842                    // Nice digital cameras actually save the focal length as a function
843                    // of how farthey are zoomed in.
844                    $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
845//                    print_r($tmp);
846                    $this->ImageInfo['h']["focalLength"] = round(sprintf("%4.2f",(double)$tmp[0],$tmp[1][0],$tmp[1][1]));
847//                    if ($tmp[1][0] > 0) $this->ImageInfo['h']["focalLength"] = $tmp[1][0];
848//                    if ($tmp[1][1] > 0) $this->ImageInfo['h']["minFocalLength"] = $tmp[1][1];
849                   
850//                    $this->ImageInfo['h']["focalLength"] = sprintf("%4.2f (%d/%d)",(double)$tmp[0],$tmp[1][0],$tmp[1][1]);
851                    break;
852
853                case TAG_SUBJECT_DISTANCE:
854                    // Inidcates the distacne the autofocus camera is focused to.
855                    // Tends to be less accurate as distance increases.
856                    //$this->ImageInfo["h"]["Distance"] =  $this->ConvertAnyFormat($ValuePtr, $Format);
857                    $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
858                    $this->ImageInfo['h']["Distance"] = sprintf("%4.2f (%d/%d)",(double)$tmp[0],$tmp[1][0],$tmp[1][1]);
859                    if ($this->ImageInfo['h']["Distance"] < 0){
860                            $this->ImageInfo['h']["focusDistance"] = "infini";
861                    } else {
862                            $this->ImageInfo['h']["focusDistance"] = sprintf("%4.2f",(double)$this->ImageInfo['h']["Distance"]);
863                    }
864
865
866                    break;
867
868                case TAG_EXPOSURETIME:
869                    // Simplest way of expressing exposure time, so I trust it most.
870                    // (overwrite previously computd value if there is one)
871                    $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
872                    $this->ImageInfo['h']["exposureTime"] = round(sprintf("%6.3f",(double)$tmp[0],$tmp[1][0],$tmp[1][1]) * 10) / 10;
873                    if ($tmp[0] <= 0.5){
874                            $this->ImageInfo['h']["exposureTime"] = sprintf("1/%d",(int)(0.5 + 1/$tmp[0]));
875                    }
876                    break;
877
878                case TAG_SHUTTERSPEED:
879                    // More complicated way of expressing exposure time, so only use
880                    // this value if we don't already have it from somewhere else.
881                    if ($this->ImageInfo[TAG_EXPOSURETIME] == 0){
882                        $sp = $this->ConvertAnyFormat($ValuePtr, $Format);
883                        $this->ImageInfo[TAG_SHUTTERSPEED] = (1/exp($sp[0]*log(2)));
884                    }
885                    break;
886
887                case TAG_FLASH:
888                    $this->ImageInfo["h"]["flashUsed"] = "Non";
889                    if ($this->ConvertAnyFormat($ValuePtr, $Format) & 7){
890                        $this->ImageInfo["h"]["flashUsed"] = "Oui";
891                    }
892                    break;
893
894                case TAG_ORIENTATION:
895                    $this->ImageInfo[TAG_ORIENTATION] = $this->ConvertAnyFormat($ValuePtr, $Format);
896                    if ($this->ImageInfo[TAG_ORIENTATION] < 1 || $this->ImageInfo[TAG_ORIENTATION] > 8){
897                            $this->debug(sprintf("Undefined rotation value %d", $this->ImageInfo[TAG_ORIENTATION], 0),1);
898                        $this->ImageInfo[TAG_ORIENTATION] = 0;
899                    }
900                    break;
901
902                case TAG_EXIF_IMAGELENGTH:
903                    //       * Image height
904                    $a = (int) $this->ConvertAnyFormat($ValuePtr, $Format);
905                    if ($this->ExifImageLength < $a) $this->ExifImageLength = $a;
906                    $this->ImageInfo[TAG_EXIF_IMAGELENGTH] = $this->ExifImageLength;
907                    $this->ImageInfo["h"]["Height"] = $this->ExifImageLength;
908                    break;
909                case TAG_EXIF_IMAGEWIDTH:
910                    // Use largest of height and width to deal with images that have been
911                    // rotated to portrait format.
912                    $a = (int) $this->ConvertAnyFormat($ValuePtr, $Format);
913                    if ($this->ExifImageWidth < $a) $this->ExifImageWidth = $a;
914                    $this->ImageInfo[TAG_EXIF_IMAGEWIDTH] = $this->ExifImageWidth;
915                    $this->ImageInfo["h"]["Width"] = $this->ExifImageWidth;
916
917                    break;
918
919                case TAG_FOCALPLANEXRES:
920                    $this->FocalplaneXRes = $this->ConvertAnyFormat($ValuePtr, $Format);
921                    $this->FocalplaneXRes = $this->FocalplaneXRes[0];
922                    $this->ImageInfo[TAG_FOCALPLANEXRES] = $this->FocalplaneXRes[0];
923                    break;
924
925                case TAG_FOCALPLANEUNITS:
926                    switch($this->ConvertAnyFormat($ValuePtr, $Format)){
927                        case 1: $this->FocalplaneUnits = 25.4; break; // inch
928                        case 2:
929                            // According to the information I was using, 2 means meters.
930                            // But looking at the Cannon powershot's files, inches is the only
931                            // sensible value.
932                            $this->FocalplaneUnits = 25.4;
933                            break;
934
935                        case 3: $this->FocalplaneUnits = 10;   break;  // centimeter
936                        case 4: $this->FocalplaneUnits = 1;    break;  // milimeter
937                        case 5: $this->FocalplaneUnits = .001; break;  // micrometer
938                    }
939                    $this->ImageInfo[TAG_FOCALPLANEUNITS] = $this->FocalplaneUnits;
940                    break;
941
942                    // Remaining cases contributed by: Volker C. Schoech (schoech@gmx.de)
943
944                case TAG_EXPOSURE_BIAS:
945                    $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
946                    $this->ImageInfo['h']["exposureBias"] = sprintf("%4.2f (%d/%d)",(double)$tmp[0],$tmp[1][0],$tmp[1][1]);
947                    break;
948
949                case TAG_WHITEBALANCE:
950                    $tmp = (int) $this->ConvertAnyFormat($ValuePtr, $Format);
951                    $tmpArr = array("1"=>"Sunny","2"=>"fluorescent","3"=>"incandescent");
952                    $this->ImageInfo['h']["whiteBalance"] =
953                        (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Cloudy");
954                    break;
955
956                case TAG_METERING_MODE:
957                    $tmp = (int) $this->ConvertAnyFormat($ValuePtr, $Format);
958
959                    $tmpArr = array("2"=>"center weight","3"=>"spot","5"=>"matrix");
960                    $this->ImageInfo['h']["meteringMode"] =
961                        (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Reserved");
962                    break;
963
964                case TAG_EXPOSURE_PROGRAM:
965                    $tmp = (int) $this->ConvertAnyFormat($ValuePtr, $Format);
966                    $tmpArr = array("2"=>"program (auto)","3"=>"aperture priority (semi-auto)","4"=>"shutter priority (semi-auto)");
967                    $this->ImageInfo['h']["exposure"] =
968                        (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Reserved");
969
970                    break;
971
972                case TAG_ISO_EQUIVALENT:
973                    $tmp = (int) $this->ConvertAnyFormat($ValuePtr, $Format);
974                    if ( $tmp < 50 ) $tmp *= 200;
975                    $this->ImageInfo['h']["isoEquiv"] = sprintf("%2d",(int)$tmp);
976                    break;
977
978                case TAG_COMPRESSION_LEVEL:
979                    $tmp = (int) $this->ConvertAnyFormat($ValuePtr, $Format);
980                    $tmpArr = array("1"=>"Basic","2"=>"Normal","4"=>"Fine");
981                    $this->ImageInfo['h']["jpegQuality"] =
982                        (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Reserved");
983                    break;
984
985                case TAG_THUMBNAIL_OFFSET:
986                    $this->ThumbnailOffset = $this->ConvertAnyFormat($ValuePtr, $Format);
987                    $this->DirWithThumbnailPtrs = $DirStart;
988                    break;
989
990                case TAG_THUMBNAIL_LENGTH:
991                    $this->ThumbnailSize = $this->ConvertAnyFormat($ValuePtr, $Format);
992                    $this->ImageInfo[TAG_THUMBNAIL_LENGTH] = $this->ThumbnailSize;
993                    break;
994
995                //----------------------------------------------
996                case TAG_IMAGE_DESC:
997                        $this->ImageInfo['h']["imageDesc"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
998                        break;
999                case TAG_X_RESOLUTION:
1000                        $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
1001                        $this->ImageInfo['h']["xResolution"] = sprintf("%4.2f (%d/%d) %s",(double)$tmp[0],$tmp[1][0],$tmp[1][1],$this->ImageInfo['h']["resolutionUnit"]);
1002                        break;
1003                case TAG_Y_RESOLUTION:
1004                        $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
1005                        $this->ImageInfo['h']["yResolution"] = sprintf("%4.2f (%d/%d) %s",(double)$tmp[0],$tmp[1][0],$tmp[1][1],$this->ImageInfo['h']["resolutionUnit"]);
1006                        break;
1007                case TAG_RESOLUTION_UNIT:
1008                        $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
1009                        $tmpArr = array("2"=>"Inches","3"=>"Centimeters");
1010
1011                        $this->ImageInfo['h']["resolutionUnit"] =
1012                            (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Reserved");
1013                        break;
1014                case TAG_SOFTWARE:
1015                        $this->ImageInfo['h']["software"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
1016                        break;
1017                case TAG_FILE_MODDATE;
1018                        $this->ImageInfo['h']["fileModifiedDate"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
1019                        break;
1020                case TAG_YCBCR_POSITIONING:
1021                        $this->ImageInfo['h']["YCbCrPositioning"] = $this->ConvertAnyFormat($ValuePtr, $Format);
1022                        break;
1023                case TAG_EXIF_VERSION:
1024                        $this->ImageInfo['h']["exifVersion"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
1025                        break;
1026                case TAG_DATE_TIME_DIGITIZED:
1027                        $this->ImageInfo['h']["dateTimeDigitized"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
1028                        break;
1029                case TAG_COMPONENT_CONFIG: // need more tests for this
1030                        $tmp = (int)$this->ConvertAnyFormat($ValuePtr, $Format);
1031
1032                        $tmpArr = array("0"=>"Does Not Exists","1"=>"Y","2"=>"Cb","3"=>"Cr","4"=>"R","5"=>"G","6"=>"B");
1033
1034                        if(strlen($tmp) < 4 ) {
1035                            $this->ImageInfo['h']["componentConfig"] = $tmpArr["0"];
1036                        } else {
1037                            for($i=0;$i<strlen($tmp);$i++) {
1038                                if($tmp["$i"] != 0) {
1039                                    $this->ImageInfo['h']["componentConfig"] .= $tmpArr[$tmp["$i"]];
1040                                }
1041                            }
1042                        }
1043                        break;
1044                case TAG_MAKER_NOTE:
1045                        //$this->ImageInfo['h']["makerNote"] = substr($ValuePtr,0,$ByteCount);
1046                        $this->ImageInfo['h']["makerNote"] = "NOT IMPLEMENTED";
1047                        break;
1048                case TAG_SUB_SEC_TIME:
1049                        $this->ImageInfo['h']["subSectionTime"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
1050                        break;
1051                case TAG_SUB_SEC_TIME_ORIG:
1052                        $this->ImageInfo['h']["subSectionTimeOriginal"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
1053                        break;
1054                case TAG_SUB_SEC_TIME_DIGITIZED:
1055                        $this->ImageInfo['h']["subSectionTimeDigtized"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
1056                        break;
1057                case TAG_FLASHPIX_VER:
1058                        $this->ImageInfo['h']["flashpixVersion"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
1059                        break;
1060                case TAG_COLOR_SPACE:
1061                        $this->ImageInfo['h']["colorSpace"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
1062                        break;
1063                case TAG_RELATED_SOUND_FILE:
1064                        $this->ImageInfo['h']["relatedSoundFile"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
1065                        break;
1066                case TAG_GPS_LATITUDE_REF:
1067                        $this->ImageInfo['h']["GPSLatitudeRef"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
1068                                                $this->ImageInfo['h']["GPSLatitudeRef"] = trim($this->ImageInfo['h']["GPSLatitudeRef"]);
1069                                                $tmp = substr($this->ImageInfo['h']["GPSLatitudeRef"],0,1);
1070                                                if($tmp == "S") {
1071                                                        $this->ImageInfo['h']["GPSLatitudeRef"] = "South latitude";
1072                                                } else if($tmp == "N") {
1073                                                        $this->ImageInfo['h']["GPSLatitudeRef"] = "North latitude";
1074                                                } else {
1075                                                        $this->ImageInfo['h']["GPSLatitudeRef"] = "Reserved";
1076                                                }
1077                        break;
1078                case TAG_GPS_LATITUDE:
1079                                                $tmp = substr($ValuePtr,0,$ByteCount);
1080
1081                                                $this->ImageInfo['h']["GPSLatitude"]["Degrees"] = ord(substr($tmp,0,1));
1082                                                $this->ImageInfo['h']["GPSLatitude"]["Minutes"] = ord(substr($tmp,1,1));
1083                                                $this->ImageInfo['h']["GPSLatitude"]["Seconds"] = ord(substr($tmp,2,1));
1084                        break;
1085
1086                case TAG_GPS_LONGITUDE:
1087                                                $tmp = substr($ValuePtr,0,$ByteCount);
1088
1089                                                $this->ImageInfo['h']["GPSLongitude"]["Degrees"] = ord(substr($tmp,0,1));
1090                                                $this->ImageInfo['h']["GPSLongitude"]["Minutes"] = ord(substr($tmp,1,1));
1091                                                $this->ImageInfo['h']["GPSLongitude"]["Seconds"] = ord(substr($tmp,2,1));
1092
1093                        break;
1094
1095                case TAG_GPS_LONGITUDE_REF:
1096                        $this->ImageInfo['h']["GPSLongitudeRef"] = substr($ValuePtr,0,$ByteCount);
1097                                                $this->ImageInfo['h']["GPSLongitudeRef"] = trim($this->ImageInfo['h']["GPSLongitudeRef"]);
1098                                                $tmp = substr($this->ImageInfo['h']["GPSLongitudeRef"],0,1);
1099                                                if($tmp == "E") {
1100                                                        $this->ImageInfo['h']["GPSLongitudeRef"] = "East Longitude";
1101                                                } else if($tmp == "W") {
1102                                                        $this->ImageInfo['h']["GPSLongitudeRef"] = "West Longitude";
1103                                                } else {
1104                                                        $this->ImageInfo['h']["GPSLongitudeRef"] = "Reserved";
1105                                                }
1106
1107                        break;
1108
1109
1110                                case TAG_GPS_TrackRef: /* Reference for direction of movement    GPSTrackRef */
1111                                        $this->ImageInfo['h']["GPSTrackRef"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
1112                                        break;
1113
1114
1115                                case TAG_GPS_GPSTrack: /* Direction of movement                                 GPSTrack */
1116                                        $this->ImageInfo['h']["GPSTrack"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
1117                                        break;
1118                                case TAG_GPS_GPSImgDirectionRef: /* Reference for direction of image       GPSImgDirectionRef */
1119                                        $this->ImageInfo['h']["GPSImgDirectionRef"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
1120                                        break;
1121                                case TAG_GPS_GPSImgDirection: /* Direction of image                     GPSImgDirection     */
1122                                        $this->ImageInfo['h']["GPSImgDirection"] = $this->ConvertAnyFormat($ValuePtr, $Format);
1123                                        break;
1124                                case TAG_GPS_GPSMapDatum: /* Geodetic survey data used              GPSMapDatum         */
1125                                        $this->ImageInfo['h']["GPSMapDatum"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
1126                                        break;
1127                                case TAG_GPS_GPSDestLatitudeRef:/* Reference for latitude of destination  GPSDestLatitudeRef  */
1128                                        $this->ImageInfo['h']["GPSDestLatitudeRef"] = substr($ValuePtr,0,$ByteCount);
1129                                        $this->ImageInfo['h']["GPSDestLatitudeRef"] = trim($this->ImageInfo['h']["GPSDestLatitudeRef"]);
1130                                        $tmp = substr($this->ImageInfo['h']["GPSDestLatitudeRef"],0,1);
1131                                        if($tmp == "S") {
1132                                                $this->ImageInfo['h']["GPSDestLatitudeRef"] = "South latitude";
1133                                        } else if($tmp == "N") {
1134                                                $this->ImageInfo['h']["GPSDestLatitudeRef"] = "North latitude";
1135                                        } else {
1136                                                $this->ImageInfo['h']["GPSDestLatitudeRef"] = "Reserved";
1137                                        }
1138
1139                                        break;
1140                                case TAG_GPS_GPSDestLatitude:/* Latitude of destination                GPSDestLatitude     */
1141                                                $tmp = substr($ValuePtr,0,$ByteCount);
1142
1143                                                $this->ImageInfo['h']["GPSDestLatitude"]["Degrees"] = ord(substr($tmp,0,1));
1144                                                $this->ImageInfo['h']["GPSDestLatitude"]["Minutes"] = ord(substr($tmp,1,1));
1145                                                $this->ImageInfo['h']["GPSDestLatitude"]["Seconds"] = ord(substr($tmp,2,1));
1146
1147                                        break;
1148                                case TAG_GPS_GPSDestLongitudeRef:/* Reference for longitude of destination GPSDestLongitudeRef 21     */
1149                                        $this->ImageInfo['h']["GPSDestLongitudeRef"] = substr($ValuePtr,0,$ByteCount);
1150                                        $this->ImageInfo['h']["GPSDestLongitudeRef"] = trim($this->ImageInfo['h']["GPSDestLongitudeRef"]);
1151                                        $tmp = substr($this->ImageInfo['h']["GPSDestLongitudeRef"],0,1);
1152                                        if($tmp == "E") {
1153                                                $this->ImageInfo['h']["GPSDestLongitudeRef"] = "East Longitude";
1154                                        } else if($tmp == "W") {
1155                                                $this->ImageInfo['h']["GPSDestLongitudeRef"] = "West Longitude";
1156                                        } else {
1157                                                $this->ImageInfo['h']["GPSDestLongitudeRef"] = "Reserved";
1158                                        }
1159
1160                                        break;
1161                                case TAG_GPS_GPSDestLongitude:/* Longitude of destination               GPSDestLongitude    22     */
1162                                        $this->ImageInfo['h']["GPSDestLongitude"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
1163                                        break;
1164                                case TAG_GPS_GPSDestBearingRef:/* Reference for bearing of destination   GPSDestBearingRef   23     */
1165                                        $this->ImageInfo['h']["GPSDestBearingRef"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
1166                                        break;
1167                                case TAG_GPS_GPSDestBearing: /* Bearing of destination                 GPSDestBearing      24     */
1168                                        $this->ImageInfo['h']["GPSDestBearing"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
1169                                        break;
1170                                case TAG_GPS_GPSDestDistanceRef:/* Reference for distance to destination  GPSDestDistanceRef  25     */
1171                                        $this->ImageInfo['h']["GPSDestDistanceRef"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
1172                                        break;
1173                                case TAG_GPS_GPSDestDistance: /* Distance to destination                GPSDestDistance     26     */
1174                                        //$this->ImageInfo['h']["GPSDestDistance"] = $this->ConvertAnyFormat($ValuePtr, $Format);
1175                                        $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
1176                                        $this->ImageInfo['h']["GPSDestDistance"] = sprintf("%4.2f (%d/%d)",(double)$tmp[0],$tmp[1][0],$tmp[1][1]);;
1177                                        break;
1178                                case TAG_GPS_GPSProcessingMethod: /* Name of GPS processing method          GPSProcessingMethod 27     */
1179                                        //$this->ImageInfo['h']["GPSProcessingMethod"] = $this->ConvertAnyFormat($ValuePtr, $Format);
1180                                        $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
1181                                        $this->ImageInfo['h']["GPSProcessingMethod"] = sprintf("%4.2f (%d/%d)",(double)$tmp[0],$tmp[1][0],$tmp[1][1]);;
1182                                        break;
1183                                case TAG_GPS_GPSAreaInformation: /* Name of GPS area                       GPSAreaInformation  28     */
1184                                        $this->ImageInfo['h']["GPSAreaInformation"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
1185                                        break;
1186                                case TAG_GPS_GPSDateStamp: /* GPS date                               GPSDateStamp        29     */
1187                                        $this->ImageInfo['h']["GPSDateStamp"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
1188                                        break;
1189                                case TAG_GPS_GPSDifferential: /* GPS differential correction            GPSDifferential     30     */
1190                                        $this->ImageInfo['h']["GPSDifferential"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
1191                                        break;
1192
1193                                case TAG_AUDIO_MU_LAW:
1194                                        $this->ImageInfo['h']["AudioMuLaw"] = $this->ConvertAnyFormat($ValuePtr, $Format);
1195                                        break;
1196                                case TAG_AUDIO_IMA_ADPCM_DESC: //  IMA-ADPCM Audio File Description Example - 40
1197                                        $this->ImageInfo['h']["AudioIMA-ADPCM-DESC"] = $this->ConvertAnyFormat($ValuePtr, $Format);
1198                                        break;
1199                                case TAG_AUDIO_MU_LAW_DESC: //  µ-Law Audio File Description Sample - 50
1200                                        $this->ImageInfo['h']["AudioMuLawDesc"] = $this->ConvertAnyFormat($ValuePtr, $Format);
1201                                        break;
1202
1203                                case TAG_EXPOSURE_INDEX:
1204                                        $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
1205                                        $this->ImageInfo['h']["ExposureIndex"] = sprintf("%4.2f (%d/%d)",(double)$tmp[0],$tmp[1][0],$tmp[1][1]);;
1206                                        break;
1207
1208                case TAG_SENSING_METHOD:
1209                        $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
1210                        $tmpArr = array("1"=>"Not Defined","2"=>"One-chip color area sensor","3"=>"Two-chip color area sensor",
1211                                        "4"=>"Three -chip color area sensor","5"=>"Color sequential area sensor",
1212                                        "6"=>"Trilinear sensor", "7"=>"Color sequential linear sensor"
1213                                        );
1214
1215                        $this->ImageInfo['h']["sensing"] =
1216                            (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Reserved");
1217                        break;
1218                case TAG_SOUCE_TYPE:
1219                        $this->ImageInfo['h']["sourceType"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
1220                        break;
1221                case TAG_SCENE_TYPE:
1222                        $this->ImageInfo['h']["sceneType"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
1223                        break;
1224                case TAG_CFA_PATTERN:
1225                        $this->ImageInfo['h']["CFAPattern"] = $this->string_format(substr($ValuePtr,0,$ByteCount));
1226                        break;
1227                case TAG_CUSTOM_RENDERED:
1228                        $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
1229                        $this->ImageInfo['h']["customRendered"] = ($mp == 0) ? 'Normal Process' : ($mp == 1 ? 'Custom Process' : 'Reserved');
1230                        break;
1231                case TAG_EXPOSURE_MODE:
1232                        $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
1233                        $tmpArr = array('Auto Exposure','Manual Exposure','Auto Bracket');
1234                        $this->ImageInfo['h']["exposureMode"] =
1235                            (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Reserved");
1236                        break;
1237                case TAG_WHITE_BALANCE:
1238                        $this->ImageInfo['h']["whiteBalance"] = $this->ConvertAnyFormat($ValuePtr, $Format);
1239                        break;
1240                case TAG_DIGITAL_ZOOM_RATIO:
1241                        $tmp = $this->ImageInfo['h']["zoomRatio"] = $this->ConvertAnyFormat($ValuePtr, $Format);
1242                        $this->ImageInfo['h']["zoomRatio"] = sprintf("%4.2f (%d/%d)",(double)$tmp[0],$tmp[1][0],$tmp[1][1]);
1243                        break;
1244                case TAG_FLENGTH_IN35MM:
1245                        $this->ImageInfo['h']["flength35mm"] = $this->ConvertAnyFormat($ValuePtr, $Format);
1246                        break;
1247                case TAG_SCREEN_CAP_TYPE:
1248                        $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
1249                        $tmpArr = array("Standard","Landscape","Portrait","Night Scene");
1250                        $this->ImageInfo['h']["screenCaptureType"] =
1251                            (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Reserved");
1252                        break;
1253                case TAG_GAIN_CONTROL:
1254                        $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
1255                        $tmpArr = array("None","Low Gain Up","High Gain Up","Low Gain Down","High Gain Down");
1256                        $this->ImageInfo['h']["gainControl"] =
1257                            (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Reserved");
1258                        break;
1259                case TAG_CONTRAST:
1260                        $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
1261                        $tmpArr = array("Normal","Soft","Hard");
1262                        $this->ImageInfo['h']["contrast"] =
1263                            (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Reserved");
1264                        break;
1265                case TAG_SATURATION:
1266                        $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
1267                        $tmpArr = array("Normal","Low Saturation","High Saturation");
1268                        $this->ImageInfo['h']["saturation"] =
1269                            (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Reserved");
1270                        break;
1271                case TAG_SHARPNESS:
1272                        $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
1273                        $tmpArr = array("Normal","Soft","Hard");
1274                        $this->ImageInfo['h']["sharpness"] =
1275                            (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Reserved");
1276                        break;
1277                case TAG_DIST_RANGE:
1278                        $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
1279                        $tmpArr = array("Unknown","Macro","Close View","Distant View");
1280                        $this->ImageInfo['h']["distanceRange"] =
1281                            (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Reserved");
1282                        break;
1283                case TAG_DEVICE_SETTING_DESC:
1284                        /*
1285                        $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
1286                        $tmpArr = array("Unknown","Macro","Close View","Distant View");
1287                        $this->ImageInfo['h']["distanceRange"] =
1288                            (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Reserved");
1289                        */
1290                        $this->ImageInfo['h']["deviceSettingDesc"] = "NOT IMPLEMENTED";
1291                        break;
1292                case TAG_COMPRESS_SCHEME:
1293                        $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
1294                        $tmpArr = array("1"=>"Uncompressed","6"=>"JPEG compression (thumbnails only)");
1295                        $this->ImageInfo['h']["compressScheme"] =
1296                            (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Reserved");
1297                        break;
1298                case TAG_IMAGE_WD:
1299                        $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
1300                        $this->ImageInfo['h']["jpegImageWidth"] = $tmp;
1301                        break;
1302                case TAG_IMAGE_HT:
1303                        $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
1304                        $this->ImageInfo['h']["jpegImageHeight"] = $tmp;
1305                        break;
1306                case TAG_IMAGE_BPS:
1307                        $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
1308                        $this->ImageInfo['h']["jpegBitsPerSample"] = $tmp;
1309                        break;
1310                case TAG_IMAGE_PHOTO_INT:
1311                        $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
1312                        $this->ImageInfo['h']["jpegPhotometricInt"] = $tmp;
1313                        $tmpArr = array("2"=>"RGB","6"=>"YCbCr");
1314                        $this->ImageInfo['h']["jpegPhotometricInt"] =
1315                            (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Reserved");
1316
1317                        break;
1318                case TAG_IMAGE_SOFFSET:
1319                        $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
1320                        $this->ImageInfo['h']["jpegStripOffsets"] = $tmp;
1321                        break;
1322                case TAG_IMAGE_SPP:
1323                        $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
1324                        $this->ImageInfo['h']["jpegSamplesPerPixel"] = $tmp;
1325                        break;
1326                case TAG_IMAGE_RPS:
1327                        $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
1328                        $this->ImageInfo['h']["jpegRowsPerStrip"] = $tmp;
1329                        break;
1330                case TAG_IMAGE_SBC:
1331                        $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
1332                        $this->ImageInfo['h']["jpegStripByteCounts"] = $tmp;
1333                        break;
1334                case TAG_IMAGE_P_CONFIG:
1335                        $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
1336                        $tmpArr = array("1"=>"Chunky Format","2"=>"Planar Format");
1337                        $this->ImageInfo['h']["jpegPlanarConfig"] =
1338                            (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Reserved");
1339                        break;
1340                case TAG_FOCALPLANE_YRESOL:
1341                        $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
1342                        $this->ImageInfo['h']["focalPlaneYResolution"] = sprintf("%4.2f (%d/%d)",(double)$tmp[0],$tmp[1][0],$tmp[1][1]);
1343                        break;
1344                case TAG_BRIGHTNESS:
1345                        $tmp = $this->ConvertAnyFormat($ValuePtr, $Format);
1346                        $this->ImageInfo['h']["brightness"] = sprintf("%4.2f (%d/%d)",(double)$tmp[0],$tmp[1][0],$tmp[1][1]);
1347                        break;
1348                //---------------------------------------------
1349                case TAG_EXIF_OFFSET:
1350                case TAG_INTEROP_OFFSET:
1351                    {
1352
1353                        $SubdirStart = substr($OffsetBase,$this->Get32u($ValuePtr[0],$ValuePtr[1],$ValuePtr[2],$ValuePtr[3]));
1354                        //if ($SubdirStart < $OffsetBase || $SubdirStart > $OffsetBase+$ExifLength){
1355                        //    debug("Illegal exif or interop ofset directory link",1);
1356                        //}else{
1357                            //echo "<h1>Calling sub-exif dir</h1>";
1358                            $this->ProcessExifDir($SubdirStart, $OffsetBase, $ExifLength);
1359                        //}
1360                        continue;
1361                    }
1362                default: {
1363                    $this->debug("UNKNOWN TAG: $Tag");
1364                    }
1365            }
1366        }
1367       
1368
1369        {
1370        // In addition to linking to subdirectories via exif tags,
1371        // there's also a potential link to another directory at the end of each
1372        // directory.  this has got to be the result of a comitee!
1373        $tmpDirStart = substr($DirStart,2+12*$NumDirEntries);
1374        if (strlen($tmpDirStart) + 4 <= strlen($OffsetBase)+$ExifLength){
1375            $Offset = $this->Get32u($tmpDirStart[0],$tmpDirStart[1],$tmpDirStart[2],$tmpDirStart[3]);
1376            if ($Offset){
1377                $SubdirStart = substr($OffsetBase,$Offset);
1378                if (strlen($SubdirStart) > strlen($OffsetBase)+$ExifLength){
1379                    if (strlen($SubdirStart) < strlen($OffsetBase)+$ExifLength+20){
1380                        // Jhead 1.3 or earlier would crop the whole directory!
1381                        // As Jhead produces this form of format incorrectness,
1382                        // I'll just let it pass silently
1383                    } else {
1384                        $this->errno = 51;
1385                        $this->errstr = "Illegal subdirectory link";
1386                        $this->debug($this->errstr,1);
1387                    }
1388                }else{
1389                    if (strlen($SubdirStart) <= strlen($OffsetBase)+$ExifLength){
1390                        $this->ProcessExifDir($SubdirStart, $OffsetBase, $ExifLength);
1391                    }
1392                }
1393            }
1394        } else {
1395            // The exif header ends before the last next directory pointer.
1396        }
1397    }
1398
1399    /**
1400    * Check if thumbnail has been cached or not.
1401    * If yes! then read the file.
1402    */
1403    if(file_exists($this->thumbnail) && $this->caching && (filemtime($this->thumbnail) == filemtime($this->file) )) {
1404        $this->ImageInfo["h"]["Thumbnail"] = $this->thumbnail;
1405        $this->ImageInfo["h"]["ThumbnailSize"] =  sprintf("%d bytes",filesize($this->thumbnail));
1406    } else{
1407        if ($this->ThumbnailSize && $this->ThumbnailOffset){
1408            if ($this->ThumbnailSize + $this->ThumbnailOffset <= $ExifLength){
1409                // The thumbnail pointer appears to be valid.  Store it.
1410                $this->ImageInfo["h"]["Thumbnail"] = substr($OffsetBase,$this->ThumbnailOffset);
1411
1412                // Save the thumbnail /
1413                if($this->caching && is_dir($this->cacheDir)) {
1414                    $this->saveThumbnail($this->thumbnail);
1415                    $this->ImageInfo["h"]["Thumbnail"] = $this->thumbnail;
1416                }
1417                $this->ImageInfo["h"]["ThumbnailSize"] =  sprintf("%d bytes",strlen($this->ImageInfo["h"]["Thumbnail"]));
1418            }
1419        }
1420    }
1421    }
1422
1423    /**
1424     * Process Exif data
1425     * @param   array    Section data as an array
1426     * @param   int  Length of the section (length of data array)
1427     *
1428     */
1429        function process_EXT_EXIF($data,$length) {
1430                        //print_r($data);
1431        }
1432
1433    /**
1434     * Process Exif data
1435     * @param   array    Section data as an array
1436     * @param   int  Length of the section (length of data array)
1437     *
1438     */
1439    function process_EXIF($data,$length) {
1440
1441        $this->debug("Exif header $length bytes long\n");
1442        if(($data[2].$data[3].$data[4].$data[5]) != "Exif") {
1443            $this->errno = 52;
1444            $this->errstr = "NOT EXIF FORMAT";
1445            $this->debug($this->errstr,1);
1446        }
1447
1448       // $this->ImageInfo["h"]["flashUsed"] = 0;
1449            /** If it s from a digicam, and it used flash, it says so. */
1450
1451        $this->FocalplaneXRes = 0;
1452        $this->FocalplaneUnits = 0;
1453        $this->ExifImageWidth = 0;
1454
1455        if(($data[8].$data[9]) == "II") {
1456            $this->debug("Exif section in Intel order\n");
1457            $this->MotorolaOrder = 0;
1458        } else if(($data[8].$data[9]) == "MM") {
1459            $this->debug("Exif section in Motorola order\n");
1460            $this->MotorolaOrder = 1;
1461        } else {
1462            $this->errno = 53;
1463            $this->errstr = "Invalid Exif alignment marker.\n";
1464            $this->debug($this->errstr,1);
1465            return;
1466        }
1467
1468        if($this->Get16u($data[10],$data[11]) != 0x2A || $this->Get32s($data[12],$data[13],$data[14],$data[15]) != 0x08) {
1469            $this->errno = 54;
1470            $this->errstr = "Invalid Exif start (1)";
1471            $this->debug($this->errstr,1);
1472        }
1473
1474        $DirWithThumbnailPtrs = NULL;
1475
1476        //$this->ProcessExifDir(array_slice($data,16),array_slice($data,8),$length);
1477        $this->ProcessExifDir(substr($data,16),substr($data,8),$length);
1478
1479        // Compute the CCD width, in milimeters.                      2
1480        if ($this->FocalplaneXRes != 0){
1481            $this->ImageInfo["h"]["CCDWidth"] = sprintf("%4.2fmm",(float)($this->ExifImageWidth * $this->FocalplaneUnits / $this->FocalplaneXRes));
1482        }
1483        /*
1484                if (isset($this->ImageInfo['h']["CCDWidth"]) && $this->ImageInfo['h']["CCDWidth"] > 0){
1485                $this->ImageInfo['h']["focalLength35mm"] = round($this->ImageInfo['h']["focalLength"] /$this->ImageInfo['h']["CCDWidth"]*36);
1486                if ($this->ImageInfo['h']["focalLength35mm"] == $this->ImageInfo['h']["focalLength"]) $this->ImageInfo['h']["focalLength35mm"]= false;
1487                }
1488                */
1489                if (isset($this->ImageInfo['h']["make"]) && isset($this->ImageInfo['h']["model"])) {
1490                        $marque = $this->ImageInfo['h']["make"];
1491                        $this->ImageInfo['h']["model"] = trim(str_replace($marque, '', $this->ImageInfo['h']["model"]));
1492                }
1493                if (isset($this->ImageInfo['h']["make"]) || isset($this->ImageInfo['h']["model"])) {
1494                        if (isset($this->ImageInfo['h']["make"])) $logo[] = trim($this->ImageInfo['h']["make"]);
1495                        if (isset($this->ImageInfo['h']["model"])) $logo[] = trim($this->ImageInfo['h']["model"]);
1496                        $logo = join("_", $logo);
1497                        $logo = mb_ereg_replace("\/", ",", $logo);
1498                        $this->ImageInfo['h']["logoAppareil"] = mb_ereg_replace("\ +", "_", "$logo.png");
1499                }
1500               
1501                if (isset($this->ImageInfo['h']["flength35mm"])) {
1502                        $this->ImageInfo['h']["focalLength35mm"] = $this->ImageInfo['h']["flength35mm"];
1503                }
1504
1505        $this->debug("Non settings part of Exif header: ".$length." bytes\n");
1506    } // end of function process_EXIF
1507
1508    /**
1509     * Converts two byte number into its equivalent int integer
1510     * @param   int
1511     * @param   int
1512     *
1513     */
1514    function Get16u($val,$by) {
1515        if($this->MotorolaOrder){
1516            return ((ord($val) << 8) | ord($by));
1517        } else {
1518            return ((ord($by) << 8) | ord($val));
1519        }
1520    }
1521
1522    /**
1523     * Converts 4-byte number into its equivalent integer
1524     *
1525     * @param   int
1526     * @param   int
1527     * @param   int
1528     * @param   int
1529     *
1530     * @return int
1531     */
1532    function Get32s($val1,$val2,$val3,$val4)
1533    {
1534        $val1 = ord($val1);
1535        $val2 = ord($val2);
1536        $val3 = ord($val3);
1537        $val4 = ord($val4);
1538
1539        if ($this->MotorolaOrder){
1540            return (($val1 << 24) | ($val2 << 16) | ($val3 << 8 ) | ($val4 << 0 ));
1541        }else{
1542            return  (($val4 << 24) | ($val3 << 16) | ($val2 << 8 ) | ($val1 << 0 ));
1543        }
1544    }
1545    /**
1546     * Converts 4-byte number into its equivalent integer with the help of Get32s
1547     *
1548     * @param   int
1549     * @param   int
1550     * @param   int
1551     * @param   int
1552     *
1553     * @return int
1554     *
1555     */
1556    function get32u($val1,$val2,$val3,$val4) {
1557        return ($this->Get32s($val1,$val2,$val3,$val4) & 0xffffffff);
1558    }
1559
1560    //--------------------------------------------------------------------------
1561    // Evaluate number, be it int, rational, or float from directory.
1562    //--------------------------------------------------------------------------
1563    function ConvertAnyFormat($ValuePtr, $Format)
1564    {
1565        $Value = 0;
1566
1567        switch($Format){
1568            case FMT_SBYTE:     $Value = $ValuePtr[0];  break;
1569            case FMT_BYTE:      $Value = $ValuePtr[0];        break;
1570
1571            case FMT_USHORT:    $Value = $this->Get16u($ValuePtr[0],$ValuePtr[1]);          break;
1572            case FMT_ULONG:     $Value = $this->Get32u($ValuePtr[0],$ValuePtr[1],$ValuePtr[2],$ValuePtr[3]);          break;
1573
1574            case FMT_URATIONAL:
1575            case FMT_SRATIONAL:
1576                {
1577
1578                    $Num = $this->Get32s($ValuePtr[0],$ValuePtr[1],$ValuePtr[2],$ValuePtr[3]);
1579                    $Den = $this->Get32s($ValuePtr[4],$ValuePtr[5],$ValuePtr[6],$ValuePtr[7]);
1580                    if ($Den == 0){
1581                        $Value = 0;
1582                    }else{
1583                        $Value = (double) ($Num/$Den);
1584                    }
1585                    return array($Value,array($Num,$Den));
1586                    break;
1587                }
1588
1589            case FMT_SSHORT:    $Value = $this->Get16u($ValuePtr[0],$ValuePtr[1]);  break;
1590            case FMT_SLONG:     $Value = $this->Get32s($ValuePtr[0],$ValuePtr[1],$ValuePtr[2],$ValuePtr[3]);                break;
1591
1592            // Not sure if this is correct (never seen float used in Exif format)
1593            case FMT_SINGLE:    $Value = $ValuePtr[0];      break;
1594            case FMT_DOUBLE:    $Value = $ValuePtr[0];             break;
1595        }
1596        return $Value;
1597    }
1598
1599    /**
1600     * Function to extract thumbnail from Exif data of the image.
1601     * and store it in a filename given by $ThumbFile
1602     *
1603     * @param   String   Files name to store the thumbnail
1604     *
1605     */
1606    function saveThumbnail($ThumbFile) {
1607         $ThumbFile = trim($ThumbFile);
1608         $file = basename($this->file);
1609
1610         if(empty($ThumbFile)) $ThumbFile = "th_$file";
1611
1612         if (!empty($this->ImageInfo["h"]["Thumbnail"])){
1613            $tp = fopen($ThumbFile,"wb");
1614            if(!$tp) {
1615                $this->errno = 2;
1616                $this->errstr = "Cannot Open file '$ThumbFile'";
1617            }
1618            fwrite($tp,$this->ImageInfo["h"]["Thumbnail"]);
1619            fclose($tp);
1620            touch($ThumbFile,filemtime($this->file));
1621         }
1622         //$this->thumbnailURL = $ThumbFile;
1623         $this->ImageInfo["h"]["Thumbnail"] = $ThumbFile;
1624    }
1625
1626    /**
1627     * Returns thumbnail url along with parameter supplied.
1628     * Should be called in src attribute of image
1629     *
1630     * @return  string  File URL
1631     *
1632     */
1633    function showThumbnail() {
1634        return "showThumbnail.php?file=".$this->file;
1635        //$this->ImageInfo["h"]["Thumbnail"]
1636    }
1637
1638    /**
1639     * Function to give back thumbail image
1640     * @return string   full image
1641     *
1642     */
1643    function getThumbnail() {
1644        return $this->ImageInfo["h"]["Thumbnail"];
1645    }
1646
1647    /**
1648    *
1649    */
1650    function getImageInfo() {
1651
1652        $imgInfo = $this->ImageInfo["h"];
1653
1654        $retArr = $imgInfo;
1655        $retArr["FileName"] = $imgInfo["FileName"];
1656        $retArr["FileSize"] = $imgInfo["FileSize"]." bytes";
1657
1658        $retArr["FileDateTime"] = date("d-M-Y H:i:s",$imgInfo["FileDateTime"]);
1659
1660        $retArr["resolution"] = $imgInfo["Width"]."x".$imgInfo["Height"];
1661
1662
1663        if ($this->ImageInfo[TAG_ORIENTATION] > 1){
1664                // Only print orientation if one was supplied, and if its not 1 (normal orientation)
1665
1666                // 1 - "The 0th row is at the visual top of the image,    and the 0th column is the visual left-hand side."
1667                // 2 - "The 0th row is at the visual top of the image,    and the 0th column is the visual right-hand side."
1668                // 3 - "The 0th row is at the visual bottom of the image, and the 0th column is the visual right-hand side."
1669                // 4 - "The 0th row is at the visual bottom of the image, and the 0th column is the visual left-hand side."
1670
1671                // 5 - "The 0th row is the visual left-hand side of of the image,  and the 0th column is the visual top."
1672                // 6 - "The 0th row is the visual right-hand side of of the image, and the 0th column is the visual top."
1673                // 7 - "The 0th row is the visual right-hand side of of the image, and the 0th column is the visual bottom."
1674                // 8 - "The 0th row is the visual left-hand side of of the image,  and the 0th column is the visual bottom."
1675
1676                // Note: The descriptions here are the same as the name of the command line
1677                // ption to pass to jpegtran to right the image
1678                $OrientTab = array(
1679                "Undefined",
1680                "Normal",           // 1
1681                "flip horizontal",  // left right reversed mirror
1682                "rotate 180",       // 3
1683                "flip vertical",    // upside down mirror
1684                "transpose",        // Flipped about top-left <--> bottom-right axis.
1685                "rotate 90",        // rotate 90 cw to right it.
1686                "transverse",       // flipped about top-right <--> bottom-left axis
1687                "rotate 270",       // rotate 270 to right it.
1688                );
1689
1690                $retArr["orientation"] = $OrientTab[$this->ImageInfo[TAG_ORIENTATION]];
1691        }
1692
1693        $retArr["color"] = ($imgInfo["IsColor"] == 0) ? "Black and white" : "Color";
1694
1695        if(isset($imgInfo["Process"])) {
1696            switch($imgInfo["Process"]) {
1697                case M_SOF0: $process = "Baseline";break;
1698                case M_SOF1: $process = "Extended sequential";break;
1699                case M_SOF2: $process = "Progressive";break;
1700                case M_SOF3: $process = "Lossless";break;
1701                case M_SOF5: $process = "Differential sequential";break;
1702                case M_SOF6: $process = "Differential progressive";break;
1703                case M_SOF7: $process = "Differential lossless";break;
1704                case M_SOF9: $process = "Extended sequential, arithmetic coding";break;
1705                case M_SOF10: $process = "Progressive, arithmetic coding";break;
1706                case M_SOF11: $process = "Lossless, arithmetic coding";break;
1707                case M_SOF13: $process = "Differential sequential, arithmetic coding";break;
1708                case M_SOF14: $process = "Differential progressive, arithmetic coding";break;
1709                case M_SOF15: $process =   "Differential lossless, arithmetic coding";break;
1710                default: $process = "Unknown";
1711            }
1712            $retArr["jpegProcess"] = $process;
1713        }
1714
1715        if(file_exists($this->thumbnailURL)) {
1716                $retArr["Thumbnail"] = "<a href='$this->thumbnailURL'>$this->thumbnailURL</a>";
1717        }
1718
1719        return $retArr;
1720    }
1721
1722        /**
1723        *
1724        */
1725        function string_format($str) {
1726                $tmpStr = "";
1727
1728                for($i=0;$i<strlen($str);$i++) {
1729                        if(ord($str[$i]) !=0) {
1730                                $tmpStr .= $str[$i];
1731                        }
1732                }
1733                return $tmpStr;
1734        }
1735    /**
1736    * Returns time in microseconds
1737    */
1738    function getmicrotime(){
1739        list($usec, $sec) = explode(" ",microtime());
1740        return ((float)$usec + (float)$sec);
1741    }
1742
1743    /**
1744    *  Get the time difference
1745    */
1746    function getDiffTime() {
1747            return ($this->getmicrotime() - $this->timeStart);
1748    }
1749
1750} // end of class
1751?>
Note: See TracBrowser for help on using the repository browser.