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

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

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

  • Property svn:executable set to *
File size: 26.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 * | JpegMetaData - a PHP based Jpeg Metadata manager                      |
13 * +-----------------------------------------------------------------------+
14 * | Copyright(C) 2010  Grum - http://www.grum.fr                          |
15 * +-----------------------------------------------------------------------+
16 * | This program is free software; you can redistribute it and/or modify  |
17 * | it under the terms of the GNU General Public License as published by  |
18 * | the Free Software Foundation                                          |
19 * |                                                                       |
20 * | This program is distributed in the hope that it will be useful, but   |
21 * | WITHOUT ANY WARRANTY; without even the implied warranty of            |
22 * | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      |
23 * | General Public License for more details.                              |
24 * |                                                                       |
25 * | You should have received a copy of the GNU General Public License     |
26 * | along with this program; if not, write to the Free Software           |
27 * | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
28 * | USA.                                                                  |
29 * +-----------------------------------------------------------------------+
30 *
31 *
32 * -----------------------------------------------------------------------------
33 *
34 * The AppMarkerSegmentReader is a class for reading the segment of a Jpeg file
35 *
36 * -----------------------------------------------------------------------------
37 *
38 * .. Notes ..
39 *
40 * The class can recognize many kind of segments, but the content is not
41 * analyzed for all of them.
42 *
43 * If you want to implement new functionnality to read segment, you must start
44 * here.
45 *
46 * Datas are exploited only for the segments :
47 *  - APP1  : for Exif IFDs & Xmp datas
48 *  - APP13 : for 8BIM Iptc blocks
49 *  - COM   : comments block
50 *
51 *
52 * This class provides theses public functions :
53 *  - (static) read
54 *  - (static) isValidMarkerHeader
55 *  - (static) markerName
56 *  - getHeader
57 *  - getOffset
58 *  - getLength
59 *  - getSubType
60 *  - dataLoaded
61 *  - getData
62 *
63 *  Read the code for help
64 *
65 * -----------------------------------------------------------------------------
66 *
67 */
68
69  require_once(JPEG_METADATA_DIR."Common/ConvertData.class.php");
70  require_once(JPEG_METADATA_DIR."Common/Data.class.php");
71
72  require_once(JPEG_METADATA_DIR."Readers/TiffReader.class.php");
73  require_once(JPEG_METADATA_DIR."Readers/XmpReader.class.php");
74  require_once(JPEG_METADATA_DIR."Readers/IptcReader.class.php");
75
76  class AppMarkerSegmentReader
77  {
78    const SEGMENT_HEAD  = 0xFF;
79    const SEGMENT_APP0  = 0xE0;
80    const SEGMENT_APP1  = 0xE1;
81    const SEGMENT_APP2  = 0xE2;
82    const SEGMENT_APP3  = 0xE3;
83    const SEGMENT_APP4  = 0xE4;
84    const SEGMENT_APP5  = 0xE5;
85    const SEGMENT_APP6  = 0xE6;
86    const SEGMENT_APP7  = 0xE7;
87    const SEGMENT_APP8  = 0xE8;
88    const SEGMENT_APP9  = 0xE9;
89    const SEGMENT_APP10 = 0xEA;
90    const SEGMENT_APP11 = 0xEB;
91    const SEGMENT_APP12 = 0xEC;
92    const SEGMENT_APP13 = 0xED;
93    const SEGMENT_APP14 = 0xEE;
94    const SEGMENT_APP15 = 0xEF;
95
96    const SEGMENT_SOF0  = 0xC0;  // Start Of Frame - Baseline DCT (huffman)
97    const SEGMENT_SOF1  = 0xC1;  // Start Of Frame - Extended sequential DCT (huffman)
98    const SEGMENT_SOF2  = 0xC2;  // Start Of Frame - Progressive DCT (huffman)
99    const SEGMENT_SOF3  = 0xC3;  // Start Of Frame - Spatial (Lossless) DCT (Huffman)
100    const SEGMENT_SOF5  = 0xC5;  // Start Of Frame - Differential sequential DCT (Huffman)
101    const SEGMENT_SOF6  = 0xC6;  // Start Of Frame - Progressive sequential DCT (Huffman)
102    const SEGMENT_SOF7  = 0xC7;  // Start Of Frame - Differential spatial DCT (Huffman)
103    const SEGMENT_SOF9  = 0xC9;  // Start Of Frame - Extended sequential DCT (arithmetic)
104    const SEGMENT_SOFA  = 0xCA;  // Start Of Frame - Progressive DCT (arithmetic)
105    const SEGMENT_SOFB  = 0xCB;  // Start Of Frame - Spatial (lossless) DCT (arithmetic)
106    const SEGMENT_SOFD  = 0xCD;  // Start Of Frame - Differential sequential DCT (arithmetic)
107    const SEGMENT_SOFE  = 0xCE;  // Start Of Frame - Differential progressive DCT (arithmetic)
108    const SEGMENT_SOFF  = 0xCF;  // Start Of Frame - Differential lossless (arithmetic)
109
110    const SEGMENT_DQT   = 0xDB;  // Define Quantization Table
111    const SEGMENT_DHT   = 0xC4;  // Define Huffman Tables
112    const SEGMENT_JPG   = 0xC8;  // Reserved for JPEG extensions
113    const SEGMENT_DAC   = 0xCC;  // Arithmetic Conditionning info
114    const SEGMENT_SOS   = 0xDA;  // Start Of Scan
115    const SEGMENT_DRI   = 0xDD;  // Define Restart Interval
116    const SEGMENT_COM   = 0xFE;  // Comment
117
118
119
120    const UNKNOWN          = "?";
121
122    /*
123     * APP0 SubTypes
124     */
125    const APP0_JFIF        = "JFIF";
126    const APP0_JFXX        = "JFXX";
127    const APP0_CIFF        = "CIFF";
128    const APP0_AVI1        = "AVI1";
129
130    /*
131     * APP1 SubTypes
132     */
133    const APP1_EXIF        = "EXIF";
134    const APP1_XMP         = "XMP";
135    const APP1_EXTENDEDXMP = "ExtendedXMP";
136
137    /*
138     * APP2 SubTypes
139     */
140    const APP2_ICCPROFILE  = "ICC Profile";
141    const APP2_FPXR        = "FlashPix";
142    const APP2_MPF         = "MPF";
143    const APP2_SAMSUNGLP   = "Samsung large preview";
144
145    /*
146     * APP3 SubTypes
147     */
148    const APP3_META        = "Meta";
149    const APP3_STIM        = "Stim";
150
151    /*
152     * APP4 SubTypes
153     */
154    const APP4_SCALADO     = "Scalado";
155
156    /*
157     * APP5 SubTypes
158     */
159    const APP5_RMETA       = "Ricoh Meta";
160
161    /*
162     * APP6 SubTypes
163     */
164    const APP6_EPPIM       = "EPPIM";
165    const APP6_NITF        = "NITF";
166
167    /*
168     * APP8 SubTypes
169     */
170    const APP8_SPIFF       = "SPIFF";
171
172    /*
173     * APP10 SubTypes
174     */
175    const APP10_COMMENT    = "Comment";
176
177    /*
178     * APP12 SubTypes
179     */
180    const APP12_PICTUREINFO = "PictureInfo";
181    const APP12_DUCKY      = "Ducky";
182
183    /*
184     * APP13 SubTypes
185     */
186    const APP13_PHOTOSHOP  = "Photoshop";
187    const APP13_ADOBECM    = "Adobe CM";
188
189    /*
190     * APP14 SubTypes
191     */
192    const APP14_ADOBE      = "Adobe";
193
194    /*
195     * APP15 SubTypes
196     */
197    const APP15_GRAPHICCONVERTER = "GraphicConverter";
198
199    /*
200     * Other SubTypes
201     */
202    const SOF0 = "Start Of Frame - Baseline DCT (huffman)";
203    const SOF1 = "Start Of Frame - Extended sequential DCT (huffman)";
204    const SOF2 = "Start Of Frame - Progressive DCT (huffman)";
205    const SOF3 = "Start Of Frame - Spatial (Lossless) DCT (Huffman)";
206    const SOF5 = "Start Of Frame - Differential sequential DCT (Huffman)";
207    const SOF6 = "Start Of Frame - Progressive sequential DCT (Huffman)";
208    const SOF7 = "Start Of Frame - Differential spatial DCT (Huffman)";
209    const SOF9 = "Start Of Frame - Extended sequential DCT (arithmetic)";
210    const SOFA = "Start Of Frame - Progressive DCT (arithmetic)";
211    const SOFB = "Start Of Frame - Spatial (lossless) DCT (arithmetic)";
212    const SOFD = "Start Of Frame - Differential sequential DCT (arithmetic)";
213    const SOFE = "Start Of Frame - Differential progressive DCT (arithmetic)";
214    const SOFF = "Start Of Frame - Differential lossless (arithmetic)";
215    const DHT  = "Define Huffman Tables";
216    const JPG  = "Reserved for JPEG extensions";
217    const DAC  = "Arithmetic Conditionning info";
218    const SOS  = "Start Of Scan";
219    const DRI  = "Define Restart Interval";
220    const COM  = "Comment";
221    const DQT  = "Define Quantization Table";
222
223
224
225    private $header = 0xFF;
226    private $offset = 0;
227    private $length = 0;
228    private $subType = "";
229    private $data = NULL;
230    private $dataLoaded = false;
231    private $workData = NULL;
232
233
234    /**
235     * try to read a marker at the designed offset
236     *
237     * @param handler $fileHandler : a handler on an opened and valid file
238     *
239     * @param ULong $offset : where start reading the segment in the file
240     *
241     * @return false if there is no marker at this offset, otherwise returns an
242     * instance of a new AppMarkerSegmentReader object
243     */
244    static public function read($fileHandler, $offset)
245    {
246      /* if end of file, return false */
247      if(feof($fileHandler)) return(false);
248
249      fseek($fileHandler, $offset);
250      $header=ConvertData::toUByte(fread($fileHandler, 1));
251
252      /*
253       * each segment header start with 0xFF
254       *
255       * if the reader byte equals 0xFF, read the next byte.
256       * the next byte must equals one of the defined segment headers (between
257       * the first and last valid segments)
258       *
259       * if the segment is valid, the next 2 bytes determine the size of the
260       * segment, excluding the header, but including the segment size
261       *
262       */
263      if($header==self::SEGMENT_HEAD)
264      {
265        $header=ConvertData::toUByte(fread($fileHandler, 1));
266        if(self::isValidMarkerHeader($header))
267        {
268          $length=ConvertData::toUShort(fread($fileHandler, 2), BYTE_ORDER_BIG_ENDIAN);
269          /*
270           * inside a segment, length include the 2 byte designed for the length
271           * size, so to read the associated data, needs to read length-2bytes
272           *
273           * the length exclude the 2bytes needed for the header identifier
274           *
275           */
276          $datas=fread($fileHandler, $length-2);
277
278          switch($header)
279          {
280            case self::SEGMENT_APP0:
281              if(preg_match('/^JFIF\x00/',$datas)>0)
282              {
283                $subType=self::APP0_JFIF;
284              }
285              elseif(preg_match('/^JFXX\x00\x10/',$datas)>0)
286              {
287                $subType=self::APP0_JFXX;
288              }
289              elseif(preg_match('/^(II|MM).{4}HEAPJPGM/s',$datas)>0)
290              {
291                $subType=self::APP0_CIFF;
292              }
293              elseif(preg_match('/^AVI1/s',$datas)>0)
294              {
295                $subType=self::APP0_AVI1;
296              }
297              else
298              {
299                $subType=self::UNKNOWN;
300              }
301              break;
302            case self::SEGMENT_APP1:
303              if(preg_match('/^Exif\x00\x00/',$datas)>0)
304              {
305                $subType=self::APP1_EXIF;
306                $datas = substr($datas, 6);
307              }
308              elseif(preg_match('/^http:\/\/ns.adobe.com\/xmp\/extension\/\x00/',$datas)>0)
309              {
310                $subType=self::APP1_EXTENDEDXMP;
311              }
312              elseif(preg_match('/^(http:\/\/|<exif:)/',$datas)>0)
313              {
314                $subType=self::APP1_XMP;
315              }
316              else
317              {
318                $subType=self::UNKNOWN;
319              }
320              break;
321            case self::SEGMENT_APP2:
322              if(preg_match('/^ICC_PROFILE\x00/',$datas)>0)
323              {
324                $subType=self::APP2_ICCPROFILE;
325              }
326              elseif(preg_match('/^FPXR\x00/',$datas)>0)
327              {
328                $subType=self::APP2_FPXR;
329              }
330              elseif(preg_match('/^MPF\x00/',$datas)>0)
331              {
332                $subType=self::APP2_MPF;
333              }
334              elseif(preg_match('/^\xff\xd8\xff\xdb/',$datas)>0)
335              {
336                $subType=self::APP2_SAMSUNGLP;
337              }
338              else
339              {
340                $subType=self::UNKNOWN;
341              }
342              break;
343            case self::SEGMENT_APP3:
344              if(preg_match('/^(Meta|META|Exif)\x00\x00/',$datas)>0)
345              {
346                $subType=self::APP3_META;
347              }
348              elseif(preg_match('/^Stim\x00/',$datas)>0)
349              {
350                $subType=self::APP3_STIM;
351              }
352              else
353              {
354                $subType=self::UNKNOWN;
355              }
356              break;
357            case self::SEGMENT_APP4:
358              if(preg_match('/^SCALADO\x00/',$datas)>0)
359              {
360                $subType=self::APP4_SCALADO;
361              }
362              else
363              {
364                $subType=self::UNKNOWN;
365              }
366              break;
367            case self::SEGMENT_APP5:
368              if(preg_match('/^RMETA\x00/',$datas)>0)
369              {
370                $subType=self::APP5_RMETA;
371              }
372              else
373              {
374                $subType=self::UNKNOWN;
375              }
376              break;
377            case self::SEGMENT_APP6:
378              if(preg_match('/^EPPIM\x00/',$datas)>0)
379              {
380                $subType=self::APP6_EPPIM;
381              }
382              elseif(preg_match('/^NTIF\x00/',$datas)>0)
383              {
384                $subType=self::APP6_NTIF;
385              }
386              else
387              {
388                $subType=self::UNKNOWN;
389              }
390              break;
391            case self::SEGMENT_APP7:
392              $subType=self::UNKNOWN;
393              break;
394            case self::SEGMENT_APP8:
395              if(preg_match('/^SPIFF\x00/',$datas)>0)
396              {
397                $subType=self::APP8_SPIFF;
398              }
399              else
400              {
401                $subType=self::UNKNOWN;
402              }
403              break;
404            case self::SEGMENT_APP9:
405              $subType=self::UNKNOWN;
406              break;
407            case self::SEGMENT_APP10:
408              if(preg_match('/^UNICODE\x00/',$datas)>0)
409              {
410                $subType=self::APP10_COMMENT;
411              }
412              else
413              {
414                $subType=self::UNKNOWN;
415              }
416              break;
417            case self::SEGMENT_APP11:
418              $subType=self::UNKNOWN;
419              break;
420            case self::SEGMENT_APP12:
421              if(preg_match('/^(\[picture info\]|Type=)/',$datas)>0)
422              {
423                $subType=self::APP12_PICTUREINFO;
424              }
425              elseif(preg_match('/^Ducky/',$datas)>0)
426              {
427                $subType=self::APP12_DUCKY;
428              }
429              else
430              {
431                $subType=self::UNKNOWN;
432              }
433              break;
434            case self::SEGMENT_APP13:
435              if(preg_match('/^(Photoshop 3.0\0|Adobe_Photoshop2.5)/',$datas)>0)
436              {
437                $subType=self::APP13_PHOTOSHOP;
438              }
439              elseif(preg_match('/^Adobe_CM/',$datas)>0)
440              {
441                $subType=self::APP13_ADOBECM;
442              }
443              else
444              {
445                $subType=self::UNKNOWN;
446              }
447              break;
448            case self::SEGMENT_APP14:
449              if(preg_match('/^Adobe/',$datas)>0)
450              {
451                $subType=self::APP14_ADOBE;
452              }
453              else
454              {
455                $subType=self::UNKNOWN;
456              }
457              break;
458            case self::SEGMENT_APP15:
459              if(preg_match('/^Q\s*(\d+)/',$datas)>0)
460              {
461                $subType=self::APP15_GRAPHICCONVERTER;
462              }
463              else
464              {
465                $subType=self::UNKNOWN;
466              }
467              break;
468            case self::SEGMENT_DQT:
469                $subType=self::DQT;
470              break;
471            case self::SEGMENT_SOF0:
472                $subType=self::SOF0;
473              break;
474            case self::SEGMENT_SOF1:
475                $subType=self::SOF1;
476              break;
477            case self::SEGMENT_SOF2:
478                $subType=self::SOF2;
479              break;
480            case self::SEGMENT_SOF3:
481                $subType=self::SOF3;
482              break;
483            case self::SEGMENT_SOF5:
484                $subType=self::SOF5;
485              break;
486            case self::SEGMENT_SOF6:
487                $subType=self::SOF6;
488              break;
489            case self::SEGMENT_SOF7:
490                $subType=self::SOF7;
491              break;
492            case self::SEGMENT_SOF9:
493                $subType=self::SOF9;
494              break;
495            case self::SEGMENT_SOFA:
496                $subType=self::SOFA;
497              break;
498            case self::SEGMENT_SOFB:
499                $subType=self::SOFB;
500              break;
501            case self::SEGMENT_SOFD:
502                $subType=self::SOFD;
503              break;
504            case self::SEGMENT_SOFE:
505                $subType=self::SOFE;
506              break;
507            case self::SEGMENT_SOFF:
508                $subType=self::SOFF;
509              break;
510            case self::SEGMENT_DHT:
511                $subType=self::DHT;
512              break;
513            case self::SEGMENT_JPG:
514                $subType=self::JPG;
515              break;
516            case self::SEGMENT_DAC:
517                $subType=self::DAC;
518              break;
519            case self::SEGMENT_SOS:
520                $subType=self::SOS;
521              break;
522            case self::SEGMENT_DRI:
523                $subType=self::DRI;
524              break;
525            case self::SEGMENT_COM:
526                $subType=self::COM;
527                break;
528            default:
529              /* in other case, return an new object Marker */
530              $subType=self::UNKNOWN;
531          }
532          return(new AppMarkerSegmentReader($header, $offset, $length+2, $subType, $datas));
533        }
534      }
535
536      return(false);
537    }
538
539    /**
540     * returns true if the given segment marker is a known segment
541     *
542     * @param UByte $value : the identifier of the segment
543     * @return Boolean
544     */
545    static function isValidMarkerHeader($value)
546    {
547      if($value==self::SEGMENT_HEAD or
548         $value==self::SEGMENT_APP0 or
549         $value==self::SEGMENT_APP1 or
550         $value==self::SEGMENT_APP2 or
551         $value==self::SEGMENT_APP3 or
552         $value==self::SEGMENT_APP4 or
553         $value==self::SEGMENT_APP5 or
554         $value==self::SEGMENT_APP6 or
555         $value==self::SEGMENT_APP7 or
556         $value==self::SEGMENT_APP8 or
557         $value==self::SEGMENT_APP9 or
558         $value==self::SEGMENT_APP10 or
559         $value==self::SEGMENT_APP11 or
560         $value==self::SEGMENT_APP12 or
561         $value==self::SEGMENT_APP13 or
562         $value==self::SEGMENT_APP14 or
563         $value==self::SEGMENT_APP15 or
564         $value==self::SEGMENT_SOF0 or
565         $value==self::SEGMENT_SOF1 or
566         $value==self::SEGMENT_SOF2 or
567         $value==self::SEGMENT_SOF3 or
568         $value==self::SEGMENT_SOF5 or
569         $value==self::SEGMENT_SOF6 or
570         $value==self::SEGMENT_SOF7 or
571         $value==self::SEGMENT_SOF9 or
572         $value==self::SEGMENT_SOFA or
573         $value==self::SEGMENT_SOFB or
574         $value==self::SEGMENT_SOFD or
575         $value==self::SEGMENT_SOFE or
576         $value==self::SEGMENT_SOFF or
577         $value==self::SEGMENT_DHT  or
578         $value==self::SEGMENT_JPG  or
579         $value==self::SEGMENT_DAC  or
580         $value==self::SEGMENT_SOS  or
581         $value==self::SEGMENT_DRI  or
582         $value==self::SEGMENT_COM  or
583         $value==self::SEGMENT_DQT)
584      {
585        return(true);
586      }
587      return(false);
588    }
589
590    /**
591     * returns the name of the given segment
592     *
593     * @param UByte $value : the identifier of the segment
594     *
595     * @return String
596     */
597    static function markerName($value)
598    {
599      switch($value)
600      {
601        case self::SEGMENT_APP0:
602          return("APP0");
603        case self::SEGMENT_APP1:
604          return("APP1");
605        case self::SEGMENT_APP2:
606          return("APP2");
607        case self::SEGMENT_APP3:
608          return("APP3");
609        case self::SEGMENT_APP4:
610          return("APP4");
611        case self::SEGMENT_APP5:
612          return("APP5");
613        case self::SEGMENT_APP6:
614          return("APP6");
615        case self::SEGMENT_APP7:
616          return("APP7");
617        case self::SEGMENT_APP8:
618          return("APP8");
619        case self::SEGMENT_APP9:
620          return("APP9");
621        case self::SEGMENT_APP10:
622          return("APP10");
623        case self::SEGMENT_APP11:
624          return("APP11");
625        case self::SEGMENT_APP12:
626          return("APP12");
627        case self::SEGMENT_APP13:
628          return("APP13");
629        case self::SEGMENT_APP14:
630          return("APP14");
631        case self::SEGMENT_APP15:
632          return("APP15");
633        case self::SEGMENT_DQT:
634          return("DQT");
635        case self::SEGMENT_SOF0:
636          return("SOF0");
637        case self::SEGMENT_SOF1:
638          return("SOF1");
639        case self::SEGMENT_SOF2:
640          return("SOF2");
641        case self::SEGMENT_SOF3:
642          return("SOF3");
643        case self::SEGMENT_SOF5:
644          return("SOF5");
645        case self::SEGMENT_SOF6:
646          return("SOF6");
647        case self::SEGMENT_SOF7:
648          return("SOF7");
649        case self::SEGMENT_SOF9:
650          return("SOF9");
651        case self::SEGMENT_SOFA:
652          return("SOFA");
653        case self::SEGMENT_SOFB:
654          return("SOFB");
655        case self::SEGMENT_SOFD:
656          return("SOFD");
657        case self::SEGMENT_SOFE:
658          return("SOFE");
659        case self::SEGMENT_SOFF:
660          return("SOFF");
661        case self::SEGMENT_DHT:
662          return("DHT");
663        case self::SEGMENT_JPG:
664          return("JPG");
665        case self::SEGMENT_DAC:
666          return("DAC");
667        case self::SEGMENT_SOS:
668          return("SOS");
669        case self::SEGMENT_DRI:
670          return("DRI");
671        case self::SEGMENT_COM:
672          return("COM");
673        default:
674          return(sprintf("%02x", $value));
675      }
676    }
677
678
679    /**
680     *
681     *
682     * @param UByte $header   : the identifier of the segment
683     *
684     * @param ULong $offset   : offset of the segment in the jpeg file
685     *
686     * @param UShort $length  : size of the segment, including the header and
687     *                          including the segment size (4bytes)
688     *
689     * @param String $subType : the subtype of the segment (for example an APP1
690     *                          segment can have EXIF or XMP datas)
691     *
692     * @param String $data    : the raw data of the segment, excluding the
693     *                          segment size and header
694     *
695     */
696    function __construct($header, $offset, $length, $subType, $data)
697    {
698      $this->header = $header;
699      $this->offset = $offset;
700      $this->length = $length;
701      $this->subType = $subType;
702      $this->workData = new Data($data);
703
704      $this->readData();
705
706      $this->workData->clear();
707    }
708
709    function __destruct()
710    {
711      unset($this->workData);
712      unset($this->data);
713    }
714
715    /**
716     * returns the identifiant of the segment (see the consts SEGMENT_xxxxxx for
717     * to know the list)
718     *
719     * @return UByte
720     */
721    public function getHeader()
722    {
723      return($this->header);
724    }
725
726
727    /**
728     * returns the offset of the segment in the jpeg file
729     *
730     * @return ULong
731     */
732    public function getOffset()
733    {
734      return($this->offset);
735    }
736
737    /**
738     * returns the length of the segment, including the segment header and the
739     * segment size (4 bytes)
740     *
741     * @return UShort
742     */
743    public function getLength()
744    {
745      return($this->length);
746    }
747
748    /**
749     * returns the subtype of the segment
750     *
751     * @return String
752     */
753    public function getSubType()
754    {
755      return($this->subType);
756    }
757
758    /**
759     * returns true if the segment data has been loaded
760     *
761     * @return Boolean
762     */
763    public function dataLoaded()
764    {
765      return($this->dataLoaded);
766    }
767
768    /**
769     * returns the data of the segment.
770     *
771     * @return depends on the segment subtype
772     */
773    public function getData()
774    {
775      return($this->data);
776    }
777
778
779    /**
780     * read the segment datas
781     */
782    private function readData()
783    {
784      switch($this->header)
785      {
786        case self::SEGMENT_APP0:
787          /* not implemented */
788          break;
789        case self::SEGMENT_APP1:
790          $this->readSegmentAPP1();
791          break;
792        case self::SEGMENT_APP2:
793          /* not implemented */
794          break;
795        case self::SEGMENT_APP3:
796          /* not implemented */
797          break;
798        case self::SEGMENT_APP4:
799          /* not implemented */
800          break;
801        case self::SEGMENT_APP5:
802          /* not implemented */
803          break;
804        case self::SEGMENT_APP6:
805          /* not implemented */
806          break;
807        case self::SEGMENT_APP7:
808          /* not implemented */
809          break;
810        case self::SEGMENT_APP8:
811          /* not implemented */
812          break;
813        case self::SEGMENT_APP9:
814          /* not implemented */
815          break;
816        case self::SEGMENT_APP10:
817          /* not implemented */
818          break;
819        case self::SEGMENT_APP11:
820          /* not implemented */
821          break;
822        case self::SEGMENT_APP12:
823          /* not implemented */
824          break;
825        case self::SEGMENT_APP13:
826          $this->readSegmentAPP13();
827          break;
828        case self::SEGMENT_APP14:
829          /* not implemented */
830          break;
831        case self::SEGMENT_APP15:
832          /* not implemented */
833          break;
834        case self::SEGMENT_COM:
835          $this->readSegmentCOM();
836          break;
837        default:
838          break;
839      }
840    }
841
842    /**
843     *  read the content of an "APP1" segment
844     */
845    private function readSegmentAPP1()
846    {
847      switch($this->subType)
848      {
849        case self::APP1_EXIF:
850          $this->data = new TiffReader($this->workData, $this->offset+10);
851          $this->dataLoaded=true;
852          break;
853        case self::APP1_XMP:
854          $this->data = new XmpReader($this->workData->readASCII());
855          $this->dataLoaded=true;
856          break;
857        case self::APP1_EXTENDED:
858          $this->data = $this->workData->readASCII();
859          $this->dataLoaded=true;
860          break;
861        default:
862          break;
863      }
864    }
865
866    /**
867     *  read the content of an "APP13" segment
868     */
869    private function readSegmentAPP13()
870    {
871      switch($this->subType)
872      {
873        case self::APP13_PHOTOSHOP:
874          $this->data = new IptcReader($this->workData->readASCII());
875          $this->dataLoaded=true;
876          break;
877        case self::APP13_ADOBECM:
878          break;
879        default:
880          break;
881      }
882    }
883
884    /**
885     *  read the content of an "COM" segment
886     */
887    private function readSegmentCOM()
888    {
889      $this->data = $this->workData->readASCII();
890      $this->dataLoaded=true;
891    }
892
893    public function toString()
894    {
895      $returned="Header: 0xff".sprintf("%02x", $this->header)." (".self::markerName($this->header).")".
896                " ; offset: 0x".sprintf("%08x", $this->offset).
897                " ; length: 0x".sprintf("%04x", $this->length).
898                " ; subType: ".$this->subType;
899      return($returned);
900    }
901
902
903  }
904
905
906 ?>
Note: See TracBrowser for help on using the repository browser.