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