function metaEval ($s,$precision=0) {
$eparts = explode('/',$s);
if (count($eparts)<2) return $s;
if (!is_numeric($eparts[0])) return $s;
if (!is_numeric($eparts[1])) return $s;
$numerator = intval($eparts[0]);
$denominator = intval($eparts[1]);
if ($denominator===0) return $s;
$v = (float) $numerator / (float) $denominator;
return round($v,$precision);
} // metaEval
function metaNormalise ($s) {
$eparts = explode('/',$s);
if (count($eparts)<2) return $s;
if (!is_numeric($eparts[0])) return $s;
if (!is_numeric($eparts[1])) return $s;
$numerator = intval($eparts[0]);
if ($numerator===1) return $s;
$denominator = intval($eparts[1]);
if ($denominator===0) return $s;
$v = (float) $denominator / (float) $numerator;
return '1/'.intval(round($v));
} // metaNormalise
class rawTag {
public function resolve ($exif) {
if (!is_array($exif)) return '';
if (!array_key_exists($this->section,$exif)) return '';
if (!array_key_exists($this->name,$exif[$this->section])) return '';
$value = $exif[$this->section][$this->name];
if ($this->evaluate!==false) $value = metaEval($value,$this->evaluate);
if ($this->normalise) $value = metaNormalise($value);
return $value;
} // resolve
private $section = '';
private $name = '';
private $evaluate = false;
private $normalise = false;
function __construct($s,$name,$e,$n) {
$this->section = $s;
$this->name = $name;
$this->evaluate = $e;
$this->normalise = $n;
} // __construct
} // rawTag
class derivedTag {
public $rawTags = array ();
public $asData = '';
public function resolve($exif) {
if ($this->numericData) {
$this->asData = 0;
}
else {
$this->asData = '""';
}
if (count($this->rawTags)<1) return '';
foreach ($this->rawTags as $rawTag) {
$value = $rawTag->resolve($exif);
if ($value==='') continue;
if ($this->exclusions) {
if (str_starts_with($value,'4294967295')) continue;
if (str_starts_with($value,'4294967296')) continue;
if (str_starts_with($value,'2147483647')) continue;
}
$data = $value;
if ($this->prefix!=='')
if (str_starts_with($data,$this->prefix))
$data = substr($data,strlen($this->prefix));
if ($this->suffix!=='')
if (str_ends_with($value,$this->suffix))
$data = substr($data,0,strlen($data)-strlen($this->suffix));
if ($this->numericData) {
$data = metaEval($data,10);
}
else {
$data = '"'.$data.'"';
}
$this->asData = $data;
if ($this->thousands) $value = number_format($value);
if ($this->prefix!=='')
if (!str_starts_with($value,$this->prefix))
$value = $this->prefix.$value;
if ($this->suffix!=='')
if (!str_ends_with($value,$this->suffix))
$value = $value.$this->suffix;
return $value;
}
return '';
} // resolve
private $numericData = false;
private $prefix = '';
private $suffix = '';
private $exclusions = false;
private $thousands = false;
function __construct ($n,$p,$s,$e,$t) {
$this->numericData = $n;
$this->prefix = $p;
$this->suffix = $s;
$this->exclusions = $e;
$this->thousands = $t;
} // __construct
} // derivedTag
// Can't extract height and width as it is either Sensor Dimensions,
// without regard for crop OR it is the resized-for-web Dimensions
// none of the values tell me the original processed image dimensions...
function resolveMeta ($filename,$tags) {
$resolved = array ();
$ext = pathinfo($filename,PATHINFO_EXTENSION);
if ($ext!=='jpg') return $resolved;
$exif = exif_read_data($filename,null,true,false);
if ($exif===false) return $resolved;
$resolved['Name'] = pathinfo($filename,PATHINFO_FILENAME);
$resolved['csv'] = $resolved['Name'];
foreach ($tags as $key => $tag) {
$v = $tag->resolve($exif);
$resolved['csv'] .= ','.$tag->asData;
if ($v!=='') $resolved[$key] = $v;
}
if (!array_key_exists('Distance',$resolved)) {
try {
$value = '';
$find = 'aux:ApproximateFocusDistance';
$fLen = strlen ($find);
$content = file_get_contents($filename);
$pos = strpos($content,$find);
if ($pos!==false) {
$distance_start = $pos+$fLen+1;
$xmp_data = substr($content, $distance_start);
if (str_starts_with($xmp_data,'"')) {
$vparts = explode('"',$xmp_data,3);
if (count($vparts)>1) $value = $vparts[1];
}
else {
$vparts = explode('<',$xmp_data,3);
$value = $vparts[0];
}
if (($value!=='') &&
!str_starts_with($value,'4294967295') &&
!str_starts_with($value,'4294967296') &&
!str_starts_with($value,'2147483647')) {
$value = sprintf('%0.2f',metaEval($value,2)).'m';
$resolved['Distance'] = $value;
}
}
}
catch (Exception $e) {
}
}
$resolved['html'] = '<div>';
if (count($resolved)>2) {
if (array_key_exists('Model',$resolved)) {
$resolved['html'] .= '<p>'.$resolved['Model'].'</p>';
}
$e = '';
if (array_key_exists('ShutterSpeed',$resolved))
$e .= $resolved['ShutterSpeed'].' ';
if (array_key_exists('Aperture',$resolved))
$e .= $resolved['Aperture'].' ';
if (array_key_exists('ISO',$resolved))
$e .= $resolved['ISO'];
$e = preg_replace('/\s+/', ' ', $e);
$e = trim($e);
if ($e!=='')
$resolved['html'] .= '<p>'.$e.'</p>';
$l = '';
if (array_key_exists('FocalLength',$resolved))
$l .= $resolved['FocalLength'].' ';
if (array_key_exists('Distance',$resolved))
$l .= '@'.$resolved['Distance'].' ';
if (array_key_exists('Lens',$resolved))
$l .= ' ('.$resolved['Lens'].')';
$l = preg_replace('/\s+/', ' ', $l);
$l = trim($l);
if ($l!=='')
$resolved['html'] .= '<p>'.$l.'</p>';
if (array_key_exists('Date',$resolved)) {
$resolved['html'] .= '<p>'.$resolved['Date'].'</p>';
}
}
else {
$resolved['html'] .= '<p>No Metadata</p>';
}
$resolved['html'] .= '</div>';
return $resolved;
} // resolveMeta
function getMeta ($filename) {
$tags = [];
$tags['Aperture'] = new derivedTag(true, 'f/', '', false,false);
$tags['Distance'] = new derivedTag(true, '', 'm', true, false);
$tags['Model'] = new derivedTag(false,'', '', false,false);
$tags['Date'] = new derivedTag(false,'', '', false,false);
$tags['Lens'] = new derivedTag(false,'', '', false,false);
$tags['ShutterSpeed'] = new derivedTag(true, '', 's', false,false);
$tags['ISO'] = new derivedTag(true, 'ISO:','', false,true);
$tags['FocalLength'] = new derivedTag(true, '', 'mm',false,false);
$tags['Aperture']->rawTags[] =
new rawTag('COMPUTED','ApertureFNumber',false,false);
$tags['Aperture']->rawTags[] =
new rawTag('EXIF','FNumber', false,false);
$tags['Distance']->rawTags[] =
new rawTag('COMPUTED','FocusDistance', false,false);
$tags['Distance']->rawTags[] =
new rawTag('EXIF','SubjectDistance', 2, false);
$tags['Model']->rawTags[] =
new rawTag('IFD0','Model', false,false);
$tags['Date']->rawTags[] =
new rawTag('EXIF','DateTimeOriginal', false,false);
$tags['Date']->rawTags[] =
new rawTag('IFD0','DateTime', false,false);
$tags['Lens']->rawTags[] =
new rawTag('EXIF','UndefinedTag:0xA434',false,false);
$tags['Lens']->rawTags[] =
new rawTag('IFD0','UndefinedTag:0xA434',false,false);
$tags['ShutterSpeed']->rawTags[] =
new rawTag('EXIF','ExposureTime', false, true);
$tags['ISO']->rawTags[] =
new rawTag('EXIF','ISOSpeedRatings', false,false);
$tags['FocalLength']->rawTags[] =
new rawTag('EXIF','FocalLength', 0, false);
return resolveMeta($filename,$tags)['html'];
} // getMeta