source: extensions/AMetaData/JpegMetaData/Readers/IfdEntryReader.class.php @ 8969

Last change on this file since 8969 was 8969, checked in by grum, 13 years ago

release 0.5.9
fix bug:2141

  • 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 IfdEntryReader class is the class dedicated to read IFD entries
36 *
37 * ======> See IfdReader.class.php to know more about an IFD structure <========
38 *
39 *
40 * An entry is made with 12 bytes
41 *  2 bytes (UShort) : tag id
42 *  2 bytes (UShort) : data format
43 *  4 bytes (ULong)  : component size
44 *  4 bytes          : value, or offset is value size is higher than 4bytes
45 *
46 * -----------------------------------------------------------------------------
47 *
48 * .. Notes ..
49 *
50 * This class provides theses public functions :
51 *  - getTagId
52 *  - getTypeName
53 *  - getValue
54 *  - getSize
55 *  - getType
56 *  - isOffset
57 *  - getExtraDataOffset
58 *  - getRaw
59 *  - getTag
60 *
61 */
62
63  require_once(JPEG_METADATA_DIR."Common/ConvertData.class.php");
64  require_once(JPEG_METADATA_DIR."Common/Tag.class.php");
65
66  class IfdEntryReader
67  {
68    private $raw = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
69    private $byteOrder = BYTE_ORDER_LITTLE_ENDIAN;
70
71    private $type = ByteType::UNKNOWN;
72    private $typeName = "Unknown";
73
74    private $size = 0;
75
76    private $isOffset = false;
77    private $extraDataOffset = 0;
78
79    private $tag = null;
80
81    /**
82     *
83     * the constructor needs :
84     *  - raw data, the 12 bytes of the IFD entry
85     *  - the byte order of TIFF segment
86     *  - the segment data, allowing to acces the extra data
87     *  - the segment data offset, allowing to compute the relative offset
88     *  - the tags definitions (a KnonwTags derived object)
89     *
90     * @param String $data
91     * @param String $byteOrder
92     * @param String $segmentData
93     * @param ULong $segmentDataOffset
94     * @param KnownTags $tagDef
95     */
96    function __construct($data, $byteOrder, $segmentData, $segmentDataOffset, $TagDef)
97    {
98      $this->tag=new Tag();
99
100      if(strlen($data)>=12)
101      {
102        $this->tag->setId(ConvertData::toUShort($data, $byteOrder));
103
104        $this->byteOrder = $byteOrder;
105        $this->raw   = substr($data,0,12);
106        $this->type  = ConvertData::toUShort(substr($data, 2), $this->byteOrder);
107        $this->size  = ConvertData::toULong(substr($data, 4), $this->byteOrder);
108
109
110        if(!isset(ByteType::$typeSizes[$this->type]))
111        {
112          /*
113           * invalid IFD marker type ?
114           * process it as dummy
115           */
116          $this->tag->setValue(0);
117        }
118        else
119        {
120          /*
121           * the entry value is stored in 4 bytes
122           * if the entry type size multiplied by the entry size is greater than 4
123           * it means that the entry value is an offset
124           */
125          $numBytes = $this->size * ByteType::$typeSizes[$this->type];
126
127          if($numBytes>4)
128          {
129            $this->isOffset = true;
130            $this->extraDataOffset = ConvertData::toULong(substr($data, 8), $this->byteOrder);
131            $this->tag->setValue($this->extractExtraData(new Data($segmentData->readASCII($this->size*ByteType::$typeSizes[$this->type], $this->extraDataOffset - $segmentDataOffset), $this->byteOrder), $this->byteOrder));
132          }
133          else
134          {
135            $this->tag->setValue($this->extractExtraData(new Data(substr($data,8), $this->byteOrder)));
136          }
137        }
138
139        switch($this->type)
140        {
141          case ByteType::UBYTE :
142            $this->typeName = "unsigned Byte (int8u)";
143            break;
144          case ByteType::ASCII :
145            $this->typeName = "ASCII";
146            break;
147          case ByteType::USHORT :
148            $this->typeName = "unsigned Short (int16u)";
149            break;
150          case ByteType::ULONG :
151            $this->typeName = "unsigned Long (int32u)";
152            break;
153          case ByteType::URATIONAL :
154            $this->typeName = "unsigned Rational (int32u int32u)";
155            break;
156          case ByteType::UNDEFINED :
157            $this->typeName = "Undefined";
158            break;
159          case ByteType::SBYTE :
160            $this->typeName = "Signed Byte (int8s)";
161            break;
162          case ByteType::SSHORT :
163            $this->typeName = "Signed Short (int16s)";
164            break;
165          case ByteType::SLONG :
166            $this->typeName = "Signed Long (int32s)";
167            break;
168          case ByteType::SRATIONAL :
169            $this->typeName = "Signed Rational (int32s int32s)";
170            break;
171          case ByteType::FLOAT :
172            $this->typeName = "Float";
173            break;
174          case ByteType::DOUBLE :
175            $this->typeName = "Double";
176            break;
177          default:
178            $this->typeName = "Unknown";
179            break;
180        }
181        //Array size...
182        $this->typeName.="[".$this->size."]";
183      }
184    }
185
186    function __destruct()
187    {
188      unset($this->tag);
189    }
190
191    /**
192     * return the tag id
193     *
194     * @return UShort
195     */
196    public function getTagId()
197    {
198      return($this->tag->getId());
199    }
200
201    /**
202     * return the name of the data type
203     *
204     * @return String
205     */
206    public function getTypeName()
207    {
208      return($this->typeName);
209    }
210
211    /**
212     * return the raw value
213     *
214     * @return type depends of the type of the tag
215     */
216    public function getValue()
217    {
218      return($this->tag->getValue());
219    }
220
221    /**
222     * return the tag size
223     *
224     * @return UShort
225     */
226    public function getSize()
227    {
228      return($this->size);
229    }
230
231    /**
232     * return the tag type
233     *
234     * @return UByte : look on the ByteType class for known values
235     */
236    public function getType()
237    {
238      return($this->type);
239    }
240
241    /**
242     * return true if entry value is an offset
243     *
244     * @return Boolean
245     */
246    public function isOffset()
247    {
248      return($this->isOffset);
249    }
250
251    /**
252     * return the extra data offset (if the tag value is in an extra data block)
253     *
254     * @return ULong
255     */
256    public function getExtraDataOffset()
257    {
258      if($this->isOffset)
259        return($this->extraDataOffset);
260      return(0);
261    }
262
263    /**
264     * return the raw data of the IFD entry
265     *
266     * @return String
267     */
268    public function getRaw()
269    {
270      return($this->raw);
271    }
272
273    /**
274     * return the Tag object of the entry
275     *
276     * @return Boolean
277     */
278    public function getTag()
279    {
280      return($this->tag);
281    }
282
283    public function toString()
284    {
285      $returned="raw: ".ConvertData::toHexDump($this->raw, ByteType::ASCII);
286
287      $returned.=" ; tag: 0x".sprintf("%04x", $this->tag->getId()).
288                 " ; type: ".str_replace(" ", "&nbsp;", sprintf(" %-36s", $this->typeName)).
289                 " ; offset: 0x".sprintf("%08x", $this->extraDataOffset).
290                 " ; value: ";
291      if(is_string($this->tag->getValue()))
292      {
293        $returned.=((strlen($this->tag->getValue())>64)?"[returns only the first 64 of ".strlen($this->tag->getValue())." bytes] ":"").substr($this->tag->getValue(),0,64);
294      }
295      else
296        $returned.=print_r($this->tag->getValue(), true);
297      return($returned);
298    }
299
300    /**
301     * this function extract the value of a Tag from the extra datas
302     *
303     * @param String $data : the data
304     */
305    private function extractExtraData($data)
306    {
307      /*
308       * A size equals 0 means an error ?
309       *
310       * A size equals 1 means the value is a single variable
311       *
312       * A size greater than 1 and a type diffrent than ASCII or UNDEFINED and
313       * the value is not an offset means that values are stored in an array
314       */
315      $returned=Array();
316
317      if($this->type==ByteType::ASCII or $this->type==ByteType::UNDEFINED)
318      {
319        return($data->readASCII($this->size,0));
320      }
321      else
322      {
323        for($i=0;$i<$this->size;$i++)
324        {
325          switch($this->type)
326          {
327            case ByteType::UBYTE :
328              $returned[]=$data->readUByte();
329              break;
330            case ByteType::USHORT :
331              $returned[]=$data->readUShort();
332              break;
333            case ByteType::ULONG :
334              $returned[]=$data->readULong();
335              break;
336            case ByteType::URATIONAL :
337              $returned[]=$data->readURational();
338              break;
339            case ByteType::SBYTE :
340              $returned[]=$data->readSByte();
341              break;
342            case ByteType::SSHORT :
343              $returned[]=$data->readSShort();
344              break;
345            case ByteType::SLONG :
346              $returned[]=$data->readSLong();
347              break;
348            case ByteType::SRATIONAL :
349              $returned[]=$data->readSRational();
350              break;
351            case ByteType::FLOAT :
352              $returned[] = $data->readFloat();
353              break;
354            case ByteType::DOUBLE :
355              $returned[] = $data->readDouble();
356              break;
357            default:
358              $returned[] = "Can't extract datas...";
359              break;
360          }
361        }
362      }
363
364      if($this->size==1)
365      {
366        return($returned[0]);
367      }
368      else
369      {
370        return($returned);
371      }
372    }
373
374  }
375
376
377
378?>
Note: See TracBrowser for help on using the repository browser.