/** * Panasonic Special data section */ public function parse($block, &$result) { $intel = true; $model = $result['IFD0']['Model']; //current place $place = 8; $offset = 8; $num = bin2hex(substr($block, $place, 4)); $place += 4; if ($intel) { $num = Horde_Image_Exif::intel2Moto($num); } $result['SubIFD']['MakerNote']['Offset'] = hexdec($num); //Get number of tags (2 bytes) $num = bin2hex(substr($block, $place, 2)); $place += 2; if ($intel) { $num = Horde_Image_Exif::intel2Moto($num); } $result['SubIFD']['MakerNote']['MakerNoteNumTags'] = hexdec($num); //loop thru all tags Each field is 12 bytes for ($i = 0; $i < hexdec($num); $i++) { //2 byte tag $tag = bin2hex(substr($block, $place, 2)); $place += 2; if ($intel) { $tag = Horde_Image_Exif::intel2Moto($tag); } $tag_name = $this->_lookupTag($tag); //2 byte type $type = bin2hex(substr($block, $place, 2)); $place += 2; if ($intel) { $type = Horde_Image_Exif::intel2Moto($type); } $this->_lookupType($type, $size); //4 byte count of number of data units $count = bin2hex(substr($block, $place, 4)); $place += 4; if ($intel) { $count = Horde_Image_Exif::intel2Moto($count); } $bytesofdata = $size * hexdec($count); //4 byte value of data or pointer to data $value = substr($block, $place, 4); $place += 4; if ($bytesofdata <= 4) { $data = $value; } else { $value = bin2hex($value); if ($intel) { $value = Horde_Image_Exif::intel2Moto($value); } $data = substr($block, hexdec($value) - $offset, $bytesofdata * 2); } $formated_data = $this->_formatData($type, $tag, $intel, $data); $result['SubIFD']['MakerNote'][$tag_name] = $formated_data; } }
/** * * @param $block * @param $result * @param $seek * @param $globalOffset * @return unknown_type */ public function parse($block, &$result, $seek, $globalOffset) { $intel = $result['Endien'] == 'Intel'; $model = $result['IFD0']['Model']; // New header for new DSLRs - Check for it because the number of bytes // that count the IFD fields differ in each case. Fixed by Zenphoto // 2/24/08 $new = false; if (substr($block, 0, 8) == "OLYMPUS") { $new = true; } elseif (substr($block, 0, 7) == "OLYMP" || substr($block, 0, 7) == "OLYMP") { $new = false; } else { // Header does not match known Olympus headers. // This is not a valid OLYMPUS Makernote. return false; } // Offset of IFD entry after Olympus header. $place = 8; $offset = 8; // Get number of tags (1 or 2 bytes, depending on New or Old makernote) $countfieldbits = $new ? 1 : 2; // New makernote repeats 1-byte value twice, so increment $place by 2 // in either case. $num = bin2hex(substr($block, $place, $countfieldbits)); $place += 2; if ($intel) { $num = Horde_Image_Exif::intel2Moto($num); } $ntags = hexdec($num); $result['SubIFD']['MakerNote']['MakerNoteNumTags'] = $ntags; //loop thru all tags Each field is 12 bytes for ($i = 0; $i < $ntags; $i++) { //2 byte tag $tag = bin2hex(substr($block, $place, 2)); $place += 2; if ($intel) { $tag = Horde_Image_Exif::intel2Moto($tag); } $tag_name = $this->_lookupTag($tag); //2 byte type $type = bin2hex(substr($block, $place, 2)); $place += 2; if ($intel) { $type = Horde_Image_Exif::intel2Moto($type); } list($type, $size) = $this->_lookupType($type); //4 byte count of number of data units $count = bin2hex(substr($block, $place, 4)); $place += 4; if ($intel) { $count = Horde_Image_Exif::intel2Moto($count); } $bytesofdata = $size * hexdec($count); //4 byte value of data or pointer to data $value = substr($block, $place, 4); $place += 4; if ($bytesofdata <= 4) { $data = $value; } else { $value = bin2hex($value); if ($intel) { $value = Horde_Image_Exif::intel2Moto($value); } //offsets are from TIFF header which is 12 bytes from the start //of the file // $v = fseek($seek, $globalOffset + hexdec($value)); $result['Errors'] = $result['Errors']++; $data = ''; } $formated_data = $this->_formatData($type, $tag, $intel, $data); $result['SubIFD']['MakerNote'][$tag_name] = $formated_data; } }
/** * * @param $block * @param $result * @return unknown_type */ public function parse($block, &$result) { $intel = $result['Endien'] == 'Intel'; $model = $result['IFD0']['Model']; //these 6 models start with "Nikon". Other models dont. if ($model == "E700" || $model == "E800" || $model == "E900" || $model == "E900S" || $model == "E910" || $model == "E950") { //current place $place = 8; $model = 0; //Get number of tags (2 bytes) $num = bin2hex(substr($block, $place, 2)); $place += 2; if ($intel) { $num = Horde_Image_Exif::intel2Moto($num); } $result['SubIFD']['MakerNote']['MakerNoteNumTags'] = hexdec($num); //loop thru all tags Each field is 12 bytes for ($i = 0; $i < hexdec($num); $i++) { //2 byte tag $tag = bin2hex(substr($block, $place, 2)); $place += 2; if ($intel) { $tag = Horde_Image_Exif::intel2Moto($tag); } $tag_name = $this->_lookupTag($tag, $model); //2 byte type $type = bin2hex(substr($block, $place, 2)); $place += 2; if ($intel) { $type = Horde_Image_Exif::intel2Moto($type); } $this->_lookupType($type, $size); //4 byte count of number of data units $count = bin2hex(substr($block, $place, 4)); $place += 4; if ($intel) { $count = Horde_Image_Exif::intel2Moto($count); } $bytesofdata = $size * hexdec($count); //4 byte value of data or pointer to data $value = substr($block, $place, 4); $place += 4; //if tag is 0002 then its the ASCII value which we know is at 140 so calc offset //THIS HACK ONLY WORKS WITH EARLY NIKON MODELS if ($tag == '0002') { $offset = hexdec($value) - 140; } if ($bytesofdata <= 4) { $data = $value; } else { $value = bin2hex($value); if ($intel) { $value = Horde_Image_Exif::intel2Moto($value); } $data = substr($block, hexdec($value) - $offset, $bytesofdata * 2); } $formated_data = $this->_formatData($type, $tag, $intel, $model, $data); $result['SubIFD']['MakerNote'][$tag_name] = $formated_data; } } else { //current place $place = 0; $model = 1; $nikon = substr($block, $place, 8); $place += 8; $endien = substr($block, $place, 4); $place += 4; //2 bytes of 0x002a $tag = bin2hex(substr($block, $place, 2)); $place += 2; //Then 4 bytes of offset to IFD0 (usually 8 which includes all 8 //bytes of TIFF header) $offset = bin2hex(substr($block, $place, 4)); $place += 4; if ($intel) { $offset = Horde_Image_Exif::intel2Moto($offset); } if (hexdec($offset) > 8) { $place += $offset - 8; } //Get number of tags (2 bytes) $num = bin2hex(substr($block, $place, 2)); $place += 2; if ($intel) { $num = Horde_Image_Exif::intel2Moto($num); } //loop thru all tags Each field is 12 bytes for ($i = 0; $i < hexdec($num); $i++) { //2 byte tag $tag = bin2hex(substr($block, $place, 2)); $place += 2; if ($intel) { $tag = Horde_Image_Exif::intel2Moto($tag); } $tag_name = $this->_lookupTag($tag, $model); //2 byte type $type = bin2hex(substr($block, $place, 2)); $place += 2; if ($intel) { $type = Horde_Image_Exif::intel2Moto($type); } $this->_lookupType($type, $size); //4 byte count of number of data units $count = bin2hex(substr($block, $place, 4)); $place += 4; if ($intel) { $count = Horde_Image_Exif::intel2Moto($count); } $bytesofdata = $size * hexdec($count); //4 byte value of data or pointer to data $value = substr($block, $place, 4); $place += 4; if ($bytesofdata <= 4) { $data = $value; } else { $value = bin2hex($value); if ($intel) { $value = Horde_Image_Exif::intel2Moto($value); } $data = substr($block, hexdec($value) + hexdec($offset) + 2, $bytesofdata); } $formated_data = $this->_formatData($type, $tag, $intel, $model, $data); $result['SubIFD']['MakerNote'][$tag_name] = $formated_data; } } }
/** * Canon Special data section. * * @see http://www.burren.cx/david/canon.html * @see http://www.burren.cx/david/canon.html * @see http://www.ozhiker.com/electronics/pjmt/jpeg_info/canon_mn.html */ public function parse($block, &$result, $seek, $globalOffset) { $place = 0; //current place if ($result['Endien'] == 'Intel') { $intel = 1; } else { $intel = 0; } $model = $result['IFD0']['Model']; //Get number of tags (2 bytes) $num = bin2hex(substr($block, $place, 2)); $place += 2; if ($intel == 1) { $num = Horde_Image_Exif::intel2Moto($num); } $result['SubIFD']['MakerNote']['MakerNoteNumTags'] = hexdec($num); //loop thru all tags Each field is 12 bytes for ($i = 0; $i < hexdec($num); $i++) { //2 byte tag $tag = bin2hex(substr($block, $place, 2)); $place += 2; if ($intel == 1) { $tag = Horde_Image_Exif::intel2Moto($tag); } $tag_name = $this->_lookupTag($tag); //2 byte type $type = bin2hex(substr($block, $place, 2)); $place += 2; if ($intel == 1) { $type = Horde_Image_Exif::intel2Moto($type); } $this->_lookupType($type, $size); //4 byte count of number of data units $count = bin2hex(substr($block, $place, 4)); $place += 4; if ($intel == 1) { $count = Horde_Image_Exif::intel2Moto($count); } $bytesofdata = $size * hexdec($count); if ($bytesofdata <= 0) { return; //if this value is 0 or less then we have read all the tags we can } //4 byte value of data or pointer to data $value = substr($block, $place, 4); $place += 4; if ($bytesofdata <= 4) { $data = $value; } else { $value = bin2hex($value); if ($intel == 1) { $value = Horde_Image_Exif::intel2Moto($value); } //offsets are from TIFF header which is 12 bytes from the start //of the file $v = fseek($seek, $globalOffset + hexdec($value)); $exiferFileSize = 0; if ($v == 0 && $bytesofdata < $exiferFileSize) { $data = fread($seek, $bytesofdata); } elseif ($v == -1) { $result['Errors'] = $result['Errors']++; $data = ''; } else { $data = ''; } } // Ensure the index exists. $result['SubIFD']['MakerNote'][$tag_name] = ''; $formated_data = $this->_formatData($type, $tag, $intel, $data, $result, $result['SubIFD']['MakerNote'][$tag_name]); $result['SubIFD']['MakerNote'][$tag_name] = $formated_data; } }
/** * GPS Special data section * * @see http://drewnoakes.com/code/exif/sampleOutput.html * @see http://www.geosnapper.com */ public function parse($block, &$result, $offset, $seek, $globalOffset) { if ($result['Endien'] == 'Intel') { $intel = 1; } else { $intel = 0; } //offsets are from TIFF header which is 12 bytes from the start of the //file $v = fseek($seek, $globalOffset + $offset); if ($v == -1) { $result['Errors'] = $result['Errors']++; } $num = bin2hex(fread($seek, 2)); if ($intel == 1) { $num = Horde_Image_Exif::intel2Moto($num); } $num = hexdec($num); $result['GPS']['NumTags'] = $num; $block = fread($seek, $num * 12); $place = 0; //loop thru all tags Each field is 12 bytes for ($i = 0; $i < $num; $i++) { //2 byte tag $tag = bin2hex(substr($block, $place, 2)); $place += 2; if ($intel == 1) { $tag = Horde_Image_Exif::intel2Moto($tag); } $tag_name = $this->_lookupTag($tag); //2 byte datatype $type = bin2hex(substr($block, $place, 2)); $place += 2; if ($intel == 1) { $type = Horde_Image_Exif::intel2Moto($type); } $this->_lookupType($type, $size); //4 byte number of elements $count = bin2hex(substr($block, $place, 4)); $place += 4; if ($intel == 1) { $count = Horde_Image_Exif::intel2Moto($count); } $bytesofdata = $size * hexdec($count); //4 byte value or pointer to value if larger than 4 bytes $value = substr($block, $place, 4); $place += 4; if ($bytesofdata <= 4) { $data = $value; } else { $value = bin2hex($value); if ($intel == 1) { $value = Horde_Image_Exif::intel2Moto($value); } //offsets are from TIFF header which is 12 bytes from the start //of the file $v = fseek($seek, $globalOffset + hexdec($value)); if ($v == 0) { $data = fread($seek, $bytesofdata); } elseif ($v == -1) { $result['Errors'] = $result['Errors']++; } } $result['GPS' . $tag_name] = $this->_formatData($type, $tag, $intel, $data); } }
/** * * @param $block * @param $result * @param $seek * @param $globalOffset * @return unknown_type */ public function parse($block, &$result, $seek, $globalOffset) { $intel = $result['Endien'] == 'Intel'; $model = $result['IFD0']['Model']; //current place $place = 8; $offset = 8; //Get number of tags (2 bytes) $num = bin2hex(substr($block, $place, 2)); $place += 2; if ($intel) { $num = Horde_Image_Exif::intel2Moto($num); } $result['SubIFD']['MakerNote']['MakerNoteNumTags'] = hexdec($num); //loop thru all tags Each field is 12 bytes for ($i = 0; $i < hexdec($num); $i++) { //2 byte tag $tag = bin2hex(substr($block, $place, 2)); $place += 2; if ($intel) { $tag = Horde_Image_Exif::intel2Moto($tag); } $tag_name = $this->_lookupTag($tag); //2 byte type $type = bin2hex(substr($block, $place, 2)); $place += 2; if ($intel) { $type = Horde_Image_Exif::intel2Moto($type); } list($type, $size) = $this->_lookupType($type); //4 byte count of number of data units $count = bin2hex(substr($block, $place, 4)); $place += 4; if ($intel) { $count = Horde_Image_Exif::intel2Moto($count); } $bytesofdata = $size * hexdec($count); //4 byte value of data or pointer to data $value = substr($block, $place, 4); $place += 4; if ($bytesofdata <= 4) { $data = $value; } else { $value = bin2hex($value); if ($intel) { $value = Horde_Image_Exif::intel2Moto($value); } //offsets are from TIFF header which is 12 bytes from the start //of the file if ($seek->seek($globalOffset + hexdec($value))) { $data = $seek->substring(0, $bytesofdata); } else { $result['Errors'] = $result['Errors']++; } } $formated_data = $this->_formatData($type, $tag, $intel, $data); $result['SubIFD']['MakerNote'][$tag_name] = $formated_data; } }
/** * * @param $type * @param $tag * @param $intel * @param $data * @return unknown_type */ protected function _formatData($type, $tag, $intel, $data) { switch ($type) { case 'ASCII': // Search for a null byte and stop there. if (($pos = strpos($data, chr(0))) !== false) { $data = substr($data, 0, $pos); } // Format certain kinds of strings nicely (Camera make etc.) if ($tag == '010f') { $data = Horde_String::ucwords(Horde_String::lower(trim($data))); } break; case 'URATIONAL': case 'SRATIONAL': $data = bin2hex($data); if ($intel == 1) { $data = Horde_Image_Exif::intel2Moto($data); } if ($intel == 1) { // intel stores them bottom-top $top = hexdec(substr($data, 8, 8)); } else { // motorola stores them top-bottom $top = hexdec(substr($data, 0, 8)); } if ($intel == 1) { // intel stores them bottom-top $bottom = hexdec(substr($data, 0, 8)); } else { // motorola stores them top-bottom $bottom = hexdec(substr($data, 8, 8)); } if ($type == 'SRATIONAL' && $top > 2147483647) { // this makes the number signed instead of unsigned $top = $top - 4294967296; } if ($bottom != 0) { $data = $top / $bottom; } elseif ($top == 0) { $data = 0; } else { $data = $top . '/' . $bottom; } // Exposure Time if ($tag == '829a') { if ($bottom != 0) { $data = $top . '/' . $bottom; } else { $data = 0; } } break; case 'USHORT': case 'SSHORT': case 'ULONG': case 'SLONG': case 'FLOAT': case 'DOUBLE': $data = bin2hex($data); if ($intel == 1) { $data = Horde_Image_Exif::intel2Moto($data); } if ($intel == 0 && ($type == 'USHORT' || $type == 'SSHORT')) { $data = substr($data, 0, 4); } $data = hexdec($data); if ($type == 'SSHORT' && $data > 32767) { // this makes the number signed instead of unsigned $data = $data - 65536; } if ($type == 'SLONG' && $data > 2147483647) { // this makes the number signed instead of unsigned $data = $data - 4294967296; } break; case 'UNDEFINED': // ExifVersion,FlashPixVersion,InteroperabilityVersion if ($tag == '9000' || $tag == 'a000' || $tag == '0002') { $data = sprintf(Horde_Image_Translation::t("version %d"), $data / 100); } break; default: $data = bin2hex($data); if ($intel == 1) { $data = Horde_Image_Exif::intel2Moto($data); } break; } return $data; }