xref: /dokuwiki/inc/JpegMeta.php (revision 55efc227eaeb2d480ff22837b78f89766b07fe5f)
1*55efc227SAndreas Gohr<?php
2*55efc227SAndreas Gohr/**
3*55efc227SAndreas Gohr * JPEG metadata reader/writer
4*55efc227SAndreas Gohr *
5*55efc227SAndreas Gohr * @license    PHP license 2.0 (http://www.php.net/license/2_02.txt)
6*55efc227SAndreas Gohr * @link
7*55efc227SAndreas Gohr * @author     Sebastian Delmont <sdelmont@zonageek.com>
8*55efc227SAndreas Gohr * @author     Andreas Gohr <andi@splitbrain.org>
9*55efc227SAndreas Gohr */
10*55efc227SAndreas Gohr
11*55efc227SAndreas Gohr// This class is a modified and enhanced version of the JPEG class by
12*55efc227SAndreas Gohr// Sebastian Delmont. Original Copyright notice follows:
13*55efc227SAndreas Gohr//
14*55efc227SAndreas Gohr// +----------------------------------------------------------------------+
15*55efc227SAndreas Gohr// | PHP version 4.0                                                      |
16*55efc227SAndreas Gohr// +----------------------------------------------------------------------+
17*55efc227SAndreas Gohr// | Copyright (c) 1997, 1998, 1999, 2000, 2001 The PHP Group             |
18*55efc227SAndreas Gohr// +----------------------------------------------------------------------+
19*55efc227SAndreas Gohr// | This source file is subject to version 2.0 of the PHP license,       |
20*55efc227SAndreas Gohr// | that is bundled with this package in the file LICENSE, and is        |
21*55efc227SAndreas Gohr// | available at through the world-wide-web at                           |
22*55efc227SAndreas Gohr// | http://www.php.net/license/2_02.txt.                                 |
23*55efc227SAndreas Gohr// | If you did not receive a copy of the PHP license and are unable to   |
24*55efc227SAndreas Gohr// | obtain it through the world-wide-web, please send a note to          |
25*55efc227SAndreas Gohr// | license@php.net so we can mail you a copy immediately.               |
26*55efc227SAndreas Gohr// +----------------------------------------------------------------------+
27*55efc227SAndreas Gohr// | Authors: Sebastian Delmont <sdelmont@zonageek.com>                   |
28*55efc227SAndreas Gohr// +----------------------------------------------------------------------+
29*55efc227SAndreas Gohr
30*55efc227SAndreas Gohrclass JpegMeta
31*55efc227SAndreas Gohr{
32*55efc227SAndreas Gohr    var $_fileName;
33*55efc227SAndreas Gohr    var $_fp = null;
34*55efc227SAndreas Gohr    var $_type = 'unknown';
35*55efc227SAndreas Gohr
36*55efc227SAndreas Gohr    var $_markers;
37*55efc227SAndreas Gohr    var $_info;
38*55efc227SAndreas Gohr
39*55efc227SAndreas Gohr
40*55efc227SAndreas Gohr    /**
41*55efc227SAndreas Gohr     * Constructor
42*55efc227SAndreas Gohr     *
43*55efc227SAndreas Gohr     * @author Sebastian Delmont <sdelmont@zonageek.com>
44*55efc227SAndreas Gohr     */
45*55efc227SAndreas Gohr    function JpegMeta($fileName)
46*55efc227SAndreas Gohr    {
47*55efc227SAndreas Gohr
48*55efc227SAndreas Gohr        $this->_fileName = $fileName;
49*55efc227SAndreas Gohr
50*55efc227SAndreas Gohr        $this->_fp = null;
51*55efc227SAndreas Gohr        $this->_type = 'unknown';
52*55efc227SAndreas Gohr
53*55efc227SAndreas Gohr        unset($this->_info);
54*55efc227SAndreas Gohr        unset($this->_markers);
55*55efc227SAndreas Gohr    }
56*55efc227SAndreas Gohr
57*55efc227SAndreas Gohr    /**
58*55efc227SAndreas Gohr     * Returns all gathered info as multidim array
59*55efc227SAndreas Gohr     *
60*55efc227SAndreas Gohr     * @author Sebastian Delmont <sdelmont@zonageek.com>
61*55efc227SAndreas Gohr     */
62*55efc227SAndreas Gohr    function & getRawInfo()
63*55efc227SAndreas Gohr    {
64*55efc227SAndreas Gohr        $this->_parseAll();
65*55efc227SAndreas Gohr
66*55efc227SAndreas Gohr        if ($this->_markers == null) {
67*55efc227SAndreas Gohr            return false;
68*55efc227SAndreas Gohr        }
69*55efc227SAndreas Gohr
70*55efc227SAndreas Gohr        return $this->_info;
71*55efc227SAndreas Gohr    }
72*55efc227SAndreas Gohr
73*55efc227SAndreas Gohr    /**
74*55efc227SAndreas Gohr     * Returns basic image info
75*55efc227SAndreas Gohr     *
76*55efc227SAndreas Gohr     * @author Sebastian Delmont <sdelmont@zonageek.com>
77*55efc227SAndreas Gohr     */
78*55efc227SAndreas Gohr    function & getBasicInfo()
79*55efc227SAndreas Gohr    {
80*55efc227SAndreas Gohr        $this->_parseAll();
81*55efc227SAndreas Gohr
82*55efc227SAndreas Gohr        $info = array();
83*55efc227SAndreas Gohr
84*55efc227SAndreas Gohr        if ($this->_markers == null) {
85*55efc227SAndreas Gohr            return false;
86*55efc227SAndreas Gohr        }
87*55efc227SAndreas Gohr
88*55efc227SAndreas Gohr        $info['Name'] = $this->_info['file']['Name'];
89*55efc227SAndreas Gohr        if (isset($this->_info['file']['Url'])) {
90*55efc227SAndreas Gohr            $info['Url'] = $this->_info['file']['Url'];
91*55efc227SAndreas Gohr            $info['NiceSize'] = "???KB";
92*55efc227SAndreas Gohr        }
93*55efc227SAndreas Gohr        else {
94*55efc227SAndreas Gohr            $info['Size'] = $this->_info['file']['Size'];
95*55efc227SAndreas Gohr            $info['NiceSize'] = $this->_info['file']['NiceSize'];
96*55efc227SAndreas Gohr        }
97*55efc227SAndreas Gohr
98*55efc227SAndreas Gohr        if (@isset($this->_info['sof']['Format'])) {
99*55efc227SAndreas Gohr            $info['Format'] = $this->_info['sof']['Format'] . " JPEG";
100*55efc227SAndreas Gohr        }
101*55efc227SAndreas Gohr        else {
102*55efc227SAndreas Gohr            $info['Format'] = $this->_info['sof']['Format'] . " JPEG";
103*55efc227SAndreas Gohr        }
104*55efc227SAndreas Gohr
105*55efc227SAndreas Gohr        if (@isset($this->_info['sof']['ColorChannels'])) {
106*55efc227SAndreas Gohr            $info['ColorMode'] = ($this->_info['sof']['ColorChannels'] > 1) ? "Color" : "B&W";
107*55efc227SAndreas Gohr        }
108*55efc227SAndreas Gohr
109*55efc227SAndreas Gohr        $info['Width'] = $this->getWidth();
110*55efc227SAndreas Gohr        $info['Height'] = $this->getHeight();
111*55efc227SAndreas Gohr        $info['DimStr'] = $this->getDimStr();
112*55efc227SAndreas Gohr
113*55efc227SAndreas Gohr        $dates = $this->getDates();
114*55efc227SAndreas Gohr
115*55efc227SAndreas Gohr        $info['DateTime'] = $dates['EarliestTime'];
116*55efc227SAndreas Gohr        $info['DateTimeStr'] = $dates['EarliestTimeStr'];
117*55efc227SAndreas Gohr
118*55efc227SAndreas Gohr        $info['HasThumbnail'] = $this->hasThumbnail();
119*55efc227SAndreas Gohr
120*55efc227SAndreas Gohr        return $info;
121*55efc227SAndreas Gohr    }
122*55efc227SAndreas Gohr
123*55efc227SAndreas Gohr
124*55efc227SAndreas Gohr    /**
125*55efc227SAndreas Gohr     * Convinience function to access nearly all available Data
126*55efc227SAndreas Gohr     * through one function
127*55efc227SAndreas Gohr     *
128*55efc227SAndreas Gohr     * @author Andreas Gohr <andi@splitbrain.org>
129*55efc227SAndreas Gohr     */
130*55efc227SAndreas Gohr    function getField($fields)
131*55efc227SAndreas Gohr    {
132*55efc227SAndreas Gohr        if(!is_array($fields)) $fields = array($fields);
133*55efc227SAndreas Gohr        $info = false;
134*55efc227SAndreas Gohr        foreach($fields as $field){
135*55efc227SAndreas Gohr            if(strtolower(substr($field,0,5)) == 'iptc.'){
136*55efc227SAndreas Gohr                $info = $this->getIPTCField(substr($field,5));
137*55efc227SAndreas Gohr            }elseif(strtolower(substr($field,0,5)) == 'exif.'){
138*55efc227SAndreas Gohr                $info = $this->getExifField(substr($field,5));
139*55efc227SAndreas Gohr            }elseif(strtolower(substr($field,0,5)) == 'file.'){
140*55efc227SAndreas Gohr                $info = $this->getFileField(substr($field,5));
141*55efc227SAndreas Gohr            }elseif(strtolower(substr($field,0,5)) == 'date.'){
142*55efc227SAndreas Gohr                $info = $this->getDateField(substr($field,5));
143*55efc227SAndreas Gohr            }elseif(strtolower($field) == 'simple.camera'){
144*55efc227SAndreas Gohr                $info = $this->getCamera();
145*55efc227SAndreas Gohr            }elseif(strtolower($field) == 'simple.raw'){
146*55efc227SAndreas Gohr                return $this->getRawInfo();
147*55efc227SAndreas Gohr            }elseif(strtolower($field) == 'simple.title'){
148*55efc227SAndreas Gohr                $info = $this->getTitle();
149*55efc227SAndreas Gohr            }else{
150*55efc227SAndreas Gohr                $info = $this->getExifField($field);
151*55efc227SAndreas Gohr            }
152*55efc227SAndreas Gohr            if($info != false) break;
153*55efc227SAndreas Gohr        }
154*55efc227SAndreas Gohr
155*55efc227SAndreas Gohr        if($info === false)  $info = $alt;
156*55efc227SAndreas Gohr        if(is_array($info)){
157*55efc227SAndreas Gohr            if(isset($info['val'])){
158*55efc227SAndreas Gohr                $info = $info['val'];
159*55efc227SAndreas Gohr            }else{
160*55efc227SAndreas Gohr                $info = join(', ',$info);
161*55efc227SAndreas Gohr            }
162*55efc227SAndreas Gohr        }
163*55efc227SAndreas Gohr        return trim($info);
164*55efc227SAndreas Gohr    }
165*55efc227SAndreas Gohr
166*55efc227SAndreas Gohr    /**
167*55efc227SAndreas Gohr     * Return a date field
168*55efc227SAndreas Gohr     *
169*55efc227SAndreas Gohr     * @author Andreas Gohr <andi@splitbrain.org>
170*55efc227SAndreas Gohr     */
171*55efc227SAndreas Gohr    function getDateField($field)
172*55efc227SAndreas Gohr    {
173*55efc227SAndreas Gohr        if (!isset($this->_info['dates'])) {
174*55efc227SAndreas Gohr            $this->_info['dates'] = $this->getDates();
175*55efc227SAndreas Gohr        }
176*55efc227SAndreas Gohr
177*55efc227SAndreas Gohr        if (isset($this->_info['dates'][$field])) {
178*55efc227SAndreas Gohr            return $this->_info['dates'][$field];
179*55efc227SAndreas Gohr        }
180*55efc227SAndreas Gohr
181*55efc227SAndreas Gohr        return false;
182*55efc227SAndreas Gohr    }
183*55efc227SAndreas Gohr
184*55efc227SAndreas Gohr    /**
185*55efc227SAndreas Gohr     * Return a file info field
186*55efc227SAndreas Gohr     *
187*55efc227SAndreas Gohr     * @author Andreas Gohr <andi@splitbrain.org>
188*55efc227SAndreas Gohr     */
189*55efc227SAndreas Gohr    function getFileField($field)
190*55efc227SAndreas Gohr    {
191*55efc227SAndreas Gohr        if (!isset($this->_info['file'])) {
192*55efc227SAndreas Gohr            $this->_parseFileInfo();
193*55efc227SAndreas Gohr        }
194*55efc227SAndreas Gohr
195*55efc227SAndreas Gohr        if (isset($this->_info['file'][$field])) {
196*55efc227SAndreas Gohr            return $this->_info['file'][$field];
197*55efc227SAndreas Gohr        }
198*55efc227SAndreas Gohr
199*55efc227SAndreas Gohr        return false;
200*55efc227SAndreas Gohr    }
201*55efc227SAndreas Gohr
202*55efc227SAndreas Gohr    /**
203*55efc227SAndreas Gohr     * Return the camera info (Maker and Model)
204*55efc227SAndreas Gohr     *
205*55efc227SAndreas Gohr     * @author Andreas Gohr <andi@splitbrain.org>
206*55efc227SAndreas Gohr     * @todo   handle makernotes
207*55efc227SAndreas Gohr     */
208*55efc227SAndreas Gohr    function getCamera(){
209*55efc227SAndreas Gohr        $make  = $this->getField(array('Exif.Make','Exif.TIFFMake'));
210*55efc227SAndreas Gohr        $model = $this->getField(array('Exif.Model','Exif.TIFFModel'));
211*55efc227SAndreas Gohr        $cam = trim("$make $model");
212*55efc227SAndreas Gohr        if(empty($cam)) return false;
213*55efc227SAndreas Gohr        return $cam;
214*55efc227SAndreas Gohr    }
215*55efc227SAndreas Gohr
216*55efc227SAndreas Gohr    /**
217*55efc227SAndreas Gohr     * Return an EXIF field
218*55efc227SAndreas Gohr     *
219*55efc227SAndreas Gohr     * @author Sebastian Delmont <sdelmont@zonageek.com>
220*55efc227SAndreas Gohr     */
221*55efc227SAndreas Gohr    function getExifField($field)
222*55efc227SAndreas Gohr    {
223*55efc227SAndreas Gohr        if (!isset($this->_info['exif'])) {
224*55efc227SAndreas Gohr            $this->_parseMarkerExif();
225*55efc227SAndreas Gohr        }
226*55efc227SAndreas Gohr
227*55efc227SAndreas Gohr        if ($this->_markers == null) {
228*55efc227SAndreas Gohr            return false;
229*55efc227SAndreas Gohr        }
230*55efc227SAndreas Gohr
231*55efc227SAndreas Gohr        if (isset($this->_info['exif'][$field])) {
232*55efc227SAndreas Gohr            return $this->_info['exif'][$field];
233*55efc227SAndreas Gohr        }
234*55efc227SAndreas Gohr
235*55efc227SAndreas Gohr        return false;
236*55efc227SAndreas Gohr    }
237*55efc227SAndreas Gohr
238*55efc227SAndreas Gohr    /**
239*55efc227SAndreas Gohr     * Return an Adobe Field
240*55efc227SAndreas Gohr     *
241*55efc227SAndreas Gohr     * @author Sebastian Delmont <sdelmont@zonageek.com>
242*55efc227SAndreas Gohr     */
243*55efc227SAndreas Gohr    function getAdobeField($field)
244*55efc227SAndreas Gohr    {
245*55efc227SAndreas Gohr        if (!isset($this->_info['adobe'])) {
246*55efc227SAndreas Gohr            $this->_parseMarkerAdobe();
247*55efc227SAndreas Gohr        }
248*55efc227SAndreas Gohr
249*55efc227SAndreas Gohr        if ($this->_markers == null) {
250*55efc227SAndreas Gohr            return false;
251*55efc227SAndreas Gohr        }
252*55efc227SAndreas Gohr
253*55efc227SAndreas Gohr        if (isset($this->_info['adobe'][$field])) {
254*55efc227SAndreas Gohr            return $this->_info['adobe'][$field];
255*55efc227SAndreas Gohr        }
256*55efc227SAndreas Gohr
257*55efc227SAndreas Gohr        return false;
258*55efc227SAndreas Gohr    }
259*55efc227SAndreas Gohr
260*55efc227SAndreas Gohr    /**
261*55efc227SAndreas Gohr     * Return an IPTC field
262*55efc227SAndreas Gohr     *
263*55efc227SAndreas Gohr     * @author Sebastian Delmont <sdelmont@zonageek.com>
264*55efc227SAndreas Gohr     */
265*55efc227SAndreas Gohr    function getIPTCField($field)
266*55efc227SAndreas Gohr    {
267*55efc227SAndreas Gohr        if (!isset($this->_info['iptc'])) {
268*55efc227SAndreas Gohr            $this->_parseMarkerAdobe();
269*55efc227SAndreas Gohr        }
270*55efc227SAndreas Gohr
271*55efc227SAndreas Gohr        if ($this->_markers == null) {
272*55efc227SAndreas Gohr            return false;
273*55efc227SAndreas Gohr        }
274*55efc227SAndreas Gohr
275*55efc227SAndreas Gohr        if (isset($this->_info['iptc'][$field])) {
276*55efc227SAndreas Gohr            return $this->_info['iptc'][$field];
277*55efc227SAndreas Gohr        }
278*55efc227SAndreas Gohr
279*55efc227SAndreas Gohr        return false;
280*55efc227SAndreas Gohr    }
281*55efc227SAndreas Gohr
282*55efc227SAndreas Gohr    /**
283*55efc227SAndreas Gohr     * Set an EXIF field
284*55efc227SAndreas Gohr     *
285*55efc227SAndreas Gohr     * @author Sebastian Delmont <sdelmont@zonageek.com>
286*55efc227SAndreas Gohr     */
287*55efc227SAndreas Gohr    function setExifField($field, $value)
288*55efc227SAndreas Gohr    {
289*55efc227SAndreas Gohr        if (!isset($this->_info['exif'])) {
290*55efc227SAndreas Gohr            $this->_parseMarkerExif();
291*55efc227SAndreas Gohr        }
292*55efc227SAndreas Gohr
293*55efc227SAndreas Gohr        if ($this->_markers == null) {
294*55efc227SAndreas Gohr            return false;
295*55efc227SAndreas Gohr        }
296*55efc227SAndreas Gohr
297*55efc227SAndreas Gohr        if ($this->_info['exif'] == false) {
298*55efc227SAndreas Gohr            $this->_info['exif'] = array();
299*55efc227SAndreas Gohr        }
300*55efc227SAndreas Gohr
301*55efc227SAndreas Gohr        $this->_info['exif'][$field] = $value;
302*55efc227SAndreas Gohr
303*55efc227SAndreas Gohr        return true;
304*55efc227SAndreas Gohr    }
305*55efc227SAndreas Gohr
306*55efc227SAndreas Gohr    /**
307*55efc227SAndreas Gohr     * Set an Adobe Field
308*55efc227SAndreas Gohr     *
309*55efc227SAndreas Gohr     * @author Sebastian Delmont <sdelmont@zonageek.com>
310*55efc227SAndreas Gohr     */
311*55efc227SAndreas Gohr    function setAdobeField($field, $value)
312*55efc227SAndreas Gohr    {
313*55efc227SAndreas Gohr        if (!isset($this->_info['adobe'])) {
314*55efc227SAndreas Gohr            $this->_parseMarkerAdobe();
315*55efc227SAndreas Gohr        }
316*55efc227SAndreas Gohr
317*55efc227SAndreas Gohr        if ($this->_markers == null) {
318*55efc227SAndreas Gohr            return false;
319*55efc227SAndreas Gohr        }
320*55efc227SAndreas Gohr
321*55efc227SAndreas Gohr        if ($this->_info['adobe'] == false) {
322*55efc227SAndreas Gohr            $this->_info['adobe'] = array();
323*55efc227SAndreas Gohr        }
324*55efc227SAndreas Gohr
325*55efc227SAndreas Gohr        $this->_info['adobe'][$field] = $value;
326*55efc227SAndreas Gohr
327*55efc227SAndreas Gohr        return true;
328*55efc227SAndreas Gohr    }
329*55efc227SAndreas Gohr
330*55efc227SAndreas Gohr    /**
331*55efc227SAndreas Gohr     * Set an IPTC field
332*55efc227SAndreas Gohr     *
333*55efc227SAndreas Gohr     * @author Sebastian Delmont <sdelmont@zonageek.com>
334*55efc227SAndreas Gohr     */
335*55efc227SAndreas Gohr    function setIPTCField($field, $value)
336*55efc227SAndreas Gohr    {
337*55efc227SAndreas Gohr        if (!isset($this->_info['iptc'])) {
338*55efc227SAndreas Gohr            $this->_parseMarkerAdobe();
339*55efc227SAndreas Gohr        }
340*55efc227SAndreas Gohr
341*55efc227SAndreas Gohr        if ($this->_markers == null) {
342*55efc227SAndreas Gohr            return false;
343*55efc227SAndreas Gohr        }
344*55efc227SAndreas Gohr
345*55efc227SAndreas Gohr        if ($this->_info['iptc'] == false) {
346*55efc227SAndreas Gohr            $this->_info['iptc'] = array();
347*55efc227SAndreas Gohr        }
348*55efc227SAndreas Gohr
349*55efc227SAndreas Gohr        $this->_info['iptc'][$field] = $value;
350*55efc227SAndreas Gohr
351*55efc227SAndreas Gohr        return true;
352*55efc227SAndreas Gohr    }
353*55efc227SAndreas Gohr
354*55efc227SAndreas Gohr    /**
355*55efc227SAndreas Gohr     * Delete an EXIF field
356*55efc227SAndreas Gohr     *
357*55efc227SAndreas Gohr     * @author Sebastian Delmont <sdelmont@zonageek.com>
358*55efc227SAndreas Gohr     */
359*55efc227SAndreas Gohr    function deleteExifField($field)
360*55efc227SAndreas Gohr    {
361*55efc227SAndreas Gohr        if (!isset($this->_info['exif'])) {
362*55efc227SAndreas Gohr            $this->_parseMarkerAdobe();
363*55efc227SAndreas Gohr        }
364*55efc227SAndreas Gohr
365*55efc227SAndreas Gohr        if ($this->_markers == null) {
366*55efc227SAndreas Gohr            return false;
367*55efc227SAndreas Gohr        }
368*55efc227SAndreas Gohr
369*55efc227SAndreas Gohr        if ($this->_info['exif'] != false) {
370*55efc227SAndreas Gohr            unset($this->_info['exif'][$field]);
371*55efc227SAndreas Gohr        }
372*55efc227SAndreas Gohr
373*55efc227SAndreas Gohr        return true;
374*55efc227SAndreas Gohr    }
375*55efc227SAndreas Gohr
376*55efc227SAndreas Gohr    /**
377*55efc227SAndreas Gohr     * Delete an Adobe field
378*55efc227SAndreas Gohr     *
379*55efc227SAndreas Gohr     * @author Sebastian Delmont <sdelmont@zonageek.com>
380*55efc227SAndreas Gohr     */
381*55efc227SAndreas Gohr    function deleteAdobeField($field)
382*55efc227SAndreas Gohr    {
383*55efc227SAndreas Gohr        if (!isset($this->_info['adobe'])) {
384*55efc227SAndreas Gohr            $this->_parseMarkerAdobe();
385*55efc227SAndreas Gohr        }
386*55efc227SAndreas Gohr
387*55efc227SAndreas Gohr        if ($this->_markers == null) {
388*55efc227SAndreas Gohr            return false;
389*55efc227SAndreas Gohr        }
390*55efc227SAndreas Gohr
391*55efc227SAndreas Gohr        if ($this->_info['adobe'] != false) {
392*55efc227SAndreas Gohr            unset($this->_info['adobe'][$field]);
393*55efc227SAndreas Gohr        }
394*55efc227SAndreas Gohr
395*55efc227SAndreas Gohr        return true;
396*55efc227SAndreas Gohr    }
397*55efc227SAndreas Gohr
398*55efc227SAndreas Gohr    /**
399*55efc227SAndreas Gohr     * Delete an IPTC field
400*55efc227SAndreas Gohr     *
401*55efc227SAndreas Gohr     * @author Sebastian Delmont <sdelmont@zonageek.com>
402*55efc227SAndreas Gohr     */
403*55efc227SAndreas Gohr    function deleteIPTCField($field)
404*55efc227SAndreas Gohr    {
405*55efc227SAndreas Gohr        if (!isset($this->_info['iptc'])) {
406*55efc227SAndreas Gohr            $this->_parseMarkerAdobe();
407*55efc227SAndreas Gohr        }
408*55efc227SAndreas Gohr
409*55efc227SAndreas Gohr        if ($this->_markers == null) {
410*55efc227SAndreas Gohr            return false;
411*55efc227SAndreas Gohr        }
412*55efc227SAndreas Gohr
413*55efc227SAndreas Gohr        if ($this->_info['iptc'] != false) {
414*55efc227SAndreas Gohr            unset($this->_info['iptc'][$field]);
415*55efc227SAndreas Gohr        }
416*55efc227SAndreas Gohr
417*55efc227SAndreas Gohr        return true;
418*55efc227SAndreas Gohr    }
419*55efc227SAndreas Gohr
420*55efc227SAndreas Gohr    /**
421*55efc227SAndreas Gohr     * Get the image's title, tries various fields
422*55efc227SAndreas Gohr     *
423*55efc227SAndreas Gohr     * @param int $max  maximum number chars (keeps words)
424*55efc227SAndreas Gohr     * @author Andreas Gohr <andi@splitbrain.org>
425*55efc227SAndreas Gohr     */
426*55efc227SAndreas Gohr    function getTitle($max=80){
427*55efc227SAndreas Gohr        $cap = '';
428*55efc227SAndreas Gohr
429*55efc227SAndreas Gohr        // try various fields
430*55efc227SAndreas Gohr        $cap = $this->getField(array('Iptc.Headline',
431*55efc227SAndreas Gohr                                     'Iptc.Caption',
432*55efc227SAndreas Gohr                                     'Exif.UserComment',
433*55efc227SAndreas Gohr                                     'Exif.TIFFUserComment',
434*55efc227SAndreas Gohr                                     'Exif.TIFFImageDescription'));
435*55efc227SAndreas Gohr        if (empty($cap)) return false;
436*55efc227SAndreas Gohr
437*55efc227SAndreas Gohr        if(!$max) return $cap;
438*55efc227SAndreas Gohr        // Shorten to 80 chars (keeping words)
439*55efc227SAndreas Gohr        $new = preg_replace('/\n.+$/','',wordwrap($cap, $max));
440*55efc227SAndreas Gohr        if($new != $cap) $new .= '...';
441*55efc227SAndreas Gohr
442*55efc227SAndreas Gohr        return $new;
443*55efc227SAndreas Gohr    }
444*55efc227SAndreas Gohr
445*55efc227SAndreas Gohr    /**
446*55efc227SAndreas Gohr     * Gather various date fields
447*55efc227SAndreas Gohr     *
448*55efc227SAndreas Gohr     * @author Sebastian Delmont <sdelmont@zonageek.com>
449*55efc227SAndreas Gohr     */
450*55efc227SAndreas Gohr    function getDates()
451*55efc227SAndreas Gohr    {
452*55efc227SAndreas Gohr        $this->_parseAll();
453*55efc227SAndreas Gohr
454*55efc227SAndreas Gohr        if ($this->_markers == null) {
455*55efc227SAndreas Gohr            return false;
456*55efc227SAndreas Gohr        }
457*55efc227SAndreas Gohr
458*55efc227SAndreas Gohr        $dates = array();
459*55efc227SAndreas Gohr
460*55efc227SAndreas Gohr        $latestTime = 0;
461*55efc227SAndreas Gohr        $latestTimeSource = "";
462*55efc227SAndreas Gohr        $earliestTime = time();
463*55efc227SAndreas Gohr        $earliestTimeSource = "";
464*55efc227SAndreas Gohr
465*55efc227SAndreas Gohr        if (@isset($this->_info['exif']['DateTime'])) {
466*55efc227SAndreas Gohr            $dates['ExifDateTime'] = $this->_info['exif']['DateTime'];
467*55efc227SAndreas Gohr
468*55efc227SAndreas Gohr            $aux = $this->_info['exif']['DateTime'];
469*55efc227SAndreas Gohr            $aux{4} = "-";
470*55efc227SAndreas Gohr            $aux{7} = "-";
471*55efc227SAndreas Gohr            $t = strtotime($aux);
472*55efc227SAndreas Gohr
473*55efc227SAndreas Gohr            if ($t > $latestTime) {
474*55efc227SAndreas Gohr                $latestTime = $t;
475*55efc227SAndreas Gohr                $latestTimeSource = "ExifDateTime";
476*55efc227SAndreas Gohr            }
477*55efc227SAndreas Gohr
478*55efc227SAndreas Gohr            if ($t < $earliestTime) {
479*55efc227SAndreas Gohr                $earliestTime = $t;
480*55efc227SAndreas Gohr                $earliestTimeSource = "ExifDateTime";
481*55efc227SAndreas Gohr            }
482*55efc227SAndreas Gohr        }
483*55efc227SAndreas Gohr
484*55efc227SAndreas Gohr        if (@isset($this->_info['exif']['DateTimeOriginal'])) {
485*55efc227SAndreas Gohr            $dates['ExifDateTimeOriginal'] = $this->_info['exif']['DateTime'];
486*55efc227SAndreas Gohr
487*55efc227SAndreas Gohr            $aux = $this->_info['exif']['DateTimeOriginal'];
488*55efc227SAndreas Gohr            $aux{4} = "-";
489*55efc227SAndreas Gohr            $aux{7} = "-";
490*55efc227SAndreas Gohr            $t = strtotime($aux);
491*55efc227SAndreas Gohr
492*55efc227SAndreas Gohr            if ($t > $latestTime) {
493*55efc227SAndreas Gohr                $latestTime = $t;
494*55efc227SAndreas Gohr                $latestTimeSource = "ExifDateTimeOriginal";
495*55efc227SAndreas Gohr            }
496*55efc227SAndreas Gohr
497*55efc227SAndreas Gohr            if ($t < $earliestTime) {
498*55efc227SAndreas Gohr                $earliestTime = $t;
499*55efc227SAndreas Gohr                $earliestTimeSource = "ExifDateTimeOriginal";
500*55efc227SAndreas Gohr            }
501*55efc227SAndreas Gohr        }
502*55efc227SAndreas Gohr
503*55efc227SAndreas Gohr        if (@isset($this->_info['exif']['DateTimeDigitized'])) {
504*55efc227SAndreas Gohr            $dates['ExifDateTimeDigitized'] = $this->_info['exif']['DateTime'];
505*55efc227SAndreas Gohr
506*55efc227SAndreas Gohr            $aux = $this->_info['exif']['DateTimeDigitized'];
507*55efc227SAndreas Gohr            $aux{4} = "-";
508*55efc227SAndreas Gohr            $aux{7} = "-";
509*55efc227SAndreas Gohr            $t = strtotime($aux);
510*55efc227SAndreas Gohr
511*55efc227SAndreas Gohr            if ($t > $latestTime) {
512*55efc227SAndreas Gohr                $latestTime = $t;
513*55efc227SAndreas Gohr                $latestTimeSource = "ExifDateTimeDigitized";
514*55efc227SAndreas Gohr            }
515*55efc227SAndreas Gohr
516*55efc227SAndreas Gohr            if ($t < $earliestTime) {
517*55efc227SAndreas Gohr                $earliestTime = $t;
518*55efc227SAndreas Gohr                $earliestTimeSource = "ExifDateTimeDigitized";
519*55efc227SAndreas Gohr            }
520*55efc227SAndreas Gohr        }
521*55efc227SAndreas Gohr
522*55efc227SAndreas Gohr        if (@isset($this->_info['iptc']['DateCreated'])) {
523*55efc227SAndreas Gohr            $dates['IPTCDateCreated'] = $this->_info['iptc']['DateCreated'];
524*55efc227SAndreas Gohr
525*55efc227SAndreas Gohr            $aux = $this->_info['iptc']['DateCreated'];
526*55efc227SAndreas Gohr            $aux = substr($aux, 0, 4) . "-" . substr($aux, 4, 2) . "-" . substr($aux, 6, 2);
527*55efc227SAndreas Gohr            $t = strtotime($aux);
528*55efc227SAndreas Gohr
529*55efc227SAndreas Gohr            if ($t > $latestTime) {
530*55efc227SAndreas Gohr                $latestTime = $t;
531*55efc227SAndreas Gohr                $latestTimeSource = "IPTCDateCreated";
532*55efc227SAndreas Gohr            }
533*55efc227SAndreas Gohr
534*55efc227SAndreas Gohr            if ($t < $earliestTime) {
535*55efc227SAndreas Gohr                $earliestTime = $t;
536*55efc227SAndreas Gohr                $earliestTimeSource = "IPTCDateCreated";
537*55efc227SAndreas Gohr            }
538*55efc227SAndreas Gohr        }
539*55efc227SAndreas Gohr
540*55efc227SAndreas Gohr        if (@isset($this->_info['file']['UnixTime'])) {
541*55efc227SAndreas Gohr            $dates['FileModified'] = $this->_info['file']['UnixTime'];
542*55efc227SAndreas Gohr
543*55efc227SAndreas Gohr            $t = $this->_info['file']['UnixTime'];
544*55efc227SAndreas Gohr
545*55efc227SAndreas Gohr            if ($t > $latestTime) {
546*55efc227SAndreas Gohr                $latestTime = $t;
547*55efc227SAndreas Gohr                $latestTimeSource = "FileModified";
548*55efc227SAndreas Gohr            }
549*55efc227SAndreas Gohr
550*55efc227SAndreas Gohr            if ($t < $earliestTime) {
551*55efc227SAndreas Gohr                $earliestTime = $t;
552*55efc227SAndreas Gohr                $earliestTimeSource = "FileModified";
553*55efc227SAndreas Gohr            }
554*55efc227SAndreas Gohr        }
555*55efc227SAndreas Gohr
556*55efc227SAndreas Gohr        $dates['Time'] = $earliestTime;
557*55efc227SAndreas Gohr        $dates['TimeSource'] = $earliestTimeSource;
558*55efc227SAndreas Gohr        $dates['TimeStr'] = date("Y-m-d H:i:s", $earliestTime);
559*55efc227SAndreas Gohr        $dates['EarliestTime'] = $earliestTime;
560*55efc227SAndreas Gohr        $dates['EarliestTimeSource'] = $earliestTimeSource;
561*55efc227SAndreas Gohr        $dates['EarliestTimeStr'] = date("Y-m-d H:i:s", $earliestTime);
562*55efc227SAndreas Gohr        $dates['LatestTime'] = $latestTime;
563*55efc227SAndreas Gohr        $dates['LatestTimeSource'] = $latestTimeSource;
564*55efc227SAndreas Gohr        $dates['LatestTimeStr'] = date("Y-m-d H:i:s", $latestTime);
565*55efc227SAndreas Gohr
566*55efc227SAndreas Gohr        return $dates;
567*55efc227SAndreas Gohr    }
568*55efc227SAndreas Gohr
569*55efc227SAndreas Gohr    /**
570*55efc227SAndreas Gohr     * Get the image width, tries various fields
571*55efc227SAndreas Gohr     *
572*55efc227SAndreas Gohr     * @author Sebastian Delmont <sdelmont@zonageek.com>
573*55efc227SAndreas Gohr     */
574*55efc227SAndreas Gohr    function getWidth()
575*55efc227SAndreas Gohr    {
576*55efc227SAndreas Gohr        if (!isset($this->_info['sof'])) {
577*55efc227SAndreas Gohr            $this->_parseMarkerSOF();
578*55efc227SAndreas Gohr        }
579*55efc227SAndreas Gohr
580*55efc227SAndreas Gohr        if ($this->_markers == null) {
581*55efc227SAndreas Gohr            return false;
582*55efc227SAndreas Gohr        }
583*55efc227SAndreas Gohr
584*55efc227SAndreas Gohr        if (isset($this->_info['sof']['ImageWidth'])) {
585*55efc227SAndreas Gohr            return $this->_info['sof']['ImageWidth'];
586*55efc227SAndreas Gohr        }
587*55efc227SAndreas Gohr
588*55efc227SAndreas Gohr        if (!isset($this->_info['exif'])) {
589*55efc227SAndreas Gohr            $this->_parseMarkerExif();
590*55efc227SAndreas Gohr        }
591*55efc227SAndreas Gohr
592*55efc227SAndreas Gohr        if (isset($this->_info['exif']['PixelXDimension'])) {
593*55efc227SAndreas Gohr            return $this->_info['exif']['PixelXDimension'];
594*55efc227SAndreas Gohr        }
595*55efc227SAndreas Gohr
596*55efc227SAndreas Gohr        return false;
597*55efc227SAndreas Gohr    }
598*55efc227SAndreas Gohr
599*55efc227SAndreas Gohr    /**
600*55efc227SAndreas Gohr     * Get the image height, tries various fields
601*55efc227SAndreas Gohr     *
602*55efc227SAndreas Gohr     * @author Sebastian Delmont <sdelmont@zonageek.com>
603*55efc227SAndreas Gohr     */
604*55efc227SAndreas Gohr    function getHeight()
605*55efc227SAndreas Gohr    {
606*55efc227SAndreas Gohr        if (!isset($this->_info['sof'])) {
607*55efc227SAndreas Gohr            $this->_parseMarkerSOF();
608*55efc227SAndreas Gohr        }
609*55efc227SAndreas Gohr
610*55efc227SAndreas Gohr        if ($this->_markers == null) {
611*55efc227SAndreas Gohr            return false;
612*55efc227SAndreas Gohr        }
613*55efc227SAndreas Gohr
614*55efc227SAndreas Gohr        if (isset($this->_info['sof']['ImageHeight'])) {
615*55efc227SAndreas Gohr            return $this->_info['sof']['ImageHeight'];
616*55efc227SAndreas Gohr        }
617*55efc227SAndreas Gohr
618*55efc227SAndreas Gohr        if (!isset($this->_info['exif'])) {
619*55efc227SAndreas Gohr            $this->_parseMarkerExif();
620*55efc227SAndreas Gohr        }
621*55efc227SAndreas Gohr
622*55efc227SAndreas Gohr        if (isset($this->_info['exif']['PixelYDimension'])) {
623*55efc227SAndreas Gohr            return $this->_info['exif']['PixelYDimension'];
624*55efc227SAndreas Gohr        }
625*55efc227SAndreas Gohr
626*55efc227SAndreas Gohr        return false;
627*55efc227SAndreas Gohr    }
628*55efc227SAndreas Gohr
629*55efc227SAndreas Gohr    /**
630*55efc227SAndreas Gohr     * Get an dimension string for use in img tag
631*55efc227SAndreas Gohr     *
632*55efc227SAndreas Gohr     * @author Sebastian Delmont <sdelmont@zonageek.com>
633*55efc227SAndreas Gohr     */
634*55efc227SAndreas Gohr    function getDimStr()
635*55efc227SAndreas Gohr    {
636*55efc227SAndreas Gohr        if ($this->_markers == null) {
637*55efc227SAndreas Gohr            return false;
638*55efc227SAndreas Gohr        }
639*55efc227SAndreas Gohr
640*55efc227SAndreas Gohr        $w = $this->getWidth();
641*55efc227SAndreas Gohr        $h = $this->getHeight();
642*55efc227SAndreas Gohr
643*55efc227SAndreas Gohr        return "width='" . $w . "' height='" . $h . "'";
644*55efc227SAndreas Gohr    }
645*55efc227SAndreas Gohr
646*55efc227SAndreas Gohr    /**
647*55efc227SAndreas Gohr     * Checks for an embedded thumbnail
648*55efc227SAndreas Gohr     *
649*55efc227SAndreas Gohr     * @author Sebastian Delmont <sdelmont@zonageek.com>
650*55efc227SAndreas Gohr     */
651*55efc227SAndreas Gohr    function hasThumbnail($which = 'any')
652*55efc227SAndreas Gohr    {
653*55efc227SAndreas Gohr        if (($which == 'any') || ($which == 'exif')) {
654*55efc227SAndreas Gohr            if (!isset($this->_info['exif'])) {
655*55efc227SAndreas Gohr                $this->_parseMarkerExif();
656*55efc227SAndreas Gohr            }
657*55efc227SAndreas Gohr
658*55efc227SAndreas Gohr            if ($this->_markers == null) {
659*55efc227SAndreas Gohr                return false;
660*55efc227SAndreas Gohr            }
661*55efc227SAndreas Gohr
662*55efc227SAndreas Gohr            if (isset($this->_info['exif']) && is_array($this->_info['exif'])) {
663*55efc227SAndreas Gohr                if (isset($this->_info['exif']['JFIFThumbnail'])) {
664*55efc227SAndreas Gohr                    return 'exif';
665*55efc227SAndreas Gohr                }
666*55efc227SAndreas Gohr            }
667*55efc227SAndreas Gohr        }
668*55efc227SAndreas Gohr
669*55efc227SAndreas Gohr        if ($which == 'adobe') {
670*55efc227SAndreas Gohr            if (!isset($this->_info['adobe'])) {
671*55efc227SAndreas Gohr                $this->_parseMarkerAdobe();
672*55efc227SAndreas Gohr            }
673*55efc227SAndreas Gohr
674*55efc227SAndreas Gohr            if ($this->_markers == null) {
675*55efc227SAndreas Gohr                return false;
676*55efc227SAndreas Gohr            }
677*55efc227SAndreas Gohr
678*55efc227SAndreas Gohr            if (isset($this->_info['adobe']) && is_array($this->_info['adobe'])) {
679*55efc227SAndreas Gohr                if (isset($this->_info['adobe']['ThumbnailData'])) {
680*55efc227SAndreas Gohr                    return 'exif';
681*55efc227SAndreas Gohr                }
682*55efc227SAndreas Gohr            }
683*55efc227SAndreas Gohr        }
684*55efc227SAndreas Gohr
685*55efc227SAndreas Gohr        return false;
686*55efc227SAndreas Gohr    }
687*55efc227SAndreas Gohr
688*55efc227SAndreas Gohr    /**
689*55efc227SAndreas Gohr     * Send embedded thumbnail to browser
690*55efc227SAndreas Gohr     *
691*55efc227SAndreas Gohr     * @author Sebastian Delmont <sdelmont@zonageek.com>
692*55efc227SAndreas Gohr     */
693*55efc227SAndreas Gohr    function sendThumbnail($which = 'any')
694*55efc227SAndreas Gohr    {
695*55efc227SAndreas Gohr        $data = null;
696*55efc227SAndreas Gohr
697*55efc227SAndreas Gohr        if (($which == 'any') || ($which == 'exif')) {
698*55efc227SAndreas Gohr            if (!isset($this->_info['exif'])) {
699*55efc227SAndreas Gohr                $this->_parseMarkerExif();
700*55efc227SAndreas Gohr            }
701*55efc227SAndreas Gohr
702*55efc227SAndreas Gohr            if ($this->_markers == null) {
703*55efc227SAndreas Gohr                return false;
704*55efc227SAndreas Gohr            }
705*55efc227SAndreas Gohr
706*55efc227SAndreas Gohr            if (isset($this->_info['exif']) && is_array($this->_info['exif'])) {
707*55efc227SAndreas Gohr                if (isset($this->_info['exif']['JFIFThumbnail'])) {
708*55efc227SAndreas Gohr                    $data =& $this->_info['exif']['JFIFThumbnail'];
709*55efc227SAndreas Gohr                }
710*55efc227SAndreas Gohr            }
711*55efc227SAndreas Gohr        }
712*55efc227SAndreas Gohr
713*55efc227SAndreas Gohr        if (($which == 'adobe') || ($data == null)){
714*55efc227SAndreas Gohr            if (!isset($this->_info['adobe'])) {
715*55efc227SAndreas Gohr                $this->_parseMarkerAdobe();
716*55efc227SAndreas Gohr            }
717*55efc227SAndreas Gohr
718*55efc227SAndreas Gohr            if ($this->_markers == null) {
719*55efc227SAndreas Gohr                return false;
720*55efc227SAndreas Gohr            }
721*55efc227SAndreas Gohr
722*55efc227SAndreas Gohr            if (isset($this->_info['adobe']) && is_array($this->_info['adobe'])) {
723*55efc227SAndreas Gohr                if (isset($this->_info['adobe']['ThumbnailData'])) {
724*55efc227SAndreas Gohr                    $data =& $this->_info['adobe']['ThumbnailData'];
725*55efc227SAndreas Gohr                }
726*55efc227SAndreas Gohr            }
727*55efc227SAndreas Gohr        }
728*55efc227SAndreas Gohr
729*55efc227SAndreas Gohr        if ($data != null) {
730*55efc227SAndreas Gohr            header("Content-type: image/jpeg");
731*55efc227SAndreas Gohr            echo $data;
732*55efc227SAndreas Gohr            return true;
733*55efc227SAndreas Gohr        }
734*55efc227SAndreas Gohr
735*55efc227SAndreas Gohr        return false;
736*55efc227SAndreas Gohr    }
737*55efc227SAndreas Gohr
738*55efc227SAndreas Gohr    /**
739*55efc227SAndreas Gohr     * Save changed Metadata
740*55efc227SAndreas Gohr     *
741*55efc227SAndreas Gohr     * @author Sebastian Delmont <sdelmont@zonageek.com>
742*55efc227SAndreas Gohr     */
743*55efc227SAndreas Gohr    function save($fileName = "") {
744*55efc227SAndreas Gohr      if ($fileName == "") {
745*55efc227SAndreas Gohr        $tmpName = $this->_fileName . ".tmp";
746*55efc227SAndreas Gohr        $this->_writeJPEG($tmpName);
747*55efc227SAndreas Gohr        if (file_exists($tmpName)) {
748*55efc227SAndreas Gohr          rename($tmpName, $this->_fileName);
749*55efc227SAndreas Gohr        }
750*55efc227SAndreas Gohr      }
751*55efc227SAndreas Gohr      else {
752*55efc227SAndreas Gohr        $this->_writeJPEG($fileName);
753*55efc227SAndreas Gohr      }
754*55efc227SAndreas Gohr    }
755*55efc227SAndreas Gohr
756*55efc227SAndreas Gohr    /*************************************************************/
757*55efc227SAndreas Gohr    /* PRIVATE FUNCTIONS (Internal Use Only!)                    */
758*55efc227SAndreas Gohr    /*************************************************************/
759*55efc227SAndreas Gohr
760*55efc227SAndreas Gohr    /*************************************************************/
761*55efc227SAndreas Gohr    function _dispose()
762*55efc227SAndreas Gohr    {
763*55efc227SAndreas Gohr        $this->_fileName = $fileName;
764*55efc227SAndreas Gohr
765*55efc227SAndreas Gohr        $this->_fp = null;
766*55efc227SAndreas Gohr        $this->_type = 'unknown';
767*55efc227SAndreas Gohr
768*55efc227SAndreas Gohr        unset($this->_markers);
769*55efc227SAndreas Gohr        unset($this->_info);
770*55efc227SAndreas Gohr    }
771*55efc227SAndreas Gohr
772*55efc227SAndreas Gohr    /*************************************************************/
773*55efc227SAndreas Gohr    function _readJPEG()
774*55efc227SAndreas Gohr    {
775*55efc227SAndreas Gohr        unset($this->_markers);
776*55efc227SAndreas Gohr        unset($this->_info);
777*55efc227SAndreas Gohr        $this->_markers = array();
778*55efc227SAndreas Gohr        $this->_info = array();
779*55efc227SAndreas Gohr
780*55efc227SAndreas Gohr        $this->_fp = @fopen($this->_fileName, 'rb');
781*55efc227SAndreas Gohr        if ($this->_fp) {
782*55efc227SAndreas Gohr            if (file_exists($this->_fileName)) {
783*55efc227SAndreas Gohr                $this->_type = 'file';
784*55efc227SAndreas Gohr            }
785*55efc227SAndreas Gohr            else {
786*55efc227SAndreas Gohr                $this->_type = 'url';
787*55efc227SAndreas Gohr            }
788*55efc227SAndreas Gohr        }
789*55efc227SAndreas Gohr        else {
790*55efc227SAndreas Gohr            $this->_fp = null;
791*55efc227SAndreas Gohr            return false;  // ERROR: Can't open file
792*55efc227SAndreas Gohr        }
793*55efc227SAndreas Gohr
794*55efc227SAndreas Gohr        // Check for the JPEG signature
795*55efc227SAndreas Gohr        $c1 = ord(fgetc($this->_fp));
796*55efc227SAndreas Gohr        $c2 = ord(fgetc($this->_fp));
797*55efc227SAndreas Gohr
798*55efc227SAndreas Gohr        if ($c1 != 0xFF || $c2 != 0xD8) {   // (0xFF + SOI)
799*55efc227SAndreas Gohr            $this->_markers = null;
800*55efc227SAndreas Gohr            return false;  // ERROR: File is not a JPEG
801*55efc227SAndreas Gohr        }
802*55efc227SAndreas Gohr
803*55efc227SAndreas Gohr        $count = 0;
804*55efc227SAndreas Gohr
805*55efc227SAndreas Gohr        $done = false;
806*55efc227SAndreas Gohr        $ok = true;
807*55efc227SAndreas Gohr
808*55efc227SAndreas Gohr        while (!$done) {
809*55efc227SAndreas Gohr            $capture = false;
810*55efc227SAndreas Gohr
811*55efc227SAndreas Gohr          // First, skip any non 0xFF bytes
812*55efc227SAndreas Gohr            $discarded = 0;
813*55efc227SAndreas Gohr            $c = ord(fgetc($this->_fp));
814*55efc227SAndreas Gohr            while (!feof($this->_fp) && ($c != 0xFF)) {
815*55efc227SAndreas Gohr                $discarded++;
816*55efc227SAndreas Gohr                $c = ord(fgetc($this->_fp));
817*55efc227SAndreas Gohr            }
818*55efc227SAndreas Gohr          // Then skip all 0xFF until the marker byte
819*55efc227SAndreas Gohr            do {
820*55efc227SAndreas Gohr                $marker = ord(fgetc($this->_fp));
821*55efc227SAndreas Gohr            } while (!feof($this->_fp) && ($marker == 0xFF));
822*55efc227SAndreas Gohr
823*55efc227SAndreas Gohr            if (feof($this->_fp)) {
824*55efc227SAndreas Gohr                return false; // ERROR: Unexpected EOF
825*55efc227SAndreas Gohr            }
826*55efc227SAndreas Gohr            if ($discarded != 0) {
827*55efc227SAndreas Gohr                return false; // ERROR: Extraneous data
828*55efc227SAndreas Gohr            }
829*55efc227SAndreas Gohr
830*55efc227SAndreas Gohr            $length = ord(fgetc($this->_fp)) * 256 + ord(fgetc($this->_fp));
831*55efc227SAndreas Gohr            if (feof($this->_fp)) {
832*55efc227SAndreas Gohr                return false; // ERROR: Unexpected EOF
833*55efc227SAndreas Gohr            }
834*55efc227SAndreas Gohr            if ($length < 2) {
835*55efc227SAndreas Gohr                return false; // ERROR: Extraneous data
836*55efc227SAndreas Gohr            }
837*55efc227SAndreas Gohr            $length = $length - 2; // The length we got counts itself
838*55efc227SAndreas Gohr
839*55efc227SAndreas Gohr            switch ($marker) {
840*55efc227SAndreas Gohr            case 0xC0:    // SOF0
841*55efc227SAndreas Gohr            case 0xC1:    // SOF1
842*55efc227SAndreas Gohr            case 0xC2:    // SOF2
843*55efc227SAndreas Gohr            case 0xC9:    // SOF9
844*55efc227SAndreas Gohr            case 0xE0:    // APP0: JFIF data
845*55efc227SAndreas Gohr            case 0xE1:    // APP1: EXIF data
846*55efc227SAndreas Gohr            case 0xED:    // APP13: IPTC / Photoshop data
847*55efc227SAndreas Gohr                $capture = true;
848*55efc227SAndreas Gohr                break;
849*55efc227SAndreas Gohr            case 0xDA:    // SOS: Start of scan... the image itself and the last block on the file
850*55efc227SAndreas Gohr                $capture = false;
851*55efc227SAndreas Gohr                $length = -1;  // This field has no length... it includes all data until EOF
852*55efc227SAndreas Gohr                $done = true;
853*55efc227SAndreas Gohr                break;
854*55efc227SAndreas Gohr            default:
855*55efc227SAndreas Gohr                $capture = true;//false;
856*55efc227SAndreas Gohr                break;
857*55efc227SAndreas Gohr            }
858*55efc227SAndreas Gohr
859*55efc227SAndreas Gohr            $this->_markers[$count] = array();
860*55efc227SAndreas Gohr            $this->_markers[$count]['marker'] = $marker;
861*55efc227SAndreas Gohr            $this->_markers[$count]['length'] = $length;
862*55efc227SAndreas Gohr
863*55efc227SAndreas Gohr            if ($capture) {
864*55efc227SAndreas Gohr                $this->_markers[$count]['data'] =& fread($this->_fp, $length);
865*55efc227SAndreas Gohr            }
866*55efc227SAndreas Gohr            elseif (!$done) {
867*55efc227SAndreas Gohr                $result = @fseek($this->_fp, $length, SEEK_CUR);
868*55efc227SAndreas Gohr              // fseek doesn't seem to like HTTP 'files', but fgetc has no problem
869*55efc227SAndreas Gohr                if (!($result === 0)) {
870*55efc227SAndreas Gohr                    for ($i = 0; $i < $length; $i++) {
871*55efc227SAndreas Gohr                        fgetc($this->_fp);
872*55efc227SAndreas Gohr                    }
873*55efc227SAndreas Gohr                }
874*55efc227SAndreas Gohr            }
875*55efc227SAndreas Gohr            $count++;
876*55efc227SAndreas Gohr        }
877*55efc227SAndreas Gohr
878*55efc227SAndreas Gohr        if ($this->_fp) {
879*55efc227SAndreas Gohr            fclose($this->_fp);
880*55efc227SAndreas Gohr            $this->_fp = null;
881*55efc227SAndreas Gohr        }
882*55efc227SAndreas Gohr
883*55efc227SAndreas Gohr        return $ok;
884*55efc227SAndreas Gohr    }
885*55efc227SAndreas Gohr
886*55efc227SAndreas Gohr    /*************************************************************/
887*55efc227SAndreas Gohr    function _parseAll()
888*55efc227SAndreas Gohr    {
889*55efc227SAndreas Gohr        if (!isset($this->_markers)) {
890*55efc227SAndreas Gohr            $this->_readJPEG();
891*55efc227SAndreas Gohr        }
892*55efc227SAndreas Gohr
893*55efc227SAndreas Gohr        if ($this->_markers == null) {
894*55efc227SAndreas Gohr            return false;
895*55efc227SAndreas Gohr        }
896*55efc227SAndreas Gohr
897*55efc227SAndreas Gohr        if (!isset($this->_info['jfif'])) {
898*55efc227SAndreas Gohr            $this->_parseMarkerJFIF();
899*55efc227SAndreas Gohr        }
900*55efc227SAndreas Gohr        if (!isset($this->_info['jpeg'])) {
901*55efc227SAndreas Gohr            $this->_parseMarkerSOF();
902*55efc227SAndreas Gohr        }
903*55efc227SAndreas Gohr        if (!isset($this->_info['exif'])) {
904*55efc227SAndreas Gohr            $this->_parseMarkerExif();
905*55efc227SAndreas Gohr        }
906*55efc227SAndreas Gohr        if (!isset($this->_info['adobe'])) {
907*55efc227SAndreas Gohr            $this->_parseMarkerAdobe();
908*55efc227SAndreas Gohr        }
909*55efc227SAndreas Gohr        if (!isset($this->_info['file'])) {
910*55efc227SAndreas Gohr            $this->_parseFileInfo();
911*55efc227SAndreas Gohr        }
912*55efc227SAndreas Gohr    }
913*55efc227SAndreas Gohr
914*55efc227SAndreas Gohr    /*************************************************************/
915*55efc227SAndreas Gohr    function _writeJPEG($outputName)
916*55efc227SAndreas Gohr    {
917*55efc227SAndreas Gohr        $this->_parseAll();
918*55efc227SAndreas Gohr
919*55efc227SAndreas Gohr        $wroteEXIF = false;
920*55efc227SAndreas Gohr        $wroteAdobe = false;
921*55efc227SAndreas Gohr
922*55efc227SAndreas Gohr        $this->_fp = @fopen($this->_fileName, 'r');
923*55efc227SAndreas Gohr        if ($this->_fp) {
924*55efc227SAndreas Gohr            if (file_exists($this->_fileName)) {
925*55efc227SAndreas Gohr                $this->_type = 'file';
926*55efc227SAndreas Gohr            }
927*55efc227SAndreas Gohr            else {
928*55efc227SAndreas Gohr                $this->_type = 'url';
929*55efc227SAndreas Gohr            }
930*55efc227SAndreas Gohr        }
931*55efc227SAndreas Gohr        else {
932*55efc227SAndreas Gohr            $this->_fp = null;
933*55efc227SAndreas Gohr            return false;  // ERROR: Can't open file
934*55efc227SAndreas Gohr        }
935*55efc227SAndreas Gohr
936*55efc227SAndreas Gohr        $this->_fpout = fopen($outputName, 'wb');
937*55efc227SAndreas Gohr        if ($this->_fpout) {
938*55efc227SAndreas Gohr        }
939*55efc227SAndreas Gohr        else {
940*55efc227SAndreas Gohr            $this->_fpout = null;
941*55efc227SAndreas Gohr            fclose($this->_fp);
942*55efc227SAndreas Gohr            $this->_fp = null;
943*55efc227SAndreas Gohr            return false;  // ERROR: Can't open output file
944*55efc227SAndreas Gohr        }
945*55efc227SAndreas Gohr
946*55efc227SAndreas Gohr        // Check for the JPEG signature
947*55efc227SAndreas Gohr        $c1 = ord(fgetc($this->_fp));
948*55efc227SAndreas Gohr        $c2 = ord(fgetc($this->_fp));
949*55efc227SAndreas Gohr
950*55efc227SAndreas Gohr        if ($c1 != 0xFF || $c2 != 0xD8) {   // (0xFF + SOI)
951*55efc227SAndreas Gohr            return false;  // ERROR: File is not a JPEG
952*55efc227SAndreas Gohr        }
953*55efc227SAndreas Gohr
954*55efc227SAndreas Gohr        fputs($this->_fpout, chr(0xFF), 1);
955*55efc227SAndreas Gohr        fputs($this->_fpout, chr(0xD8), 1); // (0xFF + SOI)
956*55efc227SAndreas Gohr
957*55efc227SAndreas Gohr        $count = 0;
958*55efc227SAndreas Gohr
959*55efc227SAndreas Gohr        $done = false;
960*55efc227SAndreas Gohr        $ok = true;
961*55efc227SAndreas Gohr
962*55efc227SAndreas Gohr        while (!$done) {
963*55efc227SAndreas Gohr          // First, skip any non 0xFF bytes
964*55efc227SAndreas Gohr            $discarded = 0;
965*55efc227SAndreas Gohr            $c = ord(fgetc($this->_fp));
966*55efc227SAndreas Gohr            while (!feof($this->_fp) && ($c != 0xFF)) {
967*55efc227SAndreas Gohr                $discarded++;
968*55efc227SAndreas Gohr                $c = ord(fgetc($this->_fp));
969*55efc227SAndreas Gohr            }
970*55efc227SAndreas Gohr          // Then skip all 0xFF until the marker byte
971*55efc227SAndreas Gohr            do {
972*55efc227SAndreas Gohr                $marker = ord(fgetc($this->_fp));
973*55efc227SAndreas Gohr            } while (!feof($this->_fp) && ($marker == 0xFF));
974*55efc227SAndreas Gohr
975*55efc227SAndreas Gohr            if (feof($this->_fp)) {
976*55efc227SAndreas Gohr                $ok = false;
977*55efc227SAndreas Gohr                break; // ERROR: Unexpected EOF
978*55efc227SAndreas Gohr            }
979*55efc227SAndreas Gohr            if ($discarded != 0) {
980*55efc227SAndreas Gohr                $ok = false;
981*55efc227SAndreas Gohr                break; // ERROR: Extraneous data
982*55efc227SAndreas Gohr            }
983*55efc227SAndreas Gohr
984*55efc227SAndreas Gohr            $length = ord(fgetc($this->_fp)) * 256 + ord(fgetc($this->_fp));
985*55efc227SAndreas Gohr            if (feof($this->_fp)) {
986*55efc227SAndreas Gohr                $ok = false;
987*55efc227SAndreas Gohr                break; // ERROR: Unexpected EOF
988*55efc227SAndreas Gohr            }
989*55efc227SAndreas Gohr            if ($length < 2) {
990*55efc227SAndreas Gohr                $ok = false;
991*55efc227SAndreas Gohr                break; // ERROR: Extraneous data
992*55efc227SAndreas Gohr            }
993*55efc227SAndreas Gohr            $length = $length - 2; // The length we got counts itself
994*55efc227SAndreas Gohr
995*55efc227SAndreas Gohr            unset($data);
996*55efc227SAndreas Gohr            if ($marker == 0xE1) { // APP1: EXIF data
997*55efc227SAndreas Gohr                $data =& $this->_createMarkerEXIF();
998*55efc227SAndreas Gohr                $wroteEXIF = true;
999*55efc227SAndreas Gohr            }
1000*55efc227SAndreas Gohr            elseif ($marker == 0xED) { // APP13: IPTC / Photoshop data
1001*55efc227SAndreas Gohr                $data =& $this->_createMarkerAdobe();
1002*55efc227SAndreas Gohr                $wroteAdobe = true;
1003*55efc227SAndreas Gohr            }
1004*55efc227SAndreas Gohr            elseif ($marker == 0xDA) { // SOS: Start of scan... the image itself and the last block on the file
1005*55efc227SAndreas Gohr                $done = true;
1006*55efc227SAndreas Gohr            }
1007*55efc227SAndreas Gohr
1008*55efc227SAndreas Gohr            if (!$wroteEXIF && (($marker < 0xE0) || ($marker > 0xEF))) {
1009*55efc227SAndreas Gohr                if (isset($this->_info['exif']) && is_array($this->_info['exif'])) {
1010*55efc227SAndreas Gohr                    $exif =& $this->_createMarkerEXIF();
1011*55efc227SAndreas Gohr                    $this->_writeJPEGMarker(0xE1, strlen($exif), $exif, 0);
1012*55efc227SAndreas Gohr                    unset($exif);
1013*55efc227SAndreas Gohr                }
1014*55efc227SAndreas Gohr                $wroteEXIF = true;
1015*55efc227SAndreas Gohr            }
1016*55efc227SAndreas Gohr
1017*55efc227SAndreas Gohr            if (!$wroteAdobe && (($marker < 0xE0) || ($marker > 0xEF))) {
1018*55efc227SAndreas Gohr                if ((isset($this->_info['adobe']) && is_array($this->_info['adobe']))
1019*55efc227SAndreas Gohr                || (isset($this->_info['iptc']) && is_array($this->_info['iptc']))) {
1020*55efc227SAndreas Gohr                    $adobe =& $this->_createMarkerAdobe();
1021*55efc227SAndreas Gohr                    $this->_writeJPEGMarker(0xED, strlen($adobe), $adobe, 0);
1022*55efc227SAndreas Gohr                    unset($adobe);
1023*55efc227SAndreas Gohr                }
1024*55efc227SAndreas Gohr                $wroteAdobe = true;
1025*55efc227SAndreas Gohr            }
1026*55efc227SAndreas Gohr
1027*55efc227SAndreas Gohr            $origLength = $length;
1028*55efc227SAndreas Gohr            if (isset($data)) {
1029*55efc227SAndreas Gohr                $length = strlen($data);
1030*55efc227SAndreas Gohr            }
1031*55efc227SAndreas Gohr
1032*55efc227SAndreas Gohr            if ($marker != -1) {
1033*55efc227SAndreas Gohr                $this->_writeJPEGMarker($marker, $length, $data, $origLength);
1034*55efc227SAndreas Gohr            }
1035*55efc227SAndreas Gohr        }
1036*55efc227SAndreas Gohr
1037*55efc227SAndreas Gohr        if ($this->_fp) {
1038*55efc227SAndreas Gohr            fclose($this->_fp);
1039*55efc227SAndreas Gohr            $this->_fp = null;
1040*55efc227SAndreas Gohr        }
1041*55efc227SAndreas Gohr
1042*55efc227SAndreas Gohr        if ($this->_fpout) {
1043*55efc227SAndreas Gohr            fclose($this->_fpout);
1044*55efc227SAndreas Gohr            $this->_fpout = null;
1045*55efc227SAndreas Gohr        }
1046*55efc227SAndreas Gohr
1047*55efc227SAndreas Gohr        return $ok;
1048*55efc227SAndreas Gohr    }
1049*55efc227SAndreas Gohr
1050*55efc227SAndreas Gohr    /*************************************************************/
1051*55efc227SAndreas Gohr    function _writeJPEGMarker($marker, $length, &$data, $origLength)
1052*55efc227SAndreas Gohr    {
1053*55efc227SAndreas Gohr        if ($length <= 0) {
1054*55efc227SAndreas Gohr            return false;
1055*55efc227SAndreas Gohr        }
1056*55efc227SAndreas Gohr
1057*55efc227SAndreas Gohr        fputs($this->_fpout, chr(0xFF), 1);
1058*55efc227SAndreas Gohr        fputs($this->_fpout, chr($marker), 1);
1059*55efc227SAndreas Gohr        fputs($this->_fpout, chr((($length + 2) & 0x0000FF00) >> 8), 1);
1060*55efc227SAndreas Gohr        fputs($this->_fpout, chr((($length + 2) & 0x000000FF) >> 0), 1);
1061*55efc227SAndreas Gohr
1062*55efc227SAndreas Gohr        if (isset($data)) {
1063*55efc227SAndreas Gohr            // Copy the generated data
1064*55efc227SAndreas Gohr            fputs($this->_fpout, $data, $length);
1065*55efc227SAndreas Gohr
1066*55efc227SAndreas Gohr            if ($origLength > 0) {   // Skip the original data
1067*55efc227SAndreas Gohr                $result = @fseek($this->_fp, $origLength, SEEK_CUR);
1068*55efc227SAndreas Gohr                // fseek doesn't seem to like HTTP 'files', but fgetc has no problem
1069*55efc227SAndreas Gohr                if ($result != 0) {
1070*55efc227SAndreas Gohr                    for ($i = 0; $i < $origLength; $i++) {
1071*55efc227SAndreas Gohr                        fgetc($this->_fp);
1072*55efc227SAndreas Gohr                    }
1073*55efc227SAndreas Gohr                }
1074*55efc227SAndreas Gohr            }
1075*55efc227SAndreas Gohr        }
1076*55efc227SAndreas Gohr        else {
1077*55efc227SAndreas Gohr            if ($marker == 0xDA) {  // Copy until EOF
1078*55efc227SAndreas Gohr                while (!feof($this->_fp)) {
1079*55efc227SAndreas Gohr                    $data =& fread($this->_fp, 1024 * 16);
1080*55efc227SAndreas Gohr                    fputs($this->_fpout, $data, strlen($data));
1081*55efc227SAndreas Gohr                }
1082*55efc227SAndreas Gohr            }
1083*55efc227SAndreas Gohr            else { // Copy only $length bytes
1084*55efc227SAndreas Gohr                $data =& fread($this->_fp, $length);
1085*55efc227SAndreas Gohr                fputs($this->_fpout, $data, $length);
1086*55efc227SAndreas Gohr            }
1087*55efc227SAndreas Gohr        }
1088*55efc227SAndreas Gohr
1089*55efc227SAndreas Gohr        return true;
1090*55efc227SAndreas Gohr    }
1091*55efc227SAndreas Gohr
1092*55efc227SAndreas Gohr    /*************************************************************/
1093*55efc227SAndreas Gohr    function _parseFileInfo()
1094*55efc227SAndreas Gohr    {
1095*55efc227SAndreas Gohr        if (file_exists($this->_fileName)) {
1096*55efc227SAndreas Gohr            $this->_info['file'] = array();
1097*55efc227SAndreas Gohr            $this->_info['file']['Name'] = basename($this->_fileName);
1098*55efc227SAndreas Gohr            $this->_info['file']['Size'] = filesize($this->_fileName);
1099*55efc227SAndreas Gohr            if ($this->_info['file']['Size'] < 1024) {
1100*55efc227SAndreas Gohr                $this->_info['file']['NiceSize'] = $this->_info['file']['Size'] . 'B';
1101*55efc227SAndreas Gohr            }
1102*55efc227SAndreas Gohr            elseif ($this->_info['file']['Size'] < (1024 * 1024)) {
1103*55efc227SAndreas Gohr                $this->_info['file']['NiceSize'] = round($this->_info['file']['Size'] / 1024) . 'KB';
1104*55efc227SAndreas Gohr            }
1105*55efc227SAndreas Gohr            elseif ($this->_info['file']['Size'] < (1024 * 1024 * 1024)) {
1106*55efc227SAndreas Gohr                $this->_info['file']['NiceSize'] = round($this->_info['file']['Size'] / 1024) . 'MB';
1107*55efc227SAndreas Gohr            }
1108*55efc227SAndreas Gohr            else {
1109*55efc227SAndreas Gohr                $this->_info['file']['NiceSize'] = $this->_info['file']['Size'] . 'B';
1110*55efc227SAndreas Gohr            }
1111*55efc227SAndreas Gohr            $this->_info['file']['UnixTime'] = filemtime($this->_fileName);
1112*55efc227SAndreas Gohr
1113*55efc227SAndreas Gohr            // Andreas Gohr <andi@splitbrain.org>
1114*55efc227SAndreas Gohr            // get image size directly from file
1115*55efc227SAndreas Gohr            $size = getimagesize($this->_fileName);
1116*55efc227SAndreas Gohr            $this->_info['file']['Width']  = $size[0];
1117*55efc227SAndreas Gohr            $this->_info['file']['Height'] = $size[1];
1118*55efc227SAndreas Gohr            // set mime types and formats
1119*55efc227SAndreas Gohr            // http://www.php.net/manual/en/function.getimagesize.php
1120*55efc227SAndreas Gohr            // http://www.php.net/manual/en/function.image-type-to-mime-type.php
1121*55efc227SAndreas Gohr            switch ($size[2]){
1122*55efc227SAndreas Gohr                case 1:
1123*55efc227SAndreas Gohr                    $this->_info['file']['Mime']   = 'image/gif';
1124*55efc227SAndreas Gohr                    $this->_info['file']['Format'] = 'GIF';
1125*55efc227SAndreas Gohr                    break;
1126*55efc227SAndreas Gohr                case 2:
1127*55efc227SAndreas Gohr                    $this->_info['file']['Mime']   = 'image/jpeg';
1128*55efc227SAndreas Gohr                    $this->_info['file']['Format'] = 'JPEG';
1129*55efc227SAndreas Gohr                    break;
1130*55efc227SAndreas Gohr                case 3:
1131*55efc227SAndreas Gohr                    $this->_info['file']['Mime']   = 'image/png';
1132*55efc227SAndreas Gohr                    $this->_info['file']['Format'] = 'PNG';
1133*55efc227SAndreas Gohr                    break;
1134*55efc227SAndreas Gohr                case 4:
1135*55efc227SAndreas Gohr                    $this->_info['file']['Mime']   = 'application/x-shockwave-flash';
1136*55efc227SAndreas Gohr                    $this->_info['file']['Format'] = 'SWF';
1137*55efc227SAndreas Gohr                    break;
1138*55efc227SAndreas Gohr                case 5:
1139*55efc227SAndreas Gohr                    $this->_info['file']['Mime']   = 'image/psd';
1140*55efc227SAndreas Gohr                    $this->_info['file']['Format'] = 'PSD';
1141*55efc227SAndreas Gohr                    break;
1142*55efc227SAndreas Gohr                case 6:
1143*55efc227SAndreas Gohr                    $this->_info['file']['Mime']   = 'image/bmp';
1144*55efc227SAndreas Gohr                    $this->_info['file']['Format'] = 'BMP';
1145*55efc227SAndreas Gohr                    break;
1146*55efc227SAndreas Gohr                case 7:
1147*55efc227SAndreas Gohr                    $this->_info['file']['Mime']   = 'image/tiff';
1148*55efc227SAndreas Gohr                    $this->_info['file']['Format'] = 'TIFF (Intel)';
1149*55efc227SAndreas Gohr                    break;
1150*55efc227SAndreas Gohr                case 8:
1151*55efc227SAndreas Gohr                    $this->_info['file']['Mime']   = 'image/tiff';
1152*55efc227SAndreas Gohr                    $this->_info['file']['Format'] = 'TIFF (Motorola)';
1153*55efc227SAndreas Gohr                    break;
1154*55efc227SAndreas Gohr                case 9:
1155*55efc227SAndreas Gohr                    $this->_info['file']['Mime']   = 'application/octet-stream';
1156*55efc227SAndreas Gohr                    $this->_info['file']['Format'] = 'JPC';
1157*55efc227SAndreas Gohr                    break;
1158*55efc227SAndreas Gohr                case 10:
1159*55efc227SAndreas Gohr                    $this->_info['file']['Mime']   = 'image/jp2';
1160*55efc227SAndreas Gohr                    $this->_info['file']['Format'] = 'JP2';
1161*55efc227SAndreas Gohr                    break;
1162*55efc227SAndreas Gohr                case 11:
1163*55efc227SAndreas Gohr                    $this->_info['file']['Mime']   = 'application/octet-stream';
1164*55efc227SAndreas Gohr                    $this->_info['file']['Format'] = 'JPX';
1165*55efc227SAndreas Gohr                    break;
1166*55efc227SAndreas Gohr                case 12:
1167*55efc227SAndreas Gohr                    $this->_info['file']['Mime']   = 'application/octet-stream';
1168*55efc227SAndreas Gohr                    $this->_info['file']['Format'] = 'JB2';
1169*55efc227SAndreas Gohr                    break;
1170*55efc227SAndreas Gohr                case 13:
1171*55efc227SAndreas Gohr                    $this->_info['file']['Mime']   = 'application/x-shockwave-flash';
1172*55efc227SAndreas Gohr                    $this->_info['file']['Format'] = 'SWC';
1173*55efc227SAndreas Gohr                    break;
1174*55efc227SAndreas Gohr                case 14:
1175*55efc227SAndreas Gohr                    $this->_info['file']['Mime']   = 'image/iff';
1176*55efc227SAndreas Gohr                    $this->_info['file']['Format'] = 'IFF';
1177*55efc227SAndreas Gohr                    break;
1178*55efc227SAndreas Gohr                case 15:
1179*55efc227SAndreas Gohr                    $this->_info['file']['Mime']   = 'image/vnd.wap.wbmp';
1180*55efc227SAndreas Gohr                    $this->_info['file']['Format'] = 'WBMP';
1181*55efc227SAndreas Gohr                    break;
1182*55efc227SAndreas Gohr                case 16:
1183*55efc227SAndreas Gohr                    $this->_info['file']['Mime']   = 'image/xbm';
1184*55efc227SAndreas Gohr                    $this->_info['file']['Format'] = 'XBM';
1185*55efc227SAndreas Gohr                    break;
1186*55efc227SAndreas Gohr                default:
1187*55efc227SAndreas Gohr                    $this->_info['file']['Mime']   = 'image/unknown';
1188*55efc227SAndreas Gohr            }
1189*55efc227SAndreas Gohr        }
1190*55efc227SAndreas Gohr        else {
1191*55efc227SAndreas Gohr            $this->_info['file'] = array();
1192*55efc227SAndreas Gohr            $this->_info['file']['Name'] = basename($this->_fileName);
1193*55efc227SAndreas Gohr            $this->_info['file']['Url'] = $this->_fileName;
1194*55efc227SAndreas Gohr        }
1195*55efc227SAndreas Gohr
1196*55efc227SAndreas Gohr        return true;
1197*55efc227SAndreas Gohr    }
1198*55efc227SAndreas Gohr
1199*55efc227SAndreas Gohr    /*************************************************************/
1200*55efc227SAndreas Gohr    function _parseMarkerJFIF()
1201*55efc227SAndreas Gohr    {
1202*55efc227SAndreas Gohr        if (!isset($this->_markers)) {
1203*55efc227SAndreas Gohr            $this->_readJPEG();
1204*55efc227SAndreas Gohr        }
1205*55efc227SAndreas Gohr
1206*55efc227SAndreas Gohr        if ($this->_markers == null) {
1207*55efc227SAndreas Gohr            return false;
1208*55efc227SAndreas Gohr        }
1209*55efc227SAndreas Gohr
1210*55efc227SAndreas Gohr        $data = null;
1211*55efc227SAndreas Gohr        $count = count($this->_markers);
1212*55efc227SAndreas Gohr        for ($i = 0; $i < $count; $i++) {
1213*55efc227SAndreas Gohr            if ($this->_markers[$i]['marker'] == 0xE0) {
1214*55efc227SAndreas Gohr                $signature = $this->_getFixedString($this->_markers[$i]['data'], 0, 4);
1215*55efc227SAndreas Gohr                if ($signature == 'JFIF') {
1216*55efc227SAndreas Gohr                    $data =& $this->_markers[$i]['data'];
1217*55efc227SAndreas Gohr                    break;
1218*55efc227SAndreas Gohr                }
1219*55efc227SAndreas Gohr            }
1220*55efc227SAndreas Gohr        }
1221*55efc227SAndreas Gohr
1222*55efc227SAndreas Gohr        if ($data == null) {
1223*55efc227SAndreas Gohr            $this->_info['jfif'] = false;
1224*55efc227SAndreas Gohr            return false;
1225*55efc227SAndreas Gohr        }
1226*55efc227SAndreas Gohr
1227*55efc227SAndreas Gohr		$pos = 0;
1228*55efc227SAndreas Gohr        $this->_info['jfif'] = array();
1229*55efc227SAndreas Gohr
1230*55efc227SAndreas Gohr
1231*55efc227SAndreas Gohr        $vmaj = $this->_getByte($data, 5);
1232*55efc227SAndreas Gohr        $vmin = $this->_getByte($data, 6);
1233*55efc227SAndreas Gohr
1234*55efc227SAndreas Gohr        $this->_info['jfif']['Version'] = sprintf('%d.%02d', $vmaj, $vmin);
1235*55efc227SAndreas Gohr
1236*55efc227SAndreas Gohr        $units = $this->_getByte($data, 7);
1237*55efc227SAndreas Gohr        switch ($units) {
1238*55efc227SAndreas Gohr        case 0:
1239*55efc227SAndreas Gohr            $this->_info['jfif']['Units'] = 'pixels';
1240*55efc227SAndreas Gohr            break;
1241*55efc227SAndreas Gohr        case 1:
1242*55efc227SAndreas Gohr            $this->_info['jfif']['Units'] = 'dpi';
1243*55efc227SAndreas Gohr            break;
1244*55efc227SAndreas Gohr        case 2:
1245*55efc227SAndreas Gohr            $this->_info['jfif']['Units'] = 'dpcm';
1246*55efc227SAndreas Gohr            break;
1247*55efc227SAndreas Gohr        default:
1248*55efc227SAndreas Gohr            $this->_info['jfif']['Units'] = 'unknown';
1249*55efc227SAndreas Gohr            break;
1250*55efc227SAndreas Gohr        }
1251*55efc227SAndreas Gohr
1252*55efc227SAndreas Gohr        $xdens = $this->_getShort($data, 8);
1253*55efc227SAndreas Gohr        $ydens = $this->_getShort($data, 10);
1254*55efc227SAndreas Gohr
1255*55efc227SAndreas Gohr        $this->_info['jfif']['XDensity'] = $xdens;
1256*55efc227SAndreas Gohr        $this->_info['jfif']['YDensity'] = $ydens;
1257*55efc227SAndreas Gohr
1258*55efc227SAndreas Gohr        $thumbx = $this->_getByte($data, 12);
1259*55efc227SAndreas Gohr        $thumby = $this->_getByte($data, 13);
1260*55efc227SAndreas Gohr
1261*55efc227SAndreas Gohr        $this->_info['jfif']['ThumbnailWidth'] = $thumbx;
1262*55efc227SAndreas Gohr        $this->_info['jfif']['ThumbnailHeight'] = $thumby;
1263*55efc227SAndreas Gohr
1264*55efc227SAndreas Gohr        return true;
1265*55efc227SAndreas Gohr    }
1266*55efc227SAndreas Gohr
1267*55efc227SAndreas Gohr    /*************************************************************/
1268*55efc227SAndreas Gohr    function _parseMarkerSOF()
1269*55efc227SAndreas Gohr    {
1270*55efc227SAndreas Gohr        if (!isset($this->_markers)) {
1271*55efc227SAndreas Gohr            $this->_readJPEG();
1272*55efc227SAndreas Gohr        }
1273*55efc227SAndreas Gohr
1274*55efc227SAndreas Gohr        if ($this->_markers == null) {
1275*55efc227SAndreas Gohr            return false;
1276*55efc227SAndreas Gohr        }
1277*55efc227SAndreas Gohr
1278*55efc227SAndreas Gohr        $data = null;
1279*55efc227SAndreas Gohr        $count = count($this->_markers);
1280*55efc227SAndreas Gohr        for ($i = 0; $i < $count; $i++) {
1281*55efc227SAndreas Gohr            switch ($this->_markers[$i]['marker']) {
1282*55efc227SAndreas Gohr            case 0xC0: // SOF0
1283*55efc227SAndreas Gohr            case 0xC1: // SOF1
1284*55efc227SAndreas Gohr            case 0xC2: // SOF2
1285*55efc227SAndreas Gohr            case 0xC9: // SOF9
1286*55efc227SAndreas Gohr                $data =& $this->_markers[$i]['data'];
1287*55efc227SAndreas Gohr                $marker = $this->_markers[$i]['marker'];
1288*55efc227SAndreas Gohr                break;
1289*55efc227SAndreas Gohr            }
1290*55efc227SAndreas Gohr        }
1291*55efc227SAndreas Gohr
1292*55efc227SAndreas Gohr        if ($data == null) {
1293*55efc227SAndreas Gohr            $this->_info['sof'] = false;
1294*55efc227SAndreas Gohr            return false;
1295*55efc227SAndreas Gohr        }
1296*55efc227SAndreas Gohr
1297*55efc227SAndreas Gohr		$pos = 0;
1298*55efc227SAndreas Gohr        $this->_info['sof'] = array();
1299*55efc227SAndreas Gohr
1300*55efc227SAndreas Gohr
1301*55efc227SAndreas Gohr        switch ($marker) {
1302*55efc227SAndreas Gohr        case 0xC0: // SOF0
1303*55efc227SAndreas Gohr            $format = 'Baseline';
1304*55efc227SAndreas Gohr            break;
1305*55efc227SAndreas Gohr        case 0xC1: // SOF1
1306*55efc227SAndreas Gohr            $format = 'Progessive';
1307*55efc227SAndreas Gohr            break;
1308*55efc227SAndreas Gohr        case 0xC2: // SOF2
1309*55efc227SAndreas Gohr            $format = 'Non-baseline';
1310*55efc227SAndreas Gohr            break;
1311*55efc227SAndreas Gohr        case 0xC9: // SOF9
1312*55efc227SAndreas Gohr            $format = 'Arithmetic';
1313*55efc227SAndreas Gohr            break;
1314*55efc227SAndreas Gohr        default:
1315*55efc227SAndreas Gohr            return false;
1316*55efc227SAndreas Gohr            break;
1317*55efc227SAndreas Gohr        }
1318*55efc227SAndreas Gohr
1319*55efc227SAndreas Gohr
1320*55efc227SAndreas Gohr        $this->_info['sof']['Format'] = $format;
1321*55efc227SAndreas Gohr
1322*55efc227SAndreas Gohr        $this->_info['sof']['SamplePrecision'] = $this->_getByte($data, $pos + 0);
1323*55efc227SAndreas Gohr        $this->_info['sof']['ImageHeight'] = $this->_getShort($data, $pos + 1);
1324*55efc227SAndreas Gohr        $this->_info['sof']['ImageWidth'] = $this->_getShort($data, $pos + 3);
1325*55efc227SAndreas Gohr        $this->_info['sof']['ColorChannels'] = $this->_getByte($data, $pos + 5);
1326*55efc227SAndreas Gohr
1327*55efc227SAndreas Gohr        return true;
1328*55efc227SAndreas Gohr    }
1329*55efc227SAndreas Gohr
1330*55efc227SAndreas Gohr    /*************************************************************/
1331*55efc227SAndreas Gohr    function _parseMarkerExif()
1332*55efc227SAndreas Gohr    {
1333*55efc227SAndreas Gohr        if (!isset($this->_markers)) {
1334*55efc227SAndreas Gohr            $this->_readJPEG();
1335*55efc227SAndreas Gohr        }
1336*55efc227SAndreas Gohr
1337*55efc227SAndreas Gohr        if ($this->_markers == null) {
1338*55efc227SAndreas Gohr            return false;
1339*55efc227SAndreas Gohr        }
1340*55efc227SAndreas Gohr
1341*55efc227SAndreas Gohr        $data = null;
1342*55efc227SAndreas Gohr        $count = count($this->_markers);
1343*55efc227SAndreas Gohr        for ($i = 0; $i < $count; $i++) {
1344*55efc227SAndreas Gohr            if ($this->_markers[$i]['marker'] == 0xE1) {
1345*55efc227SAndreas Gohr                $signature = $this->_getFixedString($this->_markers[$i]['data'], 0, 6);
1346*55efc227SAndreas Gohr                if ($signature == "Exif\0\0") {
1347*55efc227SAndreas Gohr                    $data =& $this->_markers[$i]['data'];
1348*55efc227SAndreas Gohr                    break;
1349*55efc227SAndreas Gohr                }
1350*55efc227SAndreas Gohr            }
1351*55efc227SAndreas Gohr        }
1352*55efc227SAndreas Gohr
1353*55efc227SAndreas Gohr        if ($data == null) {
1354*55efc227SAndreas Gohr            $this->_info['exif'] = false;
1355*55efc227SAndreas Gohr            return false;
1356*55efc227SAndreas Gohr        }
1357*55efc227SAndreas Gohr        $pos = 6;
1358*55efc227SAndreas Gohr        $this->_info['exif'] = array();
1359*55efc227SAndreas Gohr
1360*55efc227SAndreas Gohr        // We don't increment $pos after this because Exif uses offsets relative to this point
1361*55efc227SAndreas Gohr
1362*55efc227SAndreas Gohr        $byteAlign = $this->_getShort($data, $pos + 0);
1363*55efc227SAndreas Gohr
1364*55efc227SAndreas Gohr        if ($byteAlign == 0x4949) { // "II"
1365*55efc227SAndreas Gohr            $isBigEndian = false;
1366*55efc227SAndreas Gohr        }
1367*55efc227SAndreas Gohr        elseif ($byteAlign == 0x4D4D) { // "MM"
1368*55efc227SAndreas Gohr            $isBigEndian = true;
1369*55efc227SAndreas Gohr        }
1370*55efc227SAndreas Gohr        else {
1371*55efc227SAndreas Gohr            return false; // Unexpected data
1372*55efc227SAndreas Gohr        }
1373*55efc227SAndreas Gohr
1374*55efc227SAndreas Gohr        $alignCheck = $this->_getShort($data, $pos + 2, $isBigEndian);
1375*55efc227SAndreas Gohr        if ($alignCheck != 0x002A) // That's the expected value
1376*55efc227SAndreas Gohr            return false; // Unexpected data
1377*55efc227SAndreas Gohr
1378*55efc227SAndreas Gohr        if ($isBigEndian) {
1379*55efc227SAndreas Gohr            $this->_info['exif']['ByteAlign'] = "Big Endian";
1380*55efc227SAndreas Gohr        }
1381*55efc227SAndreas Gohr        else {
1382*55efc227SAndreas Gohr            $this->_info['exif']['ByteAlign'] = "Little Endian";
1383*55efc227SAndreas Gohr        }
1384*55efc227SAndreas Gohr
1385*55efc227SAndreas Gohr        $offsetIFD0 = $this->_getLong($data, $pos + 4, $isBigEndian);
1386*55efc227SAndreas Gohr        if ($offsetIFD0 < 8)
1387*55efc227SAndreas Gohr            return false; // Unexpected data
1388*55efc227SAndreas Gohr
1389*55efc227SAndreas Gohr        $offsetIFD1 = $this->_readIFD($data, $pos, $offsetIFD0, $isBigEndian, 'ifd0');
1390*55efc227SAndreas Gohr        if ($offsetIFD1 != 0)
1391*55efc227SAndreas Gohr            $this->_readIFD($data, $pos, $offsetIFD1, $isBigEndian, 'ifd1');
1392*55efc227SAndreas Gohr
1393*55efc227SAndreas Gohr        return true;
1394*55efc227SAndreas Gohr    }
1395*55efc227SAndreas Gohr
1396*55efc227SAndreas Gohr    /*************************************************************/
1397*55efc227SAndreas Gohr    function _readIFD($data, $base, $offset, $isBigEndian, $mode)
1398*55efc227SAndreas Gohr    {
1399*55efc227SAndreas Gohr        $EXIFTags = $this->_exifTagNames($mode);
1400*55efc227SAndreas Gohr
1401*55efc227SAndreas Gohr        $numEntries = $this->_getShort($data, $base + $offset, $isBigEndian);
1402*55efc227SAndreas Gohr        $offset += 2;
1403*55efc227SAndreas Gohr
1404*55efc227SAndreas Gohr        $exifTIFFOffset = 0;
1405*55efc227SAndreas Gohr        $exifTIFFLength = 0;
1406*55efc227SAndreas Gohr        $exifThumbnailOffset = 0;
1407*55efc227SAndreas Gohr        $exifThumbnailLength = 0;
1408*55efc227SAndreas Gohr
1409*55efc227SAndreas Gohr        for ($i = 0; $i < $numEntries; $i++) {
1410*55efc227SAndreas Gohr            $tag = $this->_getShort($data, $base + $offset, $isBigEndian);
1411*55efc227SAndreas Gohr            $offset += 2;
1412*55efc227SAndreas Gohr            $type = $this->_getShort($data, $base + $offset, $isBigEndian);
1413*55efc227SAndreas Gohr            $offset += 2;
1414*55efc227SAndreas Gohr            $count = $this->_getLong($data, $base + $offset, $isBigEndian);
1415*55efc227SAndreas Gohr            $offset += 4;
1416*55efc227SAndreas Gohr
1417*55efc227SAndreas Gohr            if (($type < 1) || ($type > 12))
1418*55efc227SAndreas Gohr                return false; // Unexpected Type
1419*55efc227SAndreas Gohr
1420*55efc227SAndreas Gohr            $typeLengths = array( -1, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8 );
1421*55efc227SAndreas Gohr
1422*55efc227SAndreas Gohr            $dataLength = $typeLengths[$type] * $count;
1423*55efc227SAndreas Gohr            if ($dataLength > 4) {
1424*55efc227SAndreas Gohr                $dataOffset = $this->_getLong($data, $base + $offset, $isBigEndian);
1425*55efc227SAndreas Gohr                $rawValue = $this->_getFixedString($data, $base + $dataOffset, $dataLength);
1426*55efc227SAndreas Gohr            }
1427*55efc227SAndreas Gohr            else {
1428*55efc227SAndreas Gohr                $rawValue = $this->_getFixedString($data, $base + $offset, $dataLength);
1429*55efc227SAndreas Gohr            }
1430*55efc227SAndreas Gohr            $offset += 4;
1431*55efc227SAndreas Gohr
1432*55efc227SAndreas Gohr            switch ($type) {
1433*55efc227SAndreas Gohr            case 1:    // UBYTE
1434*55efc227SAndreas Gohr                if ($count == 1) {
1435*55efc227SAndreas Gohr                    $value = $this->_getByte($rawValue, 0);
1436*55efc227SAndreas Gohr                }
1437*55efc227SAndreas Gohr                else {
1438*55efc227SAndreas Gohr                    $value = array();
1439*55efc227SAndreas Gohr                    for ($j = 0; $j < $count; $j++)
1440*55efc227SAndreas Gohr                        $value[$j] = $this->_getByte($rawValue, $j);
1441*55efc227SAndreas Gohr                }
1442*55efc227SAndreas Gohr                break;
1443*55efc227SAndreas Gohr            case 2:    // ASCII
1444*55efc227SAndreas Gohr                $value = $rawValue;
1445*55efc227SAndreas Gohr                break;
1446*55efc227SAndreas Gohr            case 3:    // USHORT
1447*55efc227SAndreas Gohr                if ($count == 1) {
1448*55efc227SAndreas Gohr                    $value = $this->_getShort($rawValue, 0, $isBigEndian);
1449*55efc227SAndreas Gohr                }
1450*55efc227SAndreas Gohr                else {
1451*55efc227SAndreas Gohr                    $value = array();
1452*55efc227SAndreas Gohr                    for ($j = 0; $j < $count; $j++)
1453*55efc227SAndreas Gohr                        $value[$j] = $this->_getShort($rawValue, $j * 2, $isBigEndian);
1454*55efc227SAndreas Gohr                }
1455*55efc227SAndreas Gohr                break;
1456*55efc227SAndreas Gohr            case 4:    // ULONG
1457*55efc227SAndreas Gohr                if ($count == 1) {
1458*55efc227SAndreas Gohr                    $value = $this->_getLong($rawValue, 0, $isBigEndian);
1459*55efc227SAndreas Gohr                }
1460*55efc227SAndreas Gohr                else {
1461*55efc227SAndreas Gohr                    $value = array();
1462*55efc227SAndreas Gohr                    for ($j = 0; $j < $count; $j++)
1463*55efc227SAndreas Gohr                        $value[$j] = $this->_getLong($rawValue, $j * 4, $isBigEndian);
1464*55efc227SAndreas Gohr                }
1465*55efc227SAndreas Gohr                break;
1466*55efc227SAndreas Gohr            case 5:    // URATIONAL
1467*55efc227SAndreas Gohr                if ($count == 1) {
1468*55efc227SAndreas Gohr                    $a = $this->_getLong($rawValue, 0, $isBigEndian);
1469*55efc227SAndreas Gohr                    $b = $this->_getLong($rawValue, 4, $isBigEndian);
1470*55efc227SAndreas Gohr                    $value = array();
1471*55efc227SAndreas Gohr                    $value['val'] = 0;
1472*55efc227SAndreas Gohr                    $value['num'] = $a;
1473*55efc227SAndreas Gohr                    $value['den'] = $b;
1474*55efc227SAndreas Gohr                    if (($a != 0) && ($b != 0)) {
1475*55efc227SAndreas Gohr                        $value['val'] = $a / $b;
1476*55efc227SAndreas Gohr                    }
1477*55efc227SAndreas Gohr                }
1478*55efc227SAndreas Gohr                else {
1479*55efc227SAndreas Gohr                    $value = array();
1480*55efc227SAndreas Gohr                    for ($j = 0; $j < $count; $j++) {
1481*55efc227SAndreas Gohr                        $a = $this->_getLong($rawValue, $j * 8, $isBigEndian);
1482*55efc227SAndreas Gohr                        $b = $this->_getLong($rawValue, ($j * 8) + 4, $isBigEndian);
1483*55efc227SAndreas Gohr                        $value = array();
1484*55efc227SAndreas Gohr                        $value[$j]['val'] = 0;
1485*55efc227SAndreas Gohr                        $value[$j]['num'] = $a;
1486*55efc227SAndreas Gohr                        $value[$j]['den'] = $b;
1487*55efc227SAndreas Gohr                        if (($a != 0) && ($b != 0))
1488*55efc227SAndreas Gohr                            $value[$j]['val'] = $a / $b;
1489*55efc227SAndreas Gohr                    }
1490*55efc227SAndreas Gohr                }
1491*55efc227SAndreas Gohr                break;
1492*55efc227SAndreas Gohr            case 6:    // SBYTE
1493*55efc227SAndreas Gohr                if ($count == 1) {
1494*55efc227SAndreas Gohr                    $value = $this->_getByte($rawValue, 0);
1495*55efc227SAndreas Gohr                }
1496*55efc227SAndreas Gohr                else {
1497*55efc227SAndreas Gohr                    $value = array();
1498*55efc227SAndreas Gohr                    for ($j = 0; $j < $count; $j++)
1499*55efc227SAndreas Gohr                        $value[$j] = $this->_getByte($rawValue, $j);
1500*55efc227SAndreas Gohr                }
1501*55efc227SAndreas Gohr                break;
1502*55efc227SAndreas Gohr            case 7:    // UNDEFINED
1503*55efc227SAndreas Gohr                $value = $rawValue;
1504*55efc227SAndreas Gohr                break;
1505*55efc227SAndreas Gohr            case 8:    // SSHORT
1506*55efc227SAndreas Gohr                if ($count == 1) {
1507*55efc227SAndreas Gohr                    $value = $this->_getShort($rawValue, 0, $isBigEndian);
1508*55efc227SAndreas Gohr                }
1509*55efc227SAndreas Gohr                else {
1510*55efc227SAndreas Gohr                    $value = array();
1511*55efc227SAndreas Gohr                    for ($j = 0; $j < $count; $j++)
1512*55efc227SAndreas Gohr                        $value[$j] = $this->_getShort($rawValue, $j * 2, $isBigEndian);
1513*55efc227SAndreas Gohr                }
1514*55efc227SAndreas Gohr                break;
1515*55efc227SAndreas Gohr            case 9:    // SLONG
1516*55efc227SAndreas Gohr                if ($count == 1) {
1517*55efc227SAndreas Gohr                    $value = $this->_getLong($rawValue, 0, $isBigEndian);
1518*55efc227SAndreas Gohr                }
1519*55efc227SAndreas Gohr                else {
1520*55efc227SAndreas Gohr                    $value = array();
1521*55efc227SAndreas Gohr                    for ($j = 0; $j < $count; $j++)
1522*55efc227SAndreas Gohr                        $value[$j] = $this->_getLong($rawValue, $j * 4, $isBigEndian);
1523*55efc227SAndreas Gohr                }
1524*55efc227SAndreas Gohr                break;
1525*55efc227SAndreas Gohr            case 10:   // SRATIONAL
1526*55efc227SAndreas Gohr                if ($count == 1) {
1527*55efc227SAndreas Gohr                    $a = $this->_getLong($rawValue, 0, $isBigEndian);
1528*55efc227SAndreas Gohr                    $b = $this->_getLong($rawValue, 4, $isBigEndian);
1529*55efc227SAndreas Gohr                    $value = array();
1530*55efc227SAndreas Gohr                    $value['val'] = 0;
1531*55efc227SAndreas Gohr                    $value['num'] = $a;
1532*55efc227SAndreas Gohr                    $value['den'] = $b;
1533*55efc227SAndreas Gohr                    if (($a != 0) && ($b != 0))
1534*55efc227SAndreas Gohr                        $value['val'] = $a / $b;
1535*55efc227SAndreas Gohr                }
1536*55efc227SAndreas Gohr                else {
1537*55efc227SAndreas Gohr                    $value = array();
1538*55efc227SAndreas Gohr                    for ($j = 0; $j < $count; $j++) {
1539*55efc227SAndreas Gohr                        $a = $this->_getLong($rawValue, $j * 8, $isBigEndian);
1540*55efc227SAndreas Gohr                        $b = $this->_getLong($rawValue, ($j * 8) + 4, $isBigEndian);
1541*55efc227SAndreas Gohr                        $value = array();
1542*55efc227SAndreas Gohr                        $value[$j]['val'] = 0;
1543*55efc227SAndreas Gohr                        $value[$j]['num'] = $a;
1544*55efc227SAndreas Gohr                        $value[$j]['den'] = $b;
1545*55efc227SAndreas Gohr                        if (($a != 0) && ($b != 0))
1546*55efc227SAndreas Gohr                            $value[$j]['val'] = $a / $b;
1547*55efc227SAndreas Gohr                    }
1548*55efc227SAndreas Gohr                }
1549*55efc227SAndreas Gohr                break;
1550*55efc227SAndreas Gohr            case 11:   // FLOAT
1551*55efc227SAndreas Gohr                $value = $rawValue;
1552*55efc227SAndreas Gohr                break;
1553*55efc227SAndreas Gohr
1554*55efc227SAndreas Gohr            case 12:   // DFLOAT
1555*55efc227SAndreas Gohr                $value = $rawValue;
1556*55efc227SAndreas Gohr                break;
1557*55efc227SAndreas Gohr            default:
1558*55efc227SAndreas Gohr                return false; // Unexpected Type
1559*55efc227SAndreas Gohr            }
1560*55efc227SAndreas Gohr
1561*55efc227SAndreas Gohr            $tagName = '';
1562*55efc227SAndreas Gohr            if (($mode == 'ifd0') && ($tag == 0x8769)) {  // ExifIFDOffset
1563*55efc227SAndreas Gohr                $this->_readIFD($data, $base, $value, $isBigEndian, 'exif');
1564*55efc227SAndreas Gohr            }
1565*55efc227SAndreas Gohr            elseif (($mode == 'ifd0') && ($tag == 0x8825)) {  // GPSIFDOffset
1566*55efc227SAndreas Gohr                $this->_readIFD($data, $base, $value, $isBigEndian, 'gps');
1567*55efc227SAndreas Gohr            }
1568*55efc227SAndreas Gohr            elseif (($mode == 'ifd1') && ($tag == 0x0111)) {  // TIFFStripOffsets
1569*55efc227SAndreas Gohr                $exifTIFFOffset = $value;
1570*55efc227SAndreas Gohr            }
1571*55efc227SAndreas Gohr            elseif (($mode == 'ifd1') && ($tag == 0x0117)) {  // TIFFStripByteCounts
1572*55efc227SAndreas Gohr                $exifTIFFLength = $value;
1573*55efc227SAndreas Gohr            }
1574*55efc227SAndreas Gohr            elseif (($mode == 'ifd1') && ($tag == 0x0201)) {  // TIFFJFIFOffset
1575*55efc227SAndreas Gohr                $exifThumbnailOffset = $value;
1576*55efc227SAndreas Gohr            }
1577*55efc227SAndreas Gohr            elseif (($mode == 'ifd1') && ($tag == 0x0202)) {  // TIFFJFIFLength
1578*55efc227SAndreas Gohr                $exifThumbnailLength = $value;
1579*55efc227SAndreas Gohr            }
1580*55efc227SAndreas Gohr            elseif (($mode == 'exif') && ($tag == 0xA005)) {  // InteropIFDOffset
1581*55efc227SAndreas Gohr                $this->_readIFD($data, $base, $value, $isBigEndian, 'interop');
1582*55efc227SAndreas Gohr            }
1583*55efc227SAndreas Gohr            // elseif (($mode == 'exif') && ($tag == 0x927C)) {  // MakerNote
1584*55efc227SAndreas Gohr            // }
1585*55efc227SAndreas Gohr            else {
1586*55efc227SAndreas Gohr                if (isset($EXIFTags[$tag])) {
1587*55efc227SAndreas Gohr                    $tagName = $EXIFTags[$tag];
1588*55efc227SAndreas Gohr                    if (isset($this->_info['exif'][$tagName])) {
1589*55efc227SAndreas Gohr                        if (!is_array($this->_info['exif'][$tagName])) {
1590*55efc227SAndreas Gohr                            $aux = array();
1591*55efc227SAndreas Gohr                            $aux[0] = $this->_info['exif'][$tagName];
1592*55efc227SAndreas Gohr                            $this->_info['exif'][$tagName] = $aux;
1593*55efc227SAndreas Gohr                        }
1594*55efc227SAndreas Gohr
1595*55efc227SAndreas Gohr                        $this->_info['exif'][$tagName][count($this->_info['exif'][$tagName])] = $value;
1596*55efc227SAndreas Gohr                    }
1597*55efc227SAndreas Gohr                    else {
1598*55efc227SAndreas Gohr                        $this->_info['exif'][$tagName] = $value;
1599*55efc227SAndreas Gohr                    }
1600*55efc227SAndreas Gohr                }
1601*55efc227SAndreas Gohr                else {
1602*55efc227SAndreas Gohr#echo sprintf("<h1>Unknown tag %02x (t: %d l: %d) %s in %s</h1>", $tag, $type, $count, $mode, $this->_fileName);
1603*55efc227SAndreas Gohr                    // Unknown Tags will be ignored!!!
1604*55efc227SAndreas Gohr                    // That's because the tag might be a pointer (like the Exif tag)
1605*55efc227SAndreas Gohr                    // and saving it without saving the data it points to might
1606*55efc227SAndreas Gohr                    // create an invalid file.
1607*55efc227SAndreas Gohr                }
1608*55efc227SAndreas Gohr            }
1609*55efc227SAndreas Gohr        }
1610*55efc227SAndreas Gohr
1611*55efc227SAndreas Gohr        if (($exifThumbnailOffset > 0) && ($exifThumbnailLength > 0)) {
1612*55efc227SAndreas Gohr            $this->_info['exif']['JFIFThumbnail'] = $this->_getFixedString($data, $base + $exifThumbnailOffset, $exifThumbnailLength);
1613*55efc227SAndreas Gohr        }
1614*55efc227SAndreas Gohr
1615*55efc227SAndreas Gohr        if (($exifTIFFOffset > 0) && ($exifTIFFLength > 0)) {
1616*55efc227SAndreas Gohr            $this->_info['exif']['TIFFStrips'] = $this->_getFixedString($data, $base + $exifTIFFOffset, $exifTIFFLength);
1617*55efc227SAndreas Gohr        }
1618*55efc227SAndreas Gohr
1619*55efc227SAndreas Gohr        $nextOffset = $this->_getLong($data, $base + $offset, $isBigEndian);
1620*55efc227SAndreas Gohr        return $nextOffset;
1621*55efc227SAndreas Gohr    }
1622*55efc227SAndreas Gohr
1623*55efc227SAndreas Gohr    /*************************************************************/
1624*55efc227SAndreas Gohr    function & _createMarkerExif()
1625*55efc227SAndreas Gohr    {
1626*55efc227SAndreas Gohr        $data = null;
1627*55efc227SAndreas Gohr        $count = count($this->_markers);
1628*55efc227SAndreas Gohr        for ($i = 0; $i < $count; $i++) {
1629*55efc227SAndreas Gohr            if ($this->_markers[$i]['marker'] == 0xE1) {
1630*55efc227SAndreas Gohr                $signature = $this->_getFixedString($this->_markers[$i]['data'], 0, 6);
1631*55efc227SAndreas Gohr                if ($signature == "Exif\0\0") {
1632*55efc227SAndreas Gohr                    $data =& $this->_markers[$i]['data'];
1633*55efc227SAndreas Gohr                    break;
1634*55efc227SAndreas Gohr                }
1635*55efc227SAndreas Gohr            }
1636*55efc227SAndreas Gohr        }
1637*55efc227SAndreas Gohr
1638*55efc227SAndreas Gohr        if (!isset($this->_info['exif'])) {
1639*55efc227SAndreas Gohr            return false;
1640*55efc227SAndreas Gohr        }
1641*55efc227SAndreas Gohr
1642*55efc227SAndreas Gohr        $data = "Exif\0\0";
1643*55efc227SAndreas Gohr        $pos = 6;
1644*55efc227SAndreas Gohr        $offsetBase = 6;
1645*55efc227SAndreas Gohr
1646*55efc227SAndreas Gohr        if (isset($this->_info['exif']['ByteAlign']) && ($this->_info['exif']['ByteAlign'] == "Big Endian")) {
1647*55efc227SAndreas Gohr            $isBigEndian = true;
1648*55efc227SAndreas Gohr            $aux = "MM";
1649*55efc227SAndreas Gohr            $pos = $this->_putString($data, $pos, $aux);
1650*55efc227SAndreas Gohr        }
1651*55efc227SAndreas Gohr        else {
1652*55efc227SAndreas Gohr            $isBigEndian = false;
1653*55efc227SAndreas Gohr            $aux = "II";
1654*55efc227SAndreas Gohr            $pos = $this->_putString($data, $pos, $aux);
1655*55efc227SAndreas Gohr        }
1656*55efc227SAndreas Gohr        $pos = $this->_putShort($data, $pos, 0x002A, $isBigEndian);
1657*55efc227SAndreas Gohr        $pos = $this->_putLong($data, $pos, 0x00000008, $isBigEndian); // IFD0 Offset is always 8
1658*55efc227SAndreas Gohr
1659*55efc227SAndreas Gohr        $ifd0 =& $this->_getIFDEntries($isBigEndian, 'ifd0');
1660*55efc227SAndreas Gohr        $ifd1 =& $this->_getIFDEntries($isBigEndian, 'ifd1');
1661*55efc227SAndreas Gohr
1662*55efc227SAndreas Gohr        $pos = $this->_writeIFD($data, $pos, $offsetBase, $ifd0, $isBigEndian, true);
1663*55efc227SAndreas Gohr        $pos = $this->_writeIFD($data, $pos, $offsetBase, $ifd1, $isBigEndian, false);
1664*55efc227SAndreas Gohr
1665*55efc227SAndreas Gohr        return $data;
1666*55efc227SAndreas Gohr    }
1667*55efc227SAndreas Gohr
1668*55efc227SAndreas Gohr    /*************************************************************/
1669*55efc227SAndreas Gohr    function _writeIFD(&$data, $pos, $offsetBase, &$entries, $isBigEndian, $hasNext)
1670*55efc227SAndreas Gohr    {
1671*55efc227SAndreas Gohr        $tiffData = null;
1672*55efc227SAndreas Gohr        $tiffDataOffsetPos = -1;
1673*55efc227SAndreas Gohr
1674*55efc227SAndreas Gohr        $entryCount = count($entries);
1675*55efc227SAndreas Gohr
1676*55efc227SAndreas Gohr        $dataPos = $pos + 2 + ($entryCount * 12) + 4;
1677*55efc227SAndreas Gohr        $pos = $this->_putShort($data, $pos, $entryCount, $isBigEndian);
1678*55efc227SAndreas Gohr
1679*55efc227SAndreas Gohr        for ($i = 0; $i < $entryCount; $i++) {
1680*55efc227SAndreas Gohr            $tag = $entries[$i]['tag'];
1681*55efc227SAndreas Gohr            $type = $entries[$i]['type'];
1682*55efc227SAndreas Gohr
1683*55efc227SAndreas Gohr            if ($type == -99) { // SubIFD
1684*55efc227SAndreas Gohr                $pos = $this->_putShort($data, $pos, $tag, $isBigEndian);
1685*55efc227SAndreas Gohr                $pos = $this->_putShort($data, $pos, 0x04, $isBigEndian); // LONG
1686*55efc227SAndreas Gohr                $pos = $this->_putLong($data, $pos, 0x01, $isBigEndian); // Count = 1
1687*55efc227SAndreas Gohr                $pos = $this->_putLong($data, $pos, $dataPos - $offsetBase, $isBigEndian);
1688*55efc227SAndreas Gohr
1689*55efc227SAndreas Gohr                $dataPos = $this->_writeIFD($data, $dataPos, $offsetBase, $entries[$i]['value'], $isBigEndian, false);
1690*55efc227SAndreas Gohr            }
1691*55efc227SAndreas Gohr            elseif ($type == -98) { // TIFF Data
1692*55efc227SAndreas Gohr                $pos = $this->_putShort($data, $pos, $tag, $isBigEndian);
1693*55efc227SAndreas Gohr                $pos = $this->_putShort($data, $pos, 0x04, $isBigEndian); // LONG
1694*55efc227SAndreas Gohr                $pos = $this->_putLong($data, $pos, 0x01, $isBigEndian); // Count = 1
1695*55efc227SAndreas Gohr                $tiffDataOffsetPos = $pos;
1696*55efc227SAndreas Gohr                $pos = $this->_putLong($data, $pos, 0x00, $isBigEndian); // For Now
1697*55efc227SAndreas Gohr                $tiffData =& $entries[$i]['value'] ;
1698*55efc227SAndreas Gohr            }
1699*55efc227SAndreas Gohr            else { // Regular Entry
1700*55efc227SAndreas Gohr                $pos = $this->_putShort($data, $pos, $tag, $isBigEndian);
1701*55efc227SAndreas Gohr                $pos = $this->_putShort($data, $pos, $type, $isBigEndian);
1702*55efc227SAndreas Gohr                $pos = $this->_putLong($data, $pos, $entries[$i]['count'], $isBigEndian);
1703*55efc227SAndreas Gohr                if (strlen($entries[$i]['value']) > 4) {
1704*55efc227SAndreas Gohr                    $pos = $this->_putLong($data, $pos, $dataPos - $offsetBase, $isBigEndian);
1705*55efc227SAndreas Gohr                    $dataPos = $this->_putString($data, $dataPos, $entries[$i]['value']);
1706*55efc227SAndreas Gohr                }
1707*55efc227SAndreas Gohr                else {
1708*55efc227SAndreas Gohr                    $val = str_pad($entries[$i]['value'], 4, "\0");
1709*55efc227SAndreas Gohr                    $pos = $this->_putString($data, $pos, $val);
1710*55efc227SAndreas Gohr                }
1711*55efc227SAndreas Gohr            }
1712*55efc227SAndreas Gohr        }
1713*55efc227SAndreas Gohr
1714*55efc227SAndreas Gohr        if ($tiffData != null) {
1715*55efc227SAndreas Gohr            $this->_putLong($data, $tiffDataOffsetPos, $dataPos - $offsetBase, $isBigEndian);
1716*55efc227SAndreas Gohr            $dataPos = $this->_putString($data, $dataPos, $tiffData);
1717*55efc227SAndreas Gohr        }
1718*55efc227SAndreas Gohr
1719*55efc227SAndreas Gohr        if ($hasNext) {
1720*55efc227SAndreas Gohr            $pos = $this->_putLong($data, $pos, $dataPos - $offsetBase, $isBigEndian);
1721*55efc227SAndreas Gohr        }
1722*55efc227SAndreas Gohr        else {
1723*55efc227SAndreas Gohr            $pos = $this->_putLong($data, $pos, 0, $isBigEndian);
1724*55efc227SAndreas Gohr        }
1725*55efc227SAndreas Gohr
1726*55efc227SAndreas Gohr        return $dataPos;
1727*55efc227SAndreas Gohr    }
1728*55efc227SAndreas Gohr
1729*55efc227SAndreas Gohr    /*************************************************************/
1730*55efc227SAndreas Gohr    function & _getIFDEntries($isBigEndian, $mode)
1731*55efc227SAndreas Gohr    {
1732*55efc227SAndreas Gohr        $EXIFNames = $this->_exifTagNames($mode);
1733*55efc227SAndreas Gohr        $EXIFTags = $this->_exifNameTags($mode);
1734*55efc227SAndreas Gohr        $EXIFTypeInfo = $this->_exifTagTypes($mode);
1735*55efc227SAndreas Gohr
1736*55efc227SAndreas Gohr        $ifdEntries = array();
1737*55efc227SAndreas Gohr        $entryCount = 0;
1738*55efc227SAndreas Gohr
1739*55efc227SAndreas Gohr        reset($EXIFNames);
1740*55efc227SAndreas Gohr        while (list($tag, $name) = each($EXIFNames)) {
1741*55efc227SAndreas Gohr            $type = $EXIFTypeInfo[$tag][0];
1742*55efc227SAndreas Gohr            $count = $EXIFTypeInfo[$tag][1];
1743*55efc227SAndreas Gohr            $value = null;
1744*55efc227SAndreas Gohr
1745*55efc227SAndreas Gohr            if (($mode == 'ifd0') && ($tag == 0x8769)) {  // ExifIFDOffset
1746*55efc227SAndreas Gohr                if (isset($this->_info['exif']['EXIFVersion'])) {
1747*55efc227SAndreas Gohr                    $value =& $this->_getIFDEntries($isBigEndian, "exif");
1748*55efc227SAndreas Gohr                    $type = -99;
1749*55efc227SAndreas Gohr                }
1750*55efc227SAndreas Gohr                else {
1751*55efc227SAndreas Gohr                    $value = null;
1752*55efc227SAndreas Gohr                }
1753*55efc227SAndreas Gohr            }
1754*55efc227SAndreas Gohr            elseif (($mode == 'ifd0') && ($tag == 0x8825)) {  // GPSIFDOffset
1755*55efc227SAndreas Gohr                if (isset($this->_info['exif']['GPSVersionID'])) {
1756*55efc227SAndreas Gohr                    $value =& $this->_getIFDEntries($isBigEndian, "gps");
1757*55efc227SAndreas Gohr                    $type = -99;
1758*55efc227SAndreas Gohr                }
1759*55efc227SAndreas Gohr                else {
1760*55efc227SAndreas Gohr                    $value = null;
1761*55efc227SAndreas Gohr                }
1762*55efc227SAndreas Gohr            }
1763*55efc227SAndreas Gohr            elseif (($mode == 'ifd1') && ($tag == 0x0111)) {  // TIFFStripOffsets
1764*55efc227SAndreas Gohr                if (isset($this->_info['exif']['TIFFStrips'])) {
1765*55efc227SAndreas Gohr                    $value =& $this->_info['exif']['TIFFStrips'];
1766*55efc227SAndreas Gohr                    $type = -98;
1767*55efc227SAndreas Gohr                }
1768*55efc227SAndreas Gohr                else {
1769*55efc227SAndreas Gohr                    $value = null;
1770*55efc227SAndreas Gohr                }
1771*55efc227SAndreas Gohr            }
1772*55efc227SAndreas Gohr            elseif (($mode == 'ifd1') && ($tag == 0x0117)) {  // TIFFStripByteCounts
1773*55efc227SAndreas Gohr                if (isset($this->_info['exif']['TIFFStrips'])) {
1774*55efc227SAndreas Gohr                    $value = strlen($this->_info['exif']['TIFFStrips']);
1775*55efc227SAndreas Gohr                }
1776*55efc227SAndreas Gohr                else {
1777*55efc227SAndreas Gohr                    $value = null;
1778*55efc227SAndreas Gohr                }
1779*55efc227SAndreas Gohr            }
1780*55efc227SAndreas Gohr            elseif (($mode == 'ifd1') && ($tag == 0x0201)) {  // TIFFJFIFOffset
1781*55efc227SAndreas Gohr                if (isset($this->_info['exif']['JFIFThumbnail'])) {
1782*55efc227SAndreas Gohr                    $value =& $this->_info['exif']['JFIFThumbnail'];
1783*55efc227SAndreas Gohr                    $type = -98;
1784*55efc227SAndreas Gohr                }
1785*55efc227SAndreas Gohr                else {
1786*55efc227SAndreas Gohr                    $value = null;
1787*55efc227SAndreas Gohr                }
1788*55efc227SAndreas Gohr            }
1789*55efc227SAndreas Gohr            elseif (($mode == 'ifd1') && ($tag == 0x0202)) {  // TIFFJFIFLength
1790*55efc227SAndreas Gohr                if (isset($this->_info['exif']['JFIFThumbnail'])) {
1791*55efc227SAndreas Gohr                    $value = strlen($this->_info['exif']['JFIFThumbnail']);
1792*55efc227SAndreas Gohr                }
1793*55efc227SAndreas Gohr                else {
1794*55efc227SAndreas Gohr                    $value = null;
1795*55efc227SAndreas Gohr                }
1796*55efc227SAndreas Gohr            }
1797*55efc227SAndreas Gohr            elseif (($mode == 'exif') && ($tag == 0xA005)) {  // InteropIFDOffset
1798*55efc227SAndreas Gohr                if (isset($this->_info['exif']['InteroperabilityIndex'])) {
1799*55efc227SAndreas Gohr                    $value =& $this->_getIFDEntries($isBigEndian, "interop");
1800*55efc227SAndreas Gohr                    $type = -99;
1801*55efc227SAndreas Gohr                }
1802*55efc227SAndreas Gohr                else {
1803*55efc227SAndreas Gohr                    $value = null;
1804*55efc227SAndreas Gohr                }
1805*55efc227SAndreas Gohr            }
1806*55efc227SAndreas Gohr            elseif (isset($this->_info['exif'][$name])) {
1807*55efc227SAndreas Gohr                $origValue =& $this->_info['exif'][$name];
1808*55efc227SAndreas Gohr
1809*55efc227SAndreas Gohr                // This makes it easier to process variable size elements
1810*55efc227SAndreas Gohr                if (!is_array($origValue) || isset($origValue['val'])) {
1811*55efc227SAndreas Gohr                    unset($origValue); // Break the reference
1812*55efc227SAndreas Gohr                    $origValue = array($this->_info['exif'][$name]);
1813*55efc227SAndreas Gohr                }
1814*55efc227SAndreas Gohr                $origCount = count($origValue);
1815*55efc227SAndreas Gohr
1816*55efc227SAndreas Gohr                if ($origCount == 0 ) {
1817*55efc227SAndreas Gohr                    $type = -1;  // To ignore this field
1818*55efc227SAndreas Gohr                }
1819*55efc227SAndreas Gohr
1820*55efc227SAndreas Gohr                $value = " ";
1821*55efc227SAndreas Gohr
1822*55efc227SAndreas Gohr                switch ($type) {
1823*55efc227SAndreas Gohr                case 1:    // UBYTE
1824*55efc227SAndreas Gohr                    if ($count == 0) {
1825*55efc227SAndreas Gohr                        $count = $origCount;
1826*55efc227SAndreas Gohr                    }
1827*55efc227SAndreas Gohr
1828*55efc227SAndreas Gohr                    $j = 0;
1829*55efc227SAndreas Gohr                    while (($j < $count) && ($j < $origCount)) {
1830*55efc227SAndreas Gohr
1831*55efc227SAndreas Gohr                        $this->_putByte($value, $j, $origValue[$j]);
1832*55efc227SAndreas Gohr                        $j++;
1833*55efc227SAndreas Gohr                    }
1834*55efc227SAndreas Gohr
1835*55efc227SAndreas Gohr                    while ($j < $count) {
1836*55efc227SAndreas Gohr                        $this->_putByte($value, $j, 0);
1837*55efc227SAndreas Gohr                        $j++;
1838*55efc227SAndreas Gohr                    }
1839*55efc227SAndreas Gohr                    break;
1840*55efc227SAndreas Gohr                case 2:    // ASCII
1841*55efc227SAndreas Gohr                    $v = strval($origValue[0]);
1842*55efc227SAndreas Gohr                    if (($count != 0) && (strlen($v) > $count)) {
1843*55efc227SAndreas Gohr                        $v = substr($v, 0, $count);
1844*55efc227SAndreas Gohr                    }
1845*55efc227SAndreas Gohr                    elseif (($count > 0) && (strlen($v) < $count)) {
1846*55efc227SAndreas Gohr                        $v = str_pad($v, $count, "\0");
1847*55efc227SAndreas Gohr                    }
1848*55efc227SAndreas Gohr
1849*55efc227SAndreas Gohr                    $count = strlen($v);
1850*55efc227SAndreas Gohr
1851*55efc227SAndreas Gohr                    $this->_putString($value, 0, $v);
1852*55efc227SAndreas Gohr                    break;
1853*55efc227SAndreas Gohr                case 3:    // USHORT
1854*55efc227SAndreas Gohr                    if ($count == 0) {
1855*55efc227SAndreas Gohr                        $count = $origCount;
1856*55efc227SAndreas Gohr                    }
1857*55efc227SAndreas Gohr
1858*55efc227SAndreas Gohr                    $j = 0;
1859*55efc227SAndreas Gohr                    while (($j < $count) && ($j < $origCount)) {
1860*55efc227SAndreas Gohr                        $this->_putShort($value, $j * 2, $origValue[$j], $isBigEndian);
1861*55efc227SAndreas Gohr                        $j++;
1862*55efc227SAndreas Gohr                    }
1863*55efc227SAndreas Gohr
1864*55efc227SAndreas Gohr                    while ($j < $count) {
1865*55efc227SAndreas Gohr                        $this->_putShort($value, $j * 2, 0, $isBigEndian);
1866*55efc227SAndreas Gohr                        $j++;
1867*55efc227SAndreas Gohr                    }
1868*55efc227SAndreas Gohr                    break;
1869*55efc227SAndreas Gohr                case 4:    // ULONG
1870*55efc227SAndreas Gohr                    if ($count == 0) {
1871*55efc227SAndreas Gohr                        $count = $origCount;
1872*55efc227SAndreas Gohr                    }
1873*55efc227SAndreas Gohr
1874*55efc227SAndreas Gohr                    $j = 0;
1875*55efc227SAndreas Gohr                    while (($j < $count) && ($j < $origCount)) {
1876*55efc227SAndreas Gohr                        $this->_putLong($value, $j * 4, $origValue[$j], $isBigEndian);
1877*55efc227SAndreas Gohr                        $j++;
1878*55efc227SAndreas Gohr                    }
1879*55efc227SAndreas Gohr
1880*55efc227SAndreas Gohr                    while ($j < $count) {
1881*55efc227SAndreas Gohr                        $this->_putLong($value, $j * 4, 0, $isBigEndian);
1882*55efc227SAndreas Gohr                        $j++;
1883*55efc227SAndreas Gohr                    }
1884*55efc227SAndreas Gohr                    break;
1885*55efc227SAndreas Gohr                case 5:    // URATIONAL
1886*55efc227SAndreas Gohr                    if ($count == 0) {
1887*55efc227SAndreas Gohr                        $count = $origCount;
1888*55efc227SAndreas Gohr                    }
1889*55efc227SAndreas Gohr
1890*55efc227SAndreas Gohr                    $j = 0;
1891*55efc227SAndreas Gohr                    while (($j < $count) && ($j < $origCount)) {
1892*55efc227SAndreas Gohr                        $v = $origValue[$j];
1893*55efc227SAndreas Gohr                        if (is_array($v)) {
1894*55efc227SAndreas Gohr                            $a = $v['num'];
1895*55efc227SAndreas Gohr                            $b = $v['den'];
1896*55efc227SAndreas Gohr                        }
1897*55efc227SAndreas Gohr                        else {
1898*55efc227SAndreas Gohr                            $a = 0;
1899*55efc227SAndreas Gohr                            $b = 0;
1900*55efc227SAndreas Gohr                            // TODO: Allow other types and convert them
1901*55efc227SAndreas Gohr                        }
1902*55efc227SAndreas Gohr                        $this->_putLong($value, $j * 8, $a, $isBigEndian);
1903*55efc227SAndreas Gohr                        $this->_putLong($value, ($j * 8) + 4, $b, $isBigEndian);
1904*55efc227SAndreas Gohr                        $j++;
1905*55efc227SAndreas Gohr                    }
1906*55efc227SAndreas Gohr
1907*55efc227SAndreas Gohr                    while ($j < $count) {
1908*55efc227SAndreas Gohr                        $this->_putLong($value, $j * 8, 0, $isBigEndian);
1909*55efc227SAndreas Gohr                        $this->_putLong($value, ($j * 8) + 4, 0, $isBigEndian);
1910*55efc227SAndreas Gohr                        $j++;
1911*55efc227SAndreas Gohr                    }
1912*55efc227SAndreas Gohr                    break;
1913*55efc227SAndreas Gohr                case 6:    // SBYTE
1914*55efc227SAndreas Gohr                    if ($count == 0) {
1915*55efc227SAndreas Gohr                        $count = $origCount;
1916*55efc227SAndreas Gohr                    }
1917*55efc227SAndreas Gohr
1918*55efc227SAndreas Gohr                    $j = 0;
1919*55efc227SAndreas Gohr                    while (($j < $count) && ($j < $origCount)) {
1920*55efc227SAndreas Gohr                        $this->_putByte($value, $j, $origValue[$j]);
1921*55efc227SAndreas Gohr                        $j++;
1922*55efc227SAndreas Gohr                    }
1923*55efc227SAndreas Gohr
1924*55efc227SAndreas Gohr                    while ($j < $count) {
1925*55efc227SAndreas Gohr                        $this->_putByte($value, $j, 0);
1926*55efc227SAndreas Gohr                        $j++;
1927*55efc227SAndreas Gohr                    }
1928*55efc227SAndreas Gohr                    break;
1929*55efc227SAndreas Gohr                case 7:    // UNDEFINED
1930*55efc227SAndreas Gohr                    $v = strval($origValue[0]);
1931*55efc227SAndreas Gohr                    if (($count != 0) && (strlen($v) > $count)) {
1932*55efc227SAndreas Gohr                        $v = substr($v, 0, $count);
1933*55efc227SAndreas Gohr                    }
1934*55efc227SAndreas Gohr                    elseif (($count > 0) && (strlen($v) < $count)) {
1935*55efc227SAndreas Gohr                        $v = str_pad($v, $count, "\0");
1936*55efc227SAndreas Gohr                    }
1937*55efc227SAndreas Gohr
1938*55efc227SAndreas Gohr                    $count = strlen($v);
1939*55efc227SAndreas Gohr
1940*55efc227SAndreas Gohr                    $this->_putString($value, 0, $v);
1941*55efc227SAndreas Gohr                    break;
1942*55efc227SAndreas Gohr                case 8:    // SSHORT
1943*55efc227SAndreas Gohr                    if ($count == 0) {
1944*55efc227SAndreas Gohr                        $count = $origCount;
1945*55efc227SAndreas Gohr                    }
1946*55efc227SAndreas Gohr
1947*55efc227SAndreas Gohr                    $j = 0;
1948*55efc227SAndreas Gohr                    while (($j < $count) && ($j < $origCount)) {
1949*55efc227SAndreas Gohr                        $this->_putShort($value, $j * 2, $origValue[$j], $isBigEndian);
1950*55efc227SAndreas Gohr                        $j++;
1951*55efc227SAndreas Gohr                    }
1952*55efc227SAndreas Gohr
1953*55efc227SAndreas Gohr                    while ($j < $count) {
1954*55efc227SAndreas Gohr                        $this->_putShort($value, $j * 2, 0, $isBigEndian);
1955*55efc227SAndreas Gohr                        $j++;
1956*55efc227SAndreas Gohr                    }
1957*55efc227SAndreas Gohr                    break;
1958*55efc227SAndreas Gohr                case 9:    // SLONG
1959*55efc227SAndreas Gohr                    if ($count == 0) {
1960*55efc227SAndreas Gohr                        $count = $origCount;
1961*55efc227SAndreas Gohr                    }
1962*55efc227SAndreas Gohr
1963*55efc227SAndreas Gohr                    $j = 0;
1964*55efc227SAndreas Gohr                    while (($j < $count) && ($j < $origCount)) {
1965*55efc227SAndreas Gohr                        $this->_putLong($value, $j * 4, $origValue[$j], $isBigEndian);
1966*55efc227SAndreas Gohr                        $j++;
1967*55efc227SAndreas Gohr                    }
1968*55efc227SAndreas Gohr
1969*55efc227SAndreas Gohr                    while ($j < $count) {
1970*55efc227SAndreas Gohr                        $this->_putLong($value, $j * 4, 0, $isBigEndian);
1971*55efc227SAndreas Gohr                        $j++;
1972*55efc227SAndreas Gohr                    }
1973*55efc227SAndreas Gohr                    break;
1974*55efc227SAndreas Gohr                case 10:   // SRATIONAL
1975*55efc227SAndreas Gohr                    if ($count == 0) {
1976*55efc227SAndreas Gohr                        $count = $origCount;
1977*55efc227SAndreas Gohr                    }
1978*55efc227SAndreas Gohr
1979*55efc227SAndreas Gohr                    $j = 0;
1980*55efc227SAndreas Gohr                    while (($j < $count) && ($j < $origCount)) {
1981*55efc227SAndreas Gohr                        $v = $origValue[$j];
1982*55efc227SAndreas Gohr                        if (is_array($v)) {
1983*55efc227SAndreas Gohr                            $a = $v['num'];
1984*55efc227SAndreas Gohr                            $b = $v['den'];
1985*55efc227SAndreas Gohr                        }
1986*55efc227SAndreas Gohr                        else {
1987*55efc227SAndreas Gohr                            $a = 0;
1988*55efc227SAndreas Gohr                            $b = 0;
1989*55efc227SAndreas Gohr                            // TODO: Allow other types and convert them
1990*55efc227SAndreas Gohr                        }
1991*55efc227SAndreas Gohr
1992*55efc227SAndreas Gohr                        $this->_putLong($value, $j * 8, $a, $isBigEndian);
1993*55efc227SAndreas Gohr                        $this->_putLong($value, ($j * 8) + 4, $b, $isBigEndian);
1994*55efc227SAndreas Gohr                        $j++;
1995*55efc227SAndreas Gohr                    }
1996*55efc227SAndreas Gohr
1997*55efc227SAndreas Gohr                    while ($j < $count) {
1998*55efc227SAndreas Gohr                        $this->_putLong($value, $j * 8, 0, $isBigEndian);
1999*55efc227SAndreas Gohr                        $this->_putLong($value, ($j * 8) + 4, 0, $isBigEndian);
2000*55efc227SAndreas Gohr                        $j++;
2001*55efc227SAndreas Gohr                    }
2002*55efc227SAndreas Gohr                    break;
2003*55efc227SAndreas Gohr                case 11:   // FLOAT
2004*55efc227SAndreas Gohr                    if ($count == 0) {
2005*55efc227SAndreas Gohr                        $count = $origCount;
2006*55efc227SAndreas Gohr                    }
2007*55efc227SAndreas Gohr
2008*55efc227SAndreas Gohr                    $j = 0;
2009*55efc227SAndreas Gohr                    while (($j < $count) && ($j < $origCount)) {
2010*55efc227SAndreas Gohr                        $v = strval($origValue[$j]);
2011*55efc227SAndreas Gohr                        if (strlen($v) > 4) {
2012*55efc227SAndreas Gohr                            $v = substr($v, 0, 4);
2013*55efc227SAndreas Gohr                        }
2014*55efc227SAndreas Gohr                        elseif (strlen($v) < 4) {
2015*55efc227SAndreas Gohr                            $v = str_pad($v, 4, "\0");
2016*55efc227SAndreas Gohr                        }
2017*55efc227SAndreas Gohr                        $this->_putString($value, $j * 4, $v);
2018*55efc227SAndreas Gohr                        $j++;
2019*55efc227SAndreas Gohr                    }
2020*55efc227SAndreas Gohr
2021*55efc227SAndreas Gohr                    while ($j < $count) {
2022*55efc227SAndreas Gohr                        $this->_putString($value, $j * 4, "\0\0\0\0");
2023*55efc227SAndreas Gohr                        $j++;
2024*55efc227SAndreas Gohr                    }
2025*55efc227SAndreas Gohr                    break;
2026*55efc227SAndreas Gohr                case 12:   // DFLOAT
2027*55efc227SAndreas Gohr                    if ($count == 0) {
2028*55efc227SAndreas Gohr                        $count = $origCount;
2029*55efc227SAndreas Gohr                    }
2030*55efc227SAndreas Gohr
2031*55efc227SAndreas Gohr                    $j = 0;
2032*55efc227SAndreas Gohr                    while (($j < $count) && ($j < $origCount)) {
2033*55efc227SAndreas Gohr                        $v = strval($origValue[$j]);
2034*55efc227SAndreas Gohr                        if (strlen($v) > 8) {
2035*55efc227SAndreas Gohr                            $v = substr($v, 0, 8);
2036*55efc227SAndreas Gohr                        }
2037*55efc227SAndreas Gohr                        elseif (strlen($v) < 8) {
2038*55efc227SAndreas Gohr                            $v = str_pad($v, 8, "\0");
2039*55efc227SAndreas Gohr                        }
2040*55efc227SAndreas Gohr                        $this->_putString($value, $j * 8, $v);
2041*55efc227SAndreas Gohr                        $j++;
2042*55efc227SAndreas Gohr                    }
2043*55efc227SAndreas Gohr
2044*55efc227SAndreas Gohr                    while ($j < $count) {
2045*55efc227SAndreas Gohr                        $this->_putString($value, $j * 8, "\0\0\0\0\0\0\0\0");
2046*55efc227SAndreas Gohr                        $j++;
2047*55efc227SAndreas Gohr                    }
2048*55efc227SAndreas Gohr                    break;
2049*55efc227SAndreas Gohr                default:
2050*55efc227SAndreas Gohr                    $value = null;
2051*55efc227SAndreas Gohr                    break;
2052*55efc227SAndreas Gohr                }
2053*55efc227SAndreas Gohr            }
2054*55efc227SAndreas Gohr
2055*55efc227SAndreas Gohr            if ($value != null) {
2056*55efc227SAndreas Gohr                $ifdEntries[$entryCount] = array();
2057*55efc227SAndreas Gohr                $ifdEntries[$entryCount]['tag'] = $tag;
2058*55efc227SAndreas Gohr                $ifdEntries[$entryCount]['type'] = $type;
2059*55efc227SAndreas Gohr                $ifdEntries[$entryCount]['count'] = $count;
2060*55efc227SAndreas Gohr                $ifdEntries[$entryCount]['value'] = $value;
2061*55efc227SAndreas Gohr
2062*55efc227SAndreas Gohr                $entryCount++;
2063*55efc227SAndreas Gohr            }
2064*55efc227SAndreas Gohr        }
2065*55efc227SAndreas Gohr
2066*55efc227SAndreas Gohr        return $ifdEntries;
2067*55efc227SAndreas Gohr    }
2068*55efc227SAndreas Gohr
2069*55efc227SAndreas Gohr    /*************************************************************/
2070*55efc227SAndreas Gohr    function _parseMarkerAdobe()
2071*55efc227SAndreas Gohr    {
2072*55efc227SAndreas Gohr        if (!isset($this->_markers)) {
2073*55efc227SAndreas Gohr            $this->_readJPEG();
2074*55efc227SAndreas Gohr        }
2075*55efc227SAndreas Gohr
2076*55efc227SAndreas Gohr        if ($this->_markers == null) {
2077*55efc227SAndreas Gohr            return false;
2078*55efc227SAndreas Gohr        }
2079*55efc227SAndreas Gohr
2080*55efc227SAndreas Gohr        $data = null;
2081*55efc227SAndreas Gohr        $count = count($this->_markers);
2082*55efc227SAndreas Gohr        for ($i = 0; $i < $count; $i++) {
2083*55efc227SAndreas Gohr            if ($this->_markers[$i]['marker'] == 0xED) {
2084*55efc227SAndreas Gohr                $signature = $this->_getFixedString($this->_markers[$i]['data'], 0, 14);
2085*55efc227SAndreas Gohr                if ($signature == "Photoshop 3.0\0") {
2086*55efc227SAndreas Gohr                    $data =& $this->_markers[$i]['data'];
2087*55efc227SAndreas Gohr                    break;
2088*55efc227SAndreas Gohr                }
2089*55efc227SAndreas Gohr            }
2090*55efc227SAndreas Gohr        }
2091*55efc227SAndreas Gohr
2092*55efc227SAndreas Gohr        if ($data == null) {
2093*55efc227SAndreas Gohr            $this->_info['adobe'] = false;
2094*55efc227SAndreas Gohr            $this->_info['iptc'] = false;
2095*55efc227SAndreas Gohr            return false;
2096*55efc227SAndreas Gohr        }
2097*55efc227SAndreas Gohr        $pos = 14;
2098*55efc227SAndreas Gohr        $this->_info['adobe'] = array();
2099*55efc227SAndreas Gohr        $this->_info['adobe']['raw'] = array();
2100*55efc227SAndreas Gohr        $this->_info['iptc'] = array();
2101*55efc227SAndreas Gohr
2102*55efc227SAndreas Gohr        $datasize = strlen($data);
2103*55efc227SAndreas Gohr
2104*55efc227SAndreas Gohr        while ($pos < $datasize) {
2105*55efc227SAndreas Gohr            $signature = $this->_getFixedString($data, $pos, 4);
2106*55efc227SAndreas Gohr            if ($signature != '8BIM')
2107*55efc227SAndreas Gohr                return false;
2108*55efc227SAndreas Gohr            $pos += 4;
2109*55efc227SAndreas Gohr
2110*55efc227SAndreas Gohr            $type = $this->_getShort($data, $pos);
2111*55efc227SAndreas Gohr            $pos += 2;
2112*55efc227SAndreas Gohr
2113*55efc227SAndreas Gohr            $strlen = $this->_getByte($data, $pos);
2114*55efc227SAndreas Gohr            $pos += 1;
2115*55efc227SAndreas Gohr            $header = '';
2116*55efc227SAndreas Gohr            for ($i = 0; $i < $strlen; $i++) {
2117*55efc227SAndreas Gohr                $header .= $data{$pos + $i};
2118*55efc227SAndreas Gohr            }
2119*55efc227SAndreas Gohr            $pos += $strlen + 1 - ($strlen % 2);  // The string is padded to even length, counting the length byte itself
2120*55efc227SAndreas Gohr
2121*55efc227SAndreas Gohr            $length = $this->_getLong($data, $pos);
2122*55efc227SAndreas Gohr            $pos += 4;
2123*55efc227SAndreas Gohr
2124*55efc227SAndreas Gohr            $basePos = $pos;
2125*55efc227SAndreas Gohr
2126*55efc227SAndreas Gohr            switch ($type) {
2127*55efc227SAndreas Gohr            case 0x0404: // Caption (IPTC Data)
2128*55efc227SAndreas Gohr                $pos = $this->_readIPTC($data, $pos);
2129*55efc227SAndreas Gohr                if ($pos == false)
2130*55efc227SAndreas Gohr                    return false;
2131*55efc227SAndreas Gohr                break;
2132*55efc227SAndreas Gohr            case 0x040A: // CopyrightFlag
2133*55efc227SAndreas Gohr                $this->_info['adobe']['CopyrightFlag'] = $this->_getByte($data, $pos);
2134*55efc227SAndreas Gohr                $pos += $length;
2135*55efc227SAndreas Gohr                break;
2136*55efc227SAndreas Gohr            case 0x040B: // ImageURL
2137*55efc227SAndreas Gohr                $this->_info['adobe']['ImageURL'] = $this->_getFixedString($data, $pos, $length);
2138*55efc227SAndreas Gohr                $pos += $length;
2139*55efc227SAndreas Gohr                break;
2140*55efc227SAndreas Gohr            case 0x040C: // Thumbnail
2141*55efc227SAndreas Gohr                $aux = $this->_getLong($data, $pos);
2142*55efc227SAndreas Gohr                $pos += 4;
2143*55efc227SAndreas Gohr                if ($aux == 1) {
2144*55efc227SAndreas Gohr                    $this->_info['adobe']['ThumbnailWidth'] = $this->_getLong($data, $pos);
2145*55efc227SAndreas Gohr                    $pos += 4;
2146*55efc227SAndreas Gohr                    $this->_info['adobe']['ThumbnailHeight'] = $this->_getLong($data, $pos);
2147*55efc227SAndreas Gohr                    $pos += 4;
2148*55efc227SAndreas Gohr
2149*55efc227SAndreas Gohr                    $pos += 16; // Skip some data
2150*55efc227SAndreas Gohr
2151*55efc227SAndreas Gohr                    $this->_info['adobe']['ThumbnailData'] = $this->_getFixedString($data, $pos, $length - 28);
2152*55efc227SAndreas Gohr                    $pos += $length - 28;
2153*55efc227SAndreas Gohr                }
2154*55efc227SAndreas Gohr                break;
2155*55efc227SAndreas Gohr            default:
2156*55efc227SAndreas Gohr                break;
2157*55efc227SAndreas Gohr            }
2158*55efc227SAndreas Gohr
2159*55efc227SAndreas Gohr            // We save all blocks, even those we recognized
2160*55efc227SAndreas Gohr            $label = sprintf('8BIM_0x%04x', $type);
2161*55efc227SAndreas Gohr            $this->_info['adobe']['raw'][$label] = array();
2162*55efc227SAndreas Gohr            $this->_info['adobe']['raw'][$label]['type'] = $type;
2163*55efc227SAndreas Gohr            $this->_info['adobe']['raw'][$label]['header'] = $header;
2164*55efc227SAndreas Gohr            $this->_info['adobe']['raw'][$label]['data'] =& $this->_getFixedString($data, $basePos, $length);
2165*55efc227SAndreas Gohr
2166*55efc227SAndreas Gohr            $pos = $basePos + $length + ($length % 2); // Even padding
2167*55efc227SAndreas Gohr        }
2168*55efc227SAndreas Gohr
2169*55efc227SAndreas Gohr    }
2170*55efc227SAndreas Gohr
2171*55efc227SAndreas Gohr    /*************************************************************/
2172*55efc227SAndreas Gohr    function _readIPTC(&$data, $pos = 0)
2173*55efc227SAndreas Gohr    {
2174*55efc227SAndreas Gohr        $totalLength = strlen($data);
2175*55efc227SAndreas Gohr
2176*55efc227SAndreas Gohr        $IPTCTags =& $this->_iptcTagNames();
2177*55efc227SAndreas Gohr
2178*55efc227SAndreas Gohr        while ($pos < ($totalLength - 5)) {
2179*55efc227SAndreas Gohr            $signature = $this->_getShort($data, $pos);
2180*55efc227SAndreas Gohr            if ($signature != 0x1C02)
2181*55efc227SAndreas Gohr                return $pos;
2182*55efc227SAndreas Gohr            $pos += 2;
2183*55efc227SAndreas Gohr
2184*55efc227SAndreas Gohr            $type = $this->_getByte($data, $pos);
2185*55efc227SAndreas Gohr            $pos += 1;
2186*55efc227SAndreas Gohr            $length = $this->_getShort($data, $pos);
2187*55efc227SAndreas Gohr            $pos += 2;
2188*55efc227SAndreas Gohr
2189*55efc227SAndreas Gohr            $basePos = $pos;
2190*55efc227SAndreas Gohr            $label = '';
2191*55efc227SAndreas Gohr
2192*55efc227SAndreas Gohr            if (isset($IPTCTags[$type])) {
2193*55efc227SAndreas Gohr                $label = $IPTCTags[$type];
2194*55efc227SAndreas Gohr            }
2195*55efc227SAndreas Gohr            else {
2196*55efc227SAndreas Gohr                $label = sprintf('IPTC_0x%02x', $type);
2197*55efc227SAndreas Gohr            }
2198*55efc227SAndreas Gohr
2199*55efc227SAndreas Gohr            if ($label != '') {
2200*55efc227SAndreas Gohr                if (isset($this->_info['iptc'][$label])) {
2201*55efc227SAndreas Gohr                    if (!is_array($this->_info['iptc'][$label])) {
2202*55efc227SAndreas Gohr                        $aux = array();
2203*55efc227SAndreas Gohr                        $aux[0] = $this->_info['iptc'][$label];
2204*55efc227SAndreas Gohr                        $this->_info['iptc'][$label] = $aux;
2205*55efc227SAndreas Gohr                    }
2206*55efc227SAndreas Gohr                    $this->_info['iptc'][$label][ count($this->_info['iptc'][$label]) ] = $this->_getFixedString($data, $pos, $length);
2207*55efc227SAndreas Gohr                }
2208*55efc227SAndreas Gohr                else {
2209*55efc227SAndreas Gohr                    $this->_info['iptc'][$label] = $this->_getFixedString($data, $pos, $length);
2210*55efc227SAndreas Gohr                }
2211*55efc227SAndreas Gohr            }
2212*55efc227SAndreas Gohr
2213*55efc227SAndreas Gohr            $pos = $basePos + $length; // No padding
2214*55efc227SAndreas Gohr        }
2215*55efc227SAndreas Gohr        return $pos;
2216*55efc227SAndreas Gohr    }
2217*55efc227SAndreas Gohr
2218*55efc227SAndreas Gohr    /*************************************************************/
2219*55efc227SAndreas Gohr    function & _createMarkerAdobe()
2220*55efc227SAndreas Gohr    {
2221*55efc227SAndreas Gohr        if (isset($this->_info['iptc'])) {
2222*55efc227SAndreas Gohr            if (!isset($this->_info['adobe'])) {
2223*55efc227SAndreas Gohr                $this->_info['adobe'] = array();
2224*55efc227SAndreas Gohr            }
2225*55efc227SAndreas Gohr            if (!isset($this->_info['adobe']['raw'])) {
2226*55efc227SAndreas Gohr                $this->_info['adobe']['raw'] = array();
2227*55efc227SAndreas Gohr            }
2228*55efc227SAndreas Gohr            if (!isset($this->_info['adobe']['raw']['8BIM_0x0404'])) {
2229*55efc227SAndreas Gohr                $this->_info['adobe']['raw']['8BIM_0x0404'] = array();
2230*55efc227SAndreas Gohr            }
2231*55efc227SAndreas Gohr            $this->_info['adobe']['raw']['8BIM_0x0404']['type'] = 0x0404;
2232*55efc227SAndreas Gohr            $this->_info['adobe']['raw']['8BIM_0x0404']['header'] = "Caption";
2233*55efc227SAndreas Gohr            $this->_info['adobe']['raw']['8BIM_0x0404']['data'] =& $this->_writeIPTC();
2234*55efc227SAndreas Gohr        }
2235*55efc227SAndreas Gohr
2236*55efc227SAndreas Gohr        if (isset($this->_info['adobe']['raw']) && (count($this->_info['adobe']['raw']) > 0)) {
2237*55efc227SAndreas Gohr            $data = "Photoshop 3.0\0";
2238*55efc227SAndreas Gohr            $pos = 14;
2239*55efc227SAndreas Gohr
2240*55efc227SAndreas Gohr            reset($this->_info['adobe']['raw']);
2241*55efc227SAndreas Gohr            while (list($key) = each($this->_info['adobe']['raw'])) {
2242*55efc227SAndreas Gohr                $pos = $this->_write8BIM(
2243*55efc227SAndreas Gohr                            $data,
2244*55efc227SAndreas Gohr                            $pos,
2245*55efc227SAndreas Gohr                            $this->_info['adobe']['raw'][$key]['type'],
2246*55efc227SAndreas Gohr                            $this->_info['adobe']['raw'][$key]['header'],
2247*55efc227SAndreas Gohr                            $this->_info['adobe']['raw'][$key]['data'] );
2248*55efc227SAndreas Gohr            }
2249*55efc227SAndreas Gohr        }
2250*55efc227SAndreas Gohr
2251*55efc227SAndreas Gohr        return $data;
2252*55efc227SAndreas Gohr    }
2253*55efc227SAndreas Gohr
2254*55efc227SAndreas Gohr    /*************************************************************/
2255*55efc227SAndreas Gohr    function _write8BIM(&$data, $pos, $type, $header, &$value)
2256*55efc227SAndreas Gohr    {
2257*55efc227SAndreas Gohr        $signature = "8BIM";
2258*55efc227SAndreas Gohr
2259*55efc227SAndreas Gohr        $pos = $this->_putString($data, $pos, $signature);
2260*55efc227SAndreas Gohr        $pos = $this->_putShort($data, $pos, $type);
2261*55efc227SAndreas Gohr
2262*55efc227SAndreas Gohr        $len = strlen($header);
2263*55efc227SAndreas Gohr
2264*55efc227SAndreas Gohr        $pos = $this->_putByte($data, $pos, $len);
2265*55efc227SAndreas Gohr        $pos = $this->_putString($data, $pos, $header);
2266*55efc227SAndreas Gohr        if (($len % 2) == 0) {  // Even padding, including the length byte
2267*55efc227SAndreas Gohr            $pos = $this->_putByte($data, $pos, 0);
2268*55efc227SAndreas Gohr        }
2269*55efc227SAndreas Gohr
2270*55efc227SAndreas Gohr        $len = strlen($value);
2271*55efc227SAndreas Gohr        $pos = $this->_putLong($data, $pos, $len);
2272*55efc227SAndreas Gohr        $pos = $this->_putString($data, $pos, $value);
2273*55efc227SAndreas Gohr        if (($len % 2) != 0) {  // Even padding
2274*55efc227SAndreas Gohr            $pos = $this->_putByte($data, $pos, 0);
2275*55efc227SAndreas Gohr        }
2276*55efc227SAndreas Gohr        return $pos;
2277*55efc227SAndreas Gohr    }
2278*55efc227SAndreas Gohr
2279*55efc227SAndreas Gohr    /*************************************************************/
2280*55efc227SAndreas Gohr    function & _writeIPTC()
2281*55efc227SAndreas Gohr    {
2282*55efc227SAndreas Gohr        $data = " ";
2283*55efc227SAndreas Gohr        $pos = 0;
2284*55efc227SAndreas Gohr
2285*55efc227SAndreas Gohr        $IPTCNames =& $this->_iptcNameTags();
2286*55efc227SAndreas Gohr
2287*55efc227SAndreas Gohr        reset($this->_info['iptc']);
2288*55efc227SAndreas Gohr
2289*55efc227SAndreas Gohr
2290*55efc227SAndreas Gohr        while (list($label) = each($this->_info['iptc'])) {
2291*55efc227SAndreas Gohr            $value =& $this->_info['iptc'][$label];
2292*55efc227SAndreas Gohr            $type = -1;
2293*55efc227SAndreas Gohr
2294*55efc227SAndreas Gohr            if (isset($IPTCNames[$label])) {
2295*55efc227SAndreas Gohr                $type = $IPTCNames[$label];
2296*55efc227SAndreas Gohr            }
2297*55efc227SAndreas Gohr            elseif (substr($label, 0, 7) == "IPTC_0x") {
2298*55efc227SAndreas Gohr                $type = hexdec(substr($label, 7, 2));
2299*55efc227SAndreas Gohr            }
2300*55efc227SAndreas Gohr
2301*55efc227SAndreas Gohr            if ($type != -1) {
2302*55efc227SAndreas Gohr                if (is_array($value)) {
2303*55efc227SAndreas Gohr                    for ($i = 0; $i < count($value); $i++) {
2304*55efc227SAndreas Gohr                        $pos = $this->_writeIPTCEntry($data, $pos, $type, $value[$i]);
2305*55efc227SAndreas Gohr                    }
2306*55efc227SAndreas Gohr                }
2307*55efc227SAndreas Gohr                else {
2308*55efc227SAndreas Gohr                    $pos = $this->_writeIPTCEntry($data, $pos, $type, $value);
2309*55efc227SAndreas Gohr                }
2310*55efc227SAndreas Gohr            }
2311*55efc227SAndreas Gohr        }
2312*55efc227SAndreas Gohr
2313*55efc227SAndreas Gohr        return $data;
2314*55efc227SAndreas Gohr    }
2315*55efc227SAndreas Gohr
2316*55efc227SAndreas Gohr    /*************************************************************/
2317*55efc227SAndreas Gohr    function _writeIPTCEntry(&$data, $pos, $type, &$value)
2318*55efc227SAndreas Gohr    {
2319*55efc227SAndreas Gohr        $pos = $this->_putShort($data, $pos, 0x1C02);
2320*55efc227SAndreas Gohr        $pos = $this->_putByte($data, $pos, $type);
2321*55efc227SAndreas Gohr        $pos = $this->_putShort($data, $pos, strlen($value));
2322*55efc227SAndreas Gohr        $pos = $this->_putString($data, $pos, $value);
2323*55efc227SAndreas Gohr
2324*55efc227SAndreas Gohr        return $pos;
2325*55efc227SAndreas Gohr    }
2326*55efc227SAndreas Gohr
2327*55efc227SAndreas Gohr    /*************************************************************/
2328*55efc227SAndreas Gohr    function _exifTagNames($mode)
2329*55efc227SAndreas Gohr    {
2330*55efc227SAndreas Gohr        $tags = array();
2331*55efc227SAndreas Gohr
2332*55efc227SAndreas Gohr        if ($mode == 'ifd0') {
2333*55efc227SAndreas Gohr            $tags[0x010E] = 'ImageDescription';
2334*55efc227SAndreas Gohr            $tags[0x010F] = 'Make';
2335*55efc227SAndreas Gohr            $tags[0x0110] = 'Model';
2336*55efc227SAndreas Gohr            $tags[0x0112] = 'Orientation';
2337*55efc227SAndreas Gohr            $tags[0x011A] = 'XResolution';
2338*55efc227SAndreas Gohr            $tags[0x011B] = 'YResolution';
2339*55efc227SAndreas Gohr            $tags[0x0128] = 'ResolutionUnit';
2340*55efc227SAndreas Gohr            $tags[0x0131] = 'Software';
2341*55efc227SAndreas Gohr            $tags[0x0132] = 'DateTime';
2342*55efc227SAndreas Gohr            $tags[0x013B] = 'Artist';
2343*55efc227SAndreas Gohr            $tags[0x013E] = 'WhitePoint';
2344*55efc227SAndreas Gohr            $tags[0x013F] = 'PrimaryChromaticities';
2345*55efc227SAndreas Gohr            $tags[0x0211] = 'YCbCrCoefficients';
2346*55efc227SAndreas Gohr            $tags[0x0212] = 'YCbCrSubSampling';
2347*55efc227SAndreas Gohr            $tags[0x0213] = 'YCbCrPositioning';
2348*55efc227SAndreas Gohr            $tags[0x0214] = 'ReferenceBlackWhite';
2349*55efc227SAndreas Gohr            $tags[0x8298] = 'Copyright';
2350*55efc227SAndreas Gohr            $tags[0x8769] = 'ExifIFDOffset';
2351*55efc227SAndreas Gohr            $tags[0x8825] = 'GPSIFDOffset';
2352*55efc227SAndreas Gohr        }
2353*55efc227SAndreas Gohr        if ($mode == 'ifd1') {
2354*55efc227SAndreas Gohr            $tags[0x00FE] = 'TIFFNewSubfileType';
2355*55efc227SAndreas Gohr            $tags[0x00FF] = 'TIFFSubfileType';
2356*55efc227SAndreas Gohr            $tags[0x0100] = 'TIFFImageWidth';
2357*55efc227SAndreas Gohr            $tags[0x0101] = 'TIFFImageHeight';
2358*55efc227SAndreas Gohr            $tags[0x0102] = 'TIFFBitsPerSample';
2359*55efc227SAndreas Gohr            $tags[0x0103] = 'TIFFCompression';
2360*55efc227SAndreas Gohr            $tags[0x0106] = 'TIFFPhotometricInterpretation';
2361*55efc227SAndreas Gohr            $tags[0x0107] = 'TIFFThreshholding';
2362*55efc227SAndreas Gohr            $tags[0x0108] = 'TIFFCellWidth';
2363*55efc227SAndreas Gohr            $tags[0x0109] = 'TIFFCellLength';
2364*55efc227SAndreas Gohr            $tags[0x010A] = 'TIFFFillOrder';
2365*55efc227SAndreas Gohr            $tags[0x010E] = 'TIFFImageDescription';
2366*55efc227SAndreas Gohr            $tags[0x010F] = 'TIFFMake';
2367*55efc227SAndreas Gohr            $tags[0x0110] = 'TIFFModel';
2368*55efc227SAndreas Gohr            $tags[0x0111] = 'TIFFStripOffsets';
2369*55efc227SAndreas Gohr            $tags[0x0112] = 'TIFFOrientation';
2370*55efc227SAndreas Gohr            $tags[0x0115] = 'TIFFSamplesPerPixel';
2371*55efc227SAndreas Gohr            $tags[0x0116] = 'TIFFRowsPerStrip';
2372*55efc227SAndreas Gohr            $tags[0x0117] = 'TIFFStripByteCounts';
2373*55efc227SAndreas Gohr            $tags[0x0118] = 'TIFFMinSampleValue';
2374*55efc227SAndreas Gohr            $tags[0x0119] = 'TIFFMaxSampleValue';
2375*55efc227SAndreas Gohr            $tags[0x011A] = 'TIFFXResolution';
2376*55efc227SAndreas Gohr            $tags[0x011B] = 'TIFFYResolution';
2377*55efc227SAndreas Gohr            $tags[0x011C] = 'TIFFPlanarConfiguration';
2378*55efc227SAndreas Gohr            $tags[0x0122] = 'TIFFGrayResponseUnit';
2379*55efc227SAndreas Gohr            $tags[0x0123] = 'TIFFGrayResponseCurve';
2380*55efc227SAndreas Gohr            $tags[0x0128] = 'TIFFResolutionUnit';
2381*55efc227SAndreas Gohr            $tags[0x0131] = 'TIFFSoftware';
2382*55efc227SAndreas Gohr            $tags[0x0132] = 'TIFFDateTime';
2383*55efc227SAndreas Gohr            $tags[0x013B] = 'TIFFArtist';
2384*55efc227SAndreas Gohr            $tags[0x013C] = 'TIFFHostComputer';
2385*55efc227SAndreas Gohr            $tags[0x0140] = 'TIFFColorMap';
2386*55efc227SAndreas Gohr            $tags[0x0152] = 'TIFFExtraSamples';
2387*55efc227SAndreas Gohr            $tags[0x0201] = 'TIFFJFIFOffset';
2388*55efc227SAndreas Gohr            $tags[0x0202] = 'TIFFJFIFLength';
2389*55efc227SAndreas Gohr            $tags[0x0211] = 'TIFFYCbCrCoefficients';
2390*55efc227SAndreas Gohr            $tags[0x0212] = 'TIFFYCbCrSubSampling';
2391*55efc227SAndreas Gohr            $tags[0x0213] = 'TIFFYCbCrPositioning';
2392*55efc227SAndreas Gohr            $tags[0x0214] = 'TIFFReferenceBlackWhite';
2393*55efc227SAndreas Gohr            $tags[0x8298] = 'TIFFCopyright';
2394*55efc227SAndreas Gohr            $tags[0x9286] = 'TIFFUserComment';
2395*55efc227SAndreas Gohr        }
2396*55efc227SAndreas Gohr        elseif ($mode == 'exif') {
2397*55efc227SAndreas Gohr            $tags[0x829A] = 'ExposureTime';
2398*55efc227SAndreas Gohr            $tags[0x829D] = 'FNumber';
2399*55efc227SAndreas Gohr            $tags[0x8822] = 'ExposureProgram';
2400*55efc227SAndreas Gohr            $tags[0x8824] = 'SpectralSensitivity';
2401*55efc227SAndreas Gohr            $tags[0x8827] = 'ISOSpeedRatings';
2402*55efc227SAndreas Gohr            $tags[0x8828] = 'OECF';
2403*55efc227SAndreas Gohr            $tags[0x9000] = 'EXIFVersion';
2404*55efc227SAndreas Gohr            $tags[0x9003] = 'DatetimeOriginal';
2405*55efc227SAndreas Gohr            $tags[0x9004] = 'DatetimeDigitized';
2406*55efc227SAndreas Gohr            $tags[0x9101] = 'ComponentsConfiguration';
2407*55efc227SAndreas Gohr            $tags[0x9102] = 'CompressedBitsPerPixel';
2408*55efc227SAndreas Gohr            $tags[0x9201] = 'ShutterSpeedValue';
2409*55efc227SAndreas Gohr            $tags[0x9202] = 'ApertureValue';
2410*55efc227SAndreas Gohr            $tags[0x9203] = 'BrightnessValue';
2411*55efc227SAndreas Gohr            $tags[0x9204] = 'ExposureBiasValue';
2412*55efc227SAndreas Gohr            $tags[0x9205] = 'MaxApertureValue';
2413*55efc227SAndreas Gohr            $tags[0x9206] = 'SubjectDistance';
2414*55efc227SAndreas Gohr            $tags[0x9207] = 'MeteringMode';
2415*55efc227SAndreas Gohr            $tags[0x9208] = 'LightSource';
2416*55efc227SAndreas Gohr            $tags[0x9209] = 'Flash';
2417*55efc227SAndreas Gohr            $tags[0x920A] = 'FocalLength';
2418*55efc227SAndreas Gohr            $tags[0x927C] = 'MakerNote';
2419*55efc227SAndreas Gohr            $tags[0x9286] = 'UserComment';
2420*55efc227SAndreas Gohr            $tags[0x9290] = 'SubSecTime';
2421*55efc227SAndreas Gohr            $tags[0x9291] = 'SubSecTimeOriginal';
2422*55efc227SAndreas Gohr            $tags[0x9292] = 'SubSecTimeDigitized';
2423*55efc227SAndreas Gohr            $tags[0xA000] = 'FlashPixVersion';
2424*55efc227SAndreas Gohr            $tags[0xA001] = 'ColorSpace';
2425*55efc227SAndreas Gohr            $tags[0xA002] = 'PixelXDimension';
2426*55efc227SAndreas Gohr            $tags[0xA003] = 'PixelYDimension';
2427*55efc227SAndreas Gohr            $tags[0xA004] = 'RelatedSoundFile';
2428*55efc227SAndreas Gohr            $tags[0xA005] = 'InteropIFDOffset';
2429*55efc227SAndreas Gohr            $tags[0xA20B] = 'FlashEnergy';
2430*55efc227SAndreas Gohr            $tags[0xA20C] = 'SpatialFrequencyResponse';
2431*55efc227SAndreas Gohr            $tags[0xA20E] = 'FocalPlaneXResolution';
2432*55efc227SAndreas Gohr            $tags[0xA20F] = 'FocalPlaneYResolution';
2433*55efc227SAndreas Gohr            $tags[0xA210] = 'FocalPlaneResolutionUnit';
2434*55efc227SAndreas Gohr            $tags[0xA214] = 'SubjectLocation';
2435*55efc227SAndreas Gohr            $tags[0xA215] = 'ExposureIndex';
2436*55efc227SAndreas Gohr            $tags[0xA217] = 'SensingMethod';
2437*55efc227SAndreas Gohr            $tags[0xA300] = 'FileSource';
2438*55efc227SAndreas Gohr            $tags[0xA301] = 'SceneType';
2439*55efc227SAndreas Gohr            $tags[0xA302] = 'CFAPattern';
2440*55efc227SAndreas Gohr        }
2441*55efc227SAndreas Gohr        elseif ($mode == 'interop') {
2442*55efc227SAndreas Gohr            $tags[0x0001] = 'InteroperabilityIndex';
2443*55efc227SAndreas Gohr            $tags[0x0002] = 'InteroperabilityVersion';
2444*55efc227SAndreas Gohr            $tags[0x1000] = 'RelatedImageFileFormat';
2445*55efc227SAndreas Gohr            $tags[0x1001] = 'RelatedImageWidth';
2446*55efc227SAndreas Gohr            $tags[0x1002] = 'RelatedImageLength';
2447*55efc227SAndreas Gohr        }
2448*55efc227SAndreas Gohr        elseif ($mode == 'gps') {
2449*55efc227SAndreas Gohr            $tags[0x0000] = 'GPSVersionID';
2450*55efc227SAndreas Gohr            $tags[0x0001] = 'GPSLatitudeRef';
2451*55efc227SAndreas Gohr            $tags[0x0002] = 'GPSLatitude';
2452*55efc227SAndreas Gohr            $tags[0x0003] = 'GPSLongitudeRef';
2453*55efc227SAndreas Gohr            $tags[0x0004] = 'GPSLongitude';
2454*55efc227SAndreas Gohr            $tags[0x0005] = 'GPSAltitudeRef';
2455*55efc227SAndreas Gohr            $tags[0x0006] = 'GPSAltitude';
2456*55efc227SAndreas Gohr            $tags[0x0007] = 'GPSTimeStamp';
2457*55efc227SAndreas Gohr            $tags[0x0008] = 'GPSSatellites';
2458*55efc227SAndreas Gohr            $tags[0x0009] = 'GPSStatus';
2459*55efc227SAndreas Gohr            $tags[0x000A] = 'GPSMeasureMode';
2460*55efc227SAndreas Gohr            $tags[0x000B] = 'GPSDOP';
2461*55efc227SAndreas Gohr            $tags[0x000C] = 'GPSSpeedRef';
2462*55efc227SAndreas Gohr            $tags[0x000D] = 'GPSSpeed';
2463*55efc227SAndreas Gohr            $tags[0x000E] = 'GPSTrackRef';
2464*55efc227SAndreas Gohr            $tags[0x000F] = 'GPSTrack';
2465*55efc227SAndreas Gohr            $tags[0x0010] = 'GPSImgDirectionRef';
2466*55efc227SAndreas Gohr            $tags[0x0011] = 'GPSImgDirection';
2467*55efc227SAndreas Gohr            $tags[0x0012] = 'GPSMapDatum';
2468*55efc227SAndreas Gohr            $tags[0x0013] = 'GPSDestLatitudeRef';
2469*55efc227SAndreas Gohr            $tags[0x0014] = 'GPSDestLatitude';
2470*55efc227SAndreas Gohr            $tags[0x0015] = 'GPSDestLongitudeRef';
2471*55efc227SAndreas Gohr            $tags[0x0016] = 'GPSDestLongitude';
2472*55efc227SAndreas Gohr            $tags[0x0017] = 'GPSDestBearingRef';
2473*55efc227SAndreas Gohr            $tags[0x0018] = 'GPSDestBearing';
2474*55efc227SAndreas Gohr            $tags[0x0019] = 'GPSDestDistanceRef';
2475*55efc227SAndreas Gohr            $tags[0x001A] = 'GPSDestDistance';
2476*55efc227SAndreas Gohr        }
2477*55efc227SAndreas Gohr
2478*55efc227SAndreas Gohr        return $tags;
2479*55efc227SAndreas Gohr    }
2480*55efc227SAndreas Gohr
2481*55efc227SAndreas Gohr    /*************************************************************/
2482*55efc227SAndreas Gohr    function _exifTagTypes($mode)
2483*55efc227SAndreas Gohr    {
2484*55efc227SAndreas Gohr        $tags = array();
2485*55efc227SAndreas Gohr
2486*55efc227SAndreas Gohr        if ($mode == 'ifd0') {
2487*55efc227SAndreas Gohr            $tags[0x010E] = array(2, 0); // ImageDescription -> ASCII, Any
2488*55efc227SAndreas Gohr            $tags[0x010F] = array(2, 0); // Make -> ASCII, Any
2489*55efc227SAndreas Gohr            $tags[0x0110] = array(2, 0); // Model -> ASCII, Any
2490*55efc227SAndreas Gohr            $tags[0x0112] = array(3, 1); // Orientation -> SHORT, 1
2491*55efc227SAndreas Gohr            $tags[0x011A] = array(5, 1); // XResolution -> RATIONAL, 1
2492*55efc227SAndreas Gohr            $tags[0x011B] = array(5, 1); // YResolution -> RATIONAL, 1
2493*55efc227SAndreas Gohr            $tags[0x0128] = array(3, 1); // ResolutionUnit -> SHORT
2494*55efc227SAndreas Gohr            $tags[0x0131] = array(2, 0); // Software -> ASCII, Any
2495*55efc227SAndreas Gohr            $tags[0x0132] = array(2, 20); // DateTime -> ASCII, 20
2496*55efc227SAndreas Gohr            $tags[0x013B] = array(2, 0); // Artist -> ASCII, Any
2497*55efc227SAndreas Gohr            $tags[0x013E] = array(5, 2); // WhitePoint -> RATIONAL, 2
2498*55efc227SAndreas Gohr            $tags[0x013F] = array(5, 6); // PrimaryChromaticities -> RATIONAL, 6
2499*55efc227SAndreas Gohr            $tags[0x0211] = array(5, 3); // YCbCrCoefficients -> RATIONAL, 3
2500*55efc227SAndreas Gohr            $tags[0x0212] = array(3, 2); // YCbCrSubSampling -> SHORT, 2
2501*55efc227SAndreas Gohr            $tags[0x0213] = array(3, 1); // YCbCrPositioning -> SHORT, 1
2502*55efc227SAndreas Gohr            $tags[0x0214] = array(5, 6); // ReferenceBlackWhite -> RATIONAL, 6
2503*55efc227SAndreas Gohr            $tags[0x8298] = array(2, 0); // Copyright -> ASCII, Any
2504*55efc227SAndreas Gohr            $tags[0x8769] = array(4, 1); // ExifIFDOffset -> LONG, 1
2505*55efc227SAndreas Gohr            $tags[0x8825] = array(4, 1); // GPSIFDOffset -> LONG, 1
2506*55efc227SAndreas Gohr        }
2507*55efc227SAndreas Gohr        if ($mode == 'ifd1') {
2508*55efc227SAndreas Gohr            $tags[0x00FE] = array(4, 1); // TIFFNewSubfileType -> LONG, 1
2509*55efc227SAndreas Gohr            $tags[0x00FF] = array(3, 1); // TIFFSubfileType -> SHORT, 1
2510*55efc227SAndreas Gohr            $tags[0x0100] = array(4, 1); // TIFFImageWidth -> LONG (or SHORT), 1
2511*55efc227SAndreas Gohr            $tags[0x0101] = array(4, 1); // TIFFImageHeight -> LONG (or SHORT), 1
2512*55efc227SAndreas Gohr            $tags[0x0102] = array(3, 3); // TIFFBitsPerSample -> SHORT, 3
2513*55efc227SAndreas Gohr            $tags[0x0103] = array(3, 1); // TIFFCompression -> SHORT, 1
2514*55efc227SAndreas Gohr            $tags[0x0106] = array(3, 1); // TIFFPhotometricInterpretation -> SHORT, 1
2515*55efc227SAndreas Gohr            $tags[0x0107] = array(3, 1); // TIFFThreshholding -> SHORT, 1
2516*55efc227SAndreas Gohr            $tags[0x0108] = array(3, 1); // TIFFCellWidth -> SHORT, 1
2517*55efc227SAndreas Gohr            $tags[0x0109] = array(3, 1); // TIFFCellLength -> SHORT, 1
2518*55efc227SAndreas Gohr            $tags[0x010A] = array(3, 1); // TIFFFillOrder -> SHORT, 1
2519*55efc227SAndreas Gohr            $tags[0x010E] = array(2, 0); // TIFFImageDescription -> ASCII, Any
2520*55efc227SAndreas Gohr            $tags[0x010F] = array(2, 0); // TIFFMake -> ASCII, Any
2521*55efc227SAndreas Gohr            $tags[0x0110] = array(2, 0); // TIFFModel -> ASCII, Any
2522*55efc227SAndreas Gohr            $tags[0x0111] = array(4, 0); // TIFFStripOffsets -> LONG (or SHORT), Any (one per strip)
2523*55efc227SAndreas Gohr            $tags[0x0112] = array(3, 1); // TIFFOrientation -> SHORT, 1
2524*55efc227SAndreas Gohr            $tags[0x0115] = array(3, 1); // TIFFSamplesPerPixel -> SHORT, 1
2525*55efc227SAndreas Gohr            $tags[0x0116] = array(4, 1); // TIFFRowsPerStrip -> LONG (or SHORT), 1
2526*55efc227SAndreas Gohr            $tags[0x0117] = array(4, 0); // TIFFStripByteCounts -> LONG (or SHORT), Any (one per strip)
2527*55efc227SAndreas Gohr            $tags[0x0118] = array(3, 0); // TIFFMinSampleValue -> SHORT, Any (SamplesPerPixel)
2528*55efc227SAndreas Gohr            $tags[0x0119] = array(3, 0); // TIFFMaxSampleValue -> SHORT, Any (SamplesPerPixel)
2529*55efc227SAndreas Gohr            $tags[0x011A] = array(5, 1); // TIFFXResolution -> RATIONAL, 1
2530*55efc227SAndreas Gohr            $tags[0x011B] = array(5, 1); // TIFFYResolution -> RATIONAL, 1
2531*55efc227SAndreas Gohr            $tags[0x011C] = array(3, 1); // TIFFPlanarConfiguration -> SHORT, 1
2532*55efc227SAndreas Gohr            $tags[0x0122] = array(3, 1); // TIFFGrayResponseUnit -> SHORT, 1
2533*55efc227SAndreas Gohr            $tags[0x0123] = array(3, 0); // TIFFGrayResponseCurve -> SHORT, Any (2^BitsPerSample)
2534*55efc227SAndreas Gohr            $tags[0x0128] = array(3, 1); // TIFFResolutionUnit -> SHORT, 1
2535*55efc227SAndreas Gohr            $tags[0x0131] = array(2, 0); // TIFFSoftware -> ASCII, Any
2536*55efc227SAndreas Gohr            $tags[0x0132] = array(2, 20); // TIFFDateTime -> ASCII, 20
2537*55efc227SAndreas Gohr            $tags[0x013B] = array(2, 0); // TIFFArtist -> ASCII, Any
2538*55efc227SAndreas Gohr            $tags[0x013C] = array(2, 0); // TIFFHostComputer -> ASCII, Any
2539*55efc227SAndreas Gohr            $tags[0x0140] = array(3, 0); // TIFFColorMap -> SHORT, Any (3 * 2^BitsPerSample)
2540*55efc227SAndreas Gohr            $tags[0x0152] = array(3, 0); // TIFFExtraSamples -> SHORT, Any (SamplesPerPixel - 3)
2541*55efc227SAndreas Gohr            $tags[0x0201] = array(4, 1); // TIFFJFIFOffset -> LONG, 1
2542*55efc227SAndreas Gohr            $tags[0x0202] = array(4, 1); // TIFFJFIFLength -> LONG, 1
2543*55efc227SAndreas Gohr            $tags[0x0211] = array(5, 3); // TIFFYCbCrCoefficients -> RATIONAL, 3
2544*55efc227SAndreas Gohr            $tags[0x0212] = array(3, 2); // TIFFYCbCrSubSampling -> SHORT, 2
2545*55efc227SAndreas Gohr            $tags[0x0213] = array(3, 1); // TIFFYCbCrPositioning -> SHORT, 1
2546*55efc227SAndreas Gohr            $tags[0x0214] = array(5, 6); // TIFFReferenceBlackWhite -> RATIONAL, 6
2547*55efc227SAndreas Gohr            $tags[0x8298] = array(2, 0); // TIFFCopyright -> ASCII, Any
2548*55efc227SAndreas Gohr            $tags[0x9286] = array(2, 0); // TIFFUserComment -> ASCII, Any
2549*55efc227SAndreas Gohr        }
2550*55efc227SAndreas Gohr        elseif ($mode == 'exif') {
2551*55efc227SAndreas Gohr            $tags[0x829A] = array(5, 1); // ExposureTime -> RATIONAL, 1
2552*55efc227SAndreas Gohr            $tags[0x829D] = array(5, 1); // FNumber -> RATIONAL, 1
2553*55efc227SAndreas Gohr            $tags[0x8822] = array(3, 1); // ExposureProgram -> SHORT, 1
2554*55efc227SAndreas Gohr            $tags[0x8824] = array(2, 0); // SpectralSensitivity -> ASCII, Any
2555*55efc227SAndreas Gohr            $tags[0x8827] = array(3, 0); // ISOSpeedRatings -> SHORT, Any
2556*55efc227SAndreas Gohr            $tags[0x8828] = array(7, 0); // OECF -> UNDEFINED, Any
2557*55efc227SAndreas Gohr            $tags[0x9000] = array(7, 4); // EXIFVersion -> UNDEFINED, 4
2558*55efc227SAndreas Gohr            $tags[0x9003] = array(2, 20); // DatetimeOriginal -> ASCII, 20
2559*55efc227SAndreas Gohr            $tags[0x9004] = array(2, 20); // DatetimeDigitized -> ASCII, 20
2560*55efc227SAndreas Gohr            $tags[0x9101] = array(7, 4); // ComponentsConfiguration -> UNDEFINED, 4
2561*55efc227SAndreas Gohr            $tags[0x9102] = array(5, 1); // CompressedBitsPerPixel -> RATIONAL, 1
2562*55efc227SAndreas Gohr            $tags[0x9201] = array(10, 1); // ShutterSpeedValue -> SRATIONAL, 1
2563*55efc227SAndreas Gohr            $tags[0x9202] = array(5, 1); // ApertureValue -> RATIONAL, 1
2564*55efc227SAndreas Gohr            $tags[0x9203] = array(10, 1); // BrightnessValue -> SRATIONAL, 1
2565*55efc227SAndreas Gohr            $tags[0x9204] = array(10, 1); // ExposureBiasValue -> SRATIONAL, 1
2566*55efc227SAndreas Gohr            $tags[0x9205] = array(5, 1); // MaxApertureValue -> RATIONAL, 1
2567*55efc227SAndreas Gohr            $tags[0x9206] = array(5, 1); // SubjectDistance -> RATIONAL, 1
2568*55efc227SAndreas Gohr            $tags[0x9207] = array(3, 1); // MeteringMode -> SHORT, 1
2569*55efc227SAndreas Gohr            $tags[0x9208] = array(3, 1); // LightSource -> SHORT, 1
2570*55efc227SAndreas Gohr            $tags[0x9209] = array(3, 1); // Flash -> SHORT, 1
2571*55efc227SAndreas Gohr            $tags[0x920A] = array(5, 1); // FocalLength -> RATIONAL, 1
2572*55efc227SAndreas Gohr            $tags[0x927C] = array(7, 0); // MakerNote -> UNDEFINED, Any
2573*55efc227SAndreas Gohr            $tags[0x9286] = array(7, 0); // UserComment -> UNDEFINED, Any
2574*55efc227SAndreas Gohr            $tags[0x9290] = array(2, 0); // SubSecTime -> ASCII, Any
2575*55efc227SAndreas Gohr            $tags[0x9291] = array(2, 0); // SubSecTimeOriginal -> ASCII, Any
2576*55efc227SAndreas Gohr            $tags[0x9292] = array(2, 0); // SubSecTimeDigitized -> ASCII, Any
2577*55efc227SAndreas Gohr            $tags[0xA000] = array(7, 4); // FlashPixVersion -> UNDEFINED, 4
2578*55efc227SAndreas Gohr            $tags[0xA001] = array(3, 1); // ColorSpace -> SHORT, 1
2579*55efc227SAndreas Gohr            $tags[0xA002] = array(4, 1); // PixelXDimension -> LONG (or SHORT), 1
2580*55efc227SAndreas Gohr            $tags[0xA003] = array(4, 1); // PixelYDimension -> LONG (or SHORT), 1
2581*55efc227SAndreas Gohr            $tags[0xA004] = array(2, 13); // RelatedSoundFile -> ASCII, 13
2582*55efc227SAndreas Gohr            $tags[0xA005] = array(4, 1); // InteropIFDOffset -> LONG, 1
2583*55efc227SAndreas Gohr            $tags[0xA20B] = array(5, 1); // FlashEnergy -> RATIONAL, 1
2584*55efc227SAndreas Gohr            $tags[0xA20C] = array(7, 0); // SpatialFrequencyResponse -> UNDEFINED, Any
2585*55efc227SAndreas Gohr            $tags[0xA20E] = array(5, 1); // FocalPlaneXResolution -> RATIONAL, 1
2586*55efc227SAndreas Gohr            $tags[0xA20F] = array(5, 1); // FocalPlaneYResolution -> RATIONAL, 1
2587*55efc227SAndreas Gohr            $tags[0xA210] = array(3, 1); // FocalPlaneResolutionUnit -> SHORT, 1
2588*55efc227SAndreas Gohr            $tags[0xA214] = array(3, 2); // SubjectLocation -> SHORT, 2
2589*55efc227SAndreas Gohr            $tags[0xA215] = array(5, 1); // ExposureIndex -> RATIONAL, 1
2590*55efc227SAndreas Gohr            $tags[0xA217] = array(3, 1); // SensingMethod -> SHORT, 1
2591*55efc227SAndreas Gohr            $tags[0xA300] = array(7, 1); // FileSource -> UNDEFINED, 1
2592*55efc227SAndreas Gohr            $tags[0xA301] = array(7, 1); // SceneType -> UNDEFINED, 1
2593*55efc227SAndreas Gohr            $tags[0xA302] = array(7, 0); // CFAPattern -> UNDEFINED, Any
2594*55efc227SAndreas Gohr        }
2595*55efc227SAndreas Gohr        elseif ($mode == 'interop') {
2596*55efc227SAndreas Gohr            $tags[0x0001] = array(2, 0); // InteroperabilityIndex -> ASCII, Any
2597*55efc227SAndreas Gohr            $tags[0x0002] = array(7, 4); // InteroperabilityVersion -> UNKNOWN, 4
2598*55efc227SAndreas Gohr            $tags[0x1000] = array(2, 0); // RelatedImageFileFormat -> ASCII, Any
2599*55efc227SAndreas Gohr            $tags[0x1001] = array(4, 1); // RelatedImageWidth -> LONG (or SHORT), 1
2600*55efc227SAndreas Gohr            $tags[0x1002] = array(4, 1); // RelatedImageLength -> LONG (or SHORT), 1
2601*55efc227SAndreas Gohr        }
2602*55efc227SAndreas Gohr        elseif ($mode == 'gps') {
2603*55efc227SAndreas Gohr            $tags[0x0000] = array(1, 4); // GPSVersionID -> BYTE, 4
2604*55efc227SAndreas Gohr            $tags[0x0001] = array(2, 2); // GPSLatitudeRef -> ASCII, 2
2605*55efc227SAndreas Gohr            $tags[0x0002] = array(5, 3); // GPSLatitude -> RATIONAL, 3
2606*55efc227SAndreas Gohr            $tags[0x0003] = array(2, 2); // GPSLongitudeRef -> ASCII, 2
2607*55efc227SAndreas Gohr            $tags[0x0004] = array(5, 3); // GPSLongitude -> RATIONAL, 3
2608*55efc227SAndreas Gohr            $tags[0x0005] = array(2, 2); // GPSAltitudeRef -> ASCII, 2
2609*55efc227SAndreas Gohr            $tags[0x0006] = array(5, 1); // GPSAltitude -> RATIONAL, 1
2610*55efc227SAndreas Gohr            $tags[0x0007] = array(5, 3); // GPSTimeStamp -> RATIONAL, 3
2611*55efc227SAndreas Gohr            $tags[0x0008] = array(2, 0); // GPSSatellites -> ASCII, Any
2612*55efc227SAndreas Gohr            $tags[0x0009] = array(2, 2); // GPSStatus -> ASCII, 2
2613*55efc227SAndreas Gohr            $tags[0x000A] = array(2, 2); // GPSMeasureMode -> ASCII, 2
2614*55efc227SAndreas Gohr            $tags[0x000B] = array(5, 1); // GPSDOP -> RATIONAL, 1
2615*55efc227SAndreas Gohr            $tags[0x000C] = array(2, 2); // GPSSpeedRef -> ASCII, 2
2616*55efc227SAndreas Gohr            $tags[0x000D] = array(5, 1); // GPSSpeed -> RATIONAL, 1
2617*55efc227SAndreas Gohr            $tags[0x000E] = array(2, 2); // GPSTrackRef -> ASCII, 2
2618*55efc227SAndreas Gohr            $tags[0x000F] = array(5, 1); // GPSTrack -> RATIONAL, 1
2619*55efc227SAndreas Gohr            $tags[0x0010] = array(2, 2); // GPSImgDirectionRef -> ASCII, 2
2620*55efc227SAndreas Gohr            $tags[0x0011] = array(5, 1); // GPSImgDirection -> RATIONAL, 1
2621*55efc227SAndreas Gohr            $tags[0x0012] = array(2, 0); // GPSMapDatum -> ASCII, Any
2622*55efc227SAndreas Gohr            $tags[0x0013] = array(2, 2); // GPSDestLatitudeRef -> ASCII, 2
2623*55efc227SAndreas Gohr            $tags[0x0014] = array(5, 3); // GPSDestLatitude -> RATIONAL, 3
2624*55efc227SAndreas Gohr            $tags[0x0015] = array(2, 2); // GPSDestLongitudeRef -> ASCII, 2
2625*55efc227SAndreas Gohr            $tags[0x0016] = array(5, 3); // GPSDestLongitude -> RATIONAL, 3
2626*55efc227SAndreas Gohr            $tags[0x0017] = array(2, 2); // GPSDestBearingRef -> ASCII, 2
2627*55efc227SAndreas Gohr            $tags[0x0018] = array(5, 1); // GPSDestBearing -> RATIONAL, 1
2628*55efc227SAndreas Gohr            $tags[0x0019] = array(2, 2); // GPSDestDistanceRef -> ASCII, 2
2629*55efc227SAndreas Gohr            $tags[0x001A] = array(5, 1); // GPSDestDistance -> RATIONAL, 1
2630*55efc227SAndreas Gohr        }
2631*55efc227SAndreas Gohr
2632*55efc227SAndreas Gohr        return $tags;
2633*55efc227SAndreas Gohr    }
2634*55efc227SAndreas Gohr
2635*55efc227SAndreas Gohr    /*************************************************************/
2636*55efc227SAndreas Gohr    function _exifNameTags($mode)
2637*55efc227SAndreas Gohr    {
2638*55efc227SAndreas Gohr        $tags = $this->_exifTagNames($mode);
2639*55efc227SAndreas Gohr        return $this->_names2Tags($tags);
2640*55efc227SAndreas Gohr    }
2641*55efc227SAndreas Gohr
2642*55efc227SAndreas Gohr    /*************************************************************/
2643*55efc227SAndreas Gohr    function _iptcTagNames()
2644*55efc227SAndreas Gohr    {
2645*55efc227SAndreas Gohr        $tags = array();
2646*55efc227SAndreas Gohr        $tags[0x14] = 'SuplementalCategories';
2647*55efc227SAndreas Gohr        $tags[0x19] = 'Keywords';
2648*55efc227SAndreas Gohr        $tags[0x78] = 'Caption';
2649*55efc227SAndreas Gohr        $tags[0x7A] = 'CaptionWriter';
2650*55efc227SAndreas Gohr        $tags[0x69] = 'Headline';
2651*55efc227SAndreas Gohr        $tags[0x28] = 'SpecialInstructions';
2652*55efc227SAndreas Gohr        $tags[0x0F] = 'Category';
2653*55efc227SAndreas Gohr        $tags[0x50] = 'Byline';
2654*55efc227SAndreas Gohr        $tags[0x55] = 'BylineTitle';
2655*55efc227SAndreas Gohr        $tags[0x6E] = 'Credit';
2656*55efc227SAndreas Gohr        $tags[0x73] = 'Source';
2657*55efc227SAndreas Gohr        $tags[0x74] = 'CopyrightNotice';
2658*55efc227SAndreas Gohr        $tags[0x05] = 'ObjectName';
2659*55efc227SAndreas Gohr        $tags[0x5A] = 'City';
2660*55efc227SAndreas Gohr        $tags[0x5F] = 'ProvinceState';
2661*55efc227SAndreas Gohr        $tags[0x65] = 'CountryName';
2662*55efc227SAndreas Gohr        $tags[0x67] = 'OriginalTransmissionReference';
2663*55efc227SAndreas Gohr        $tags[0x37] = 'DateCreated';
2664*55efc227SAndreas Gohr        $tags[0x0A] = 'CopyrightFlag';
2665*55efc227SAndreas Gohr
2666*55efc227SAndreas Gohr        return $tags;
2667*55efc227SAndreas Gohr    }
2668*55efc227SAndreas Gohr
2669*55efc227SAndreas Gohr    /*************************************************************/
2670*55efc227SAndreas Gohr    function & _iptcNameTags()
2671*55efc227SAndreas Gohr    {
2672*55efc227SAndreas Gohr        $tags = $this->_iptcTagNames();
2673*55efc227SAndreas Gohr        return $this->_names2Tags($tags);
2674*55efc227SAndreas Gohr    }
2675*55efc227SAndreas Gohr
2676*55efc227SAndreas Gohr    /*************************************************************/
2677*55efc227SAndreas Gohr    function _names2Tags($tags2Names)
2678*55efc227SAndreas Gohr    {
2679*55efc227SAndreas Gohr        $names2Tags = array();
2680*55efc227SAndreas Gohr        reset($tags2Names);
2681*55efc227SAndreas Gohr        while (list($tag, $name) = each($tags2Names)) {
2682*55efc227SAndreas Gohr            $names2Tags[$name] = $tag;
2683*55efc227SAndreas Gohr        }
2684*55efc227SAndreas Gohr
2685*55efc227SAndreas Gohr        return $names2Tags;
2686*55efc227SAndreas Gohr    }
2687*55efc227SAndreas Gohr
2688*55efc227SAndreas Gohr    /*************************************************************/
2689*55efc227SAndreas Gohr    function _getByte(&$data, $pos)
2690*55efc227SAndreas Gohr    {
2691*55efc227SAndreas Gohr        return ord($data{$pos});
2692*55efc227SAndreas Gohr    }
2693*55efc227SAndreas Gohr
2694*55efc227SAndreas Gohr    /*************************************************************/
2695*55efc227SAndreas Gohr    function _putByte(&$data, $pos, $val)
2696*55efc227SAndreas Gohr    {
2697*55efc227SAndreas Gohr        $val = intval($val);
2698*55efc227SAndreas Gohr
2699*55efc227SAndreas Gohr        $data{$pos} = chr($val);
2700*55efc227SAndreas Gohr
2701*55efc227SAndreas Gohr        return $pos + 1;
2702*55efc227SAndreas Gohr    }
2703*55efc227SAndreas Gohr
2704*55efc227SAndreas Gohr    /*************************************************************/
2705*55efc227SAndreas Gohr    function _getShort(&$data, $pos, $bigEndian = true)
2706*55efc227SAndreas Gohr    {
2707*55efc227SAndreas Gohr        if ($bigEndian) {
2708*55efc227SAndreas Gohr            return (ord($data{$pos}) << 8)
2709*55efc227SAndreas Gohr                   + ord($data{$pos + 1});
2710*55efc227SAndreas Gohr        }
2711*55efc227SAndreas Gohr        else {
2712*55efc227SAndreas Gohr            return ord($data{$pos})
2713*55efc227SAndreas Gohr                   + (ord($data{$pos + 1}) << 8);
2714*55efc227SAndreas Gohr        }
2715*55efc227SAndreas Gohr    }
2716*55efc227SAndreas Gohr
2717*55efc227SAndreas Gohr    /*************************************************************/
2718*55efc227SAndreas Gohr    function _putShort(&$data, $pos = 0, $val, $bigEndian = true)
2719*55efc227SAndreas Gohr    {
2720*55efc227SAndreas Gohr        $val = intval($val);
2721*55efc227SAndreas Gohr
2722*55efc227SAndreas Gohr        if ($bigEndian) {
2723*55efc227SAndreas Gohr            $data{$pos + 0} = chr(($val & 0x0000FF00) >> 8);
2724*55efc227SAndreas Gohr            $data{$pos + 1} = chr(($val & 0x000000FF) >> 0);
2725*55efc227SAndreas Gohr        }
2726*55efc227SAndreas Gohr        else {
2727*55efc227SAndreas Gohr            $data{$pos + 0} = chr(($val & 0x00FF) >> 0);
2728*55efc227SAndreas Gohr            $data{$pos + 1} = chr(($val & 0xFF00) >> 8);
2729*55efc227SAndreas Gohr        }
2730*55efc227SAndreas Gohr
2731*55efc227SAndreas Gohr        return $pos + 2;
2732*55efc227SAndreas Gohr    }
2733*55efc227SAndreas Gohr
2734*55efc227SAndreas Gohr    /*************************************************************/
2735*55efc227SAndreas Gohr    function _getLong(&$data, $pos, $bigEndian = true)
2736*55efc227SAndreas Gohr    {
2737*55efc227SAndreas Gohr        if ($bigEndian) {
2738*55efc227SAndreas Gohr            return (ord($data{$pos}) << 24)
2739*55efc227SAndreas Gohr                   + (ord($data{$pos + 1}) << 16)
2740*55efc227SAndreas Gohr                   + (ord($data{$pos + 2}) << 8)
2741*55efc227SAndreas Gohr                   + ord($data{$pos + 3});
2742*55efc227SAndreas Gohr        }
2743*55efc227SAndreas Gohr        else {
2744*55efc227SAndreas Gohr            return ord($data{$pos})
2745*55efc227SAndreas Gohr                   + (ord($data{$pos + 1}) << 8)
2746*55efc227SAndreas Gohr                   + (ord($data{$pos + 2}) << 16)
2747*55efc227SAndreas Gohr                   + (ord($data{$pos + 3}) << 24);
2748*55efc227SAndreas Gohr        }
2749*55efc227SAndreas Gohr    }
2750*55efc227SAndreas Gohr
2751*55efc227SAndreas Gohr    /*************************************************************/
2752*55efc227SAndreas Gohr    function _putLong(&$data, $pos, $val, $bigEndian = true)
2753*55efc227SAndreas Gohr    {
2754*55efc227SAndreas Gohr        $val = intval($val);
2755*55efc227SAndreas Gohr
2756*55efc227SAndreas Gohr        if ($bigEndian) {
2757*55efc227SAndreas Gohr            $data{$pos + 0} = chr(($val & 0xFF000000) >> 24);
2758*55efc227SAndreas Gohr            $data{$pos + 1} = chr(($val & 0x00FF0000) >> 16);
2759*55efc227SAndreas Gohr            $data{$pos + 2} = chr(($val & 0x0000FF00) >> 8);
2760*55efc227SAndreas Gohr            $data{$pos + 3} = chr(($val & 0x000000FF) >> 0);
2761*55efc227SAndreas Gohr        }
2762*55efc227SAndreas Gohr        else {
2763*55efc227SAndreas Gohr            $data{$pos + 0} = chr(($val & 0x000000FF) >> 0);
2764*55efc227SAndreas Gohr            $data{$pos + 1} = chr(($val & 0x0000FF00) >> 8);
2765*55efc227SAndreas Gohr            $data{$pos + 2} = chr(($val & 0x00FF0000) >> 16);
2766*55efc227SAndreas Gohr            $data{$pos + 3} = chr(($val & 0xFF000000) >> 24);
2767*55efc227SAndreas Gohr        }
2768*55efc227SAndreas Gohr
2769*55efc227SAndreas Gohr        return $pos + 4;
2770*55efc227SAndreas Gohr    }
2771*55efc227SAndreas Gohr
2772*55efc227SAndreas Gohr    /*************************************************************/
2773*55efc227SAndreas Gohr    function & _getNullString(&$data, $pos)
2774*55efc227SAndreas Gohr    {
2775*55efc227SAndreas Gohr        $str = '';
2776*55efc227SAndreas Gohr        $max = strlen($data);
2777*55efc227SAndreas Gohr
2778*55efc227SAndreas Gohr        while ($pos < $max) {
2779*55efc227SAndreas Gohr            if (ord($data{$pos}) == 0) {
2780*55efc227SAndreas Gohr                return $str;
2781*55efc227SAndreas Gohr            }
2782*55efc227SAndreas Gohr            else {
2783*55efc227SAndreas Gohr                $str .= $data{$pos};
2784*55efc227SAndreas Gohr            }
2785*55efc227SAndreas Gohr            $pos++;
2786*55efc227SAndreas Gohr        }
2787*55efc227SAndreas Gohr
2788*55efc227SAndreas Gohr        return $str;
2789*55efc227SAndreas Gohr    }
2790*55efc227SAndreas Gohr
2791*55efc227SAndreas Gohr    /*************************************************************/
2792*55efc227SAndreas Gohr    function & _getFixedString(&$data, $pos, $length = -1)
2793*55efc227SAndreas Gohr    {
2794*55efc227SAndreas Gohr        if ($length == -1) {
2795*55efc227SAndreas Gohr            $length = strlen($data) - $pos;
2796*55efc227SAndreas Gohr        }
2797*55efc227SAndreas Gohr
2798*55efc227SAndreas Gohr        return substr($data, $pos, $length);
2799*55efc227SAndreas Gohr    }
2800*55efc227SAndreas Gohr
2801*55efc227SAndreas Gohr    /*************************************************************/
2802*55efc227SAndreas Gohr    function _putString(&$data, $pos, &$str)
2803*55efc227SAndreas Gohr    {
2804*55efc227SAndreas Gohr        $len = strlen($str);
2805*55efc227SAndreas Gohr        for ($i = 0; $i < $len; $i++) {
2806*55efc227SAndreas Gohr          $data{$pos + $i} = $str{$i};
2807*55efc227SAndreas Gohr        }
2808*55efc227SAndreas Gohr
2809*55efc227SAndreas Gohr        return $pos + $len;
2810*55efc227SAndreas Gohr    }
2811*55efc227SAndreas Gohr
2812*55efc227SAndreas Gohr    /*************************************************************/
2813*55efc227SAndreas Gohr    function _hexDump(&$data, $start = 0, $length = -1)
2814*55efc227SAndreas Gohr    {
2815*55efc227SAndreas Gohr        if (($length == -1) || (($length + $start) > strlen($data))) {
2816*55efc227SAndreas Gohr            $end = strlen($data);
2817*55efc227SAndreas Gohr        }
2818*55efc227SAndreas Gohr        else {
2819*55efc227SAndreas Gohr            $end = $start + $length;
2820*55efc227SAndreas Gohr        }
2821*55efc227SAndreas Gohr
2822*55efc227SAndreas Gohr        $ascii = '';
2823*55efc227SAndreas Gohr        $count = 0;
2824*55efc227SAndreas Gohr
2825*55efc227SAndreas Gohr        echo "<tt>\n";
2826*55efc227SAndreas Gohr
2827*55efc227SAndreas Gohr        while ($start < $end) {
2828*55efc227SAndreas Gohr            if (($count % 16) == 0) {
2829*55efc227SAndreas Gohr                echo sprintf('%04d', $count) . ': ';
2830*55efc227SAndreas Gohr            }
2831*55efc227SAndreas Gohr
2832*55efc227SAndreas Gohr            $c = ord($data{$start});
2833*55efc227SAndreas Gohr            $count++;
2834*55efc227SAndreas Gohr            $start++;
2835*55efc227SAndreas Gohr
2836*55efc227SAndreas Gohr            $aux = dechex($c);
2837*55efc227SAndreas Gohr            if (strlen($aux) == 1)
2838*55efc227SAndreas Gohr                echo '0';
2839*55efc227SAndreas Gohr            echo $aux . ' ';
2840*55efc227SAndreas Gohr
2841*55efc227SAndreas Gohr            if ($c == 60)
2842*55efc227SAndreas Gohr                $ascii .= '&lt;';
2843*55efc227SAndreas Gohr            elseif ($c == 62)
2844*55efc227SAndreas Gohr                $ascii .= '&gt;';
2845*55efc227SAndreas Gohr            elseif ($c == 32)
2846*55efc227SAndreas Gohr                $ascii .= '&nbsp;';
2847*55efc227SAndreas Gohr            elseif ($c > 32)
2848*55efc227SAndreas Gohr                $ascii .= chr($c);
2849*55efc227SAndreas Gohr            else
2850*55efc227SAndreas Gohr                $ascii .= '.';
2851*55efc227SAndreas Gohr
2852*55efc227SAndreas Gohr            if (($count % 4) == 0) {
2853*55efc227SAndreas Gohr                echo ' - ';
2854*55efc227SAndreas Gohr            }
2855*55efc227SAndreas Gohr
2856*55efc227SAndreas Gohr            if (($count % 16) == 0) {
2857*55efc227SAndreas Gohr                echo ': ' . $ascii . "<br>\n";
2858*55efc227SAndreas Gohr                $ascii = '';
2859*55efc227SAndreas Gohr            }
2860*55efc227SAndreas Gohr        }
2861*55efc227SAndreas Gohr
2862*55efc227SAndreas Gohr        if ($ascii != '') {
2863*55efc227SAndreas Gohr            while (($count % 16) != 0) {
2864*55efc227SAndreas Gohr                echo '-- ';
2865*55efc227SAndreas Gohr                $count++;
2866*55efc227SAndreas Gohr                if (($count % 4) == 0) {
2867*55efc227SAndreas Gohr                    echo ' - ';
2868*55efc227SAndreas Gohr                }
2869*55efc227SAndreas Gohr            }
2870*55efc227SAndreas Gohr            echo ': ' . $ascii . "<br>\n";
2871*55efc227SAndreas Gohr        }
2872*55efc227SAndreas Gohr
2873*55efc227SAndreas Gohr        echo "</tt>\n";
2874*55efc227SAndreas Gohr    }
2875*55efc227SAndreas Gohr
2876*55efc227SAndreas Gohr/*****************************************************************/
2877*55efc227SAndreas Gohr}
2878*55efc227SAndreas Gohr
2879*55efc227SAndreas Gohr/* vim: set expandtab tabstop=4 shiftwidth=4: */
2880*55efc227SAndreas Gohr
2881