source: extensions/AMetaData/JpegMetaData/Readers/IptcReader.class.php @ 4698

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

[Plugin:AMetaData] Finished to comment the JpegMetaData classes and rename some methods

  • Property svn:executable set to *
File size: 10.6 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 IptcReader class is the dedicated class to read IPTC from the APP13
36 * segment
37 *
38 * The APP13 segment (the 'photoshop' segment) contain 8BIM blocks.
39 * The IPTC are stored inside the specific 0x0404 block. If there is more than
40 * one 8BIM 0x0404 block, the IptcReader reads all blocks and merge IPTC tags.
41 *
42 * =======> See HeightBIMReader.class.php to know more about 8BIM blocks <======
43 *
44 * -----------------------------------------------------------------------------
45 *
46 * .. Notes ..
47 *
48 * The IptcReader class is derived from the GenericReader class.
49 *
50 * ======> See GenericReader.class.php to know more about common methods <======
51 *
52 * This class provides theses public functions :
53 *  - optimizeDateTime
54 *
55 * -----------------------------------------------------------------------------
56 */
57
58  require_once(JPEG_METADATA_DIR."Common/Data.class.php");
59  require_once(JPEG_METADATA_DIR."Readers/HeightBIMReader.class.php");
60  require_once(JPEG_METADATA_DIR."TagDefinitions/IptcTags.class.php");
61
62
63  class IptcReader extends GenericReader
64  {
65    const HEADER_1 = "Photoshop 3.0\x00";
66    const HEADER_2 = "Adobe_Photoshop2.5:\x00";
67
68    private $header = "";
69
70    /**
71     * The constructor needs, like the ancestor, the datas to be parsed
72     *
73     * @param String $data
74     */
75    function __construct($data)
76    {
77      parent::__construct($data);
78
79      /*
80       * read the header
81       * if header is a valid header, read entries
82       */
83      if($this->readHeader())
84      {
85        $this->initializeEntries();
86      }
87    }
88
89    public function toString()
90    {
91      $returned="IPTC ; NbEntries: ".sprintf("%02d", $this->nbEntries);
92      return($returned);
93    }
94
95    /**
96     * All IPTC Date & Time are separated into distinct tags
97     * this function complete "date" tags with the associated "time" tags, and
98     * delete the "time" tags
99     *
100     * Example :
101     *  0x146 "Date Sent" = 2009/12/24 => tag value : 2009/12/24 00:00:00
102     *  0x150 "Time Sent" = 19:43:28   => tag value : 0001/01/01 19:43:28
103     *
104     * Optimize Date merge date & time => tag value : 2009/12/24 19:43:28
105     *
106     */
107    public function optimizeDateTime()
108    {
109      $assoc=Array(
110        Array(0x0146, 0x0150),
111        Array(0x021E, 0x0223),
112        Array(0x0225, 0x0226),
113        Array(0x0237, 0x023C),
114        Array(0x023E, 0x023F),
115      );
116
117      foreach($assoc as $val)
118      {
119        $tagD=$this->getTagIndexById($val[0]);
120        $tagT=$this->getTagIndexById($val[1]);
121
122        if($tagD>-1 and $tagT>-1)
123        {
124          /*
125           * can't use the timestamp function because not compatible with php < 5.3
126           */
127          $this->entries[$tagD]->getLabel()->setTime(
128            (int)$this->entries[$tagT]->getLabel()->format("H"),
129            (int)$this->entries[$tagT]->getLabel()->format("i"),
130            (int)$this->entries[$tagT]->getLabel()->format("s")
131          );
132          array_splice($this->entries, $tagT, 1);
133        }
134      }
135    }
136
137
138    /**
139     * initialize the definition for IPTC tags
140     */
141    protected function initializeTagDef()
142    {
143      $this->tagDef = new IptcTags();
144    }
145
146    /**
147     * read the header of the APP13 segment, and try to determinate wich kind of
148     * data are stored
149     *
150     * at now, only "Photoshop 3.0" data structure is known
151     * the "Adobe_Photoshop2.5" data structure is not recognized yet
152     *
153     * @return Boolean : true if the header is known
154     */
155    private function readHeader()
156    {
157      $this->data->seek();
158      $header=$this->data->readASCII(strlen(self::HEADER_1));
159      if($header==self::HEADER_1)
160      {
161        $this->header=$header;
162        return(true);
163      }
164
165      $this->data->seek();
166      $header=$this->data->readASCII(strlen(self::HEADER_2));
167      if($header==self::HEADER_2)
168      {
169        $this->header=$header;
170        /*
171         * structure from an HEADER_2 is not known....
172         */
173        return(false);
174      }
175
176      return(false);
177    }
178
179    /**
180     * reads all the 8BIM blocks of the segment. If the 8BIM block is an IPTC
181     * block, read all the IPTC entries and set the Tag properties
182     *
183     * An entry is a Tag object
184     *
185     * Add the entry to the entries array
186     *
187     */
188    protected function initializeEntries()
189    {
190      $blocks=explode("8BIM", $this->data->readASCII());
191      foreach($blocks as $key=> $val)
192      {
193        $block=new HeightBIMReader("8BIM".$val);
194        if($block->isValid())
195        {
196          /* merge entries from all 8BIM blocks */
197          $this->entries=array_merge($this->entries, $block->getTags());
198        }
199        unset($block);
200      }
201
202      foreach($this->entries as $key => $tag)
203      {
204        $this->setTagProperties($tag);
205      }
206    }
207
208    /**
209     * Interprets the tag values into 'human readable values'
210     *
211     * @param Tag $entry
212     */
213    private function setTagProperties($tag)
214    {
215      /*
216       * if the given tag id is defined, analyzing its values
217       */
218      if($this->tagDef->tagIdExists($tag->getId()))
219      {
220        $tagProperties=$this->tagDef->getTagById($tag->getId());
221
222        $tag->setKnown(true);
223        $tag->setName($tagProperties['tagName']);
224        $tag->setImplemented($tagProperties['implemented']);
225        $tag->setTranslatable($tagProperties['translatable']);
226
227        /*
228         * if there is values defined for the tag, analyze it
229         */
230        if(array_key_exists('tagValues', $tagProperties))
231        {
232          if(array_key_exists($tag->getValue(), $tagProperties['tagValues']))
233          {
234            $tag->setLabel($tagProperties['tagValues'][$tag->getValue()]);
235          }
236          else
237          {
238            $tag->setLabel("[unknow value 0x".sprintf("%04x", $tag->getValue())."]");
239          }
240        }
241        else
242        {
243          /*
244           * there is no values defined for the tag, analyzing it with dedicated
245           * function
246           */
247          $tag->setLabel($this->processSpecialTag($tag->getId(), $tag->getValue(), 0, 0));
248        }
249      }
250    }
251
252    /**
253     * this function can be overrided to process special tags
254     */
255    protected function processSpecialTag($tagId, $values, $type, $valuesOffset=0)
256    {
257      switch($tagId)
258      {
259        /*
260         * Tags managed
261         */
262        case 0x0105: // 2:05  - Destination
263        case 0x011E: // 1:30  - Service Identifier
264        case 0x0128: // 1:40  - Envelope Number
265        case 0x0132: // 1:50  - Product I.D.
266        case 0x0205: // 2:05  - Title
267        case 0x0207: // 2:07  - Edit Status
268        case 0x020F: // 2:15  - Category
269        case 0x0214: // 2:20  - Supplemental Category
270        case 0x0216: // 2:22  - Fixture Identifier
271        case 0x0219: // 2:25  - Keywords
272        case 0x021A: // 2:25  - Content Location Code
273        case 0x021B: // 2:25  - Content Location Name
274        case 0x0228: // 2:40  - Special Instructions
275        case 0x0241: // 2:65  - Originating Program
276        case 0x0246: // 2:70  - Program Version
277        case 0x0250: // 2:80  - By-line
278        case 0x0255: // 2:80  - By-line Title
279        case 0x025A: // 2:90  - City
280        case 0x025C: // 2:92  - Sublocation
281        case 0x025F: // 2:95  - Province/State
282        case 0x0264: // 2:100 - Country Code
283        case 0x0265: // 2:101 - Country
284        case 0x0267: // 2:103 - Original Transmission Reference
285        case 0x0269: // 2:105 - Headline
286        case 0x026E: // 2:110 - credit
287        case 0x0273: // 2:115 - source
288        case 0x0274: // 2:116 - Copyright Notice
289        case 0x0276: // 2:118 - Contact
290        case 0x0278: // 2:120 - Description
291        case 0x027A: // 2:122 - Writer/Editor
292        case 0x0287: // 2:150 - Language Identifier
293          $returned=$values;
294          break;
295        case 0x0114: // 1:20  - File Format
296          $tag=$this->tagDef->getTagById(0x0114);
297          $returned=$tag['tagValues.special'][ConvertData::toUShort($values, BYTE_ORDER_BIG_ENDIAN)];
298          break;
299        case 0x0203: // 2:03  - Object Type Reference
300        case 0x0204: // 2:04  - Intellectual Genre
301          $returned=explode(":", $values);
302          break;
303        case 0x0146: // 1:70  - Date Sent
304        case 0x021E: // 2:30  - Release Date
305        case 0x0225: // 2:37  - Expiration Date
306        case 0x0237: // 2:55  - Date Created
307        case 0x023E: // 2:62  - Digital Creation Date
308          $returned=ConvertData::toDateTime($values);
309          break;
310        case 0x0150: // 1:80  - Time Sent
311        case 0x0223: // 2:35  - Release Time
312        case 0x0226: // 2:38  - Expiration Time
313        case 0x023C: // 2:60  - Time Created
314        case 0x023F: // 2:63  - Digital Creation Time
315          $returned=ConvertData::toDateTime("00010101T".$values);
316          break;
317        /*
318         * Tags not managed
319         */
320        default:
321          $returned="Not yet implemented;".ConvertData::toHexDump($tagId, ByteType::USHORT)." => ".ConvertData::toHexDump($values, $type, 64)." [$values]";
322          break;
323      }
324      return($returned);
325    }
326  }
327
328
329
330
331?>
Note: See TracBrowser for help on using the repository browser.