Overview

Packages

  • Image
  • None

Classes

  • Horde_Image_Exif_Parser_Canon
  • Horde_Image_Exif_Parser_Fujifilm
  • Horde_Image_Exif_Parser_Gps
  • Horde_Image_Exif_Parser_Nikon
  • Horde_Image_Exif_Parser_Olympus
  • Horde_Image_Exif_Parser_Panasonic
  • Horde_Image_Exif_Parser_Sanyo
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: /**
  3:  * @author   Michael J. Rubinsky <mrubinsk@horde.org>
  4:  * @author   Jan Schneider <jan@horde.org>
  5:  * @category Horde
  6:  * @package  Image
  7:  */
  8: 
  9: /**
 10:  * Exifer
 11:  * Extracts EXIF information from digital photos.
 12:  *
 13:  * Copyright © 2003 Jake Olefsky
 14:  * http://www.offsky.com/software/exif/index.php
 15:  * jake@olefsky.com
 16:  *
 17:  * ------------
 18:  *
 19:  * This program is free software; you can redistribute it and/or modify it
 20:  * under the terms of the GNU General Public License as published by the Free
 21:  * Software Foundation; either version 2 of the License, or (at your option)
 22:  * any later version.
 23:  *
 24:  * This program is distributed in the hope that it will be useful, but WITHOUT
 25:  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 26:  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 27:  * more details. http://www.horde.org/licenses/gpl
 28:  */
 29: class Horde_Image_Exif_Parser_Nikon extends Horde_Image_Exif_Parser_Base
 30: {
 31:     /**
 32:      *
 33:      * @param $tag
 34:      * @param $model
 35:      * @return unknown_type
 36:      */
 37:     protected function _lookupTag($tag, $model)
 38:     {
 39:         switch ($model) {
 40:         case 0:
 41:             switch($tag) {
 42:             case '0003': $tag = 'Quality'; break;
 43:             case '0004': $tag = 'ColorMode'; break;
 44:             case '0005': $tag = 'ImageAdjustment'; break;
 45:             case '0006': $tag = 'CCDSensitivity'; break;
 46:             case '0007': $tag = 'WhiteBalance'; break;
 47:             case '0008': $tag = 'Focus'; break;
 48:             case '0009': $tag = 'Unknown2'; break;
 49:             case '000a': $tag = 'DigitalZoom'; break;
 50:             case '000b': $tag = 'Converter'; break;
 51:             default:     $tag = 'unknown: ' . $tag; break;
 52:             }
 53:             break;
 54: 
 55:         case 1:
 56:             switch($tag) {
 57:             case '0002': $tag = 'ISOSetting'; break;
 58:             case '0003': $tag = 'ColorMode'; break;
 59:             case '0004': $tag = 'Quality'; break;
 60:             case '0005': $tag = 'Whitebalance'; break;
 61:             case '0006': $tag = 'ImageSharpening'; break;
 62:             case '0007': $tag = 'FocusMode'; break;
 63:             case '0008': $tag = 'FlashSetting'; break;
 64:             case '0009': $tag = 'FlashMode'; break;
 65:             case '000b': $tag = 'WhiteBalanceFine'; break;
 66:             case '000f': $tag = 'ISOSelection'; break;
 67:             case '0013': $tag = 'ISOSelection2'; break;
 68:             case '0080': $tag = 'ImageAdjustment'; break;
 69:             case '0081': $tag = 'ToneCompensation'; break;
 70:             case '0082': $tag = 'Adapter'; break;
 71:             case '0083': $tag = 'LensType'; break;
 72:             case '0084': $tag = 'LensInfo'; break;
 73:             case '0085': $tag = 'ManualFocusDistance'; break;
 74:             case '0086': $tag = 'DigitalZoom'; break;
 75:             case '0087': $tag = 'FlashUsed'; break;
 76:             case '0088': $tag = 'AFFocusPosition'; break;
 77:             case '008d': $tag = 'ColorMode'; break;
 78:             case '0090': $tag = 'LightType'; break;
 79:             case '0094': $tag = 'Saturation'; break;
 80:             case '0095': $tag = 'NoiseReduction'; break;
 81:             case '0010': $tag = 'DataDump'; break;
 82:             default:     $tag = 'unknown: ' . $tag; break;
 83:             }
 84:             break;
 85:         }
 86: 
 87:         return $tag;
 88:     }
 89: 
 90:     /**
 91:      *
 92:      * @param $type
 93:      * @param $tag
 94:      * @param $intel
 95:      * @param $model
 96:      * @param $data
 97:      * @return unknown_type
 98:      */
 99:     protected function _formatData($type, $tag, $intel, $model, $data)
100:     {
101:         switch ($type) {
102:         case 'URATIONAL':
103:         case 'SRATIONAL':
104:             $data = bin2hex($data);
105:             if ($intel) {
106:                 $data = Horde_Image_Exif::intel2Moto($data);
107:             }
108:             $top = hexdec(substr($data, 8, 8));
109:             $bottom = hexdec(substr($data, 0, 8));
110:             if ($bottom != 0) {
111:                 $data = $top / $bottom;
112:             } elseif ($top == 0) {
113:                 $data = 0;
114:             } else {
115:                 $data = $top . '/' . $bottom;
116:             }
117: 
118:             if ($tag == '0085' && $model == 1) {
119:                 //ManualFocusDistance
120:                 $data = $data . ' m';
121:             }
122:             if ($tag == '0086' && $model == 1) {
123:                 //DigitalZoom
124:                 $data = $data . 'x';
125:             }
126:             if ($tag == '000a' && $model == 0) {
127:                 //DigitalZoom
128:                 $data = $data . 'x';
129:             }
130:             break;
131: 
132:         case 'USHORT':
133:         case 'SSHORT':
134:         case 'ULONG':
135:         case 'SLONG':
136:         case 'FLOAT':
137:         case 'DOUBLE':
138:             $data = bin2hex($data);
139:             if ($intel) {
140:                 $data = Horde_Image_Exif::intel2Moto($data);
141:             }
142:             $data = hexdec($data);
143:             if ($model != 0) {
144:                 break;
145:             }
146: 
147:             switch ($tag) {
148:             case '0003':
149:                 //Quality
150:                 switch ($data) {
151:                 case 1:  $data = Horde_Image_Translation::t("VGA Basic"); break;
152:                 case 2:  $data = Horde_Image_Translation::t("VGA Normal"); break;
153:                 case 3:  $data = Horde_Image_Translation::t("VGA Fine"); break;
154:                 case 4:  $data = Horde_Image_Translation::t("SXGA Basic"); break;
155:                 case 5:  $data = Horde_Image_Translation::t("SXGA Normal"); break;
156:                 case 6:  $data = Horde_Image_Translation::t("SXGA Fine"); break;
157:                 default: $data = Horde_Image_Translation::t("Unknown") . ': ' . $data; break;
158:                 }
159:                 break;
160: 
161:             case '0004':
162:                 //Color
163:                 switch ($data) {
164:                 case 1:  $data = Horde_Image_Translation::t("Color"); break;
165:                 case 2:  $data = Horde_Image_Translation::t("Monochrome"); break;
166:                 default: $data = Horde_Image_Translation::t("Unknown") . ': ' . $data; break;
167:                 }
168:                 break;
169: 
170:             case '0005':
171:                 //Image Adjustment
172:                 switch ($data) {
173:                 case 0:  $data = Horde_Image_Translation::t("Normal"); break;
174:                 case 1:  $data = Horde_Image_Translation::t("Bright+"); break;
175:                 case 2:  $data = Horde_Image_Translation::t("Bright-"); break;
176:                 case 3:  $data = Horde_Image_Translation::t("Contrast+"); break;
177:                 case 4:  $data = Horde_Image_Translation::t("Contrast-"); break;
178:                 default: $data = Horde_Image_Translation::t("Unknown") . ': ' . $data; break;
179:                 }
180:                 break;
181: 
182:             case '0006':
183:                 //CCD Sensitivity
184:                 switch ($data) {
185:                 case 0:  $data = 'ISO-80'; break;
186:                 case 2:  $data = 'ISO-160'; break;
187:                 case 4:  $data = 'ISO-320'; break;
188:                 case 5:  $data = 'ISO-100'; break;
189:                 default: $data = Horde_Image_Translation::t("Unknown") . ': ' . $data; break;
190:                 }
191:                 break;
192: 
193:             case '0007':
194:                 //White Balance
195:                 switch ($data) {
196:                 case 0:  $data = Horde_Image_Translation::t("Auto"); break;
197:                 case 1:  $data = Horde_Image_Translation::t("Preset"); break;
198:                 case 2:  $data = Horde_Image_Translation::t("Daylight"); break;
199:                 case 3:  $data = Horde_Image_Translation::t("Incandescense"); break;
200:                 case 4:  $data = Horde_Image_Translation::t("Flourescence"); break;
201:                 case 5:  $data = Horde_Image_Translation::t("Cloudy"); break;
202:                 case 6:  $data = Horde_Image_Translation::t("SpeedLight"); break;
203:                 default: $data = Horde_Image_Translation::t("Unknown") . ': ' . $data; break;
204:                 }
205:                 break;
206: 
207:             case '000b':
208:                 //Converter
209:                 switch ($data) {
210:                 case 0:  $data = Horde_Image_Translation::t("None"); break;
211:                 case 1:  $data = Horde_Image_Translation::t("Fisheye"); break;
212:                 default: $data = Horde_Image_Translation::t("Unknown") . ': ' . $data; break;
213:                 }
214:                 break;
215:             }
216: 
217:         case 'UNDEFINED':
218:             if ($model != 1) {
219:                 break;
220:             }
221: 
222:             switch ($tag) {
223:             case '0001':
224:                 $data = $data/100;
225:                 break;
226:             case '0088':
227:                 //AF Focus Position
228:                 $temp = Horde_Image_Translation::t("Center");
229:                 $data = bin2hex($data);
230:                 $data = str_replace('01', 'Top', $data);
231:                 $data = str_replace('02', 'Bottom', $data);
232:                 $data = str_replace('03', 'Left', $data);
233:                 $data = str_replace('04', 'Right', $data);
234:                 $data = str_replace('00', '', $data);
235:                 if (!strlen($data)) {
236:                     $data = $temp;
237:                 }
238:                 break;
239:             }
240:             break;
241: 
242:         default:
243:             $data = bin2hex($data);
244:             if ($intel) {
245:                 $data = Horde_Image_Exif::intel2Moto($data);
246:             }
247:             if ($model != 1) {
248:                 break;
249:             }
250: 
251:             switch ($tag) {
252:             case '0083':
253:                 //Lens Type
254:                 $data = hexdec(substr($data, 0, 2));
255:                 switch ($data) {
256:                 case 0:  $data = Horde_Image_Translation::t("AF non D"); break;
257:                 case 1:  $data = Horde_Image_Translation::t("Manual"); break;
258:                 case 2:  $data = 'AF-D or AF-S'; break;
259:                 case 6:  $data = 'AF-D G'; break;
260:                 case 10:  $data = 'AF-D VR'; break;
261:                 default: $data = Horde_Image_Translation::t("Unknown") . ': ' . $data; break;
262:                 }
263:                 break;
264: 
265:             case '0087':
266:                 //Flash type
267:                 $data = hexdec(substr($data,0,2));
268:                 switch ($data) {
269:                 case 0:  $data = Horde_Image_Translation::t("Did Not Fire"); break;
270:                 case 4:  $data = Horde_Image_Translation::t("Unknown"); break;
271:                 case 7:  $data = Horde_Image_Translation::t("External"); break;
272:                 case 9:  $data = Horde_Image_Translation::t("On Camera"); break;
273:                 default: $data = Horde_Image_Translation::t("Unknown") . ': ' . $data; break;
274:                 }
275:                 break;
276:             }
277: 
278:             break;
279:         }
280: 
281:         return $data;
282:     }
283: 
284:     /**
285:      *
286:      * @param $block
287:      * @param $result
288:      * @return unknown_type
289:      */
290:     public function parse($block, &$result)
291:     {
292:         $intel = $result['Endien'] == 'Intel';
293:         $model = $result['IFD0']['Model'];
294: 
295:         //these 6 models start with "Nikon".  Other models dont.
296:         if ($model == "E700\0" ||
297:             $model == "E800\0" ||
298:             $model == "E900\0" ||
299:             $model == "E900S\0" ||
300:             $model == "E910\0" ||
301:             $model == "E950\0") {
302:             //current place
303:             $place = 8;
304:             $model = 0;
305: 
306:             //Get number of tags (2 bytes)
307:             $num = bin2hex(substr($block, $place, 2));
308:             $place += 2;
309:             if ($intel) {
310:                 $num = Horde_Image_Exif::intel2Moto($num);
311:             }
312:             $result['SubIFD']['MakerNote']['MakerNoteNumTags'] = hexdec($num);
313: 
314:             //loop thru all tags  Each field is 12 bytes
315:             for ($i = 0; $i < hexdec($num); $i++) {
316:                 //2 byte tag
317:                 $tag = bin2hex(substr($block, $place, 2));
318:                 $place += 2;
319:                 if ($intel) {
320:                     $tag = Horde_Image_Exif::intel2Moto($tag);
321:                 }
322:                 $tag_name = $this->_lookupTag($tag, $model);
323: 
324:                 //2 byte type
325:                 $type = bin2hex(substr($block, $place, 2));
326:                 $place += 2;
327:                 if ($intel) {
328:                     $type = Horde_Image_Exif::intel2Moto($type);
329:                 }
330:                 $this->_lookupType($type, $size);
331: 
332:                 //4 byte count of number of data units
333:                 $count = bin2hex(substr($block, $place, 4));
334:                 $place += 4;
335:                 if ($intel) {
336:                     $count = Horde_Image_Exif::intel2Moto($count);
337:                 }
338:                 $bytesofdata = $size * hexdec($count);
339: 
340:                 //4 byte value of data or pointer to data
341:                 $value = substr($block, $place, 4);
342:                 $place += 4;
343: 
344:                 //if tag is 0002 then its the ASCII value which we know is at 140 so calc offset
345:                 //THIS HACK ONLY WORKS WITH EARLY NIKON MODELS
346:                 if ($tag == '0002') {
347:                     $offset = hexdec($value) - 140;
348:                 }
349:                 if ($bytesofdata <= 4) {
350:                     $data = $value;
351:                 } else {
352:                     $value = bin2hex($value);
353:                     if ($intel) {
354:                         $value = Horde_Image_Exif::intel2Moto($value);
355:                     }
356:                     $data = substr($block, hexdec($value) - $offset, $bytesofdata * 2);
357:                 }
358:                 $formated_data = $this->_formatData($type, $tag, $intel, $model, $data);
359:                 $result['SubIFD']['MakerNote'][$tag_name] = $formated_data;
360:             }
361:         } else {
362:             //current place
363:             $place = 0;
364:             $model = 1;
365: 
366:             $nikon = substr($block, $place, 8);
367:             $place += 8;
368:             $endien = substr($block, $place, 4);
369:             $place += 4;
370: 
371:             //2 bytes of 0x002a
372:             $tag = bin2hex(substr($block, $place, 2));
373:             $place += 2;
374: 
375:             //Then 4 bytes of offset to IFD0 (usually 8 which includes all 8
376:             //bytes of TIFF header)
377:             $offset = bin2hex(substr($block, $place, 4));
378:             $place += 4;
379:             if ($intel) {
380:                 $offset = Horde_Image_Exif::intel2Moto($offset);
381:             }
382:             if (hexdec($offset) > 8) {
383:                 $place += $offset - 8;
384:             }
385: 
386:             //Get number of tags (2 bytes)
387:             $num = bin2hex(substr($block, $place, 2));
388:             $place += 2;
389:             if ($intel) {
390:                 $num = Horde_Image_Exif::intel2Moto($num);
391:             }
392: 
393:             //loop thru all tags  Each field is 12 bytes
394:             for ($i = 0; $i < hexdec($num); $i++) {
395:                 //2 byte tag
396:                 $tag = bin2hex(substr($block, $place, 2));
397:                 $place += 2;
398:                 if ($intel) {
399:                     $tag = Horde_Image_Exif::intel2Moto($tag);
400:                 }
401:                 $tag_name = $this->_lookupTag($tag, $model);
402: 
403:                 //2 byte type
404:                 $type = bin2hex(substr($block, $place, 2));
405:                 $place += 2;
406:                 if ($intel) {
407:                     $type = Horde_Image_Exif::intel2Moto($type);
408:                 }
409:                 $this->_lookupType($type, $size);
410: 
411:                 //4 byte count of number of data units
412:                 $count = bin2hex(substr($block, $place, 4));
413:                 $place += 4;
414:                 if ($intel) {
415:                     $count = Horde_Image_Exif::intel2Moto($count);
416:                 }
417:                 $bytesofdata = $size * hexdec($count);
418: 
419:                 //4 byte value of data or pointer to data
420:                 $value = substr($block, $place, 4);
421:                 $place += 4;
422: 
423:                 if ($bytesofdata <= 4) {
424:                     $data = $value;
425:                 } else {
426:                     $value = bin2hex($value);
427:                     if ($intel) {
428:                         $value = Horde_Image_Exif::intel2Moto($value);
429:                     }
430:                     $data = substr($block, hexdec($value) + hexdec($offset) + 2, $bytesofdata);
431:                 }
432:                 $formated_data = $this->_formatData($type, $tag, $intel, $model, $data);
433:                 $result['SubIFD']['MakerNote'][$tag_name] = $formated_data;
434:             }
435:         }
436:     }
437: }
API documentation generated by ApiGen