source: spip-zone/_plugins_/metadonnees_photo/inc/exifWriter.php @ 34889

Last change on this file since 34889 was 34889, checked in by arno@…, 11 years ago

Suppression des ereg.

File size: 13.8 KB
Line 
1<?php
2/**
3 * PHP Class to write EXIF information back to image
4 *
5 * Vinay Yadav < vinay@vinayras.com >
6 
7 * http://www.vinayras.com/project/phpexifrw.php
8 * http://www.sanisoft.com/phpexifrw/
9 
10 * For more information on EXIF
11 * http://www.exif.org/
12 *
13 * Features:
14 *   - Write comments to image
15 */
16
17/**
18 * PHP Class to read, write and transfer EXIF information
19 * that most of the digital camera produces
20 * Currenty it can only read JPEG file.
21 */
22 /**
23 * @author Vinay Yadav (vinayRas) < vinay@vinayras.com >
24 *
25 * @version 1.0
26 * @licence http://opensource.org/licenses/lgpl-license.php GNU LGPL
27 */
28require_once("exifReader.inc");
29
30/**
31*
32*/
33class phpExifWriter extends phpExifReader {
34
35    /**
36    *  Constructor
37    */
38    function phpExifWriter($image) {
39         $this->phpExifReader($image);
40         $this->processFile();
41    }
42
43    /**
44     * Modifies or sets value of specified Tag -
45     * @param   hex   Tag, whose value has to be set
46     * @param   string   Tags value
47     *
48     */
49    function setExifData($param,$value) {
50        $this->ImageInfo["$param"] = $value;
51    }
52
53    /**
54     * This functiion writes back the modifed exif data into the imageinfo array -
55     * NOTE: This code is still INCOMPLETE and does not work.
56     *
57     */
58    function modifyExifDetails() {
59
60        $newData[0] = $this->sections[$this->exifSection]["data"][0];
61        $newData[1] = $this->sections[$this->exifSection]["data"][1];
62
63        $newData[2] = 'E'; $newData[3] = 'x';
64        $newData[4] = 'i'; $newData[5] = 'f';
65        $newData[6] = $this->sections[$this->exifSection]["data"][6];
66        $newData[7] = $this->sections[$this->exifSection]["data"][7];
67
68        if($this->MotorolaOrder == 1) {
69            $newData[8] = 'M';$newData[9] = 'M';
70        } else {
71            $newData[8] = 'I';$newData[9] = 'I';
72        }
73
74        $newData[10] = chr(42 >> 8);
75        $newData[11] = chr(42);
76
77        $newData[12] = chr(0);
78        $newData[13] = chr(0);
79        $newData[14] = chr(0);
80        $newData[15] = chr(8);
81
82        $newData[16] = 1;
83        $newData[17] = 1;
84
85        $totalLength = 16; $totalElements = 0;
86        $offset = 10+(15*12);
87        $otherDataArr = array();
88        foreach($this->ImageInfo as $tag => $val) {
89
90          if(is_array($val)) continue;
91
92          if(mb_eregi("0x",$tag)) {
93
94            // format
95            $fmt = $this->getFormat($tag);
96            if($fmt == -1) continue;
97
98            $tmpTag = hexdec($tag);
99            // tag
100            $newData[] = chr($tmpTag >> 8);
101            $newData[] = chr($tmpTag);
102
103            $newData[] = chr($fmt >> 8);
104            $newData[] = chr($fmt);
105
106            echo "<br>TAG:$tag - Format:$fmt - Value:$val";
107            //components
108            $chars = preg_split('//', $val, -1, PREG_SPLIT_NO_EMPTY);
109            $ByteCount = count($chars);
110
111            $Components = ceil($ByteCount / $this->BytesPerFormat[$fmt]);
112
113            $newData[] = chr($Components >> 24);
114            $newData[] = chr($Components >> 16);
115            $newData[] = chr($Components >> 8);
116            $newData[] = chr($Components);
117
118            echo "<br>ByteCount: $ByteCount";
119            if($ByteCount <= 4) {
120                $newData[] = chr($chars[0] >> 8);
121                $newData[] = chr($chars[0]);
122
123                $newData[] = (isset($chars[2])) ? chr($chars[2]) : '';
124                $newData[] = (isset($chars[3])) ? chr($chars[3]) : '';
125            } else {
126                $newData[] = chr($offset >> 24);
127                $newData[] = chr($offset >> 16);
128                $newData[] = chr($offset >> 8);
129                $newData[] = chr($offset);
130
131
132                if($fmt != FMT_STRING) {
133                    $arr = $this->ConvertAnyFormatBack($val,$fmt);
134                    $chars = $arr;
135                    $ByteCount = 8;
136                }
137                $offset+=$ByteCount;
138
139                $otherDataArr = array_merge($otherDataArr,$chars);
140            }
141            $totalLength += 12+$ByteCount;
142            $totalElements++;
143          }
144        }
145        $newData = array_merge($newData,$otherDataArr);
146
147        /**
148         * Write the thumbnail back to the exif section
149         * Dont know if this works -
150         */
151        /**
152        if($this->thumbnail) {
153            echo "Thumnail Size:".count($this->ImageInfo["ThumbnailPointer"]);
154
155            $tmpTag = hexdec();
156            // tag
157            $newData[] = chr($tmpTag >> 8);
158            $newData[] = chr($tmpTag);
159
160            // format
161            $fmt = $this->getFormat($tag);
162            $newData[] = chr($fmt >> 8);
163            $newData[] = chr($fmt);
164
165            //components
166            $chars = preg_split('//', $val, -1, PREG_SPLIT_NO_EMPTY);
167            $ByteCount = count($chars);
168
169            $Components = $ByteCount / $this->BytesPerFormat[$fmt];
170
171            $newData[] = chr($Components >> 32);
172            $newData[] = chr($Components >> 16);
173            $newData[] = chr($Components >> 8);
174            $newData[] = chr($Components);
175
176
177            //$newData = array_merge($newData,$chars);
178
179            $newData = array_merge($newData,$this->ImageInfo["ThumbnailPointer"]);
180            $totalLength += count($this->ImageInfo["ThumbnailPointer"]);
181        }
182         */
183
184        $totalLength += 2;
185        $newData[0] = chr($totalLength >> 8);
186        $newData[1] = chr($totalLength);
187
188        $newData[16] = chr($totalElements >> 8);
189        $newData[17] = chr($totalElements);
190
191        $this->sections[$this->exifSection]["data"] = $newData;
192        $this->sections[$this->exifSection]["size"] = $totalLength;
193
194    }
195
196    /**
197     * Searched for the tag specified in the sections list
198     *
199     * @param   hex  Tag to search for
200     *
201     * @return  int
202            -1 - Tag not found
203     */
204    function findMarker($marker) {
205            for($i=0;$i<$this->currSection;$i++) {
206                if($this->sections[$i]["type"] == $marker) {
207                    return $i;
208                }
209            }
210            return -1;
211    }
212
213    /**
214     * Adds comment to the image.
215     * NOTE: Will have to call writeExif for the comments and
216     *       other data to be written back to image.
217     * @param   string Commnent as string
218     *
219     */
220    function addComment($comment) {
221
222        /** check if comments already exists! */
223        $commentSection = $this->findMarker(M_COM);
224        if($commentSection == -1) {
225            // make 3rd element as comment section - Push-up all elements
226            for($i=$this->currSection;$i>2;$i--) {
227                $this->sections[$i]["type"] = $this->sections[$i-1]["type"];
228                $this->sections[$i]["data"] = $this->sections[$i-1]["data"];
229                $this->sections[$i]["size"] = $this->sections[$i-1]["size"];
230            }
231            $this->currSection++;
232            $commentSection = 2;
233        }
234
235        $data[0] = 0;  // dummy data
236        $data[1] = 0;  // dummy data
237
238        $chars = preg_split('//', $comment, -1, PREG_SPLIT_NO_EMPTY);
239        $data = array_merge($data,$chars);
240
241        $this->sections[$commentSection]["size"] = count($data);
242
243        $data[0] = chr($this->sections[$commentSection]["size"] >> 8);
244        $data[1] = chr($this->sections[$commentSection]["size"]);
245
246        $this->sections[$commentSection]["type"] = M_COM;
247        $this->sections[$commentSection]["data"] = $data;
248    }
249
250    /**
251     * Return the format of data of any tag.
252     *
253     * @param   hex Tag whose format has to looked for
254     *
255     * @return int Return the format as int
256     *
257     */
258    function getFormat($tag) {
259
260        switch($tag) {
261            //$FMT_BYTE_ARRAY
262
263
264            //$FMT_STRING_ARRAY
265            case TAG_MAKE:
266            case TAG_MODEL:
267            case TAG_SOFTWARE:
268            case TAG_ARTIST:
269            case TAG_COPYRIGHT:
270            case TAG_DATETIME_ORIGINAL:
271            case TAG_IMAGE_DESC:
272                return FMT_STRING;
273                break;
274
275            //$FMT_USHORT_ARRAY
276            case TAG_ORIENTATION:
277            case TAG_EXPOSURE_PROGRAM:
278            case TAG_METERING_MODE:
279            case TAG_FLASH:
280            case TAG_EXIF_IMAGEWIDTH:
281            case TAG_EXIF_IMAGELENGTH:
282                return FMT_USHORT;
283                break;
284
285            //$FMT_ULONG_ARRAY
286            case TAG_THUMBNAIL_LENGTH:
287                return FMT_ULONG;
288                break;
289
290            //$FMT_URATIONAL_ARRAY
291            case TAG_EXPOSURETIME:
292            case TAG_FNUMBER:
293            case TAG_COMPRESSION_LEVEL:
294            case TAG_APERTURE:
295            case TAG_MAXAPERTURE:
296            case TAG_FOCALLENGTH:
297                return FMT_URATIONAL;
298                break;
299            //$FMT_SBYTE_ARRAY
300            //$FMT_UNDEFINED_ARRAY
301            //$FMT_SSHORT_ARRAY
302            //$FMT_SLONG_ARRAY
303
304            //$FMT_SRATIONAL_ARRAY
305            case TAG_SHUTTERSPEED:
306            case TAG_EXPOSURE_BIAS:
307                return FMT_SRATIONAL;
308                break;
309
310            //$FMT_SINGLE_ARRAY
311            //$FMT_DOUBLE_ARRAY
312
313            default:
314                $this->debug("UNDEFINED TAG:",$tag);
315                return -1;
316        }
317    }
318
319    /**
320     *
321     * Reverse of ConvertAnyFormat, - Incomplete
322     * TODO:
323            only FMT_URATIONAL, FMT_SRATIONAL works
324     *
325     */
326    function ConvertAnyFormatBack($Value, $Format)
327    {
328        //$Value = 0;
329        switch($Format){
330            case FMT_SBYTE:     $Value = $ValuePtr[0];  break;
331            case FMT_BYTE:      $Value = $ValuePtr[0];  break;
332
333            case FMT_USHORT:    $Value = $this->Get16u($ValuePtr[0],$ValuePtr[1]); break;
334            case FMT_ULONG:     $Value = $this->Get32u($ValuePtr[0],$ValuePtr[1],$ValuePtr[2],$ValuePtr[3]); break;
335
336            case FMT_URATIONAL:
337            case FMT_SRATIONAL:
338                {
339
340                    $num = $Value[1][0];
341                    $Den = $Value[1][1];
342
343                    $ValuePtr[0] = chr($num >> 24);
344                    $ValuePtr[1] = chr($num >> 16);
345                    $ValuePtr[2] = chr($num >> 8);
346                    $ValuePtr[3] = chr($num);
347
348                    $ValuePtr[4] = chr($Den >> 24);
349                    $ValuePtr[5] = chr($Den >> 16);
350                    $ValuePtr[6] = chr($Den >> 8);
351                    $ValuePtr[7] = chr($Den);
352
353                    break;
354                }
355
356            case FMT_SSHORT:    $Value = $this->Get16u($ValuePtr[0],$ValuePtr[1]);  break;
357            case FMT_SLONG:     $Value = $this->Get32s($ValuePtr[0],$ValuePtr[1],$ValuePtr[2],$ValuePtr[3]); break;
358
359            // Not sure if this is correct (never seen float used in Exif format)
360            case FMT_SINGLE:    $Value = $ValuePtr[0];      break;
361            case FMT_DOUBLE:    $Value = $ValuePtr[0];             break;
362            default:
363                return -1;
364        }
365        return $ValuePtr;
366    }
367
368    /**
369     * Returns the raw exif information stored
370     *
371     */
372    function getExif() {
373        if($this->exifSection > -1) {
374                return $this->sections[$this->exifSection]["data"];
375        }
376        /** Exif data does not exists  */
377        return -1;
378    }
379
380    /**
381     * Addes raw exif information
382     *
383     * @param   string    Exif Data to be added.
384     *
385     * NOTE: This function will blindly replace any existing EXIF data
386     */
387    function addExif($exifData) {
388        $exifSection = $this->findMarker(M_EXIF);
389        if($exifSection == -1) {
390            // make 3rd element as comment section - Push-up all elements
391            for($i=$this->currSection;$i>2;$i--) {
392                $this->sections[$i]["type"] = $this->sections[$i-1]["type"];
393                $this->sections[$i]["data"] = $this->sections[$i-1]["data"];
394                $this->sections[$i]["size"] = $this->sections[$i-1]["size"];
395            }
396            $exifSection = 2;
397            $this->currSection++;
398        }
399
400        $this->sections[$exifSection]["type"] = M_EXIF;
401        $this->sections[$exifSection]["data"] = $exifData;
402        $this->sections[$exifSection]["size"] = strlen($exifData);
403    }
404
405    /**
406     * Write the whole image back into a file.
407     *  This function does not write back to the same file.
408     *  You need to specify a filename
409     *
410     * @param   string    filename to save the JPEG content to
411     */
412    function writeImage($file) {
413
414        $file = trim($file);
415        if(empty($file)) {
416            $this->errno = 3;
417            $this->errstr = "File name not provided!";
418            debug($this->errstr,1);
419        }
420
421        $fp = fopen($file,"wb");
422
423        /** Initial static jpeg marker. */
424        fwrite($fp,chr(0xff));
425        fwrite($fp,chr(0xd8));
426
427        if ($this->sections[0]["type"] != M_EXIF && $this->sections[0]["type"] != M_JFIF){
428            $JfifHead = array(
429                chr(0xff), chr(M_JFIF),
430                chr(0x00), chr(0x10), 'J' , 'F' , 'I' , 'F' , chr(0x00), chr(0x01),
431                chr(0x01), chr(0x01), chr(0x01), chr(0x2C), chr(0x01), chr(0x2C), chr(0x00), chr(0x00)
432            );
433
434            fwrite($fp,implode("",$JfifHead));
435        }
436
437        /** write each section back into the file */
438        for($key=0;$key<$this->currSection-1;$key++) {
439          if(!empty($this->sections[$key]["data"])) {
440            fwrite($fp,chr(0xff));
441            fwrite($fp,chr($this->sections[$key]["type"]));
442            /**
443              dat acan be array as well as string. Check the data-type of data.
444              If it is an array then convert it to string.
445            */
446            if(is_array($this->sections[$key]["data"])) {
447                $this->sections[$key]["data"] = implode("",$this->sections[$key]["data"]);
448            }
449            fwrite($fp,$this->sections[$key]["data"]);
450          }
451        }
452        // Write the remaining image data.
453            if(is_array($this->sections[$key]["data"])) {
454                $this->sections[$key]["data"] = implode("",$this->sections[$key]["data"]);
455            }
456            fwrite($fp,$this->sections[$key]["data"]);
457        fclose($fp);
458    }
459
460} // end of class
461?>
Note: See TracBrowser for help on using the repository browser.