/_plugins_/metadonnees_photo/trunk/inc/exifWriter.php
PHP | 463 lines | 240 code | 69 blank | 154 comment | 31 complexity | dc2b386519189302147ed657c47cbc15 MD5 | raw file
- <?php
- /**
- * PHP Class to write EXIF information back to image
- *
- * Vinay Yadav < vinay@vinayras.com >
-
- * http://www.vinayras.com/project/phpexifrw.php
- * http://www.sanisoft.com/phpexifrw/
-
- * For more information on EXIF
- * http://www.exif.org/
- *
- * Features:
- * - Write comments to image
- */
- if (!defined("_ECRIRE_INC_VERSION")) return;
- /**
- * PHP Class to read, write and transfer EXIF information
- * that most of the digital camera produces
- * Currenty it can only read JPEG file.
- */
- /**
- * @author Vinay Yadav (vinayRas) < vinay@vinayras.com >
- *
- * @version 1.0
- * @licence http://opensource.org/licenses/lgpl-license.php GNU LGPL
- */
- require_once("exifReader.inc");
- /**
- *
- */
- class phpExifWriter extends phpExifReader {
- /**
- * Constructor
- */
- function phpExifWriter($image) {
- $this->phpExifReader($image);
- $this->processFile();
- }
- /**
- * Modifies or sets value of specified Tag -
- * @param hex Tag, whose value has to be set
- * @param string Tags value
- *
- */
- function setExifData($param,$value) {
- $this->ImageInfo["$param"] = $value;
- }
- /**
- * This functiion writes back the modifed exif data into the imageinfo array -
- * NOTE: This code is still INCOMPLETE and does not work.
- *
- */
- function modifyExifDetails() {
- $newData[0] = $this->sections[$this->exifSection]["data"][0];
- $newData[1] = $this->sections[$this->exifSection]["data"][1];
- $newData[2] = 'E'; $newData[3] = 'x';
- $newData[4] = 'i'; $newData[5] = 'f';
- $newData[6] = $this->sections[$this->exifSection]["data"][6];
- $newData[7] = $this->sections[$this->exifSection]["data"][7];
- if($this->MotorolaOrder == 1) {
- $newData[8] = 'M';$newData[9] = 'M';
- } else {
- $newData[8] = 'I';$newData[9] = 'I';
- }
- $newData[10] = chr(42 >> 8);
- $newData[11] = chr(42);
- $newData[12] = chr(0);
- $newData[13] = chr(0);
- $newData[14] = chr(0);
- $newData[15] = chr(8);
- $newData[16] = 1;
- $newData[17] = 1;
- $totalLength = 16; $totalElements = 0;
- $offset = 10+(15*12);
- $otherDataArr = array();
- foreach($this->ImageInfo as $tag => $val) {
- if(is_array($val)) continue;
- if(mb_eregi("0x",$tag)) {
- // format
- $fmt = $this->getFormat($tag);
- if($fmt == -1) continue;
- $tmpTag = hexdec($tag);
- // tag
- $newData[] = chr($tmpTag >> 8);
- $newData[] = chr($tmpTag);
- $newData[] = chr($fmt >> 8);
- $newData[] = chr($fmt);
- echo "<br>TAG:$tag - Format:$fmt - Value:$val";
- //components
- $chars = preg_split('//', $val, -1, PREG_SPLIT_NO_EMPTY);
- $ByteCount = count($chars);
- $Components = ceil($ByteCount / $this->BytesPerFormat[$fmt]);
- $newData[] = chr($Components >> 24);
- $newData[] = chr($Components >> 16);
- $newData[] = chr($Components >> 8);
- $newData[] = chr($Components);
- echo "<br>ByteCount: $ByteCount";
- if($ByteCount <= 4) {
- $newData[] = chr($chars[0] >> 8);
- $newData[] = chr($chars[0]);
- $newData[] = (isset($chars[2])) ? chr($chars[2]) : '';
- $newData[] = (isset($chars[3])) ? chr($chars[3]) : '';
- } else {
- $newData[] = chr($offset >> 24);
- $newData[] = chr($offset >> 16);
- $newData[] = chr($offset >> 8);
- $newData[] = chr($offset);
- if($fmt != FMT_STRING) {
- $arr = $this->ConvertAnyFormatBack($val,$fmt);
- $chars = $arr;
- $ByteCount = 8;
- }
- $offset+=$ByteCount;
- $otherDataArr = array_merge($otherDataArr,$chars);
- }
- $totalLength += 12+$ByteCount;
- $totalElements++;
- }
- }
- $newData = array_merge($newData,$otherDataArr);
- /**
- * Write the thumbnail back to the exif section
- * Dont know if this works -
- */
- /**
- if($this->thumbnail) {
- echo "Thumnail Size:".count($this->ImageInfo["ThumbnailPointer"]);
- $tmpTag = hexdec();
- // tag
- $newData[] = chr($tmpTag >> 8);
- $newData[] = chr($tmpTag);
- // format
- $fmt = $this->getFormat($tag);
- $newData[] = chr($fmt >> 8);
- $newData[] = chr($fmt);
- //components
- $chars = preg_split('//', $val, -1, PREG_SPLIT_NO_EMPTY);
- $ByteCount = count($chars);
- $Components = $ByteCount / $this->BytesPerFormat[$fmt];
- $newData[] = chr($Components >> 32);
- $newData[] = chr($Components >> 16);
- $newData[] = chr($Components >> 8);
- $newData[] = chr($Components);
- //$newData = array_merge($newData,$chars);
- $newData = array_merge($newData,$this->ImageInfo["ThumbnailPointer"]);
- $totalLength += count($this->ImageInfo["ThumbnailPointer"]);
- }
- */
- $totalLength += 2;
- $newData[0] = chr($totalLength >> 8);
- $newData[1] = chr($totalLength);
- $newData[16] = chr($totalElements >> 8);
- $newData[17] = chr($totalElements);
- $this->sections[$this->exifSection]["data"] = $newData;
- $this->sections[$this->exifSection]["size"] = $totalLength;
- }
- /**
- * Searched for the tag specified in the sections list
- *
- * @param hex Tag to search for
- *
- * @return int
- -1 - Tag not found
- */
- function findMarker($marker) {
- for($i=0;$i<$this->currSection;$i++) {
- if($this->sections[$i]["type"] == $marker) {
- return $i;
- }
- }
- return -1;
- }
- /**
- * Adds comment to the image.
- * NOTE: Will have to call writeExif for the comments and
- * other data to be written back to image.
- * @param string Commnent as string
- *
- */
- function addComment($comment) {
- /** check if comments already exists! */
- $commentSection = $this->findMarker(M_COM);
- if($commentSection == -1) {
- // make 3rd element as comment section - Push-up all elements
- for($i=$this->currSection;$i>2;$i--) {
- $this->sections[$i]["type"] = $this->sections[$i-1]["type"];
- $this->sections[$i]["data"] = $this->sections[$i-1]["data"];
- $this->sections[$i]["size"] = $this->sections[$i-1]["size"];
- }
- $this->currSection++;
- $commentSection = 2;
- }
- $data[0] = 0; // dummy data
- $data[1] = 0; // dummy data
- $chars = preg_split('//', $comment, -1, PREG_SPLIT_NO_EMPTY);
- $data = array_merge($data,$chars);
- $this->sections[$commentSection]["size"] = count($data);
- $data[0] = chr($this->sections[$commentSection]["size"] >> 8);
- $data[1] = chr($this->sections[$commentSection]["size"]);
- $this->sections[$commentSection]["type"] = M_COM;
- $this->sections[$commentSection]["data"] = $data;
- }
- /**
- * Return the format of data of any tag.
- *
- * @param hex Tag whose format has to looked for
- *
- * @return int Return the format as int
- *
- */
- function getFormat($tag) {
- switch($tag) {
- //$FMT_BYTE_ARRAY
- //$FMT_STRING_ARRAY
- case TAG_MAKE:
- case TAG_MODEL:
- case TAG_SOFTWARE:
- case TAG_ARTIST:
- case TAG_COPYRIGHT:
- case TAG_DATETIME_ORIGINAL:
- case TAG_IMAGE_DESC:
- return FMT_STRING;
- break;
- //$FMT_USHORT_ARRAY
- case TAG_ORIENTATION:
- case TAG_EXPOSURE_PROGRAM:
- case TAG_METERING_MODE:
- case TAG_FLASH:
- case TAG_EXIF_IMAGEWIDTH:
- case TAG_EXIF_IMAGELENGTH:
- return FMT_USHORT;
- break;
- //$FMT_ULONG_ARRAY
- case TAG_THUMBNAIL_LENGTH:
- return FMT_ULONG;
- break;
- //$FMT_URATIONAL_ARRAY
- case TAG_EXPOSURETIME:
- case TAG_FNUMBER:
- case TAG_COMPRESSION_LEVEL:
- case TAG_APERTURE:
- case TAG_MAXAPERTURE:
- case TAG_FOCALLENGTH:
- return FMT_URATIONAL;
- break;
- //$FMT_SBYTE_ARRAY
- //$FMT_UNDEFINED_ARRAY
- //$FMT_SSHORT_ARRAY
- //$FMT_SLONG_ARRAY
- //$FMT_SRATIONAL_ARRAY
- case TAG_SHUTTERSPEED:
- case TAG_EXPOSURE_BIAS:
- return FMT_SRATIONAL;
- break;
- //$FMT_SINGLE_ARRAY
- //$FMT_DOUBLE_ARRAY
- default:
- $this->debug("UNDEFINED TAG:",$tag);
- return -1;
- }
- }
- /**
- *
- * Reverse of ConvertAnyFormat, - Incomplete
- * TODO:
- only FMT_URATIONAL, FMT_SRATIONAL works
- *
- */
- function ConvertAnyFormatBack($Value, $Format)
- {
- //$Value = 0;
- switch($Format){
- case FMT_SBYTE: $Value = $ValuePtr[0]; break;
- case FMT_BYTE: $Value = $ValuePtr[0]; break;
- case FMT_USHORT: $Value = $this->Get16u($ValuePtr[0],$ValuePtr[1]); break;
- case FMT_ULONG: $Value = $this->Get32u($ValuePtr[0],$ValuePtr[1],$ValuePtr[2],$ValuePtr[3]); break;
- case FMT_URATIONAL:
- case FMT_SRATIONAL:
- {
- $num = $Value[1][0];
- $Den = $Value[1][1];
- $ValuePtr[0] = chr($num >> 24);
- $ValuePtr[1] = chr($num >> 16);
- $ValuePtr[2] = chr($num >> 8);
- $ValuePtr[3] = chr($num);
- $ValuePtr[4] = chr($Den >> 24);
- $ValuePtr[5] = chr($Den >> 16);
- $ValuePtr[6] = chr($Den >> 8);
- $ValuePtr[7] = chr($Den);
- break;
- }
- case FMT_SSHORT: $Value = $this->Get16u($ValuePtr[0],$ValuePtr[1]); break;
- case FMT_SLONG: $Value = $this->Get32s($ValuePtr[0],$ValuePtr[1],$ValuePtr[2],$ValuePtr[3]); break;
- // Not sure if this is correct (never seen float used in Exif format)
- case FMT_SINGLE: $Value = $ValuePtr[0]; break;
- case FMT_DOUBLE: $Value = $ValuePtr[0]; break;
- default:
- return -1;
- }
- return $ValuePtr;
- }
- /**
- * Returns the raw exif information stored
- *
- */
- function getExif() {
- if($this->exifSection > -1) {
- return $this->sections[$this->exifSection]["data"];
- }
- /** Exif data does not exists */
- return -1;
- }
- /**
- * Addes raw exif information
- *
- * @param string Exif Data to be added.
- *
- * NOTE: This function will blindly replace any existing EXIF data
- */
- function addExif($exifData) {
- $exifSection = $this->findMarker(M_EXIF);
- if($exifSection == -1) {
- // make 3rd element as comment section - Push-up all elements
- for($i=$this->currSection;$i>2;$i--) {
- $this->sections[$i]["type"] = $this->sections[$i-1]["type"];
- $this->sections[$i]["data"] = $this->sections[$i-1]["data"];
- $this->sections[$i]["size"] = $this->sections[$i-1]["size"];
- }
- $exifSection = 2;
- $this->currSection++;
- }
- $this->sections[$exifSection]["type"] = M_EXIF;
- $this->sections[$exifSection]["data"] = $exifData;
- $this->sections[$exifSection]["size"] = strlen($exifData);
- }
- /**
- * Write the whole image back into a file.
- * This function does not write back to the same file.
- * You need to specify a filename
- *
- * @param string filename to save the JPEG content to
- */
- function writeImage($file) {
- $file = trim($file);
- if(empty($file)) {
- $this->errno = 3;
- $this->errstr = "File name not provided!";
- debug($this->errstr,1);
- }
- $fp = fopen($file,"wb");
- /** Initial static jpeg marker. */
- fwrite($fp,chr(0xff));
- fwrite($fp,chr(0xd8));
- if ($this->sections[0]["type"] != M_EXIF && $this->sections[0]["type"] != M_JFIF){
- $JfifHead = array(
- chr(0xff), chr(M_JFIF),
- chr(0x00), chr(0x10), 'J' , 'F' , 'I' , 'F' , chr(0x00), chr(0x01),
- chr(0x01), chr(0x01), chr(0x01), chr(0x2C), chr(0x01), chr(0x2C), chr(0x00), chr(0x00)
- );
- fwrite($fp,implode("",$JfifHead));
- }
- /** write each section back into the file */
- for($key=0;$key<$this->currSection-1;$key++) {
- if(!empty($this->sections[$key]["data"])) {
- fwrite($fp,chr(0xff));
- fwrite($fp,chr($this->sections[$key]["type"]));
- /**
- dat acan be array as well as string. Check the data-type of data.
- If it is an array then convert it to string.
- */
- if(is_array($this->sections[$key]["data"])) {
- $this->sections[$key]["data"] = implode("",$this->sections[$key]["data"]);
- }
- fwrite($fp,$this->sections[$key]["data"]);
- }
- }
- // Write the remaining image data.
- if(is_array($this->sections[$key]["data"])) {
- $this->sections[$key]["data"] = implode("",$this->sections[$key]["data"]);
- }
- fwrite($fp,$this->sections[$key]["data"]);
- fclose($fp);
- }
- } // end of class
- ?>