1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29:
30: class Horde_Image_Exif_Bundled extends Horde_Image_Exif_Base
31: {
32: public function getData($image)
33: {
34: $raw = $this->_readData($image);
35: $exif = array();
36: foreach ($raw as $key => $value) {
37: if ($key == 'IFD0' || $key == 'SubIFD') {
38: foreach ($value as $subkey => $subvalue) {
39: $exif[$subkey] = $subvalue;
40: }
41: } else {
42: $exif[$key] = $value;
43: }
44: }
45:
46:
47: $exif['FileSize'] = @filesize($imageFile);
48:
49: return $this->_processData($exif);
50: }
51:
52: 53: 54: 55: 56: 57:
58: protected function _readData($path)
59: {
60:
61: $in = @fopen($path, 'rb');
62: $seek = @fopen($path, 'rb');
63: $globalOffset = 0;
64: $result = array('Errors' => 0);
65:
66:
67: if (!$in || !$seek) {
68: $result['Errors'] = 1;
69: $result['Error'][$result['Errors']] = Horde_Image_Translation::t("The file could not be opened.");
70: return $result;
71: }
72:
73:
74: $data = bin2hex(fread($in, 2));
75: if ($data == 'ffd8') {
76: $result['ValidJpeg'] = 1;
77: } else {
78: $result['ValidJpeg'] = 0;
79: fclose($in);
80: fclose($seek);
81: return $result;
82: }
83:
84: $result['ValidIPTCData'] = 0;
85: $result['ValidJFIFData'] = 0;
86: $result['ValidEXIFData'] = 0;
87: $result['ValidAPP2Data'] = 0;
88: $result['ValidCOMData'] = 0;
89:
90:
91: $data = bin2hex(fread($in, 2));
92: $size = bin2hex(fread($in, 2));
93:
94:
95: while(!feof($in) && $data != 'ffe1' && $data != 'ffc0' && $data != 'ffd9') {
96: switch ($data) {
97: case 'ffe0':
98:
99: $result['ValidJFIFData'] = 1;
100: $result['JFIF']['Size'] = hexdec($size);
101: if (hexdec($size) - 2 > 0) {
102: $data = fread($in, hexdec($size) - 2);
103: $result['JFIF']['Data'] = $data;
104: }
105: $result['JFIF']['Identifier'] = substr($data, 0, 5);
106: $result['JFIF']['ExtensionCode'] = bin2hex(substr($data, 6, 1));
107: $globalOffset += hexdec($size) + 2;
108: break;
109:
110: case 'ffed':
111:
112: $result['ValidIPTCData'] = 1;
113: $result['IPTC']['Size'] = hexdec($size);
114: if (hexdec($size) - 2 > 0) {
115: $data = fread($in, hexdec($size) - 2);
116: $result['IPTC']['Data'] = $data ;
117: }
118: $globalOffset += hexdec($size) + 2;
119: break;
120:
121: case 'ffe2':
122:
123: $result['ValidAPP2Data'] = 1;
124: $result['APP2']['Size'] = hexdec($size);
125: if (hexdec($size) - 2 > 0) {
126: $data = fread($in, hexdec($size) - 2);
127: $result['APP2']['Data'] = $data ;
128: }
129: $globalOffset += hexdec($size) + 2;
130: break;
131:
132: case 'fffe':
133:
134: $result['ValidCOMData'] = 1;
135: $result['COM']['Size'] = hexdec($size);
136: if (hexdec($size) - 2 > 0) {
137: $data = fread($in, hexdec($size) - 2);
138: $result['COM']['Data'] = $data ;
139: }
140: $globalOffset += hexdec($size) + 2;
141: break;
142:
143: case 'ffe1':
144: $result['ValidEXIFData'] = 1;
145: break;
146: }
147:
148: $data = bin2hex(fread($in, 2));
149: $size = bin2hex(fread($in, 2));
150: }
151:
152: if ($data != 'ffe1') {
153: fclose($in);
154: fclose($seek);
155: return $result;
156: }
157:
158: $result['ValidEXIFData'] = 1;
159:
160:
161: $result['APP1Size'] = hexdec($size);
162:
163:
164: $header = fread($in, 6);
165:
166:
167: $header = fread($in, 2);
168: switch ($header) {
169: case 'II':
170: $intel = 1;
171: $result['Endien'] = 'Intel';
172: break;
173: case 'MM':
174: $intel = 0;
175: $result['Endien'] = 'Motorola';
176: break;
177: default:
178:
179: $intel = 1;
180: $result['Endien'] = 'Unknown';
181: break;
182: }
183:
184:
185: $tag = bin2hex(fread( $in, 2 ));
186:
187:
188:
189: $offset = bin2hex(fread($in, 4));
190: if ($intel == 1) {
191: $offset = Horde_Image_Exif::intel2Moto($offset);
192: }
193:
194:
195: if (hexdec($offset) > 100000) {
196: $result['ValidEXIFData'] = 0;
197: fclose($in);
198: fclose($seek);
199: return $result;
200: }
201:
202: if (hexdec($offset) > 8) {
203: $unknown = fread($in, hexdec($offset) - 8);
204: }
205:
206:
207: $globalOffset += 12;
208:
209:
210:
211: $num = bin2hex(fread($in, 2));
212: if ($intel == 1) {
213: $num = Horde_Image_Exif::intel2Moto($num);
214: }
215: $num = hexdec($num);
216: $result['IFD0NumTags'] = $num;
217:
218:
219: if ($num < 1000) {
220: for ($i = 0; $i < $num; $i++) {
221: $this->_readEntry($result, $in, $seek, $intel, 'IFD0', $globalOffset);
222: }
223: } else {
224: $result['Errors'] = $result['Errors'] + 1;
225: $result['Error'][$result['Errors']] = 'Illegal size for IFD0';
226: }
227:
228:
229: $offset = bin2hex(fread($in, 4));
230: if ($intel == 1) {
231: $offset = Horde_Image_Exif::intel2Moto($offset);
232: }
233: $result['IFD1Offset'] = hexdec($offset);
234:
235:
236: if (!isset($result['IFD0']['ExifOffset']) ||
237: $result['IFD0']['ExifOffset'] == 0) {
238: fclose($in);
239: fclose($seek);
240: return $result;
241: }
242:
243:
244: $ExitOffset = $result['IFD0']['ExifOffset'];
245: $v = fseek($in, $globalOffset + $ExitOffset);
246: if ($v == -1) {
247: $result['Errors'] = $result['Errors'] + 1;
248: $result['Error'][$result['Errors']] = Horde_Image_Translation::t("Couldnt Find SubIFD");
249: }
250:
251:
252:
253: $num = bin2hex(fread($in, 2));
254: if ($intel == 1) {
255: $num = Horde_Image_Exif::intel2Moto($num);
256: }
257: $num = hexdec($num);
258: $result['SubIFDNumTags'] = $num;
259:
260:
261: if ($num < 1000) {
262: for ($i = 0; $i < $num; $i++) {
263: $this->_readEntry($result, $in, $seek, $intel, 'SubIFD', $globalOffset);
264: }
265: } else {
266: $result['Errors'] = $result['Errors'] + 1;
267: $result['Error'][$result['Errors']] = Horde_Image_Translation::t("Illegal size for SubIFD");
268: }
269:
270:
271:
272:
273:
274:
275: if (!isset($result['IFD1Offset']) || $result['IFD1Offset'] == 0) {
276: fclose($in);
277: fclose($seek);
278: return $result;
279: }
280:
281:
282: $v = fseek($in, $globalOffset + $result['IFD1Offset']);
283: if ($v == -1) {
284: $result['Errors'] = $result['Errors'] + 1;
285: $result['Error'][$result['Errors']] = Horde_Image_Translation::t("Couldnt Find IFD1");
286: }
287:
288:
289:
290: $num = bin2hex(fread($in, 2));
291: if ($intel == 1) {
292: $num = Horde_Image_Exif::intel2Moto($num);
293: }
294: $num = hexdec($num);
295: $result['IFD1NumTags'] = $num;
296:
297:
298: if ($num < 1000) {
299: for ($i = 0; $i < $num; $i++) {
300: $this->_readEntry($result, $in, $seek, $intel, 'IFD1', $globalOffset);
301: }
302: } else {
303: $result['Errors'] = $result['Errors'] + 1;
304: $result['Error'][$result['Errors']] = Horde_Image_Translation::t("Illegal size for IFD1");
305: }
306:
307:
308: if ($result['IFD1']['JpegIFOffset'] > 0 &&
309: $result['IFD1']['JpegIFByteCount'] > 0) {
310: $v = fseek($seek, $globalOffset + $result['IFD1']['JpegIFOffset']);
311: if ($v == 0) {
312: $data = fread($seek, $result['IFD1']['JpegIFByteCount']);
313: } else if ($v == -1) {
314: $result['Errors'] = $result['Errors'] + 1;
315: }
316: $result['IFD1']['ThumbnailData'] = $data;
317: }
318:
319:
320: if (!isset($result['SubIFD']['ExifInteroperabilityOffset']) ||
321: $result['SubIFD']['ExifInteroperabilityOffset'] == 0) {
322: fclose($in);
323: fclose($seek);
324: return $result;
325: }
326:
327:
328: $v = fseek($in, $globalOffset + $result['SubIFD']['ExifInteroperabilityOffset']);
329: if ($v == -1) {
330: $result['Errors'] = $result['Errors'] + 1;
331: $result['Error'][$result['Errors']] = Horde_Image_Translation::t("Couldnt Find InteroperabilityIFD");
332: }
333:
334:
335:
336: $num = bin2hex(fread($in, 2));
337: if ($intel == 1) {
338: $num = Horde_Image_Exif::intel2Moto($num);
339: }
340: $num = hexdec($num);
341: $result['InteroperabilityIFDNumTags'] = $num;
342:
343:
344: if ($num < 1000) {
345: for ($i = 0; $i < $num; $i++) {
346: $this->_readEntry($result, $in, $seek, $intel, 'InteroperabilityIFD', $globalOffset);
347: }
348: } else {
349: $result['Errors'] = $result['Errors'] + 1;
350: $result['Error'][$result['Errors']] = Horde_Image_Translation::t("Illegal size for InteroperabilityIFD");
351: }
352:
353: fclose($in);
354: fclose($seek);
355: return $result;
356: }
357:
358: 359: 360: 361: 362: 363: 364: 365: 366: 367:
368: protected function _readEntry(&$result, $in, $seek, $intel, $ifd_name,
369: $globalOffset)
370: {
371:
372: if (feof($in)) {
373: $result['Errors'] = $result['Errors'] + 1;
374: return;
375: }
376:
377:
378: $tag = bin2hex(fread($in, 2));
379: if ($intel == 1) {
380: $tag = Horde_Image_Exif::intel2Moto($tag);
381: }
382: $tag_name = $this->_lookupTag($tag);
383:
384:
385: $type = bin2hex(fread($in, 2));
386: if ($intel == 1) {
387: $type = Horde_Image_Exif::intel2Moto($type);
388: }
389: $this->_lookupType($type, $size);
390:
391:
392: $count = bin2hex(fread($in, 4));
393: if ($intel == 1) {
394: $count = Horde_Image_Exif::intel2Moto($count);
395: }
396: $bytesofdata = $size * hexdec($count);
397:
398:
399: $value = fread($in, 4);
400:
401:
402: if ($bytesofdata <= 4) {
403: $data = $value;
404: } elseif ($bytesofdata < 100000) {
405:
406: $value = bin2hex($value);
407: if ($intel == 1) {
408: $value = Horde_Image_Exif::intel2Moto($value);
409: }
410:
411: $v = fseek($seek, $globalOffset+hexdec($value));
412: if ($v == 0) {
413: $data = fread($seek, $bytesofdata);
414: } elseif ($v == -1) {
415: $result['Errors'] = $result['Errors'] + 1;
416: }
417: } else {
418:
419: $result['Errors'] = $result['Errors'] + 1;
420: return;
421: }
422:
423:
424: switch ($tag_name) {
425: case 'MakerNote':
426: $make = Horde_String::lower($result['IFD0']['Make']);
427: $parser = null;
428: if (strpos($make, 'nikon') !== false) {
429: $parser = new Horde_Image_Exif_Parser_Nikon();
430: $result[$ifd_name]['KnownMaker'] = 1;
431: } elseif (strpos($make, 'olympus') !== false) {
432: $parser = new Horde_Image_Exif_Parser_Olympus();
433: $result[$ifd_name]['KnownMaker'] = 1;
434: } elseif (strpos($make, 'canon') !== false) {
435: $parser = new Horde_Image_Exif_Parser_Canon();
436: $result[$ifd_name]['KnownMaker'] = 1;
437: } elseif (strpos($make, 'fujifilm') !== false) {
438: $parser = new Horde_Image_Exif_Parser_Fujifilm();
439: $result[$ifd_name]['KnownMaker'] = 1;
440: } elseif (strpos($make, 'sanyo') !== false) {
441: $parser = new Horde_Image_Exif_Parser_Sanyo();
442: $result[$ifd_name]['KnownMaker'] = 1;
443: } elseif (strpos($make, 'panasonic') !== false) {
444: $parser = new Horde_Image_Exif_Parser_Panasonic();
445: $result[$ifd_name]['KnownMaker'] = 1;
446: } else {
447: $result[$ifd_name]['KnownMaker'] = 0;
448: }
449: if ($parser) {
450: $parser->parse($data, $result, $seek, $globalOffset);
451: }
452: break;
453:
454: case 'GPSInfoOffset':
455: $formated_data = $this->_formatData($type, $tag, $intel, $data);
456: $result[$ifd_name]['GPSInfo'] = $formated_data;
457: $parser = new Horde_Image_Exif_Parser_Gps();
458: $parser->parse($data, $result, $formated_data, $seek, $globalOffset);
459: break;
460:
461: default:
462:
463: $formated_data = $this->_formatData($type, $tag, $intel, $data);
464: $result[$ifd_name][$tag_name] = $formated_data;
465: }
466: }
467:
468: 469: 470: 471: 472:
473: protected function _lookupTag($tag)
474: {
475: switch($tag)
476: {
477:
478:
479: case '000b': $tag = 'ACDComment'; break;
480:
481: case '00fe': $tag = 'ImageType'; break;
482:
483: case '0106': $tag = 'PhotometricInterpret'; break;
484:
485: case '010e': $tag = 'ImageDescription'; break;
486:
487: case '010f': $tag = 'Make'; break;
488:
489: case '0110': $tag = 'Model'; break;
490:
491: case '0112': $tag = 'Orientation'; break;
492:
493: case '0115': $tag = 'SamplePerPixel'; break;
494:
495: case '011a': $tag = 'xResolution'; break;
496:
497: case '011b': $tag = 'yResolution'; break;
498:
499: case '011c': $tag = 'PlanarConfig'; break;
500:
501: case '0128': $tag = 'ResolutionUnit'; break;
502:
503: case '0131': $tag = 'Software'; break;
504:
505: case '0132': $tag = 'DateTime'; break;
506:
507: case '013b': $tag = 'Artist'; break;
508:
509: case '013c': $tag = 'HostComputer'; break;
510:
511: case '013e': $tag = 'WhitePoint'; break;
512:
513: case '013f': $tag = 'PrimaryChromaticities'; break;
514:
515: case '0211': $tag = 'YCbCrCoefficients'; break;
516:
517: case '0213': $tag = 'YCbCrPositioning'; break;
518:
519: case '0214': $tag = 'ReferenceBlackWhite'; break;
520:
521: case '8298': $tag = 'Copyright'; break;
522:
523: case '8649': $tag = 'PhotoshopSettings'; break;
524: case '8825': $tag = 'GPSInfoOffset'; break;
525:
526: case '8769': $tag = 'ExifOffset'; break;
527:
528:
529:
530: case '829a': $tag = 'ExposureTime'; break;
531:
532: case '829d': $tag = 'FNumber'; break;
533:
534: case '8822': $tag = 'ExposureProgram'; break;
535:
536: case '8824': $tag = 'SpectralSensitivity'; break;
537:
538: case '8827': $tag = 'ISOSpeedRatings'; break;
539:
540: case '9000': $tag = 'ExifVersion'; break;
541:
542: case '9003': $tag = 'DateTimeOriginal'; break;
543:
544: case '9004': $tag = 'DateTimedigitized'; break;
545:
546: case '9101': $tag = 'ComponentsConfiguration'; break;
547:
548: case '9102': $tag = 'CompressedBitsPerPixel'; break;
549:
550: case '9201': $tag = 'ShutterSpeedValue'; break;
551:
552: case '9202': $tag = 'ApertureValue'; break;
553:
554: case '9203': $tag = 'BrightnessValue'; break;
555:
556: case '9204': $tag = 'ExposureBiasValue'; break;
557:
558: case '9205': $tag = 'MaxApertureValue'; break;
559:
560: case '9206': $tag = 'SubjectDistance'; break;
561:
562: case '9207': $tag = 'MeteringMode'; break;
563:
564: case '9208': $tag = 'LightSource'; break;
565:
566: case '9209': $tag = 'Flash'; break;
567:
568: case '920a': $tag = 'FocalLength'; break;
569:
570: case '9213': $tag = 'ImageHistory'; break;
571:
572: case '927c': $tag = 'MakerNote'; break;
573:
574: case '9286': $tag = 'UserComment'; break;
575:
576: case '9290': $tag = 'SubsecTime'; break;
577:
578: case '9291': $tag = 'SubsecTimeOriginal'; break;
579:
580: case '9292': $tag = 'SubsecTimeDigitized'; break;
581:
582: case 'a000': $tag = 'FlashPixVersion'; break;
583:
584: case 'a001': $tag = 'ColorSpace'; break;
585:
586: case 'a002': $tag = 'ExifImageWidth'; break;
587:
588: case 'a003': $tag = 'ExifImageHeight'; break;
589:
590: case 'a004': $tag = 'RelatedSoundFile'; break;
591:
592: case 'a005': $tag = 'ExifInteroperabilityOffset'; break;
593:
594: case 'a20c': $tag = 'SpacialFreqResponse'; break;
595:
596: case 'a20b': $tag = 'FlashEnergy'; break;
597:
598: case 'a20e': $tag = 'FocalPlaneXResolution'; break;
599:
600: case 'a20f': $tag = 'FocalPlaneYResolution'; break;
601:
602: case 'a210': $tag = 'FocalPlaneResolutionUnit'; break;
603:
604: case 'a214': $tag = 'SubjectLocation'; break;
605:
606: case 'a215': $tag = 'ExposureIndex'; break;
607:
608: case 'a217': $tag = 'SensingMethod'; break;
609:
610: case 'a300': $tag = 'FileSource'; break;
611:
612: case 'a301': $tag = 'SceneType'; break;
613:
614: case 'a302': $tag = 'CFAPattern'; break;
615:
616: case 'a401': $tag = 'CustomerRender'; break;
617:
618: case 'a402': $tag = 'ExposureMode'; break;
619:
620: case 'a403': $tag = 'WhiteBalance'; break;
621:
622: case 'a404': $tag = 'DigitalZoomRatio'; break;
623: case 'a405': $tag = 'FocalLengthIn35mmFilm';break;
624:
625: case 'a406': $tag = 'SceneCaptureMode'; break;
626:
627: case 'a407': $tag = 'GainControl'; break;
628:
629: case 'a408': $tag = 'Contrast'; break;
630:
631: case 'a409': $tag = 'Saturation'; break;
632:
633: case 'a40a': $tag = 'Sharpness'; break;
634:
635:
636:
637: case '0001': $tag = 'InteroperabilityIndex'; break;
638:
639: case '0002': $tag = 'InteroperabilityVersion'; break;
640:
641: case '1000': $tag = 'RelatedImageFileFormat'; break;
642:
643: case '1001': $tag = 'RelatedImageWidth'; break;
644:
645:
646: case '1002': $tag = 'RelatedImageLength'; break;
647:
648:
649: case '0100': $tag = 'ImageWidth'; break;
650:
651: case '0101': $tag = 'ImageLength'; break;
652:
653: case '0102': $tag = 'BitsPerSample'; break;
654:
655: case '0103': $tag = 'Compression'; break;
656:
657: case '0106': $tag = 'PhotometricInterpretation'; break;
658:
659: case '010e': $tag = 'ThumbnailDescription'; break;
660:
661: case '010f': $tag = 'ThumbnailMake'; break;
662:
663: case '0110': $tag = 'ThumbnailModel'; break;
664:
665: case '0111': $tag = 'StripOffsets'; break;
666:
667: case '0112': $tag = 'ThumbnailOrientation'; break;
668:
669: case '0115': $tag = 'SamplesPerPixel'; break;
670:
671: case '0116': $tag = 'RowsPerStrip'; break;
672:
673: case '0117': $tag = 'StripByteCounts'; break;
674:
675: case '011a': $tag = 'ThumbnailXResolution'; break;
676:
677: case '011b': $tag = 'ThumbnailYResolution'; break;
678:
679: case '011c': $tag = 'PlanarConfiguration'; break;
680:
681: case '0128': $tag = 'ThumbnailResolutionUnit'; break;
682: case '0201': $tag = 'JpegIFOffset'; break;
683: case '0202': $tag = 'JpegIFByteCount'; break;
684: case '0212': $tag = 'YCbCrSubSampling'; break;
685:
686:
687: case '00ff': $tag = 'SubfileType'; break;
688: case '012d': $tag = 'TransferFunction'; break;
689: case '013d': $tag = 'Predictor'; break;
690: case '0142': $tag = 'TileWidth'; break;
691: case '0143': $tag = 'TileLength'; break;
692: case '0144': $tag = 'TileOffsets'; break;
693: case '0145': $tag = 'TileByteCounts'; break;
694: case '014a': $tag = 'SubIFDs'; break;
695: case '015b': $tag = 'JPEGTables'; break;
696: case '828d': $tag = 'CFARepeatPatternDim'; break;
697: case '828e': $tag = 'CFAPattern'; break;
698: case '828f': $tag = 'BatteryLevel'; break;
699: case '83bb': $tag = 'IPTC/NAA'; break;
700: case '8773': $tag = 'InterColorProfile'; break;
701:
702: case '8828': $tag = 'OECF'; break;
703: case '8829': $tag = 'Interlace'; break;
704: case '882a': $tag = 'TimeZoneOffset'; break;
705: case '882b': $tag = 'SelfTimerMode'; break;
706: case '920b': $tag = 'FlashEnergy'; break;
707: case '920c': $tag = 'SpatialFrequencyResponse'; break;
708: case '920d': $tag = 'Noise'; break;
709: case '9211': $tag = 'ImageNumber'; break;
710: case '9212': $tag = 'SecurityClassification'; break;
711: case '9214': $tag = 'SubjectLocation'; break;
712: case '9215': $tag = 'ExposureIndex'; break;
713: case '9216': $tag = 'TIFF/EPStandardID'; break;
714: case 'a20b': $tag = 'FlashEnergy'; break;
715:
716: default: $tag = 'unknown:'.$tag; break;
717: }
718:
719: return $tag;
720: }
721:
722: 723: 724: 725: 726: 727: 728: 729:
730: protected function _formatData($type, $tag, $intel, $data)
731: {
732: switch ($type) {
733: case 'ASCII':
734:
735: if (($pos = strpos($data, chr(0))) !== false) {
736: $data = substr($data, 0, $pos);
737: }
738:
739: if ($tag == '010f') {
740: $data = ucwords(strtolower(trim($data)));
741: }
742: break;
743:
744: case 'URATIONAL':
745: case 'SRATIONAL':
746: $data = bin2hex($data);
747: if ($intel == 1) {
748: $data = Horde_Image_Exif::intel2Moto($data);
749: }
750:
751: if ($intel == 1) {
752:
753: $top = hexdec(substr($data, 8, 8));
754: } else {
755:
756: $top = hexdec(substr($data, 0, 8));
757: }
758:
759: if ($intel == 1) {
760:
761: $bottom = hexdec(substr($data, 0, 8));
762: } else {
763:
764: $bottom = hexdec(substr($data, 8, 8));
765: }
766:
767: if ($type == 'SRATIONAL' && $top > 2147483647) {
768:
769: $top = $top - 4294967296;
770: }
771: if ($bottom != 0) {
772: $data = $top / $bottom;
773: } elseif ($top == 0) {
774: $data = 0;
775: } else {
776: $data = $top . '/' . $bottom;
777: }
778:
779:
780: if ($tag == '829a') {
781: if ($bottom != 0) {
782: $data = $top . '/' . $bottom;
783: } else {
784: $data = 0;
785: }
786: }
787: break;
788:
789: case 'USHORT':
790: case 'SSHORT':
791: case 'ULONG':
792: case 'SLONG':
793: case 'FLOAT':
794: case 'DOUBLE':
795: $data = bin2hex($data);
796: if ($intel == 1) {
797: $data = Horde_Image_Exif::intel2Moto($data);
798: }
799: if ($intel == 0 && ($type == 'USHORT' || $type == 'SSHORT')) {
800: $data = substr($data, 0, 4);
801: }
802: $data = hexdec($data);
803: if ($type == 'SSHORT' && $data > 32767) {
804:
805: $data = $data - 65536;
806: }
807: if ($type == 'SLONG' && $data > 2147483647) {
808:
809: $data = $data - 4294967296;
810: }
811: break;
812:
813: case 'UNDEFINED':
814:
815: if ($tag == '9000' || $tag == 'a000' || $tag == '0002') {
816: $data = sprintf(Horde_Image_Translation::t("version %d"), $data / 100);
817: }
818: break;
819:
820: default:
821: $data = bin2hex($data);
822: if ($intel == 1) {
823: $data = Horde_Image_Exif::intel2Moto($data);
824: }
825: break;
826: }
827:
828: return $data;
829: }
830:
831: 832: 833: 834: 835: 836:
837: protected function _lookupType(&$type, &$size)
838: {
839: switch ($type) {
840: case '0001': $type = 'UBYTE'; $size = 1; break;
841: case '0002': $type = 'ASCII'; $size = 1; break;
842: case '0003': $type = 'USHORT'; $size = 2; break;
843: case '0004': $type = 'ULONG'; $size = 4; break;
844: case '0005': $type = 'URATIONAL'; $size = 8; break;
845: case '0006': $type = 'SBYTE'; $size = 1; break;
846: case '0007': $type = 'UNDEFINED'; $size = 1; break;
847: case '0008': $type = 'SSHORT'; $size = 2; break;
848: case '0009': $type = 'SLONG'; $size = 4; break;
849: case '000a': $type = 'SRATIONAL'; $size = 8; break;
850: case '000b': $type = 'FLOAT'; $size = 4; break;
851: case '000c': $type = 'DOUBLE'; $size = 8; break;
852: default: $type = 'error:'.$type; $size = 0; break;
853: }
854:
855: return $type;
856: }
857:
858: public function supportedCategories()
859: {
860: return array('EXIF');
861: }
862:
863: }