From a0d8fb6e3d8c4fd31d34f6825a253870b2557710 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=C3=86var=20Arnfj=C3=B6r=C3=B0=20Bjarmason?= Date: Thu, 21 Apr 2005 20:22:11 +0000 Subject: [PATCH] * Removed exifReader.inc and added a function which does roughly the same thing to Image.php. --- includes/Image.php | 162 ++++- includes/exifReader.inc | 1494 --------------------------------------- 2 files changed, 142 insertions(+), 1514 deletions(-) delete mode 100644 includes/exifReader.inc diff --git a/includes/Image.php b/includes/Image.php index 897224e961..405213511f 100644 --- a/includes/Image.php +++ b/includes/Image.php @@ -3,10 +3,6 @@ * @package MediaWiki */ -if ( $wgShowEXIF ) { - require_once ( 'exifReader.inc' ) ; -} - /** * Class to represent an image * @@ -1127,29 +1123,30 @@ class Image function retrieveExifData () { global $wgShowEXIF ; - if ( ! $wgShowEXIF ) return array () ; - - $file = $this->imagePath ; - $per = new phpExifReader ( $file ) ; - $per->processFile () ; - $a = $per->getImageInfo() ; - unset ( $a["FileName"] ) ; - unset ( $a["Thumbnail"] ) ; - return $a ; + if ( ! $wgShowEXIF ) return array (); + if ( $this->type !== '2' ) return array (); + + $exif = exif_read_data( $this->imagePath ); + $exif = $this->stripExifData( $exif ); + return $exif ; } function getExifData () { - global $wgShowEXIF ; - if ( ! $wgShowEXIF ) return array () ; + global $wgRequest, $wgShowEXIF; - $ret = unserialize ( $this->exif ) ; - if ( count ( $ret ) == 0 ) { # No EXIF data was stored for this image + if ( ! $wgShowEXIF ) return array (); + + $action = $wgRequest->getVal( 'action' ); # Allow forced updates + + $ret = unserialize ( $this->exif ); + + if ( count( $ret) == 0 || $action == 'purge' ) { # No EXIF data was stored for this image $this->updateExifData() ; $ret = unserialize ( $this->exif ) ; - } - - return $ret ; } + + return $ret ; + } function updateExifData () { global $wgShowEXIF ; @@ -1169,7 +1166,132 @@ class Image array( 'img_name' => $this->name ), $fname ); + } + + /** + * Strip out potentially nasty exif data such as raw binaries + * (thumbnails), these values are from version 2.2 of the EXIF + * specification, note that I've commented some of them out, this is + * because their Type is "UNDEFINED", meaning that they potentially + * contain binary data. + * + * @author Ævar Arnfjörð Bjarmason + * @link http://exif.org/specifications.html + * @link http://exif.org/Exif2-2.PDF (see page 22 and 30) + * + * @param array $exif + * @return array + */ + function stripExifData( $exif = array() ) { + $whitelist = array( + # Other tags + 'Make', # Image input equipment manufacturer + 'Model', # Image input equipment model + 'Software', # Software used + 'Artist', # Person who created the image + 'Copyright', # Copyright holder + + # Tags relating to image structure + 'ImageWidth', # Image width + 'ImageLength', # Image height + 'Orientation', # Orientation of image + 'SamplesPerPixel', # Number of components + 'PlanarConfiguration', # Image data arrangement + 'YCbCrSubSampling', # Subsampling ratio of Y to C + 'YCbCrPositioning', # Y and C positioning + 'XResolution', # Image resolution in width direction + 'YResolution', # Image resolution in height direction + 'ResolutionUnit', # Unit of X and Y resolution + + # Tags relating to recording offset + 'StripOffsets', # Image data location + 'RowsPerStrip', # Number of rows per strip + 'StripByteCounts', # Bytes per compressed strip + 'JPEGInterchangeFormat', # Offset to JPEG SOI + 'JPEGInterchangeFormatLength', # Bytes of JPEG data + + # Tags relating to image data characteristics + 'TransferFunction', # Transfer function + 'WhitePoint', # White point chromaticity + 'PrimaryChromaticities', # Chromaticities of primarities + 'YCbCrCoefficients', # Color space transformation matrix coefficients + 'ReferenceBlackWhite', # Pair of black and white reference values + + # Tags relating to version + #'ExifVersion', # Exif version + #'FlashpixVersion', # Supported Flashpix version + + # Tags relating to Image Data Characteristics + 'ColorSpace', # Color space information + #'ComponentsConfiguration', # Meaning of each component + 'CompressedBitsPerPixel', # Image compression mode + 'PixelYDimension', # Valid image width + 'PixelXDimension', # Valind image height + + # Tags relating to User Information + #'MakerNote', # Manufacturer notes + #'UserComment', # User commentss + + # Tag relating to related file information + #'RelatedSoundFile', # Related audio file + + # Other tags + 'ImageUniqueID', # Unique image ID + + # Tags relating to picture-taking conditions + 'ExposureTime', # Exposure time + 'FNumber', # F Number + 'ExposureProgram', # Exposure Program + 'SpectralSensitivity', # Spectral sensitivity + 'ISOSpeedRatings', # ISO speed rating + #'OECF', # Optoelectronic conversion factor + 'ShutterSpeedValue', # Shutter speed + 'ApertureValue', # Aperture + 'BrightnessValue', # Brightness + 'ExposureBiasValue', # Exposure bias + 'MaxApertureValue', # Maximum land aperture + 'SubjectDistance', # Subject distance + 'MeteringMode', # Metering mode + 'LightSource', # Light source + 'Flash', # Flash + 'FocalLength', # Lens focal length + 'SubjectArea', # Subject area + 'FlashEnergy', # Flash energy + #'SpartialFrequencyResponse', # Spartial frequency response + 'FocalPlaneXRessolution', # Focal plane X resolution + 'FocalPlaneYRessolution', # Focal plane Y resolution + 'FocalPlaneResolutionUnit', # Focal plane resolution unit + 'SubjectLocation', # Subject location + 'ExposureIndex', # Exposure index + 'SensingMethod', # Sensing method + #'FileSource', # File source + #'SceneType', # Scene type + #'CFAPattern', # CFA pattern + 'CustomRendered', # Custom image processing + 'ExposureMode', # Exposure mode + 'WhiteBalance', # White Balance + 'DigitalZoomRatio', # Digital zoom ration + 'FocalLengthIn35mmFilm', # Focal length in 35 mm film + 'SceneCaptureType', # Scene capture type + 'GainControl', # Scene control + 'Contrast', # Contrast + 'Saturation', # Saturation + 'Sharpness', # Sharpness + #'DeviceSettingDescription', # Desice settings description + 'SubjectDistanceRange', # Subject distance range + + # TODO: GPS attribute information on page 52 of the spec + ); + + $new = array(); + foreach ($whitelist as $tag) { + if ( array_key_exists($tag, $exif) ) { + $new[$tag] = $exif[$tag]; + } } + unset($exif); + return $new; + } } //class diff --git a/includes/exifReader.inc b/includes/exifReader.inc deleted file mode 100644 index 3bcc74f79f..0000000000 --- a/includes/exifReader.inc +++ /dev/null @@ -1,1494 +0,0 @@ - - Concept by Tarique Sani < tarique@sanisoft.com > - - * http://www.vinayras.com/project/phpexifrw.php - * http://www.sanisoft.com/phpexifrw/ - * - * For more information on EXIF - * http://www.exif.org/ - * - * Features: - * - Read Exif Information - * - Extract and display emdedded thumbnails - * - * Tested With - - - Sony - - Cybershot (Sony) - - DSC-D700 - - PowerShotA5 - - SANYO Electric Co.,Ltd - - SR6 - - SX113 - - OLYMPUS OPTICAL CO.,LTD - - C960Z,D460Z - - Canon - PowerShot A40 (Canon) - Canon DIGITAL IXUS - - RICOH - - Caplio RR30 - - RDC-5300 - - NIKON - - D100 (NIKON CORPORATION) - - E5700 (NIKON) - - E950 - - CASIO QV-8000SX - - KODAK - - DC290 Zoom Digital Camera (V01.00) [Eastman Kodak Company] - - DC210 Zoom (V05.00) [Eastman Kodak Company] - - KODAK DC240 ZOOM DIGITAL CAMERA - - FujiFilm - DX10 - FinePix40i - MX-1700ZOOM - * - * - */ - -/** * Start Of Frame N */ -define("M_SOF0",0xC0); -/** * N indicates which compression process */ -define("M_SOF1",0xC1); -/** * Only SOF0-SOF2 are now in common use */ -define("M_SOF2",0xC2); -/** * */ -define("M_SOF3",0xC3); -/** * NB: codes C4 and CC are NOT SOF markers */ -define("M_SOF5",0xC5); -/** * */ -define("M_SOF6",0xC6); -/** * */ -define("M_SOF7",0xC7); -/** * */ -define("M_SOF9",0xC9); -/** * */ -define("M_SOF10",0xCA); -/** * */ -define("M_SOF11",0xCB); -/** * */ -define("M_SOF13",0xCD); -/** * */ -define("M_SOF14",0xCE); -/** * */ -define("M_SOF15",0xCF); -/** * Start Of Image (beginning of datastream) */ -define("M_SOI",0xD8); -/** * End Of Image (end of datastream) */ -define("M_EOI",0xD9); -/** * Start Of Scan (begins compressed data) */ -define("M_SOS",0xDA); -/** * Jfif marker */ -define("M_JFIF",0xE0); -/** * Exif marker */ -define("M_EXIF",0xE1); -/** * Image Title -- */ -define("M_COM",0xFE); - -define("NUM_FORMATS","12"); - -/** * Tag Data Format */ -define("FMT_BYTE","1"); -/** * ASCII */ -define("FMT_STRING","2"); -/** * Short */ -define("FMT_USHORT","3"); -/** * Long */ -define("FMT_ULONG","4"); -/** * Rational */ -define("FMT_URATIONAL","5"); -/** * Byte */ -define("FMT_SBYTE","6"); -/** * Undefined */ -define("FMT_UNDEFINED","7"); -/** * Short */ -define("FMT_SSHORT","8"); -/** * Long */ -define("FMT_SLONG","9"); -/** * Rational */ -define("FMT_SRATIONAL","10"); -/** * Single */ -define("FMT_SINGLE","11"); -/** * Double */ -define("FMT_DOUBLE","12"); - -/** * Exif IFD */ -define("TAG_EXIF_OFFSET","0x8769"); -/** * Interoperability tag */ -define("TAG_INTEROP_OFFSET","0xa005"); -/** * Image input equipment manufacturer */ -define("TAG_MAKE","0x010F"); -/** * Image input equipment model */ -define("TAG_MODEL","0x0110"); -/** * Orientation of image */ -define("TAG_ORIENTATION","0x0112"); -/** * Exposure Time */ -define("TAG_EXPOSURETIME","0x829A"); -/** * F Number */ -define("TAG_FNUMBER","0x829D"); -/** * Shutter Speed */ -define("TAG_SHUTTERSPEED","0x9201"); -/** * Aperture */ -define("TAG_APERTURE","0x9202"); -/** * Aperture */ -define("TAG_MAXAPERTURE","0x9205"); -/** * Lens Focal Length */ -define("TAG_FOCALLENGTH","0x920A"); -/** * The date and time when the original image data was generated. */ -define("TAG_DATETIME_ORIGINAL","0x9003"); -/** * User Comments */ -define("TAG_USERCOMMENT","0x9286"); -/** * subject Location */ -define("TAG_SUBJECT_DISTANCE","0x9206"); -/** * Flash */ -define("TAG_FLASH","0x9209"); -/** * Focal Plane X Resolution */ -define("TAG_FOCALPLANEXRES","0xa20E"); -/** * Focal Plane Resolution Units */ -define("TAG_FOCALPLANEUNITS","0xa210"); -/** * Image Width */ -define("TAG_EXIF_IMAGEWIDTH","0xA002"); -/** * Image Height */ -define("TAG_EXIF_IMAGELENGTH","0xA003"); -/** * Exposure Bias */ -define("TAG_EXPOSURE_BIAS","0x9204"); -/** * Light Source */ -define("TAG_WHITEBALANCE","0x9208"); -/** * Metering Mode */ -define("TAG_METERING_MODE","0x9207"); -/** * Exposure Program */ -define("TAG_EXPOSURE_PROGRAM","0x8822"); -/** * ISO Equivalent Speed Rating */ -define("TAG_ISO_EQUIVALENT","0x8827"); -/** * Compressed Bits Per Pixel */ -define("TAG_COMPRESSION_LEVEL","0x9102"); -/** * Thumbnail Start Offset */ -define("TAG_THUMBNAIL_OFFSET","0x0201"); -/** * Thumbnail Length */ -define("TAG_THUMBNAIL_LENGTH","0x0202"); -/** * Image Marker */ -define("PSEUDO_IMAGE_MARKER",0x123); -/** * Max Image Title Length */ -define("MAX_COMMENT",2000); - -define("TAG_ARTIST","0x013B"); -define("TAG_COPYRIGHT","0x8298"); - -//-------------------------------- - -define("TAG_IMAGE_WD","0x0100"); // image width -define("TAG_IMAGE_HT","0x0101"); // image height -define("TAG_IMAGE_BPS","0x0102"); // Bits Per sample - -define("TAG_IMAGE_PHOTO_INT","0x0106"); // photometricinterpretation -define("TAG_IMAGE_SOFFSET","0x0111"); // stripoffsets - -define("TAG_IMAGE_SPP","0x0115"); // Samples per pixel - 277 -define("TAG_IMAGE_RPS","0x0116"); // RowsPerStrip - 278 -define("TAG_IMAGE_SBC","0x0117"); // StripByteCounts - 279 - -define("TAG_IMAGE_P_CONFIG","0x011C"); // Planar Configuration - 284 - -define("TAG_IMAGE_DESC","0x010E"); // image title -define("TAG_X_RESOLUTION","0x011A"); // Image resolution in width direction -define("TAG_Y_RESOLUTION","0x011B"); // Image resolution in height direction -define("TAG_RESOLUTION_UNIT","0x0128"); // Unit of X and Y resolution -define("TAG_SOFTWARE","0x0131"); // Software used -define("TAG_FILE_MODDATE","0x0132"); // DateTime File change date and time -define("TAG_YCBCR_POSITIONING","0x0213"); // Y and C positioning -define("TAG_EXIF_VERSION","0x9000"); // Exif version -define("TAG_DATE_TIME_DIGITIZED","0x9004"); // Date and time of digital data -define("TAG_COMPONENT_CONFIG","0x9101"); // Component configuration -define("TAG_MAKER_NOTE","0x927C"); -define("TAG_SUB_SEC_TIME","0x9290"); -define("TAG_SUB_SEC_TIME_ORIG","0x9291"); -define("TAG_SUB_SEC_TIME_DIGITIZED","0x9292"); -define("TAG_FLASHPIX_VER","0xA000"); //FlashPixVersion -define("TAG_COLOR_SPACE","0xA001"); //ColorSpace -define("TAG_RELATED_SOUND_FILE","0xA004"); //Related audio file - -define("TAG_GPS_LATITUDE_REF","0x0001"); // -define("TAG_GPS_LATITUDE","0x0002"); // - -define("TAG_SENSING_METHOD","0xA217"); // SensingMethod - -define("TAG_SOUCE_TYPE","0xA300"); // FileSource -define("TAG_SCENE_TYPE","0xA301"); // SceneType - -define("TAG_CFA_PATTERN","0xA302"); // CFA Pattern - -/** Tags in EXIF 2.2 Only */ -define("TAG_COMPRESS_SCHEME","0x0103"); // -define("TAG_CUSTOM_RENDERED","0xA401"); // CustomRendered -define("TAG_EXPOSURE_MODE","0xA402"); // Exposure mode ExposureMode -define("TAG_WHITE_BALANCE","0xA403"); // White balance WhiteBalance -define("TAG_DIGITAL_ZOOM_RATIO","0xA404"); // Digital zoom ratio DigitalZoomRatio -define("TAG_FLENGTH_IN35MM","0xA405"); // Focal length in 35 mm film FocalLengthIn35mmFilm -define("TAG_SCREEN_CAP_TYPE","0xA406"); // Scene capture type SceneCaptureType -define("TAG_GAIN_CONTROL","0xA407"); //Gain control -define("TAG_CONTRAST","0xA408"); // Contrast -define("TAG_SATURATION","0xA409"); // Saturation -define("TAG_SHARPNESS","0xA40A"); // Sharpness -define("TAG_DEVICE_SETTING_DESC","0xA40B"); // SDevice settings description DeviceSettingDescription -define("TAG_DIST_RANGE","0xA40C"); //Subject distance range SubjectDistanceRange - -define("TAG_FOCALPLANE_YRESOL","0xA20F");; //FocalPlaneYResolution -define("TAG_BRIGHTNESS","0x9203");; //Brightness -//-------------------------------- -/** error Description */ -/** - 1 - File does not exists! - 2 - - 3 - Filename not provided - - 10 - too many padding bytes - 11 - "invalid marker" - 12 - Premature end of file? - - - 51 - "Illegal subdirectory link" - 52 - "NOT EXIF FORMAT" - 53 - "Invalid Exif alignment marker.\n" - 54 - "Invalid Exif start (1)" - -*/ - - -/** - * 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@sanisoft.com > - * - * @todo Writing exif information to the file. - * @todo Add EXIF audio reading methods (I think it exists!) - * @todo Support of additional tags. - * @todo Handling Unicode character in UserComment tag of EXif Information. - * - * @version 0.5 - * @licence http://opensource.org/licenses/lgpl-license.php GNU LGPL - */ -class phpExifReader { - - /*** - * Array containg all Exif and JPEG image attributes - * into regular expressions for themselves. - * $ImageInfo[TAG] = TAG_VALUE; - * - * @var array - * @access private - * - */ - var $ImageInfo = array(); - - var $MotorolaOrder = 0; - var $ExifImageWidth = 0; // - var $FocalplaneXRes = 0; // - var $FocalplaneUnits = 0; // - var $sections = array(); - var $currSection = 0; /** Stores total number fo Sections */ - - var $BytesPerFormat = array(0,1,1,2,4,8,1,1,2,4,8,4,8); - - var $ReadMode = array( - "READ_EXIF" => 1, - "READ_IMAGE" => 2, - "READ_ALL" => 3 - ); - - var $ImageReadMode = 3; /** related to $RealMode arrays values */ - var $file = ""; /** JPEG file to parse for EXIF data */ - var $newFile = 1; /** flag to check if the current file has been parsed or not. */ - - var $thumbnail = ""; /* Name of thumbnail */ - var $thumbnailURL = ""; /* */ - - var $exifSection = -1; // market the exif section index oout of all sections - - var $errno = 0; - var $errstr = ""; - - var $debug = false; - - // Caching ralated variables - var $caching = false; /* Should cacheing of image thumnails be allowed? */ - var $cacheDir = ""; /* Checkout constructor for default path. */ - - /** - * Constructor - * @param string File name to be parsed. - * - */ - function phpExifReader($file = "") { - $this->timeStart = $this->getmicrotime(); - if(!empty($file)) { - $this->file = $file; - } - - /** - * Initialize some variables. Avoid lots of errors with fulll error_reporting - */ - $this->ExifImageLength = 0; - $this->ImageInfo['h']["resolutionUnit"] = 0; - - $this->ImageInfo[TAG_MAXAPERTURE] = 0; - $this->ImageInfo[TAG_ISO_EQUIVALENT] = 0; - $this->ImageInfo[TAG_ORIENTATION] = 0; - - $this->ThumbnailSize = 0; - - if($this->caching) { - $this->cacheDir = dirname(__FILE__)."/.cache_thumbs"; - - /** - * If Cache directory does not exists then attempt to create it. - */ - if(!is_dir($this->cacheDir)) { - mkdir($this->cacheDir); - } - - // Prepare the ame of thumbnail - if(is_dir($this->cacheDir)) { - $this->thumbnail = $this->cacheDir."/".basename($this->file); - $this->thumbnailURL = ".cache_thumbs/".basename($this->file); - } - } - - /** check if file exists! */ - if(!file_exists($this->file)) { - $this->errno = 1; - $this->errstr = "File '".$this->file."' does not exists!"; - } - $this->currSection = 0; - - $this->processFile(); - } - - /** - * Show Debugging information - * - * @param string Debugging message to display - * @param int Type of error (0 - Warning, 1 - Error) - * @return void - * - */ - function debug($str,$TYPE = 0,$file="",$line=0) { - if($this->debug) { - echo "
[$file:$line:".($this->getDiffTime())."]$str"; - flush(); - if($TYPE == 1) { - exit; - } - } - } - - /** - * Processes the whole file. - * - */ - function processFile() { - /** dont reparse the whole file. */ - if(!$this->newFile) return true; - - if(!file_exists($this->file)) { - echo "
Error: File ".($this->file)."does not exists!"; - exit; - } - - $this->debug("Stating Processing of ".$this->newFile,0,__FILE__,__LINE__); - - $i = 0; $exitAll = 0; - /** Open the JPEG in binary safe reading mode */ - $fp = fopen($this->file,"rb"); - - $this->ImageInfo["h"]["FileName"] = $this->file; - $this->ImageInfo["h"]["FileSize"] = filesize($this->file); /** Size of the File */ - $this->ImageInfo["h"]["FileDateTime"] = filectime($this->file); /** File node change time */ - - /** check whether jped image or not */ - $a = fgetc($fp); - if (ord($a) != 0xff || ord(fgetc($fp)) != M_SOI){ - $this->debug("Not a JPEG FILE",1); - $this->errorno = 1; - $this->errorstr = "File '".$this->file."' is not a JPEG File!"; - } - $tmpTestLevel = 0; - /** Examines each byte one-by-one */ - while(!feof($fp)) { - $data = array(); - for ($a=0;$a<7;$a++){ - $marker = fgetc($fp); - if (ord($marker) != 0xff) break; - if ($a >= 6){ - $this->errno = 10; - $this->errstr = "too many padding bytes!"; - $this->debug($this->errstr,1); - return false; - } - } - - if (ord($marker) == 0xff){ - // 0xff is legal padding, but if we get that many, something's wrong. - $this->errno = 10; - $this->errstr = "too many padding bytes!"; - $this->debug($this->errstr,1); - } - - $marker = ord($marker); - $this->sections[$this->currSection]["type"] = $marker; - - // Read the length of the section. - $lh = ord(fgetc($fp)); - $ll = ord(fgetc($fp)); - - $itemlen = ($lh << 8) | $ll; - - if ($itemlen < 2){ - $this->errno = 11; - $this->errstr = "invalid marker"; - $this->debug($this->errstr,1); - } - $this->sections[$this->currSection]["size"] = $itemlen; - - $tmpDataArr = array(); /** Temporary Array */ - - $tmpStr = fread($fp,$itemlen-2); - /* - $tmpDataArr[] = chr($lh); - $tmpDataArr[] = chr($ll); - - $chars = preg_split('//', $tmpStr, -1, PREG_SPLIT_NO_EMPTY); - $tmpDataArr = array_merge($tmpDataArr,$chars); - - $data = $tmpDataArr; - */ - $data = chr($lh).chr($ll).$tmpStr; - - $this->sections[$this->currSection]["data"] = $data; - - $this->debug("

".$this->currSection.":

"); - //print_r($data); - $this->debug("
"); - - //if(count($data) != $itemlen) { - if(strlen($data) != $itemlen) { - $this->errno = 12; - $this->errstr = "Premature end of file?"; - $this->debug($this->errstr,1); - } - - $this->currSection++; /** */ - - switch($marker) { - case M_SOS: - $this->debug("
Found '".M_SOS."' Section, Prcessing it...
");; - // If reading entire image is requested, read the rest of the data. - if ($this->ImageReadMode & $this->ReadMode["READ_IMAGE"]){ - // Determine how much file is left. - $cp = ftell($fp); - fseek($fp,0, SEEK_END); - $ep = ftell($fp); - fseek($fp, $cp, SEEK_SET); - - $size = $ep-$cp; - $got = fread($fp, $size); - - $this->sections[$this->currSection]["data"] = $got; - $this->sections[$this->currSection]["size"] = $size; - $this->sections[$this->currSection]["type"] = PSEUDO_IMAGE_MARKER; - $this->currSection++; - $HaveAll = 1; - $exitAll =1; - } - $this->debug("
'".M_SOS."' Section, PROCESSED
"); - break; - case M_COM: // Comment section - $this->debug("
Found '".M_COM."'(Comment) Section, Processing
"); - $this->process_COM($data, $itemlen); - $this->debug("
'".M_COM."'(Comment) Section, PROCESSED
"); - - $tmpTestLevel++; - break; - case M_SOI: - $this->debug("
=== START OF IMAGE =====
"); - break; - case M_EOI: - $this->debug("
=== END OF IMAGE =====
"); - break; - case M_JFIF: - // Regular jpegs always have this tag, exif images have the exif - // marker instead, althogh ACDsee will write images with both markers. - // this program will re-create this marker on absence of exif marker. - // hence no need to keep the copy from the file. - //echo "
=== M_JFIF =====
"; - $this->sections[--$this->currSection]["data"] = ""; - break; - case M_EXIF: - // Seen files from some 'U-lead' software with Vivitar scanner - // that uses marker 31 for non exif stuff. Thus make sure - // it says 'Exif' in the section before treating it as exif. - $this->debug("
Found '".M_EXIF."'(Exif) Section, Proccessing
"); - $this->exifSection = $this->currSection-1; - if (($this->ImageReadMode & $this->ReadMode["READ_EXIF"]) && ($data[2].$data[3].$data[4].$data[5]) == "Exif"){ - $this->process_EXIF($data, $itemlen); - }else{ - // Discard this section. - $this->sections[--$this->currSection]["data"] = ""; - } - $this->debug("
'".M_EXIF."'(Exif) Section, PROCESSED
"); - $tmpTestLevel++; - break; - case M_SOF0: - case M_SOF1: - case M_SOF2: - case M_SOF3: - case M_SOF5: - case M_SOF6: - case M_SOF7: - case M_SOF9: - case M_SOF10: - case M_SOF11: - case M_SOF13: - case M_SOF14: - case M_SOF15: - $this->debug("
Found M_SOFn Section, Processing
"); - $this->process_SOFn($data,$marker); - $this->debug("
M_SOFn Section, PROCESSED
"); - break; - default: - $this->debug("DEFAULT: Jpeg section marker 0x$marker x size $itemlen\n"); - } - $i++; - if($exitAll == 1) break; - //if($tmpTestLevel == 2) break; - } - fclose($fp); - $this->newFile = 0; - } - - /** - * Changing / Assiging new file - * @param string JPEG file to process - * - */ - function assign($file) { - - if(!empty($file)) { - $this->file = $file; - } - - /** check for existance of file! */ - if(!file_exists($this->file)) { - $this->errorno = 1; - $this->errorstr = "File '".$this->file."' does not exists!"; - } - $this->newFile = 1; - } - - /** - * Process SOFn section of Image - * @param array An array containing whole section. - * @param hex Marker to specify the type of section. - * - */ - function process_SOFn($data,$marker) { - $data_precision = 0; - $num_components = 0; - - $data_precision = ord($data[2]); - - if($this->debug) { - print("Image Dimension Calculation:"); - print("((ord($data[3]) << 8) | ord($data[4]));"); - } - $this->ImageInfo["h"]["Height"] = ((ord($data[3]) << 8) | ord($data[4])); - $this->ImageInfo["h"]["Width"] = ((ord($data[5]) << 8) | ord($data[6])); - - $num_components = ord($data[7]); - - if ($num_components == 3){ - $this->ImageInfo["h"]["IsColor"] = 1; - }else{ - $this->ImageInfo["h"]["IsColor"] = 0; - } - - $this->ImageInfo["h"]["Process"] = $marker; - $this->debug("JPEG image is ".$this->ImageInfo["h"]["Width"]." * ".$this->ImageInfo["h"]["Height"].", $num_components color components, $data_precision bits per sample\n"); - } - - /** - * Process Comments - * @param array Section data - * @param int Length of the section - * - */ - function process_COM($data,$length) { - if ($length > MAX_COMMENT) $length = MAX_COMMENT; - /** Truncate if it won't fit in our structure. */ - - $nch = 0; $Comment = ""; - for ($a=2;$a<$length;$a++){ - $ch = $data[$a]; - if ($ch == '\r' && $data[$a+1] == '\n') continue; // Remove cr followed by lf. - - $Comment .= $ch; - } - //$this->ImageInfo[M_COM] = $Comment; - $this->ImageInfo["h"]["imageComment"] = $Comment; - $this->debug("COM marker comment: $Comment\n"); - } - /** - * Process one of the nested EXIF directories. - * @param string All directory information - * @param string whole Section - * @param int Length of exif section - * - */ - function ProcessExifDir($DirStart, $OffsetBase, $ExifLength) { - - $NumDirEntries = 0; - $ValuePtr = array(); - - $NumDirEntries = $this->Get16u($DirStart[0],$DirStart[1]); - - - $this->debug("
Directory with $NumDirEntries entries\n"); - - for ($de=0;$de<$NumDirEntries;$de++){ - //$DirEntry = array_slice($DirStart,2+12*$de); - $DirEntry = substr($DirStart,2+12*$de); - - $Tag = $this->Get16u($DirEntry[0],$DirEntry[1]); - $Format = $this->Get16u($DirEntry[2],$DirEntry[3]); - $Components = $this->Get32u($DirEntry[4],$DirEntry[5],$DirEntry[6],$DirEntry[7]); - - /** - if ((Format-1) >= NUM_FORMATS) { - // (-1) catches illegal zero case as unsigned underflows to positive large. - ErrNonfatal("Illegal number format %d for tag %04x", Format, Tag); - continue; - } - */ - - $ByteCount = $Components * $this->BytesPerFormat[$Format]; - - if ($ByteCount > 4){ - $OffsetVal = $this->Get32u($DirEntry[8],$DirEntry[9],$DirEntry[10],$DirEntry[11]); - if ($OffsetVal+$ByteCount > $ExifLength){ - $this->debug("Illegal value pointer($OffsetVal) for tag $Tag",1); - } - //$ValuePtr = array_slice($OffsetBase,$OffsetVal); - $ValuePtr = substr($OffsetBase,$OffsetVal); - } else { - //$ValuePtr = array_slice($DirEntry,8); - $ValuePtr = substr($DirEntry,8); - } - - switch($Tag){ - - case TAG_MAKE: - $this->ImageInfo["h"]["make"] = substr($ValuePtr,0,$ByteCount); - break; - - case TAG_MODEL: - $this->ImageInfo["h"]["model"] = substr($ValuePtr,0,$ByteCount); - break; - - case TAG_DATETIME_ORIGINAL: - $this->ImageInfo[TAG_DATETIME_ORIGINAL] = substr($ValuePtr,0,$ByteCount); - $this->ImageInfo["h"]["DateTime"] = substr($ValuePtr,0,$ByteCount); - break; - - case TAG_USERCOMMENT: - // Olympus has this padded with trailing spaces. Remove these first. - for ($a=$ByteCount;;){ - $a--; - if ($ValuePtr[$a] == ' '){ - //$ValuePtr[$a] = '\0'; - } else { - break; - } - if ($a == 0) break; - } - - // Copy the comment - if (($ValuePtr[0].$ValuePtr[1].$ValuePtr[2].$ValuePtr[3].$ValuePtr[4]) == "ASCII"){ - for ($a=5;$a<10;$a++){ - $c = $ValuePtr[$a]; - if ($c != '\0' && $c != ' '){ - $tmp = substr($ValuePtr,0,$ByteCount); - break; - } - } - } else if (($ValuePtr[0].$ValuePtr[1].$ValuePtr[2].$ValuePtr[3].$ValuePtr[4].$ValuePtr[5].$ValuePtr[6]) == "Unicode"){ - $tmp = substr($ValuePtr,0,$ByteCount); - // * Handle Unicode characters here... - } else { - //$this->ImageInfo[TAG_USERCOMMENT] = implode("",array_slice($ValuePtr,0,$ByteCount)); - $tmp = substr($ValuePtr,0,$ByteCount); - } - $this->ImageInfo['h']["exifComment"] = $tmp; - break; - - case TAG_ARTIST: - $this->ImageInfo['h']["artist"] = substr($ValuePtr,0,$ByteCount); - break; - - case TAG_COPYRIGHT: - $this->ImageInfo['h']["copyright"] = htmlentities(substr($ValuePtr,0,$ByteCount)); - break; - - case TAG_FNUMBER: - // Simplest way of expressing aperture, so I trust it the most. - // (overwrite previously computd value if there is one) - $tmp = $this->ConvertAnyFormat(substr($ValuePtr,0), $Format); - $this->ImageInfo['h']["fnumber"] = sprintf("f/%3.1f",(double)$tmp[0]); - break; - - case TAG_APERTURE: - case TAG_MAXAPERTURE: - // More relevant info always comes earlier, so only use this field if we don't - // have appropriate aperture information yet. - if (!isset($this->ImageInfo['h']["aperture"])){ - $tmpArr = $this->ConvertAnyFormat($ValuePtr, $Format); - $this->ImageInfo['h']["aperture"] = exp($tmpArr[0]*log(2)*0.5); - } - break; - - case TAG_FOCALLENGTH: - // Nice digital cameras actually save the focal length as a function - // of how farthey are zoomed in. - $tmp = $this->ConvertAnyFormat($ValuePtr, $Format); - $this->ImageInfo['h']["focalLength"] = sprintf("%4.2f (%d/%d)",(double)$tmp[0],$tmp[1][0],$tmp[1][1]); - if (isset($this->ImageInfo['h']["CCDWidth"])){ - $this->ImageInfo['h']["focalLength"] .= sprintf("(35mm equivalent: %dmm)",(int)($tmp[0]/$this->ImageInfo['h']["CCDWidth"]*36 + 0.5)); - } - break; - - case TAG_SUBJECT_DISTANCE: - // Inidcates the distacne the autofocus camera is focused to. - // Tends to be less accurate as distance increases. - //$this->ImageInfo["h"]["Distance"] = $this->ConvertAnyFormat($ValuePtr, $Format); - $tmp = $this->ConvertAnyFormat($ValuePtr, $Format); - $this->ImageInfo['h']["Distance"] = sprintf("%4.2f (%d/%d)",(double)$tmp[0],$tmp[1][0],$tmp[1][1]); - if ($this->ImageInfo['h']["Distance"] < 0){ - $this->ImageInfo['h']["focusDistance"] = "Infinite"; - } else { - $this->ImageInfo['h']["focusDistance"] = sprintf("%4.2fm",(double)$this->ImageInfo['h']["Distance"]); - } - - - break; - - case TAG_EXPOSURETIME: - // Simplest way of expressing exposure time, so I trust it most. - // (overwrite previously computd value if there is one) - $tmp = $this->ConvertAnyFormat($ValuePtr, $Format); - $this->ImageInfo['h']["exposureTime"] = sprintf("%6.3f s (%d/%d)",(double)$tmp[0],$tmp[1][0],$tmp[1][1]); - if ($tmp[0] <= 0.5){ - $this->ImageInfo['h']["exposureTime"] .= sprintf(" (1/%d)",(int)(0.5 + 1/$tmp[0])); - } - break; - - case TAG_SHUTTERSPEED: - // More complicated way of expressing exposure time, so only use - // this value if we don't already have it from somewhere else. - if (isset($this->ImageInfo[TAG_EXPOSURETIME]) && $this->ImageInfo[TAG_EXPOSURETIME] == 0){ - $sp = $this->ConvertAnyFormat($ValuePtr, $Format); - $this->ImageInfo[TAG_SHUTTERSPEED] = (1/exp($sp[0]*log(2))); - } - break; - - case TAG_FLASH: - $this->ImageInfo["h"]["flashUsed"] = "No"; - if ($this->ConvertAnyFormat($ValuePtr, $Format) & 7){ - $this->ImageInfo["h"]["flashUsed"] = "Yes"; - } - break; - - case TAG_ORIENTATION: - $this->ImageInfo[TAG_ORIENTATION] = $this->ConvertAnyFormat($ValuePtr, $Format); - if ($this->ImageInfo[TAG_ORIENTATION] < 1 || $this->ImageInfo[TAG_ORIENTATION] > 8){ - $this->debug(sprintf("Undefined rotation value %d", $this->ImageInfo[TAG_ORIENTATION], 0),1); - $this->ImageInfo[TAG_ORIENTATION] = 0; - } - break; - - case TAG_EXIF_IMAGELENGTH: - // * Image height - $a = (int) $this->ConvertAnyFormat($ValuePtr, $Format); - if ($this->ExifImageLength < $a) $this->ExifImageLength = $a; - $this->ImageInfo[TAG_EXIF_IMAGELENGTH] = $this->ExifImageLength; - $this->ImageInfo["h"]["Height"] = $this->ExifImageLength; - break; - case TAG_EXIF_IMAGEWIDTH: - // Use largest of height and width to deal with images that have been - // rotated to portrait format. - $a = (int) $this->ConvertAnyFormat($ValuePtr, $Format); - if ($this->ExifImageWidth < $a) $this->ExifImageWidth = $a; - $this->ImageInfo[TAG_EXIF_IMAGEWIDTH] = $this->ExifImageWidth; - $this->ImageInfo["h"]["Width"] = $this->ExifImageWidth; - - break; - - case TAG_FOCALPLANEXRES: - $this->FocalplaneXRes = $this->ConvertAnyFormat($ValuePtr, $Format); - $this->FocalplaneXRes = $this->FocalplaneXRes[0]; - $this->ImageInfo[TAG_FOCALPLANEXRES] = $this->FocalplaneXRes[0]; - break; - - case TAG_FOCALPLANEUNITS: - switch($this->ConvertAnyFormat($ValuePtr, $Format)){ - case 1: $this->FocalplaneUnits = 25.4; break; // inch - case 2: - // According to the information I was using, 2 means meters. - // But looking at the Cannon powershot's files, inches is the only - // sensible value. - $this->FocalplaneUnits = 25.4; - break; - - case 3: $this->FocalplaneUnits = 10; break; // centimeter - case 4: $this->FocalplaneUnits = 1; break; // milimeter - case 5: $this->FocalplaneUnits = .001; break; // micrometer - } - $this->ImageInfo[TAG_FOCALPLANEUNITS] = $this->FocalplaneUnits; - break; - - // Remaining cases contributed by: Volker C. Schoech (schoech@gmx.de) - - case TAG_EXPOSURE_BIAS: - $tmp = $this->ConvertAnyFormat($ValuePtr, $Format); - $this->ImageInfo['h']["exposureBias"] = sprintf("%4.2f (%d/%d)",(double)$tmp[0],$tmp[1][0],$tmp[1][1]); - break; - - case TAG_WHITEBALANCE: - $tmp = (int) $this->ConvertAnyFormat($ValuePtr, $Format); - $tmpArr = array("1"=>"Sunny","2"=>"fluorescent","3"=>"incandescent"); - $this->ImageInfo['h']["whiteBalance"] = - (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Cloudy"); - break; - - case TAG_METERING_MODE: - $tmp = (int) $this->ConvertAnyFormat($ValuePtr, $Format); - - $tmpArr = array("2"=>"center weight","3"=>"spot","5"=>"matrix"); - $this->ImageInfo['h']["meteringMode"] = - (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Reserved"); - break; - - case TAG_EXPOSURE_PROGRAM: - $tmp = (int) $this->ConvertAnyFormat($ValuePtr, $Format); - $tmpArr = array("2"=>"program (auto)","3"=>"aperture priority (semi-auto)","4"=>"shutter priority (semi-auto)"); - $this->ImageInfo['h']["exposure"] = - (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Reserved"); - - break; - - case TAG_ISO_EQUIVALENT: - $tmp = (int) $this->ConvertAnyFormat($ValuePtr, $Format); - if ( $tmp < 50 ) $tmp *= 200; - $this->ImageInfo['h']["isoEquiv"] = sprintf("%2d",(int)$tmp); - break; - - case TAG_COMPRESSION_LEVEL: - $tmp = (int) $this->ConvertAnyFormat($ValuePtr, $Format); - $tmpArr = array("1"=>"Basic","2"=>"Normal","4"=>"Fine"); - $this->ImageInfo['h']["jpegQuality"] = - (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Reserved"); - break; - - case TAG_THUMBNAIL_OFFSET: - $this->ThumbnailOffset = $this->ConvertAnyFormat($ValuePtr, $Format); - $this->DirWithThumbnailPtrs = $DirStart; - break; - - case TAG_THUMBNAIL_LENGTH: - $this->ThumbnailSize = $this->ConvertAnyFormat($ValuePtr, $Format); - $this->ImageInfo[TAG_THUMBNAIL_LENGTH] = $this->ThumbnailSize; - break; - - //---------------------------------------------- - case TAG_IMAGE_DESC: - $this->ImageInfo['h']["imageDesc"] = substr($ValuePtr,0,$ByteCount); - break; - case TAG_X_RESOLUTION: - $tmp = $this->ConvertAnyFormat($ValuePtr, $Format); - $this->ImageInfo['h']["xResolution"] = sprintf("%4.2f (%d/%d) %s",(double)$tmp[0],$tmp[1][0],$tmp[1][1],$this->ImageInfo['h']["resolutionUnit"]); - break; - case TAG_Y_RESOLUTION: - $tmp = $this->ConvertAnyFormat($ValuePtr, $Format); - $this->ImageInfo['h']["yResolution"] = sprintf("%4.2f (%d/%d) %s",(double)$tmp[0],$tmp[1][0],$tmp[1][1],$this->ImageInfo['h']["resolutionUnit"]); - break; - case TAG_RESOLUTION_UNIT: - $tmp = $this->ConvertAnyFormat($ValuePtr, $Format); - $tmpArr = array("2"=>"Inches","3"=>"Centimeters"); - - $this->ImageInfo['h']["resolutionUnit"] = - (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Reserved"); - break; - case TAG_SOFTWARE: - $this->ImageInfo['h']["software"] = substr($ValuePtr,0,$ByteCount); - break; - case TAG_FILE_MODDATE; - $this->ImageInfo['h']["fileModifiedDate"] = substr($ValuePtr,0,$ByteCount); - break; - case TAG_YCBCR_POSITIONING: - $this->ImageInfo['h']["YCbCrPositioning"] = $this->ConvertAnyFormat($ValuePtr, $Format); - break; - case TAG_EXIF_VERSION: - $this->ImageInfo['h']["exifVersion"] = substr($ValuePtr,0,$ByteCount); - break; - case TAG_DATE_TIME_DIGITIZED: - $this->ImageInfo['h']["dateTimeDigitized"] = substr($ValuePtr,0,$ByteCount); - break; - case TAG_COMPONENT_CONFIG: // need more tests for this - $tmp = (int)$this->ConvertAnyFormat($ValuePtr, $Format); - - $tmpArr = array("0"=>"Does Not Exists","1"=>"Y","2"=>"Cb","3"=>"Cr","4"=>"R","5"=>"G","6"=>"B"); - - if(strlen($tmp) < 4 ) { - $this->ImageInfo['h']["componentConfig"] = $tmpArr["0"]; - } else { - for($i=0;$iImageInfo['h']["componentConfig"] .= $tmpArr[$tmp["$i"]]; - } - } - } - break; - case TAG_MAKER_NOTE: - //$this->ImageInfo['h']["makerNote"] = substr($ValuePtr,0,$ByteCount); - $this->ImageInfo['h']["makerNote"] = "NOT IMPLEMENTED"; - break; - case TAG_SUB_SEC_TIME: - $this->ImageInfo['h']["subSectionTime"] = substr($ValuePtr,0,$ByteCount); - break; - case TAG_SUB_SEC_TIME_ORIG: - $this->ImageInfo['h']["subSectionTimeOriginal"] = substr($ValuePtr,0,$ByteCount); - break; - case TAG_SUB_SEC_TIME_DIGITIZED: - $this->ImageInfo['h']["subSectionTimeDigtized"] = substr($ValuePtr,0,$ByteCount); - break; - case TAG_FLASHPIX_VER: - $this->ImageInfo['h']["flashpixVersion"] = substr($ValuePtr,0,$ByteCount); - break; - case TAG_COLOR_SPACE: - $this->ImageInfo['h']["colorSpace"] = substr($ValuePtr,0,$ByteCount); - break; - case TAG_RELATED_SOUND_FILE: - $this->ImageInfo['h']["relatedSoundFile"] = substr($ValuePtr,0,$ByteCount); - break; - case TAG_GPS_LATITUDE_REF: - $this->ImageInfo['h']["GPSLatitudeRef"] = substr($ValuePtr,0,$ByteCount); - break; - case TAG_GPS_LATITUDE: - $this->ImageInfo['h']["GPSLatitude"] = substr($ValuePtr,0,$ByteCount); - break; - case TAG_SENSING_METHOD: - $tmp = $this->ConvertAnyFormat($ValuePtr, $Format); - $tmpArr = array("1"=>"Not Defined","2"=>"One-chip color area sensor","3"=>"Two-chip color area sensor", - "4"=>"Three -chip color area sensor","5"=>"Color sequential area sensor", - "6"=>"Trilinear sensor", "7"=>"Color sequential linear sensor" - ); - - $this->ImageInfo['h']["sensing"] = - (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Reserved"); - break; - case TAG_SOUCE_TYPE: - $this->ImageInfo['h']["sourceType"] = substr($ValuePtr,0,$ByteCount); - break; - case TAG_SCENE_TYPE: - $this->ImageInfo['h']["sceneType"] = substr($ValuePtr,0,$ByteCount); - break; - case TAG_CFA_PATTERN: - $this->ImageInfo['h']["CFAPattern"] = substr($ValuePtr,0,$ByteCount); - break; - case TAG_CUSTOM_RENDERED: - $tmp = $this->ConvertAnyFormat($ValuePtr, $Format); - $this->ImageInfo['h']["customRendered"] = ($tmp == 0) ? 'Normal Process' : ($tmp == 1 ? 'Custom Process' : 'Reserved'); - break; - case TAG_EXPOSURE_MODE: - $tmp = $this->ConvertAnyFormat($ValuePtr, $Format); - $tmpArr = array('Auto Exposure','Manual Exposure','Auto Bracket'); - $this->ImageInfo['h']["exposureMode"] = - (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Reserved"); - break; - case TAG_WHITE_BALANCE: - $this->ImageInfo['h']["whiteBalance"] = $this->ConvertAnyFormat($ValuePtr, $Format); - break; - case TAG_DIGITAL_ZOOM_RATIO: - $tmp = $this->ImageInfo['h']["zoomRatio"] = $this->ConvertAnyFormat($ValuePtr, $Format); - $this->ImageInfo['h']["zoomRatio"] = sprintf("%4.2f (%d/%d)",(double)$tmp[0],$tmp[1][0],$tmp[1][1]); - break; - case TAG_FLENGTH_IN35MM: - $this->ImageInfo['h']["flength35mm"] = $this->ConvertAnyFormat($ValuePtr, $Format); - break; - case TAG_SCREEN_CAP_TYPE: - $tmp = $this->ConvertAnyFormat($ValuePtr, $Format); - $tmpArr = array("Standard","Landscape","Portrait","Night Scene"); - $this->ImageInfo['h']["screenCaptureType"] = - (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Reserved"); - break; - case TAG_GAIN_CONTROL: - $tmp = $this->ConvertAnyFormat($ValuePtr, $Format); - $tmpArr = array("None","Low Gain Up","High Gain Up","Low Gain Down","High Gain Down"); - $this->ImageInfo['h']["gainControl"] = - (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Reserved"); - break; - case TAG_CONTRAST: - $tmp = $this->ConvertAnyFormat($ValuePtr, $Format); - $tmpArr = array("Normal","Soft","Hard"); - $this->ImageInfo['h']["contrast"] = - (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Reserved"); - break; - case TAG_SATURATION: - $tmp = $this->ConvertAnyFormat($ValuePtr, $Format); - $tmpArr = array("Normal","Low Saturation","High Saturation"); - $this->ImageInfo['h']["saturation"] = - (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Reserved"); - break; - case TAG_SHARPNESS: - $tmp = $this->ConvertAnyFormat($ValuePtr, $Format); - $tmpArr = array("Normal","Soft","Hard"); - $this->ImageInfo['h']["sharpness"] = - (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Reserved"); - break; - case TAG_DIST_RANGE: - $tmp = $this->ConvertAnyFormat($ValuePtr, $Format); - $tmpArr = array("Unknown","Macro","Close View","Distant View"); - $this->ImageInfo['h']["distanceRange"] = - (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Reserved"); - break; - case TAG_DEVICE_SETTING_DESC: - /* - $tmp = $this->ConvertAnyFormat($ValuePtr, $Format); - $tmpArr = array("Unknown","Macro","Close View","Distant View"); - $this->ImageInfo['h']["distanceRange"] = - (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Reserved"); - */ - $this->ImageInfo['h']["deviceSettingDesc"] = "NOT IMPLEMENTED"; - break; - case TAG_COMPRESS_SCHEME: - $tmp = $this->ConvertAnyFormat($ValuePtr, $Format); - $tmpArr = array("1"=>"Uncompressed","6"=>"JPEG compression (thumbnails only)"); - $this->ImageInfo['h']["compressScheme"] = - (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Reserved"); - break; - case TAG_IMAGE_WD: - $tmp = $this->ConvertAnyFormat($ValuePtr, $Format); - $this->ImageInfo['h']["jpegImageWidth"] = $tmp; - break; - case TAG_IMAGE_HT: - $tmp = $this->ConvertAnyFormat($ValuePtr, $Format); - $this->ImageInfo['h']["jpegImageHeight"] = $tmp; - break; - case TAG_IMAGE_BPS: - $tmp = $this->ConvertAnyFormat($ValuePtr, $Format); - $this->ImageInfo['h']["jpegBitsPerSample"] = $tmp; - break; - case TAG_IMAGE_PHOTO_INT: - $tmp = $this->ConvertAnyFormat($ValuePtr, $Format); - $this->ImageInfo['h']["jpegPhotometricInt"] = $tmp; - $tmpArr = array("2"=>"RGB","6"=>"YCbCr"); - $this->ImageInfo['h']["jpegPhotometricInt"] = - (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Reserved"); - - break; - case TAG_IMAGE_SOFFSET: - $tmp = $this->ConvertAnyFormat($ValuePtr, $Format); - $this->ImageInfo['h']["jpegStripOffsets"] = $tmp; - break; - case TAG_IMAGE_SPP: - $tmp = $this->ConvertAnyFormat($ValuePtr, $Format); - $this->ImageInfo['h']["jpegSamplesPerPixel"] = $tmp; - break; - case TAG_IMAGE_RPS: - $tmp = $this->ConvertAnyFormat($ValuePtr, $Format); - $this->ImageInfo['h']["jpegRowsPerStrip"] = $tmp; - break; - case TAG_IMAGE_SBC: - $tmp = $this->ConvertAnyFormat($ValuePtr, $Format); - $this->ImageInfo['h']["jpegStripByteCounts"] = $tmp; - break; - case TAG_IMAGE_P_CONFIG: - $tmp = $this->ConvertAnyFormat($ValuePtr, $Format); - $tmpArr = array("1"=>"Chunky Format","2"=>"Planar Format"); - $this->ImageInfo['h']["jpegPlanarConfig"] = - (isset($tmpArr["$tmp"]) ? $tmpArr["$tmp"] : "Reserved"); - break; - case TAG_FOCALPLANE_YRESOL: - $tmp = $this->ConvertAnyFormat($ValuePtr, $Format); - $this->ImageInfo['h']["focalPlaneYResolution"] = sprintf("%4.2f (%d/%d)",(double)$tmp[0],$tmp[1][0],$tmp[1][1]); - break; - case TAG_BRIGHTNESS: - $tmp = $this->ConvertAnyFormat($ValuePtr, $Format); - $this->ImageInfo['h']["brightness"] = sprintf("%4.2f (%d/%d)",(double)$tmp[0],$tmp[1][0],$tmp[1][1]); - break; - //--------------------------------------------- - case TAG_EXIF_OFFSET: - case TAG_INTEROP_OFFSET: - { - - $SubdirStart = substr($OffsetBase,$this->Get32u($ValuePtr[0],$ValuePtr[1],$ValuePtr[2],$ValuePtr[3])); - //if ($SubdirStart < $OffsetBase || $SubdirStart > $OffsetBase+$ExifLength){ - // debug("Illegal exif or interop ofset directory link",1); - //}else{ - //echo "

Calling sub-exif dir

"; - $this->ProcessExifDir($SubdirStart, $OffsetBase, $ExifLength); - //} - continue; - } - default: { - $this->debug("UNKNOWN TAG: $Tag"); - } - } - } - - { - // In addition to linking to subdirectories via exif tags, - // there's also a potential link to another directory at the end of each - // directory. this has got to be the result of a comitee! - $tmpDirStart = substr($DirStart,2+12*$NumDirEntries); - if (strlen($tmpDirStart) + 4 <= strlen($OffsetBase)+$ExifLength){ - $Offset = $this->Get32u($tmpDirStart[0],$tmpDirStart[1],$tmpDirStart[2],$tmpDirStart[3]); - if ($Offset){ - $SubdirStart = substr($OffsetBase,$Offset); - if (strlen($SubdirStart) > strlen($OffsetBase)+$ExifLength){ - if (strlen($SubdirStart) < strlen($OffsetBase)+$ExifLength+20){ - // Jhead 1.3 or earlier would crop the whole directory! - // As Jhead produces this form of format incorrectness, - // I'll just let it pass silently - } else { - $this->errno = 51; - $this->errstr = "Illegal subdirectory link"; - $this->debug($this->errstr,1); - } - }else{ - if (strlen($SubdirStart) <= strlen($OffsetBase)+$ExifLength){ - $this->ProcessExifDir($SubdirStart, $OffsetBase, $ExifLength); - } - } - } - } else { - // The exif header ends before the last next directory pointer. - } - } - - /** - * Check if thumbnail has been cached or not. - * If yes! then read the file. - */ - if(file_exists($this->thumbnail) && $this->caching && (filemtime($this->thumbnail) == filemtime($this->file) )) { - $this->ImageInfo["h"]["Thumbnail"] = $this->thumbnail; - $this->ImageInfo["h"]["ThumbnailSize"] = sprintf("%d bytes",filesize($this->thumbnail)); - } else{ - if ($this->ThumbnailSize && $this->ThumbnailOffset){ - if ($this->ThumbnailSize + $this->ThumbnailOffset <= $ExifLength){ - // The thumbnail pointer appears to be valid. Store it. - $this->ImageInfo["h"]["Thumbnail"] = substr($OffsetBase,$this->ThumbnailOffset); - - // Save the thumbnail / - if($this->caching && is_dir($this->cacheDir)) { - $this->saveThumbnail($this->thumbnail); - $this->ImageInfo["h"]["Thumbnail"] = $this->thumbnail; - } - $this->ImageInfo["h"]["ThumbnailSize"] = sprintf("%d bytes",strlen($this->ImageInfo["h"]["Thumbnail"])); - } - } - } - } - - /** - * Process Exif data - * @param array Section data as an array - * @param int Length of the section (length of data array) - * - */ - function process_EXIF($data,$length) { - - $this->debug("Exif header $length bytes long\n"); - if(($data[2].$data[3].$data[4].$data[5]) != "Exif") { - $this->errno = 52; - $this->errstr = "NOT EXIF FORMAT"; - $this->debug($this->errstr,1); - } - - $this->ImageInfo["h"]["FlashUsed"] = 0; - /** If it s from a digicam, and it used flash, it says so. */ - - $this->FocalplaneXRes = 0; - $this->FocalplaneUnits = 0; - $this->ExifImageWidth = 0; - - if(($data[8].$data[9]) == "II") { - $this->debug("Exif section in Intel order\n"); - $this->MotorolaOrder = 0; - } else if(($data[8].$data[9]) == "MM") { - $this->debug("Exif section in Motorola order\n"); - $this->MotorolaOrder = 1; - } else { - $this->errno = 53; - $this->errstr = "Invalid Exif alignment marker.\n"; - $this->debug($this->errstr,1); - return; - } - - if($this->Get16u($data[10],$data[11]) != 0x2A || $this->Get32s($data[12],$data[13],$data[14],$data[15]) != 0x08) { - $this->errno = 54; - $this->errstr = "Invalid Exif start (1)"; - $this->debug($this->errstr,1); - } - - $DirWithThumbnailPtrs = NULL; - - //$this->ProcessExifDir(array_slice($data,16),array_slice($data,8),$length); - $this->ProcessExifDir(substr($data,16),substr($data,8),$length); - - // Compute the CCD width, in milimeters. 2 - if ($this->FocalplaneXRes != 0){ - $this->ImageInfo["h"]["CCDWidth"] = sprintf("%4.2fmm",(float)($this->ExifImageWidth * $this->FocalplaneUnits / $this->FocalplaneXRes)); - } - - $this->debug("Non settings part of Exif header: ".$length." bytes\n"); - } // end of function process_EXIF - - /** - * Converts two byte number into its equivalent int integer - * @param int - * @param int - * - */ - function Get16u($val,$by) { - if($this->MotorolaOrder){ - return ((ord($val) << 8) | ord($by)); - } else { - return ((ord($by) << 8) | ord($val)); - } - } - - /** - * Converts 4-byte number into its equivalent integer - * - * @param int - * @param int - * @param int - * @param int - * - * @return int - */ - function Get32s($val1,$val2,$val3,$val4) - { - $val1 = ord($val1); - $val2 = ord($val2); - $val3 = ord($val3); - $val4 = ord($val4); - - if ($this->MotorolaOrder){ - return (($val1 << 24) | ($val2 << 16) | ($val3 << 8 ) | ($val4 << 0 )); - }else{ - return (($val4 << 24) | ($val3 << 16) | ($val2 << 8 ) | ($val1 << 0 )); - } - } - /** - * Converts 4-byte number into its equivalent integer with the help of Get32s - * - * @param int - * @param int - * @param int - * @param int - * - * @return int - * - */ - function get32u($val1,$val2,$val3,$val4) { - return ($this->Get32s($val1,$val2,$val3,$val4) & 0xffffffff); - } - - //-------------------------------------------------------------------------- - // Evaluate number, be it int, rational, or float from directory. - //-------------------------------------------------------------------------- - function ConvertAnyFormat($ValuePtr, $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 = $this->Get32s($ValuePtr[0],$ValuePtr[1],$ValuePtr[2],$ValuePtr[3]); - $Den = $this->Get32s($ValuePtr[4],$ValuePtr[5],$ValuePtr[6],$ValuePtr[7]); - if ($Den == 0){ - $Value = 0; - }else{ - $Value = (double) ($Num/$Den); - } - return array($Value,array($Num,$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; - } - return $Value; - } - - /** - * Function to extract thumbnail from Exif data of the image. - * and store it in a filename given by $ThumbFile - * - * @param String Files name to store the thumbnail - * - */ - function saveThumbnail($ThumbFile) { - $ThumbFile = trim($ThumbFile); - $file = basename($this->file); - - if(empty($ThumbFile)) $ThumbFile = "th_$file"; - - if (!empty($this->ImageInfo["h"]["Thumbnail"])){ - $tp = fopen($ThumbFile,"wb"); - if(!$tp) { - $this->errno = 2; - $this->errstr = "Cannot Open file '$ThumbFile'"; - } - fwrite($tp,$this->ImageInfo["h"]["Thumbnail"]); - fclose($tp); - touch($ThumbFile,filemtime($this->file)); - } - //$this->thumbnailURL = $ThumbFile; - $this->ImageInfo["h"]["Thumbnail"] = $ThumbFile; - } - - /** - * Returns thumbnail url along with parameter supplied. - * Should be called in src attribute of image - * - * @return string File URL - * - */ - function showThumbnail() { - return "showThumbnail.php?file=".$this->file; - //$this->ImageInfo["h"]["Thumbnail"] - } - - /** - * Function to give back thumbail image - * @return string full image - * - */ - function getThumbnail() { - return $this->ImageInfo["h"]["Thumbnail"]; - } - - /** - * - */ - function getImageInfo() { - - $imgInfo = $this->ImageInfo["h"]; - - if ( !isset ( $imgInfo["Width"] ) ) return array ( "EXIF" => "NO" ) ; # Dummy entry to distinguish von empty (=never generated) one - - $retArr = $imgInfo; - $retArr["FileName"] = $imgInfo["FileName"]; - $retArr["FileSize"] = $imgInfo["FileSize"]." bytes"; - - $retArr["FileDateTime"] = date("d-M-Y H:i:s",$imgInfo["FileDateTime"]); - - $retArr["resolution"] = $imgInfo["Width"]."x".$imgInfo["Height"]; - - - if ($this->ImageInfo[TAG_ORIENTATION] > 1){ - // Only print orientation if one was supplied, and if its not 1 (normal orientation) - - // 1 - "The 0th row is at the visual top of the image, and the 0th column is the visual left-hand side." - // 2 - "The 0th row is at the visual top of the image, and the 0th column is the visual right-hand side." - // 3 - "The 0th row is at the visual bottom of the image, and the 0th column is the visual right-hand side." - // 4 - "The 0th row is at the visual bottom of the image, and the 0th column is the visual left-hand side." - - // 5 - "The 0th row is the visual left-hand side of of the image, and the 0th column is the visual top." - // 6 - "The 0th row is the visual right-hand side of of the image, and the 0th column is the visual top." - // 7 - "The 0th row is the visual right-hand side of of the image, and the 0th column is the visual bottom." - // 8 - "The 0th row is the visual left-hand side of of the image, and the 0th column is the visual bottom." - - // Note: The descriptions here are the same as the name of the command line - // ption to pass to jpegtran to right the image - $OrientTab = array( - "Undefined", - "Normal", // 1 - "flip horizontal", // left right reversed mirror - "rotate 180", // 3 - "flip vertical", // upside down mirror - "transpose", // Flipped about top-left <--> bottom-right axis. - "rotate 90", // rotate 90 cw to right it. - "transverse", // flipped about top-right <--> bottom-left axis - "rotate 270", // rotate 270 to right it. - ); - - $retArr["orientation"] = $OrientTab[$this->ImageInfo[TAG_ORIENTATION]]; - } - - $retArr["color"] = ($imgInfo["IsColor"] == 0) ? "Black and white" : "Color"; - - if(isset($imgInfo["Process"])) { - switch($imgInfo["Process"]) { - case M_SOF0: $process = "Baseline";break; - case M_SOF1: $process = "Extended sequential";break; - case M_SOF2: $process = "Progressive";break; - case M_SOF3: $process = "Lossless";break; - case M_SOF5: $process = "Differential sequential";break; - case M_SOF6: $process = "Differential progressive";break; - case M_SOF7: $process = "Differential lossless";break; - case M_SOF9: $process = "Extended sequential, arithmetic coding";break; - case M_SOF10: $process = "Progressive, arithmetic coding";break; - case M_SOF11: $process = "Lossless, arithmetic coding";break; - case M_SOF13: $process = "Differential sequential, arithmetic coding";break; - case M_SOF14: $process = "Differential progressive, arithmetic coding";break; - case M_SOF15: $process = "Differential lossless, arithmetic coding";break; - default: $process = "Unknown"; - } - $retArr["jpegProcess"] = $process; - } - - if(file_exists($this->thumbnailURL)) { - $retArr["Thumbnail"] = "$this->thumbnailURL"; - } - - return $retArr; - } - - /** - * Returns time in microseconds - */ - function getmicrotime(){ - list($usec, $sec) = explode(" ",microtime()); - return ((float)$usec + (float)$sec); - } - - /** - * Get the time difference - */ - function getDiffTime() { - return ($this->getmicrotime() - $this->timeStart); - } -} // end of class -?> -- 2.20.1