Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <?php
- $exif = new Exif("test.jpg");
- $dt = "2011:08:10 12:00:00";
- $exif->add_entry("DateTime", TagEntry::FORMAT_ASCII_STRINGS, 19, $dt);
- $exif->add_entry("DateTimeOriginal", TagEntry::FORMAT_ASCII_STRINGS, 19, $dt);
- $exif->add_entry("DateTimeDigitized", TagEntry::FORMAT_ASCII_STRINGS, 19, $dt);
- file_put_contents("test2.jpg", $exif->to_binary());
- class TagEntry {
- const BYTE_SIZE = 12;
- const FORMAT_UNSIGNED_BYTE = 1;
- const FORMAT_ASCII_STRINGS = 2;
- const FORMAT_UNSIGNED_SHORT = 3;
- const FORMAT_UNSIGNED_LONG = 4;
- const FORMAT_UNSIGNED_RATIONAL = 5;
- const FORMAT_SIGNED_BYTE = 6;
- const FORMAT_UNDEFINED = 7;
- const FORMAT_SIGNED_SHORT = 8;
- const FORMAT_SIGNED_LONG = 9;
- const FORMAT_SIGNED_RATIONAL = 10;
- const FORMAT_SIGNED_FLOAT = 11;
- const FORMAT_DOUBLE_FLOAT = 12;
- var $_data_size = array(
- self::FORMAT_UNSIGNED_BYTE => 1,
- self::FORMAT_ASCII_STRINGS => 1,
- self::FORMAT_UNSIGNED_SHORT => 2,
- self::FORMAT_UNSIGNED_LONG => 4,
- self::FORMAT_UNSIGNED_RATIONAL => 8,
- self::FORMAT_SIGNED_BYTE => 1,
- self::FORMAT_UNDEFINED => 1,
- self::FORMAT_SIGNED_SHORT => 2,
- self::FORMAT_SIGNED_LONG => 4,
- self::FORMAT_SIGNED_RATIONAL => 8,
- self::FORMAT_SIGNED_FLOAT => 4,
- self::FORMAT_DOUBLE_FLOAT => 8,
- );
- var $_tag; // 0xXXXX
- var $_format;
- var $_num;
- var $_val;
- var $_offset = 0;
- function __construct($tag, $format, $num, $val){
- $this->_tag = $tag;
- $this->_format = $format;
- $this->_num = $num;
- $this->_val = $val;
- }
- function is_over_size(){
- $size = $this->size();
- return ($size > 4);
- }
- function size(){
- return $this->_data_size[$this->_format] * $this->_num;
- }
- function to_binary(){
- $data = "";
- $data .= pack("v", $this->_tag);
- $data .= pack("v", $this->_format);
- $data .= pack("V", $this->_num);
- if($this->_offset){
- $data .= pack("V", $this->_offset);
- }
- else{
- $data .= $this->_val;
- }
- return $data;
- }
- }
- class IFD {
- var $_enabled_tags;
- var $_entries;
- function __construct(){
- $this->_enabled_tags = array();
- $this->_entries = array();
- }
- function is_enabled_tag($tag){
- return ( ! empty($this->_enabled_tags[$tag]));
- }
- function add_entry($tag, $format, $num, $val){
- if( ! $this->is_enabled_tag($tag)){
- return FALSE;
- }
- $this->_entries[$tag] = new TagEntry($this->_enabled_tags[$tag], $format, $num, $val);
- }
- function has_entry(){
- return (count(array_values($this->_entries)) > 0);
- }
- function to_binary($base, $has_next_ifd = FALSE){
- if( ! $this->has_entry()){
- return array(0, "", "", "");
- }
- $entries = array_values($this->_entries);
- $entries_count = count($entries);
- // pointer of base + byte of entry_count_area + byte of entries + byte of next_link_area
- $data_section_base = $base + 2 + TagEntry::BYTE_SIZE * count($entries) + 4;
- $dir_section = "";
- $next_link = "";
- $data_section = "";
- // 2byte - number of entry
- $dir_section .= pack("v", $entries_count);
- // 12byte * n - entries
- foreach($entries as $entry){
- if($entry->is_over_size()){
- $size = $entry->size();
- $val = $entry->_val;
- $entry->_offset = $data_section_base;
- $data_section_base += $size;
- $data_section .= $val;
- }
- $dir_section .= $entry->to_binary();
- }
- // 4byte - offset to next ifd
- if($has_next_ifd){
- $size = strlen($dir_section) + 4 + strlen($data_section);
- $next_link .= pack("V", $base + $size);
- }
- else{
- $next_link .= pack("V", 0);
- }
- return array(strlen($dir_section . $next_link . $data_section), $dir_section, $next_link, $data_section);
- }
- }
- class IFD0 extends IFD {
- function __construct(){
- parent::__construct();
- $this->_enabled_tags = array(
- "ImageDescription" => 0x010e,
- "Make" => 0x010f,
- "Model" => 0x0110,
- "Orientation" => 0x0112,
- "XResolution" => 0x011a,
- "YResolution" => 0x011b,
- "ResolutionUnit" => 0x0128,
- "Software" => 0x0131,
- "DateTime" => 0x0132,
- "WhitePoint" => 0x013e,
- "PrimaryChromaticities" => 0x013f,
- "YCbCrCoefficients" => 0x0211,
- "YCbCrPositioning" => 0x0213,
- "ReferenceBlackWhite" => 0x0214,
- "Copyright" => 0x8298,
- "ExifIFDPointer" => 0x8769,
- );
- }
- function to_binary($base, $has_next_ifd = FALSE){
- if( ! $this->has_entry()){
- return array(0, "", "", "");
- }
- // dummy entry
- $this->add_entry("ExifIFDPointer", TagEntry::FORMAT_UNSIGNED_LONG, 1, pack("V", 0));
- list($size, $dir, $link, $data) = parent::to_binary($base, $has_next_ifd);
- $exif_ifd_base = $base + $size;
- // set real entry
- $this->add_entry("ExifIFDPointer", TagEntry::FORMAT_UNSIGNED_LONG, 1, pack("V", $exif_ifd_base));
- // recalc
- return parent::to_binary($base, $has_next_ifd);
- }
- }
- class IFDExif extends IFD {
- function __construct(){
- parent::__construct();
- $this->_enabled_tags = array(
- "ExposureTime" => 0x829a,
- "FNumber" => 0x829d,
- "ExposureProgram" => 0x8822,
- "ISOSpeedRatings" => 0x8827,
- "ExifVersion" => 0x9000,
- "DateTimeOriginal" => 0x9003,
- "DateTimeDigitized" => 0x9004,
- "ComponentsConfiguration" => 0x9101,
- "CompressedBitsPerPixel" => 0x9102,
- "ShutterSpeedValue" => 0x9201,
- "ApertureValue" => 0x9202,
- "BrightnessValue" => 0x9203,
- "ExposureBiasValue" => 0x9204,
- "MaxApertureValue" => 0x9205,
- "SubjectDistance" => 0x9206,
- "MeteringMode" => 0x9207,
- "LightSource" => 0x9208,
- "Flash" => 0x9209,
- "FocalLength" => 0x920a,
- "MakerNote" => 0x927c,
- "UserComment" => 0x9286,
- "SubsecTime" => 0x9290,
- "SubsecTimeOriginal" => 0x9291,
- "SubsecTimeDigitized" => 0x9292,
- "FlashPixVersion" => 0xa000,
- "ColorSpace" => 0xa001,
- "ExifImageWidth" => 0xa002,
- "ExifImageHeight" => 0xa003,
- "RelatedSoundFile" => 0xa004,
- "InteroperabilityIFDPointer" => 0xa005,
- "FocalPlaneXResolution" => 0xa20e,
- "FocalPlaneYResolution" => 0xa20f,
- "FocalPlaneResolutionUnit" => 0xa210,
- "ExposureIndex" => 0xa215,
- "SensingMethod" => 0xa217,
- "FileSource" => 0xa300,
- "SceneType" => 0xa301,
- "CFAPattern" => 0xa302,
- );
- }
- }
- class IFD1 extends IFD {
- function __construct(){
- parent::__construct();
- $this->_enabled_tags = array(
- "ImageWidth" => 0x0100,
- "ImageLength" => 0x0101,
- "BitsPerSample" => 0x0102,
- "Compression" => 0x0103,
- "PhotometricInterpretation" => 0x0106,
- "StripOffsets" => 0x0111,
- "Orientation" => 0x0112,
- "SamplesPerPixel" => 0x0115,
- "RowsPerStrip" => 0x0116,
- "StripByteConunts" => 0x0117,
- "XResolution" => 0x011a,
- "YResolution" => 0x011b,
- "PlanarConfiguration" => 0x011c,
- "ResolutionUnit" => 0x0128,
- "JpegInterchangeFormat" => 0x0201,
- "JpegInterchangeFormatLength" => 0x0202,
- "YCbCrCoefficients" => 0x0211,
- "YCbCrSubSampling" => 0x0212,
- "YCbCrPositioning" => 0x0213,
- "ReferenceBlackWhite" => 0x0214,
- );
- }
- }
- class Exif {
- var $_ifd0;
- var $_ifdexif;
- var $_ifd1;
- var $_path;
- function __construct($path){
- $this->_ifd0 = new IFD0();
- $this->_ifdexif = new IFDExif();
- $this->_ifd1 = new IFD1();
- $this->_path = $path;
- $this->_ifd0->add_entry("Make", TagEntry::FORMAT_ASCII_STRINGS, 4, str_pad("", 4));
- $this->_ifd0->add_entry("Model", TagEntry::FORMAT_ASCII_STRINGS, 4, str_pad("", 4));
- $this->_ifd0->add_entry("DateTime", TagEntry::FORMAT_ASCII_STRINGS, 19, str_pad("", 19));
- $this->_ifdexif->add_entry("DateTimeOriginal", TagEntry::FORMAT_ASCII_STRINGS, 19, str_pad("", 19));
- $this->_ifdexif->add_entry("DateTimeDigitized", TagEntry::FORMAT_ASCII_STRINGS, 19, str_pad("", 19));
- }
- function add_entry($tag, $format, $num, $val){
- if($this->_ifd0->is_enabled_tag($tag)){
- $this->_ifd0->add_entry($tag, $format, $num, $val);
- }
- else if($this->_ifdexif->is_enabled_tag($tag)){
- $this->_ifdexif->add_entry($tag, $format, $num, $val);
- }
- else if($this->_ifd1->is_enabled_tag($tag)){
- $this->_ifd1->add_entry($tag, $format, $num, $val);
- }
- else{
- return FALSE;
- }
- }
- function to_binary(){
- $reader = new Reader($this->_path);
- $data = "";
- // SOI(2byte)
- $data .= $reader->read(2);
- // APP0
- $marker = $reader->read_unsigned_short();
- if($marker == 0xFFE0){
- $size = $reader->read_unsigned_short();
- $data .= pack("n", $marker);
- $data .= pack("n", $size);
- $data .= $reader->read($size - 2); // exclude size area
- }
- else{
- // back
- $reader->seek(-2);
- }
- // APP1
- $app1 = "";
- // Exif header
- $app1 .= "Exif" . pack("n", 0x0000);
- // Tiff header - intel format
- $base = 8;
- $app1 .= "II" . pack("v", 0x002A) . pack("V", $base);
- $current_base = $base;
- // IFD0
- list($ifd0_size, $ifd0_dir, $ifd0_link, $ifd0_data) =
- $this->_ifd0->to_binary($current_base, $this->_ifd1->has_entry());
- $current_base += $ifd0_size;
- // ExifIFD
- list($ifdexif_size, $ifdexif_dir, $ifdexif_link, $ifdexif_data) = $this->_ifdexif->to_binary($current_base);
- $current_base += $ifdexif_size;
- // IFD1
- list($ifd1_size, $ifd1_dir, $ifd1_link, $ifd1_data) = $this->_ifd1->to_binary($current_base);
- $current_base += $ifd1_size;
- $app1 .= $ifd0_dir;
- if($this->_ifd1->has_entry()){
- $app1 .= pack("V", $base + $ifd0_size + $ifdexif_size);
- }
- else{
- $app1 .= $ifd0_link;
- }
- $app1 .= $ifd0_data;
- $app1 .= $ifdexif_dir . $ifdexif_link . $ifdexif_data;
- $app1 .= $ifd1_dir . $ifd1_link . $ifd1_data;
- if($ifd0_size + $ifdexif_size + $ifd1_size > 0){
- // Marker
- $data .= pack("n", 0xFFE1);
- // App1 size
- $data .= pack("n", 2 + strlen($app1));
- // App1 data
- $data .= $app1;
- }
- // remain data
- $data .= $reader->read();
- $reader->close();
- return $data;
- }
- }
- class Reader {
- const BYTE_ORDER_BE = 1;
- const BYTE_ORDER_LE = 2;
- function __construct($path = ""){
- $this->_byte_order = self::BYTE_ORDER_BE;
- if($path){
- $this->open($path);
- }
- }
- function open($path){
- $this->_fp = fopen($path, "r");
- }
- function close(){
- fclose($this->_fp);
- }
- function set_byte_order($order){
- $this->_byte_order = $order;
- }
- function get_byte_order($order){
- return $this->_byte_order;
- }
- function is_be(){
- return ($this->_byte_order == self::BYTE_ORDER_BE);
- }
- function is_le(){
- return ( ! $this->is_be());
- }
- function seek($offset){
- fseek($this->_fp, $offset, SEEK_CUR);
- }
- function read($length = 0){
- if(feof($this->_fp)){
- return NULL;
- }
- if($length){
- return fread($this->_fp, $length);
- }
- else{
- $data = '';
- while( ! feof($this->_fp)){
- $data .= fread($this->_fp, 4096);
- }
- return $data;
- }
- }
- function read_hex_string($length){
- $data = $this->read($length);
- $format = "H*";
- return array_shift(unpack($format, $data));
- }
- function read_byte(){
- $data = $this->read(1);
- $format = "c";
- return array_shift(unpack($format, $data));
- }
- function read_unsigned_byte(){
- $data = $this->read(1);
- $format = "C";
- return array_shift(unpack($format, $data));
- }
- function read_unsigned_short(){
- $data = $this->read(2);
- $format = ($this->is_be()) ? "n" : "v";
- return array_shift(unpack($format, $data));
- }
- function read_unsigned_long(){
- $data = $this->read(4);
- $format = ($this->is_be()) ? "N" : "V";
- return array_shift(unpack($format, $data));
- }
- }
Add Comment
Please, Sign In to add comment