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

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

Fixes some little bugs

  • Property svn:executable set to *
File size: 10.4 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         * the entry value is stored in 4 bytes
111         * if the entry type size multiplied by the entry size is greater than 4
112         * it means that the entry value is an offset
113         */
114        $numBytes = $this->size * ByteType::$typeSizes[$this->type];
115
116        if($numBytes>4)
117        {
118          $this->isOffset = true;
119          $this->extraDataOffset = ConvertData::toULong(substr($data, 8), $this->byteOrder);
120          $this->tag->setValue($this->extractExtraData(new Data($segmentData->readASCII($this->size*ByteType::$typeSizes[$this->type], $this->extraDataOffset - $segmentDataOffset), $this->byteOrder), $this->byteOrder));
121        }
122        else
123        {
124          $this->tag->setValue($this->extractExtraData(new Data(substr($data,8), $this->byteOrder)));
125        }
126
127        switch($this->type)
128        {
129          case ByteType::UBYTE :
130            $this->typeName = "unsigned Byte (int8u)";
131            break;
132          case ByteType::ASCII :
133            $this->typeName = "ASCII";
134            break;
135          case ByteType::USHORT :
136            $this->typeName = "unsigned Short (int16u)";
137            break;
138          case ByteType::ULONG :
139            $this->typeName = "unsigned Long (int32u)";
140            break;
141          case ByteType::URATIONAL :
142            $this->typeName = "unsigned Rational (int32u int32u)";
143            break;
144          case ByteType::UNDEFINED :
145            $this->typeName = "Undefined";
146            break;
147          case ByteType::SBYTE :
148            $this->typeName = "Signed Byte (int8s)";
149            break;
150          case ByteType::SSHORT :
151            $this->typeName = "Signed Short (int16s)";
152            break;
153          case ByteType::SLONG :
154            $this->typeName = "Signed Long (int32s)";
155            break;
156          case ByteType::SRATIONAL :
157            $this->typeName = "Signed Rational (int32s int32s)";
158            break;
159          case ByteType::FLOAT :
160            $this->typeName = "Float";
161            break;
162          case ByteType::DOUBLE :
163            $this->typeName = "Double";
164            break;
165          default:
166            $this->typeName = "Unknown";
167            break;
168        }
169        //Array size...
170        $this->typeName.="[".$this->size."]";
171      }
172    }
173
174    function __destruct()
175    {
176      unset($this->tag);
177    }
178
179    /**
180     * return the tag id
181     *
182     * @return UShort
183     */
184    public function getTagId()
185    {
186      return($this->tag->getId());
187    }
188
189    /**
190     * return the name of the data type
191     *
192     * @return String
193     */
194    public function getTypeName()
195    {
196      return($this->typeName);
197    }
198
199    /**
200     * return the raw value
201     *
202     * @return type depends of the type of the tag
203     */
204    public function getValue()
205    {
206      return($this->tag->getValue());
207    }
208
209    /**
210     * return the tag size
211     *
212     * @return UShort
213     */
214    public function getSize()
215    {
216      return($this->size);
217    }
218
219    /**
220     * return the tag type
221     *
222     * @return UByte : look on the ByteType class for known values
223     */
224    public function getType()
225    {
226      return($this->type);
227    }
228
229    /**
230     * return true if entry value is an offset
231     *
232     * @return Boolean
233     */
234    public function isOffset()
235    {
236      return($this->isOffset);
237    }
238
239    /**
240     * return the extra data offset (if the tag value is in an extra data block)
241     *
242     * @return ULong
243     */
244    public function getExtraDataOffset()
245    {
246      if($this->isOffset)
247        return($this->extraDataOffset);
248      return(0);
249    }
250
251    /**
252     * return the raw data of the IFD entry
253     *
254     * @return String
255     */
256    public function getRaw()
257    {
258      return($this->raw);
259    }
260
261    /**
262     * return the Tag object of the entry
263     *
264     * @return Boolean
265     */
266    public function getTag()
267    {
268      return($this->tag);
269    }
270
271
272    public function toString()
273    {
274      $returned="raw: ".ConvertData::toHexDump($this->raw, ByteType::ASCII);
275
276      $returned.=" ; tag: 0x".sprintf("%04x", $this->tag->getId()).
277                 " ; type: ".str_replace(" ", "&nbsp;", sprintf(" %-36s", $this->typeName)).
278                 " ; offset: 0x".sprintf("%08x", $this->extraDataOffset).
279                 " ; value: ";
280      if(is_string($this->tag->getValue()))
281      {
282        $returned.=((strlen($this->tag->getValue())>64)?"[returns only the first 64 of ".strlen($this->tag->getValue())." bytes] ":"").substr($this->tag->getValue(),0,64);
283      }
284      else
285        $returned.=print_r($this->tag->getValue(), true);
286      return($returned);
287    }
288
289    /**
290     * this function extract the value of a Tag from the extra datas
291     *
292     * @param String $data : the data
293     */
294    private function extractExtraData($data)
295    {
296      /*
297       * A size equals 0 means an error ?
298       *
299       * A size equals 1 means the value is a single variable
300       *
301       * A size greater than 1 and a type diffrent than ASCII or UNDEFINED and
302       * the value is not an offset means that values are stored in an array
303       */
304      $returned=Array();
305
306      if($this->type==ByteType::ASCII or $this->type==ByteType::UNDEFINED)
307      {
308        return($data->readASCII($this->size,0));
309      }
310      else
311      {
312        for($i=0;$i<$this->size;$i++)
313        {
314          switch($this->type)
315          {
316            case ByteType::UBYTE :
317              $returned[]=$data->readUByte();
318              break;
319            case ByteType::USHORT :
320              $returned[]=$data->readUShort();
321              break;
322            case ByteType::ULONG :
323              $returned[]=$data->readULong();
324              break;
325            case ByteType::URATIONAL :
326              $returned[]=$data->readURational();
327              break;
328            case ByteType::SBYTE :
329              $returned[]=$data->readSByte();
330              break;
331            case ByteType::SSHORT :
332              $returned[]=$data->readSShort();
333              break;
334            case ByteType::SLONG :
335              $returned[]=$data->readSLong();
336              break;
337            case ByteType::SRATIONAL :
338              $returned[]=$data->readSRational();
339              break;
340            case ByteType::FLOAT :
341              $returned[] = $data->readFloat();
342              break;
343            case ByteType::DOUBLE :
344              $returned[] = $data->readDouble();
345              break;
346            default:
347              $returned[] = "Can't extract datas...";
348              break;
349          }
350        }
351      }
352
353      if($this->size==1)
354      {
355        return($returned[0]);
356      }
357      else
358      {
359        return($returned);
360      }
361    }
362
363  }
364
365
366
367?>
Note: See TracBrowser for help on using the repository browser.