source: extensions/AMetaData/JpegMetaData/Readers/XmpReader.class.php.bak @ 4686

Last change on this file since 4686 was 4686, checked in by grum, 14 years ago

[Plugin:AMetaData] prepare the directory for a future plugin

  • Property svn:executable set to *
File size: 18.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 *
14 * -----------------------------------------------------------------------------
15 * a voir sil n'est pas plus judicieux de dériver cette classe de GenericReader
16 * plutôt que SegmentReader
17 * -----------------------------------------------------------------------------
18 */
19
20  require_once(JPEG_METADATA_DIR."Common/Data.class.php");
21  require_once(JPEG_METADATA_DIR."Common/XmlData.class.php");
22  require_once(JPEG_METADATA_DIR."Readers/SegmentReader.class.php");
23  require_once(JPEG_METADATA_DIR."TagDefinitions/XmpTags.class.php");
24
25  class XmpReader extends SegmentReader
26  {
27    private $xml = "";
28    private $xmlData = NULL;
29    private $tags = Array();
30
31    private $tagDef = null;
32
33    private $xmpTag2Exif = NULL;
34
35    function __construct(Data $data)
36    {
37      parent::__construct($data);
38
39      $this->xml=explode("\x00", $data->readASCII());
40      if(count($this->xml)>1)
41      {
42        $this->xml=$this->xml[1];
43      }
44      else
45      {
46        $this->xml="";
47      }
48
49      $this->xmpTag2Exif = new XmpTag2Exif("", 0, 0);
50
51      $this->xmlData = new XmlData($this->xml);
52      $this->tagDef = new XmpTags();
53
54      $this->loadTags();
55
56      $this->isValid = $this->xmlData->isValid();
57      $this->isLoaded = $this->xmlData->isLoaded();
58
59    }
60
61    function __destruct()
62    {
63      unset($this->tags);
64      unset($this->tagDef);
65      unset($this->xmpTag2Exif);
66    }
67
68    public function getTags()
69    {
70      return($this->tags);
71    }
72
73    public function toString()
74    {
75      $returned=$this->xml;
76      return($returned);
77    }
78
79    private function loadTags()
80    {
81      if($this->xmlData->hasNodes())
82      {
83        $this->processNode($this->xmlData->getFirstNode());
84      }
85    }
86
87    private function processNode($node)
88    {
89      if(!is_null($node))
90      {
91        $node->setName($this->processNodeName($node->getName()));
92
93        foreach($node->getAttributes() as $key => $val)
94        {
95          $val['name']=$this->processNodeName($val['name']);
96          $this->addTag($val['name'], $val['value']);
97        }
98
99        if(!is_null($node->getValue()))
100        {
101          $this->addTag($node->getName(), $node->getValue());
102        }
103
104        if($node->hasChilds())
105        {
106          $this->processChildNode($node);
107        }
108
109        $this->processNode($node->getNextNode());
110      }
111    }
112
113    private function processNodeName($nodeName)
114    {
115      /*
116       * 'xap' schema have to be interpreted as a 'xmp' schema
117       * rename all 'xap' nodes in 'xmp' nodes
118       */
119      $name=preg_replace(Array("/^(xap:)/", "/^(xapMM:)/"), Array("xmp:", "xmpMM:"), $nodeName);
120
121      return($name);
122    }
123
124    private function processChildNode($node)
125    {
126      switch($node->getName())
127      {
128        /*
129         * child must be 'rdf:Seq', 'rdf:Bag' or 'rdf:Alt'
130         */
131        case "dc:contributor" : // bag
132        case "dc:creator" : // seq
133        case "dc:date" : // seq
134        case "dc:description" : // alt
135        case "dc:language" : // bag
136        case "dc:publisher" : // bag
137        case "dc:relation" : // bag
138        case "dc:rights" : // alt
139        case "dc:subject" : // bag
140        case "dc:title" : // alt
141        case "dc:Type" : // bag
142        case "xmp:Advisory" : // bag
143        case "xmp:Identifier" : // bag
144        case "xmp:Thumbnails" : // alt
145        case "xmpRights:Owner" : // bag
146        case "xmpRights:UsageTerms" : // alt
147        case "xmpMM:History" : // seq
148        case "xmpMM:Versions" : // seq
149        case "xmpBJ:JobRef" : // bag
150        case "xmpTPg:Fonts" : // bag
151        case "xmpTPg:Colorants" : // seq
152        case "xmpTPg:PlateNames" : // seq
153        case "photoshop:SupplementalCategories" : // bag
154        case "crs:ToneCurve" : // seq
155        case "tiff:BitsPerSample" : // seq
156        case "tiff:YCbCrSubSampling" : // seq
157        case "tiff:TransferFunction" : // seq
158        case "tiff:WhitePoint" : // seq
159        case "tiff:PrimaryChromaticities" : // seq
160        case "tiff:YCbCrCoefficients" : // seq
161        case "tiff:ReferenceBlackWhite" : // seq
162        case "tiff:ImageDescription" : // alt
163        case "tiff:Copyright" : // alt
164        case "exif:ComponentsConfiguration" : // seq
165        case "exif:UserComment" : // alt
166        case "exif:ISOSpeedRatings" : // seq
167        case "exif:SubjectArea" : // seq
168        case "exif:SubjectLocation" : // seq
169        case "Iptc4xmpCore:Scene": //bag
170        case "Iptc4xmpCore:SubjectCode": //bag
171          $child=$node->getFirstChild();
172          switch($child->getName())
173          {
174            case "rdf:Seq":
175              $type="seq";
176              break;
177            case "rdf:Bag":
178              $type="bag";
179              break;
180            case "rdf:Alt":
181              $type="alt";
182              break;
183            default:
184              $type="n/a";
185              break;
186          }
187          if($type=="seq" or $type=="bag" or $type="alt")
188          {
189            $value=Array('type' => $type, 'values' => Array());
190            $childNode=$child->getFirstChild();
191            while(!is_null($childNode))
192            {
193              if($childNode->getName() == "rdf:li")
194              {
195                if($type=="alt")
196                {
197                  $attributes=$childNode->getAttributes();
198                  if(count($attributes)>0)
199                  {
200                    $attributes=$attributes[0];
201                  }
202                  else
203                  {
204                    $attributes="n/a";
205                  }
206                  $value['values'][]=Array('type' => $attributes, 'value' => $childNode->getValue());
207                }
208                else
209                {
210                  $value['values'][]=$childNode->getValue();
211                }
212              }
213              $childNode=$childNode->getNextNode();
214            }
215            $this->addTag($node->getName(), $value);
216          }
217          break;
218        default:
219          $this->processNode($node->getFirstChild());
220          break;
221      }
222    }
223
224    private function addTag($name, $value)
225    {
226      $tag=new Tag($name, $value, $name);
227
228      if($this->tagDef->tagIdExists($name))
229      {
230        $tagProperties=$this->tagDef->getTagById($name);
231
232        $tag->setIsKnown(true);
233        $tag->setIsImplemented($tagProperties['implemented']);
234
235
236        if(array_key_exists('name', $tagProperties))
237        {
238          $tag->setName($tagProperties['name']);
239        }
240
241        /*
242         * if there is values defined for the tag, analyze it
243         */
244        if(array_key_exists('tagValues', $tagProperties))
245        {
246          if(array_key_exists($value, $tagProperties['tagValues']))
247          {
248            $tag->setLabel($tagProperties['tagValues'][$value]);
249          }
250          else
251          {
252            $tag->setLabel("[unknow value '".$value."']");
253          }
254        }
255        else
256        {
257          /*
258           * there is no values defined for the tag, analyzing it with dedicated
259           * function
260           */
261          if(array_key_exists('exifTag', $tagProperties))
262          {
263            $tag->setLabel($this->xmp2Exif($name, $tagProperties['exifTag'], $value));
264          }
265          else
266          {
267            $tag->setLabel($this->processSpecialTag($name, $value));
268          }
269
270        }
271      }
272
273      $this->tags[]=$tag;
274    }
275
276    private function processSpecialTag($name, $value)
277    {
278      /*
279       * Note : exif & tiff values are not processed in this function
280       */
281      switch($name)
282      {
283        case "x:xmptk":
284        case "dc:coverage":
285        case "dc:format":
286        case "dc:identifier":
287        case "dc:relation":
288        case "dc:source":
289        case "dc:title":
290        case "xmp:BaseURL":
291        case "xmp:CreatorTool":
292        case "xmp:Label":
293        case "xmp:Nickname":
294        case "xmp:Rating:":
295        case "xmpRights:Certificate":
296        case "xmpRights:Marked":
297        case "xmpRights:UsageTerms":
298        case "xmpRights:WebStatement":
299        case "xmpMM:DocumentID":
300        case "xmpMM:InstanceID":
301        case "xmpMM:Manager":
302        case "xmpMM:ManageTo":
303        case "xmpMM:ManageUI":
304        case "xmpMM:ManagerVariant":
305        case "xmpMM:RenditionParams":
306        case "xmpMM:VersionID":
307        case "xmpMM:LastURL":
308        case "photoshop:AuthorsPosition":
309        case "photoshop:CaptionWriter":
310        case "photoshop:Category":
311        case "photoshop:City":
312        case "photoshop:Country":
313        case "photoshop:Credit":
314        case "photoshop:Headline":
315        case "photoshop:Instructions":
316        case "photoshop:Source":
317        case "photoshop:State":
318        case "photoshop:TransmissionReference":
319        case "crs:AutoBrightness":
320        case "crs:AutoContrast":
321        case "crs:AutoExposure":
322        case "crs:AutoShadows":
323        case "crs:BlueHue":
324        case "crs:BlueSaturation":
325        case "crs:Brightness":
326        case "crs:CameraProfile":
327        case "crs:ChromaticAberrationB":
328        case "crs:ChromaticAberrationR":
329        case "crs:ColorNoiseReduction":
330        case "crs:Contrast":
331        case "crs:CropTop":
332        case "crs:CropLeft":
333        case "crs:CropBottom":
334        case "crs:CropRight":
335        case "crs:CropAngle":
336        case "crs:CropWidth":
337        case "crs:CropHeight":
338        case "crs:Exposure":
339        case "crs:GreenHue":
340        case "crs:GreenSaturation":
341        case "crs:HasCrop":
342        case "crs:HasSettings":
343        case "crs:LuminanceSmoothing":
344        case "crs:RawFileName":
345        case "crs:RedHue":
346        case "crs:RedSaturation":
347        case "crs:Saturation":
348        case "crs:Shadows":
349        case "crs:ShadowTint":
350        case "crs:Sharpness":
351        case "crs:Temperature":
352        case "crs:Tint":
353        case "crs:Version":
354        case "crs:VignetteAmount":
355        case "crs:VignetteMidpoint":
356        case "Iptc4xmpCore:CountryCode":
357        case "Iptc4xmpCore:Location":
358        case "Iptc4xmpCore:CiEmailWork":
359        case "Iptc4xmpCore:CiUrlWork":
360        case "Iptc4xmpCore:CiTelWork":
361        case "Iptc4xmpCore:CiAdrExtadr":
362        case "Iptc4xmpCore:CiAdrPcode":
363        case "Iptc4xmpCore:CiAdrCity":
364        case "Iptc4xmpCore:CiAdrCtry":
365          $returned=$value;
366          break;
367        case "Iptc4xmpCore:IntellectualGenre":
368          $returned=explode(":", $value);
369          break;
370        case "xmp:CreateDate":
371        case "xmp:ModifyDate":
372        case "xmp:MetadataDate":
373        case "tiff:DateTime":
374        case "photoshop:DateCreated":
375        case "Iptc4xmpCore:DateCreated":
376          $returned=ConvertData::toDateTime($value);
377          break;
378        case "dc:contributor" : // bag
379        case "dc:creator" : // seq
380        case "dc:date" : // seq
381        case "dc:description" : // alt
382        case "dc:language" : // bag
383        case "dc:publisher" : // bag
384        case "dc:relation" : // bag
385        case "dc:rights" : // alt
386        case "dc:subject" : // bag
387        case "dc:title" : // alt
388        case "dc:Type" : // bag
389        case "xmp:Advisory" : // bag
390        case "xmp:Identifier" : // bag
391        case "xmp:Thumbnails" : // alt
392        case "xmpRights:Owner" : // bag
393        case "xmpRights:UsageTerms" : // alt
394        case "xmpMM:History" : // seq
395        case "xmpMM:Versions" : // seq
396        case "xmpBJ:JobRef" : // bag
397        case "xmpTPg:Fonts" : // bag
398        case "xmpTPg:Colorants" : // seq
399        case "xmpTPg:PlateNames" : // seq
400        case "photoshop:SupplementalCategories" : // bag
401        case "crs:ToneCurve" : // seq
402        case "tiff:BitsPerSample" : // seq
403        case "tiff:YCbCrSubSampling" : // seq
404        case "tiff:TransferFunction" : // seq
405        case "tiff:WhitePoint" : // seq
406        case "tiff:PrimaryChromaticities" : // seq
407        case "tiff:YCbCrCoefficients" : // seq
408        case "tiff:ReferenceBlackWhite" : // seq
409        case "tiff:ImageDescription" : // alt
410        case "tiff:Copyright" : // alt
411        case "exif:ComponentsConfiguration" : // seq
412        case "exif:UserComment" : // alt
413        case "exif:ISOSpeedRatings" : // seq
414        case "exif:SubjectArea" : // seq
415        case "exif:SubjectLocation" : // seq
416          $returned=$value;
417          break;
418        case "Iptc4xmpCore:Scene": //bag
419          $tag=$this->tagDef->getTagById('Iptc4xmpCore:Scene');
420          $returned=$value;
421          foreach($returned['values'] as $key=>$val)
422          {
423            if(array_key_exists($val, $tag['tagValues.special']))
424              $returned['values'][$key]=$tag['tagValues.special'][$val];
425          }
426          break;
427        case "Iptc4xmpCore:SubjectCode": //bag
428          $returned=$value;
429          foreach($returned['values'] as $key=>$val)
430          {
431            $tmp=explode(":", $val);
432
433            $returned['values'][$key]=Array();
434
435            if(count($tmp)>=1)
436              $returned['values'][$key]['IPR']=$tmp[0];
437
438            if(count($tmp)>=2)
439              $returned['values'][$key]['subjectCode']=$tmp[1];
440
441            if(count($tmp)>=3)
442              $returned['values'][$key]['subjectName']=$tmp[2];
443
444            if(count($tmp)>=4)
445              $returned['values'][$key]['subjectMatterName']=$tmp[3];
446
447            if(count($tmp)>=5)
448              $returned['values'][$key]['subjectDetailName']=$tmp[4];
449          }
450          break;
451        default:
452          $returned="Not yet implemented; $name";
453          break;
454      }
455      return($returned);
456    }
457
458    private function xmp2Exif($tagName, $exifTag, $xmpValue)
459    {
460      switch($tagName)
461      {
462        /* integers */
463        case "tiff:ImageWidth":
464        case "tiff:ImageLength":
465        case "tiff:PhotometricInterpretation":
466        case "tiff:Orientation":
467        case "tiff:SamplesPerPixel":
468        case "tiff:PlanarConfiguration":
469        case "tiff:YCbCrSubSampling":
470        case "tiff:YCbCrPositioning":
471        case "tiff:ResolutionUnit":
472        case "exif:ColorSpace":
473        case "exif:PixelXDimension":
474        case "exif:PixelYDimension":
475        case "exif:MeteringMode":
476        case "exif:LightSource":
477        case "exif:FlashEnergy":
478        case "exif:FocalPlaneResolutionUnit":
479        case "exif:SensingMethod":
480        case "exif:FileSource":
481        case "exif:SceneType":
482        case "exif:CustomRendered":
483        case "exif:ExposureMode":
484        case "exif:WhiteBalance":
485        case "exif:FocalLengthIn35mmFilm":
486        case "exif:SceneCaptureType":
487        case "exif:GainControl":
488        case "exif:Contrast":
489        case "exif:Saturation":
490        case "exif:Sharpness":
491        case "exif:SubjectDistanceRange":
492        case "exif:GPSAltitudeRef":
493        case "exif:GPSDifferential":
494          $returned=(int)$xmpValue;
495          $type=ByteType::ULONG;
496          break;
497        /* specials */
498        case "tiff:BitsPerSample":
499        case "tiff:Compression":
500        case "tiff:TransferFunction":
501        case "tiff:WhitePoint":
502        case "tiff:PrimaryChromaticities":
503        case "tiff:YCbCrCoefficients":
504        case "tiff:ReferenceBlackWhite":
505        case "exif:ComponentsConfiguration":
506        case "exif:ExposureProgram":
507        case "exif:ISOSpeedRatings":
508        case "exif:OECF":
509        case "exif:Flash":
510        case "exif:SubjectArea":
511        case "exif:SpatialFrequencyResponse":
512        case "exif:SubjectLocation":
513        case "exif:CFAPattern":
514        case "exif:DeviceSettingDescription":
515        case "exif:GPSLatitude":
516        case "exif:GPSLongitude":
517        case "exif:GPSDestLatitude":
518        case "exif:GPSDestLongitude":
519          $returned=$xmpValue;
520          $type=ByteType::UNDEFINED;
521          break;
522        /* rational */
523        case "tiff:XResolution":
524        case "tiff:YResolution":
525        case "exif:CompressedBitsPerPixel":
526        case "exif:ExposureTime":
527        case "exif:FNumber":
528        case "exif:ShutterSpeedValue":
529        case "exif:ApertureValue":
530        case "exif:BrightnessValue":
531        case "exif:ExposureBiasValue":
532        case "exif:MaxApertureValue":
533        case "exif:SubjectDistance":
534        case "exif:FocalLength":
535        case "exif:FocalPlaneXResolution":
536        case "exif:FocalPlaneYResolution":
537        case "exif:ExposureIndex":
538        case "exif:DigitalZoomRatio":
539        case "exif:GPSAltitude":
540        case "exif:GPSDOP":
541        case "exif:GPSSpeed":
542        case "exif:GPSTrack":
543        case "exif:GPSImgDirection":
544        case "exif:GPSDestBearing":
545        case "exif:GPSDestDistance":
546          $computed=explode("/", $xmpValue);
547          $returned=Array((int)$computed[0], (int)$computed[1]);
548          $type=ByteType::URATIONAL;
549          break;
550        /* dates & texts */
551        case "tiff:DateTime":
552        case "tiff:ImageDescription":
553        case "tiff:Make":
554        case "tiff:Model":
555        case "tiff:Software":
556        case "tiff:Artist":
557        case "tiff:Copyright":
558        case "exif:ExifVersion":
559        case "exif:FlashpixVersion":
560        case "exif:UserComment":
561        case "exif:RelatedSoundFile":
562        case "exif:DateTimeOriginal":
563        case "exif:DateTimeDigitized":
564        case "exif:SpectralSensitivity":
565        case "exif:ImageUniqueID":
566        case "exif:GPSVersionID":
567        case "exif:GPSTimeStamp":
568        case "exif:GPSSatellites":
569        case "exif:GPSStatus":
570        case "exif:GPSMeasureMode":
571        case "exif:GPSSpeedRef":
572        case "exif:GPSTrackRef":
573        case "exif:GPSImgDirectionRef":
574        case "exif:GPSMapDatum":
575        case "exif:GPSDestBearingRef":
576        case "exif:GPSDestDistanceRef":
577        case "exif:GPSProcessingMethod":
578        case "exif:GPSAreaInformation":
579          $returned=$xmpValue;
580          $type=ByteType::ASCII;
581          break;
582        default:
583          $returned="Unknown tag: $tagName => $xmpValue";
584          break;
585      }
586      if(is_array($returned))
587      {
588        if(array_key_exists('type', $returned))
589        {
590          if($returned['type']=='alt')
591          {
592          }
593          else
594          {
595            foreach($returned['values'] as $key => $val)
596            {
597              $returned['values'][$key]['value']=$this->xmpTag2Exif->convert($exifTag, $val['value'], $type);
598            }
599          }
600        }
601        else
602        {
603          return($this->xmpTag2Exif->convert($exifTag, $returned, $type));
604        }
605      }
606      return($returned);
607    }
608
609  }
610
611
612  class XmpTag2Exif extends IfdReader
613  {
614    public function convert($exifTag, $value, $type)
615    {
616      return($this->processSpecialTag($exifTag, $value, $type));
617    }
618  }
619
620?>
621
Note: See TracBrowser for help on using the repository browser.