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

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

Optimize some memory leak and some bugged lines of code

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