source: extensions/AMetaData/JpegMetaData/Readers/XmpReader.class.php

Last change on this file was 17554, checked in by grum, 12 years ago

feature:2701
bug:2702
bug:2720
bug:2722

  • Property svn:executable set to *
File size: 24.5 KB
Line 
1<?php
2/*
3 * --:: JPEG MetaDatas ::-------------------------------------------------------
4 *
5 *  Author    : Grum
6 *   email    : grum at piwigo.org
7 *   website  : http://photos.grum.fr
8 *
9 *   << May the Little SpaceFrog be with you ! >>
10 *
11 *
12 * +-----------------------------------------------------------------------+
13 * | JpegMetaData - a PHP based Jpeg Metadata manager                      |
14 * +-----------------------------------------------------------------------+
15 * | Copyright(C) 2010  Grum - http://www.grum.fr                          |
16 * +-----------------------------------------------------------------------+
17 * | This program is free software; you can redistribute it and/or modify  |
18 * | it under the terms of the GNU General Public License as published by  |
19 * | the Free Software Foundation                                          |
20 * |                                                                       |
21 * | This program is distributed in the hope that it will be useful, but   |
22 * | WITHOUT ANY WARRANTY; without even the implied warranty of            |
23 * | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      |
24 * | General Public License for more details.                              |
25 * |                                                                       |
26 * | You should have received a copy of the GNU General Public License     |
27 * | along with this program; if not, write to the Free Software           |
28 * | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
29 * | USA.                                                                  |
30 * +-----------------------------------------------------------------------+
31 *
32 *
33 * -----------------------------------------------------------------------------
34 *
35 * The XmpReader class is the dedicated class to read XMP from the APP1 segment
36 *
37 * -----------------------------------------------------------------------------
38 *
39 * .. Notes ..
40 *
41 * The XmpReader class is derived from the GenericReader class.
42 *
43 * ======> See GenericReader.class.php to know more about common methods <======
44 *
45 * -----------------------------------------------------------------------------
46 */
47
48  require_once(JPEG_METADATA_DIR."Common/Data.class.php");
49  require_once(JPEG_METADATA_DIR."Common/XmlData.class.php");
50  require_once(JPEG_METADATA_DIR."Readers/GenericReader.class.php");
51  require_once(JPEG_METADATA_DIR."TagDefinitions/XmpTags.class.php");
52
53  class XmpReader extends GenericReader
54  {
55    protected $schema = Schemas::XMP;
56
57    private $xmlData = NULL;
58
59    private $xmpTag2Exif = NULL;
60
61    /**
62     * The constructor needs, like the ancestor, the datas to be parsed
63     *
64     * @param String $data
65     */
66    function __construct($data)
67    {
68      /**
69       * XML data are given from an APP1 segement.
70       *
71       * The XMP header ends with a \x00 char, so XML data can be extracted
72       * after the \x00 char
73       *
74       */
75      $this->data=explode("\x00", $data);
76      if(count($this->data)>1)
77      {
78        $this->data=$this->data[1];
79      }
80      else
81      {
82        $this->data="";
83      }
84
85      parent::__construct($this->data);
86
87      $this->xmpTag2Exif = new XmpTag2Exif("", 0, 0);
88
89      $this->xmlData = new XmlData($this->data->readASCII(-1,0));
90      $this->tagDef = new XmpTags();
91
92      $this->loadTags();
93
94      $this->isValid = $this->xmlData->isValid();
95      $this->isLoaded = $this->xmlData->isLoaded();
96
97    }
98
99    function __destruct()
100    {
101      unset($this->xmlData);
102      unset($this->xmpTag2Exif);
103      parent::__destruct();
104    }
105
106    public function toString()
107    {
108      $returned=$this->data->readASCII(-1,0);
109      return($returned);
110    }
111
112    /**
113     * This function load tags from the xml tree
114     */
115    private function loadTags()
116    {
117      if($this->xmlData->hasNodes())
118      {
119        $this->processNode($this->xmlData->getFirstNode());
120      }
121    }
122
123    /**
124     * this function analyze the node properties
125     *  - attributes are converted in Tag through a call to the addTag function
126     *  - childs are processed by a specific call to the processChildNode
127     *    function
128     *  - next node is processed by a recursive call
129     *
130     * @param XmlNode $node
131     */
132    private function processNode($node)
133    {
134      if(!is_null($node))
135      {
136        $node->setName($this->processNodeName($node->getName()));
137
138        foreach($node->getAttributes() as $key => $val)
139        {
140          $val['name']=$this->processNodeName($val['name']);
141          $this->addTag($val['name'], $val['value']);
142        }
143
144        if(!is_null($node->getValue()))
145        {
146          $this->addTag($node->getName(), $node->getValue());
147        }
148
149        if($node->hasChilds())
150        {
151          $this->processChildNode($node);
152        }
153
154        $this->processNode($node->getNextNode());
155      }
156    }
157
158
159    /**
160     * 'xap' schemas have to be interpreted as a 'xmp' schemas
161     * so, this function rename all 'xap' nodes in 'xmp' nodes
162     *
163     * @param String $nodeName
164     */
165    private function processNodeName($nodeName)
166    {
167      $name=preg_replace(Array("/^(xap:)/", "/^(xapMM:)/"), Array("xmp:", "xmpMM:"), $nodeName);
168
169      return($name);
170    }
171
172
173    /**
174     * childs node are 'seq', 'alt' or 'bag' type and needs a specific
175     * interpretation
176     *
177     * this function process this kind of data, and add it in the Tag entries
178     *
179     * if child node is not a special a specific node, process it as a normal
180     * node
181     *
182     * @param XmlNode $node
183     */
184    private function processChildNode($node)
185    {
186      switch($node->getName())
187      {
188        /*
189         * child must be 'rdf:Seq', 'rdf:Bag' or 'rdf:Alt'
190         */
191        case "dc:contributor" : // bag
192        case "dc:creator" : // seq
193        case "dc:date" : // seq
194        case "dc:description" : // alt
195        case "dc:language" : // bag
196        case "dc:publisher" : // bag
197        case "dc:relation" : // bag
198        case "dc:rights" : // alt
199        case "dc:subject" : // bag
200        case "dc:title" : // alt
201        case "dc:Type" : // bag
202        case "xmp:Advisory" : // bag
203        case "xmp:Identifier" : // bag
204        case "xmp:Thumbnails" : // alt
205        case "xmpRights:Owner" : // bag
206        case "xmpRights:UsageTerms" : // alt
207        case "xmpMM:History" : // seq
208        case "xmpMM:Versions" : // seq
209        case "xmpBJ:JobRef" : // bag
210        case "xmpTPg:Fonts" : // bag
211        case "xmpTPg:Colorants" : // seq
212        case "xmpTPg:PlateNames" : // seq
213        case "photoshop:SupplementalCategories" : // bag
214        case "crs:ToneCurve" : // seq
215        case "tiff:BitsPerSample" : // seq
216        case "tiff:YCbCrSubSampling" : // seq
217        case "tiff:TransferFunction" : // seq
218        case "tiff:WhitePoint" : // seq
219        case "tiff:PrimaryChromaticities" : // seq
220        case "tiff:YCbCrCoefficients" : // seq
221        case "tiff:ReferenceBlackWhite" : // seq
222        case "tiff:ImageDescription" : // alt
223        case "tiff:Copyright" : // alt
224        case "exif:ComponentsConfiguration" : // seq
225        case "exif:UserComment" : // alt
226        case "exif:ISOSpeedRatings" : // seq
227        case "exif:SubjectArea" : // seq
228        case "exif:SubjectLocation" : // seq
229        case "Iptc4xmpCore:Scene": //bag
230        case "Iptc4xmpCore:SubjectCode": //bag
231        case "digiKam:TagsList": //seq
232        case "lr:hierarchicalSubject": //bag
233          $child=$node->getFirstChild();
234          switch($child->getName())
235          {
236            case "rdf:Seq":
237              $type="seq";
238              break;
239            case "rdf:Bag":
240              $type="bag";
241              break;
242            case "rdf:Alt":
243              $type="alt";
244              break;
245            default:
246              $type="n/a";
247              break;
248          }
249
250          $types=array('simple', 'seq', 'bag', 'alt');
251          $tagProperties=$this->tagDef->getTagById($node->getName());
252
253          if($type=="seq" or $type=="bag" or $type=="alt")
254          {
255            if($type!=$types[$tagProperties['type']])
256              $type=$types[$tagProperties['type']]; // if container type is not accorded with XMP schema, force it to right value
257
258            $value=Array('type' => $type, 'values' => Array());
259            $childNode=$child->getFirstChild();
260            while(!is_null($childNode))
261            {
262              if($childNode->getName() == "rdf:li")
263              {
264                if($type=="alt")
265                {
266                  $attributes=$childNode->getAttributes();
267                  if(count($attributes)>0)
268                  {
269                    $attributes=$attributes[0];
270                  }
271                  else
272                  {
273                    $attributes="n/a";
274                  }
275                  $value['values'][]=Array('type' => $attributes, 'value' => $childNode->getValue());
276                }
277                else
278                {
279                  $childNode->delAttributes(); // remove all attributes => only 'alt' type can have attributes
280                  $value['values'][]=$childNode->getValue();
281                }
282              }
283              $childNode=$childNode->getNextNode();
284            }
285            $this->addTag($node->getName(), $value);
286          }
287          unset($child);
288          break;
289        default:
290          $this->processNode($node->getFirstChild());
291          break;
292      }
293    }
294
295    /**
296     * add a Tag to the entries.
297     * name and value are needed, the function made the rest (interpret the
298     * value into a 'human readable' value)
299     *
300     * @param String $name : the name of the tag
301     * @param $value       : can be of any type
302     */
303    private function addTag($name, $value)
304    {
305      $tag=new Tag($name, $value, $name);
306
307      if($this->tagDef->tagIdExists($name))
308      {
309        $tagProperties=$this->tagDef->getTagById($name);
310
311        $tag->setKnown(true);
312        $tag->setImplemented($tagProperties['implemented']);
313        $tag->setTranslatable($tagProperties['translatable']);
314        $tag->setSchema($this->schema);
315
316        if(array_key_exists('name', $tagProperties))
317        {
318          $tag->setName($tagProperties['name']);
319        }
320
321        /*
322         * if there is values defined for the tag, analyze it
323         */
324        if(array_key_exists('tagValues', $tagProperties))
325        {
326          if(array_key_exists($value, $tagProperties['tagValues']))
327          {
328            $tag->setLabel($tagProperties['tagValues'][$value]);
329          }
330          else
331          {
332            $tag->setLabel("[unknown value '".$value."']");
333          }
334        }
335        else
336        {
337          /*
338           * there is no values defined for the tag, analyzing it with dedicated
339           * function
340           */
341          if(array_key_exists('exifTag', $tagProperties))
342          {
343            $tag->setLabel($this->xmp2Exif($name, $tagProperties['exifTag'], $value));
344          }
345          else
346          {
347            $tag->setLabel($this->processSpecialTag($name, $value));
348          }
349
350        }
351        unset($tagProperties);
352      }
353
354      $this->entries[]=$tag;
355      unset($tag);
356    }
357
358    /**
359     * this function do the interpretation of specials tags
360     *
361     * the function return the interpreted value for the tag
362     *
363     * @param $name              : the name of the tag
364     * @param $value             : 'raw' value to be interpreted
365     */
366    private function processSpecialTag($name, $value)
367    {
368      /*
369       * Note : exif & tiff values are not processed in this function
370       */
371      switch($name)
372      {
373        case "x:xmptk":
374        case "aux:Lens":
375        case "aux:Firmware":
376        case "aux:SerialNumber":
377        case "dc:coverage":
378        case "dc:format":
379        case "dc:identifier":
380        case "dc:relation":
381        case "dc:source":
382        case "dc:title":
383        case "dc:CreatorTool":
384        case "xmp:BaseURL":
385        case "xmp:CreatorTool":
386        case "xmp:Label":
387        case "xmp:Nickname":
388        case "xmp:Rating:":
389        case "xmpRights:Certificate":
390        case "xmpRights:Marked":
391        case "xmpRights:UsageTerms":
392        case "xmpRights:WebStatement":
393        case "xmpMM:DocumentID":
394        case "xmpMM:InstanceID":
395        case "xmpMM:Manager":
396        case "xmpMM:ManageTo":
397        case "xmpMM:ManageUI":
398        case "xmpMM:ManagerVariant":
399        case "xmpMM:RenditionParams":
400        case "xmpMM:VersionID":
401        case "xmpMM:LastURL":
402        case "photoshop:AuthorsPosition":
403        case "photoshop:CaptionWriter":
404        case "photoshop:Category":
405        case "photoshop:City":
406        case "photoshop:Country":
407        case "photoshop:Credit":
408        case "photoshop:Headline":
409        case "photoshop:Instructions":
410        case "photoshop:Source":
411        case "photoshop:State":
412        case "photoshop:TransmissionReference":
413        case "photoshop:ICCProfile":
414        case "crs:AutoBrightness":
415        case "crs:AutoContrast":
416        case "crs:AutoExposure":
417        case "crs:AutoShadows":
418        case "crs:BlueHue":
419        case "crs:BlueSaturation":
420        case "crs:Brightness":
421        case "crs:CameraProfile":
422        case "crs:ChromaticAberrationB":
423        case "crs:ChromaticAberrationR":
424        case "crs:ColorNoiseReduction":
425        case "crs:Contrast":
426        case "crs:CropTop":
427        case "crs:CropLeft":
428        case "crs:CropBottom":
429        case "crs:CropRight":
430        case "crs:CropAngle":
431        case "crs:CropWidth":
432        case "crs:CropHeight":
433        case "crs:Exposure":
434        case "crs:GreenHue":
435        case "crs:GreenSaturation":
436        case "crs:HasCrop":
437        case "crs:HasSettings":
438        case "crs:LuminanceSmoothing":
439        case "crs:RawFileName":
440        case "crs:RedHue":
441        case "crs:RedSaturation":
442        case "crs:Saturation":
443        case "crs:Shadows":
444        case "crs:ShadowTint":
445        case "crs:Sharpness":
446        case "crs:Temperature":
447        case "crs:Tint":
448        case "crs:Version":
449        case "crs:VignetteAmount":
450        case "crs:VignetteMidpoint":
451        case "Iptc4xmpCore:CountryCode":
452        case "Iptc4xmpCore:Location":
453        case "Iptc4xmpCore:CiEmailWork":
454        case "Iptc4xmpCore:CiUrlWork":
455        case "Iptc4xmpCore:CiTelWork":
456        case "Iptc4xmpCore:CiAdrExtadr":
457        case "Iptc4xmpCore:CiAdrPcode":
458        case "Iptc4xmpCore:CiAdrCity":
459        case "Iptc4xmpCore:CiAdrCtry":
460          $returned=$value;
461          break;
462        case "Iptc4xmpCore:IntellectualGenre":
463          $returned=explode(":", $value);
464          if(!is_array($returned)) $returned=array($returned); // force the value to be an array
465          break;
466        case "exif:GPSLatitude":
467        case "exif:GPSLongitude":
468        case "exif:GPSDestLatitude":
469        case "exif:GPSDestLongitude":
470          $returned=Array('coord' => "", 'card'=>"");
471
472          preg_match_all('/(\d{1,3}),(\d{1,2})(?:\.(\d*)){0,1}(N|S|E|W)/', $value, $result);
473          if(is_array($result) and
474             isset($result[1]) and
475             isset($result[2]) and
476             isset($result[3]) and
477             isset($result[4]) and
478             isset($result[1][0]) and
479             isset($result[2][0]) and
480             isset($result[3][0]) and
481             isset($result[4][0]))
482          {
483            $returned['coord']=$result[1][0]."° ".$result[2][0]."' ";
484            if(trim($result[3][0])!="")
485            {
486              $returned['coord'].= round(("0.".$result[3][0])*60,2)."\"";
487            }
488            switch($result[4][0])
489            {
490              case "N":
491                $returned['card']="North";
492                break;
493              case "S":
494                $returned['card']="South";
495                break;
496              case "E":
497                $returned['card']="East";
498                break;
499              case "W":
500                $returned['card']="West";
501                break;
502            }
503          }
504
505          $type=ByteType::UNDEFINED;
506          break;
507        case "xmp:CreateDate":
508        case "xmp:ModifyDate":
509        case "xmp:MetadataDate":
510        case "tiff:DateTime":
511        case "photoshop:DateCreated":
512        case "Iptc4xmpCore:DateCreated":
513          $returned=ConvertData::toDateTime($value);
514          break;
515        case "dc:contributor" : // bag
516        case "dc:creator" : // seq
517        case "dc:date" : // seq
518        case "dc:description" : // alt
519        case "dc:language" : // bag
520        case "dc:publisher" : // bag
521        case "dc:relation" : // bag
522        case "dc:rights" : // alt
523        case "dc:subject" : // bag
524        case "dc:title" : // alt
525        case "dc:Type" : // bag
526        case "xmp:Advisory" : // bag
527        case "xmp:Identifier" : // bag
528        case "xmp:Thumbnails" : // alt
529        case "xmpRights:Owner" : // bag
530        case "xmpRights:UsageTerms" : // alt
531        case "xmpMM:History" : // seq
532        case "xmpMM:Versions" : // seq
533        case "xmpBJ:JobRef" : // bag
534        case "xmpTPg:Fonts" : // bag
535        case "xmpTPg:Colorants" : // seq
536        case "xmpTPg:PlateNames" : // seq
537        case "photoshop:SupplementalCategories" : // bag
538        case "crs:ToneCurve" : // seq
539        case "tiff:BitsPerSample" : // seq
540        case "tiff:YCbCrSubSampling" : // seq
541        case "tiff:TransferFunction" : // seq
542        case "tiff:WhitePoint" : // seq
543        case "tiff:PrimaryChromaticities" : // seq
544        case "tiff:YCbCrCoefficients" : // seq
545        case "tiff:ReferenceBlackWhite" : // seq
546        case "tiff:ImageDescription" : // alt
547        case "tiff:Copyright" : // alt
548        case "exif:ComponentsConfiguration" : // seq
549        case "exif:UserComment" : // alt
550        case "exif:ISOSpeedRatings" : // seq
551        case "exif:SubjectArea" : // seq
552        case "exif:SubjectLocation" : // seq
553        case "digiKam:TagsList": //seq
554        case "lr:hierarchicalSubject": //seq
555          $returned=$value;
556          break;
557        case "Iptc4xmpCore:Scene": //bag
558          $tag=$this->tagDef->getTagById('Iptc4xmpCore:Scene');
559          $returned=$value;
560          foreach($returned['values'] as $key=>$val)
561          {
562            if(array_key_exists($val, $tag['tagValues.special']))
563              $returned['values'][$key]=$tag['tagValues.special'][$val];
564          }
565          unset($tag);
566          break;
567        case "Iptc4xmpCore:SubjectCode": //bag
568          $returned=$value;
569          foreach($returned['values'] as $key=>$val)
570          {
571            $tmp=explode(":", $val);
572
573            $returned['values'][$key]=Array();
574
575            if(count($tmp)>=1)
576              $returned['values'][$key]['IPR']=$tmp[0];
577
578            if(count($tmp)>=2)
579              $returned['values'][$key]['subjectCode']=$tmp[1];
580
581            if(count($tmp)>=3)
582              $returned['values'][$key]['subjectName']=$tmp[2];
583
584            if(count($tmp)>=4)
585              $returned['values'][$key]['subjectMatterName']=$tmp[3];
586
587            if(count($tmp)>=5)
588              $returned['values'][$key]['subjectDetailName']=$tmp[4];
589
590            unset($tmp);
591          }
592          break;
593        default:
594          $returned="Not yet implemented; $name";
595          break;
596      }
597      return($returned);
598    }
599
600    /**
601     * this function convert the value from XMP 'exif' or XMP 'tiff' data by
602     * using an instance of a XmpTag2Exif object (using exif tag object allows
603     * not coding the same things twice)
604     */
605    private function xmp2Exif($tagName, $exifTag, $xmpValue)
606    {
607      switch($tagName)
608      {
609        /* integers */
610        case "tiff:ImageWidth":
611        case "tiff:ImageLength":
612        case "tiff:PhotometricInterpretation":
613        case "tiff:Orientation":
614        case "tiff:SamplesPerPixel":
615        case "tiff:PlanarConfiguration":
616        case "tiff:YCbCrSubSampling":
617        case "tiff:YCbCrPositioning":
618        case "tiff:ResolutionUnit":
619        case "exif:ColorSpace":
620        case "exif:PixelXDimension":
621        case "exif:PixelYDimension":
622        case "exif:MeteringMode":
623        case "exif:LightSource":
624        case "exif:FlashEnergy":
625        case "exif:FocalPlaneResolutionUnit":
626        case "exif:SensingMethod":
627        case "exif:FileSource":
628        case "exif:SceneType":
629        case "exif:CustomRendered":
630        case "exif:ExposureMode":
631        case "exif:Balance":
632        case "exif:FocalLengthIn35mmFilm":
633        case "exif:SceneCaptureType":
634        case "exif:GainControl":
635        case "exif:Contrast":
636        case "exif:Saturation":
637        case "exif:Sharpness":
638        case "exif:SubjectDistanceRange":
639        case "exif:GPSAltitudeRef":
640        case "exif:GPSDifferential":
641          if(is_int($xmpValue))
642          {
643            $returned=(int)$xmpValue;
644          }
645          else
646          {
647            $returned=0;
648          }
649          $type=ByteType::ULONG;
650          break;
651        /* specials */
652        case "tiff:BitsPerSample":
653        case "tiff:Compression":
654        case "tiff:TransferFunction":
655        case "tiff:WhitePoint":
656        case "tiff:PrimaryChromaticities":
657        case "tiff:YCbCrCoefficients":
658        case "tiff:ReferenceBlackWhite":
659        case "exif:ComponentsConfiguration":
660        case "exif:ExposureProgram":
661        case "exif:ISOSpeedRatings":
662        case "exif:OECF":
663        case "exif:Flash":
664        case "exif:SubjectArea":
665        case "exif:SpatialFrequencyResponse":
666        case "exif:SubjectLocation":
667        case "exif:CFAPattern":
668        case "exif:DeviceSettingDescription":
669          $returned=$xmpValue;
670          $type=ByteType::UNDEFINED;
671          break;
672        /* rational */
673        case "tiff:XResolution":
674        case "tiff:YResolution":
675        case "exif:CompressedBitsPerPixel":
676        case "exif:ExposureTime":
677        case "exif:FNumber":
678        case "exif:ShutterSpeedValue":
679        case "exif:ApertureValue":
680        case "exif:BrightnessValue":
681        case "exif:ExposureBiasValue":
682        case "exif:MaxApertureValue":
683        case "exif:SubjectDistance":
684        case "exif:FocalLength":
685        case "exif:FocalPlaneXResolution":
686        case "exif:FocalPlaneYResolution":
687        case "exif:ExposureIndex":
688        case "exif:DigitalZoomRatio":
689        case "exif:GPSAltitude":
690        case "exif:GPSDOP":
691        case "exif:GPSSpeed":
692        case "exif:GPSTrack":
693        case "exif:GPSImgDirection":
694        case "exif:GPSDestBearing":
695        case "exif:GPSDestDistance":
696          $computed=explode("/", $xmpValue);
697          if(is_array($computed) and is_int($computed[0]) and is_int($computed[1]))
698          {
699            $returned=Array((int)$computed[0], (int)$computed[1]);
700          }
701          else
702          {
703            $returned=array(0,1);
704          }
705          $type=ByteType::URATIONAL;
706          unset($computed);
707          break;
708        /* dates & texts */
709        case "tiff:DateTime":
710        case "tiff:ImageDescription":
711        case "tiff:Make":
712        case "tiff:Model":
713        case "tiff:Software":
714        case "tiff:Artist":
715        case "tiff:Copyright":
716        case "exif:ExifVersion":
717        case "exif:FlashpixVersion":
718        case "exif:UserComment":
719        case "exif:RelatedSoundFile":
720        case "exif:DateTimeOriginal":
721        case "exif:DateTimeDigitized":
722        case "exif:SpectralSensitivity":
723        case "exif:ImageUniqueID":
724        case "exif:GPSVersionID":
725        case "exif:GPSTimeStamp":
726        case "exif:GPSSatellites":
727        case "exif:GPSStatus":
728        case "exif:GPSMeasureMode":
729        case "exif:GPSSpeedRef":
730        case "exif:GPSTrackRef":
731        case "exif:GPSImgDirectionRef":
732        case "exif:GPSMapDatum":
733        case "exif:GPSDestBearingRef":
734        case "exif:GPSDestDistanceRef":
735        case "exif:GPSProcessingMethod":
736        case "exif:GPSAreaInformation":
737          $returned=$xmpValue;
738          $type=ByteType::ASCII;
739          break;
740        default:
741          $returned="Unknown tag: $tagName => $xmpValue";
742          break;
743      }
744      if(is_array($returned))
745      {
746        if(array_key_exists('type', $returned))
747        {
748          if($returned['type']=='alt')
749          {
750          }
751          else
752          {
753            foreach($returned['values'] as $key => $val)
754            {
755              $returned['values'][$key]['value']=$this->xmpTag2Exif->convert($exifTag, $val['value'], $type);
756            }
757          }
758        }
759        else
760        {
761          return($this->xmpTag2Exif->convert($exifTag, $returned, $type));
762        }
763      }
764      return($returned);
765    }
766
767  }
768
769  /**
770   * The XmpTag2Exif is derived from the IfdReader class
771   *
772   * This function provides the public function 'convert', allowing to convert
773   * 'exif' datas in 'human readable' values
774   *
775   */
776  class XmpTag2Exif extends IfdReader
777  {
778    public function convert($exifTag, $value, $type)
779    {
780      return($this->processSpecialTag($exifTag, $value, $type));
781    }
782  }
783
784?>
Note: See TracBrowser for help on using the repository browser.