Rework meta data display on photo page #45
@ -8,6 +8,8 @@
|
|||||||
|
|
||||||
class ViewPhoto extends HTMLController
|
class ViewPhoto extends HTMLController
|
||||||
{
|
{
|
||||||
|
private Image $photo;
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
// Ensure we're logged in at this point.
|
// Ensure we're logged in at this point.
|
||||||
@ -19,44 +21,36 @@ class ViewPhoto extends HTMLController
|
|||||||
if (empty($photo))
|
if (empty($photo))
|
||||||
throw new NotFoundException();
|
throw new NotFoundException();
|
||||||
|
|
||||||
|
$this->photo = $photo->getImage();
|
||||||
|
|
||||||
Session::resetSessionToken();
|
Session::resetSessionToken();
|
||||||
|
|
||||||
parent::__construct($photo->getTitle() . ' - ' . SITE_TITLE);
|
parent::__construct($this->photo->getTitle() . ' - ' . SITE_TITLE);
|
||||||
|
|
||||||
if (!empty($_POST))
|
if (!empty($_POST))
|
||||||
$this->handleTagging($photo->getImage());
|
$this->handleTagging();
|
||||||
else
|
else
|
||||||
$this->handleViewPhoto($photo);
|
$this->handleViewPhoto();
|
||||||
}
|
}
|
||||||
|
|
||||||
private function handleViewPhoto(Asset $photo)
|
private function handleViewPhoto()
|
||||||
{
|
{
|
||||||
$page = new PhotoPage($photo->getImage());
|
$page = new PhotoPage($this->photo);
|
||||||
|
|
||||||
// Exif data?
|
// Any (EXIF) meta data?
|
||||||
$exif = EXIF::fromFile($photo->getFullPath());
|
$metaData = $this->prepareMetaData();
|
||||||
if ($exif)
|
$page->setMetaData($metaData);
|
||||||
$page->setExif($exif);
|
|
||||||
|
|
||||||
// What tag are we browsing?
|
// What tag are we browsing?
|
||||||
$tag = isset($_GET['in']) ? Tag::fromId($_GET['in']) : null;
|
$tag = isset($_GET['in']) ? Tag::fromId($_GET['in']) : null;
|
||||||
$id_tag = isset($tag) ? $tag->id_tag : null;
|
if (isset($tag))
|
||||||
|
$page->setTag($tag);
|
||||||
// Find previous photo in set.
|
|
||||||
$previous_url = $photo->getUrlForPreviousInSet($id_tag);
|
|
||||||
if ($previous_url)
|
|
||||||
$page->setPreviousPhotoUrl($previous_url);
|
|
||||||
|
|
||||||
// ... and the next photo, too.
|
|
||||||
$next_url = $photo->getUrlForNextInSet($id_tag);
|
|
||||||
if ($next_url)
|
|
||||||
$page->setNextPhotoUrl($next_url);
|
|
||||||
|
|
||||||
$this->page->adopt($page);
|
$this->page->adopt($page);
|
||||||
$this->page->setCanonicalUrl($photo->getPageUrl());
|
$this->page->setCanonicalUrl($this->photo->getPageUrl());
|
||||||
}
|
}
|
||||||
|
|
||||||
private function handleTagging(Image $photo)
|
private function handleTagging()
|
||||||
{
|
{
|
||||||
header('Content-Type: text/json; charset=utf-8');
|
header('Content-Type: text/json; charset=utf-8');
|
||||||
|
|
||||||
@ -70,7 +64,7 @@ class ViewPhoto extends HTMLController
|
|||||||
// We are!
|
// We are!
|
||||||
if (!isset($_POST['delete']))
|
if (!isset($_POST['delete']))
|
||||||
{
|
{
|
||||||
$photo->linkTags([(int) $_POST['id_tag']]);
|
$this->photo->linkTags([(int) $_POST['id_tag']]);
|
||||||
echo json_encode(['success' => true]);
|
echo json_encode(['success' => true]);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
@ -78,9 +72,43 @@ class ViewPhoto extends HTMLController
|
|||||||
// ... deleting, that is.
|
// ... deleting, that is.
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$photo->unlinkTags([(int) $_POST['id_tag']]);
|
$this->photo->unlinkTags([(int) $_POST['id_tag']]);
|
||||||
echo json_encode(['success' => true]);
|
echo json_encode(['success' => true]);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function prepareMetaData()
|
||||||
|
{
|
||||||
|
if (!($exif = EXIF::fromFile($this->photo->getFullPath())))
|
||||||
|
throw new UnexpectedValueException('Photo file not found!');
|
||||||
|
|
||||||
|
$metaData = [];
|
||||||
|
|
||||||
|
if (!empty($exif->created_timestamp))
|
||||||
|
$metaData['Date Taken'] = date("j M Y, H:i:s", $exif->created_timestamp);
|
||||||
|
|
||||||
|
if ($author = $this->photo->getAuthor())
|
||||||
|
$metaData['Uploaded by'] = $author->getfullName();
|
||||||
|
|
||||||
|
if (!empty($exif->camera))
|
||||||
|
$metaData['Camera Model'] = $exif->camera;
|
||||||
|
|
||||||
|
if (!empty($exif->shutter_speed))
|
||||||
|
$metaData['Shutter Speed'] = $exif->shutterSpeedFraction();
|
||||||
|
|
||||||
|
if (!empty($exif->aperture))
|
||||||
|
$metaData['Aperture'] = 'f/' . number_format($exif->aperture, 1);
|
||||||
Aaron marked this conversation as resolved
Outdated
|
|||||||
|
|
||||||
|
if (!empty($exif->focal_length))
|
||||||
|
$metaData['Focal Length'] = $exif->focal_length . ' mm';
|
||||||
Aaron marked this conversation as resolved
Outdated
minnozz
commented
Maybe re-add the Maybe re-add the `mm` unit?
|
|||||||
|
|
||||||
|
if (!empty($exif->iso))
|
||||||
|
$metaData['ISO Speed'] = $exif->iso;
|
||||||
|
|
||||||
|
if (!empty($exif->software))
|
||||||
|
$metaData['Software'] = $exif->software;
|
||||||
|
|
||||||
|
return $metaData;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -697,11 +697,11 @@ class Asset
|
|||||||
$params);
|
$params);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getUrlForPreviousInSet($id_tag = null)
|
public function getUrlForPreviousInSet(?Tag $tag)
|
||||||
{
|
{
|
||||||
$row = Registry::get('db')->queryAssoc('
|
$row = Registry::get('db')->queryAssoc('
|
||||||
SELECT a.*
|
SELECT a.*
|
||||||
' . (isset($id_tag) ? '
|
' . (isset($tag) ? '
|
||||||
FROM assets_tags AS t
|
FROM assets_tags AS t
|
||||||
INNER JOIN assets AS a ON a.id_asset = t.id_asset
|
INNER JOIN assets AS a ON a.id_asset = t.id_asset
|
||||||
WHERE t.id_tag = {int:id_tag} AND
|
WHERE t.id_tag = {int:id_tag} AND
|
||||||
@ -715,24 +715,24 @@ class Asset
|
|||||||
LIMIT 1',
|
LIMIT 1',
|
||||||
[
|
[
|
||||||
'id_asset' => $this->id_asset,
|
'id_asset' => $this->id_asset,
|
||||||
'id_tag' => $id_tag,
|
'id_tag' => $tag->id_tag,
|
||||||
'date_captured' => $this->date_captured,
|
'date_captured' => $this->date_captured,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if ($row)
|
if ($row)
|
||||||
{
|
{
|
||||||
$obj = self::byRow($row, 'object');
|
$obj = self::byRow($row, 'object');
|
||||||
return $obj->getPageUrl() . ($id_tag ? '?in=' . $id_tag : '');
|
return $obj->getPageUrl() . ($tag ? '?in=' . $tag->id_tag : '');
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getUrlForNextInSet($id_tag = null)
|
public function getUrlForNextInSet(?Tag $tag)
|
||||||
{
|
{
|
||||||
$row = Registry::get('db')->queryAssoc('
|
$row = Registry::get('db')->queryAssoc('
|
||||||
SELECT a.*
|
SELECT a.*
|
||||||
' . (isset($id_tag) ? '
|
' . (isset($tag) ? '
|
||||||
FROM assets_tags AS t
|
FROM assets_tags AS t
|
||||||
INNER JOIN assets AS a ON a.id_asset = t.id_asset
|
INNER JOIN assets AS a ON a.id_asset = t.id_asset
|
||||||
WHERE t.id_tag = {int:id_tag} AND
|
WHERE t.id_tag = {int:id_tag} AND
|
||||||
@ -746,14 +746,14 @@ class Asset
|
|||||||
LIMIT 1',
|
LIMIT 1',
|
||||||
[
|
[
|
||||||
'id_asset' => $this->id_asset,
|
'id_asset' => $this->id_asset,
|
||||||
'id_tag' => $id_tag,
|
'id_tag' => $tag->id_tag,
|
||||||
'date_captured' => $this->date_captured,
|
'date_captured' => $this->date_captured,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if ($row)
|
if ($row)
|
||||||
{
|
{
|
||||||
$obj = self::byRow($row, 'object');
|
$obj = self::byRow($row, 'object');
|
||||||
return $obj->getPageUrl() . ($id_tag ? '?in=' . $id_tag : '');
|
return $obj->getPageUrl() . ($tag ? '?in=' . $tag->id_tag : '');
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
|
@ -523,7 +523,7 @@ a#previous_photo:hover, a#next_photo:hover {
|
|||||||
right: 0;
|
right: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#sub_photo h2, #sub_photo h3, #photo_exif_box h3, #user_actions_box h3 {
|
#sub_photo h2, #sub_photo h3 {
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
}
|
}
|
||||||
#sub_photo #tag_list {
|
#sub_photo #tag_list {
|
||||||
@ -542,18 +542,17 @@ a#previous_photo:hover, a#next_photo:hover {
|
|||||||
opacity: 1.0;
|
opacity: 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.photo_meta {
|
||||||
#photo_exif_box dt {
|
background-color: var(--bs-body-bg);
|
||||||
|
box-shadow: 0 0.25rem 0.5rem rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
.photo_meta li {
|
||||||
|
padding: 0.6rem 1rem;
|
||||||
|
}
|
||||||
|
.photo_meta h4 {
|
||||||
|
font-family: 'Coda', sans-serif;
|
||||||
|
font-size: inherit;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
float: left;
|
|
||||||
clear: left;
|
|
||||||
width: 120px;
|
|
||||||
}
|
|
||||||
#photo_exif_box dt:after {
|
|
||||||
content: ':';
|
|
||||||
}
|
|
||||||
#photo_exif_box dd {
|
|
||||||
float: left;
|
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -583,13 +582,6 @@ a#previous_photo:hover, a#next_photo:hover {
|
|||||||
#previous_photo, #next_photo {
|
#previous_photo, #next_photo {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
#sub_photo, #photo_exif_box {
|
|
||||||
float: none;
|
|
||||||
margin: 30px 0;
|
|
||||||
padding: 10px;
|
|
||||||
width: auto;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -8,26 +8,15 @@
|
|||||||
|
|
||||||
class PhotoPage extends Template
|
class PhotoPage extends Template
|
||||||
{
|
{
|
||||||
protected $photo;
|
private $photo;
|
||||||
private $exif;
|
private $metaData;
|
||||||
private $previous_photo_url = '';
|
private $tag;
|
||||||
private $next_photo_url = '';
|
|
||||||
|
|
||||||
public function __construct(Image $photo)
|
public function __construct(Image $photo)
|
||||||
{
|
{
|
||||||
$this->photo = $photo;
|
$this->photo = $photo;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setPreviousPhotoUrl($url)
|
|
||||||
{
|
|
||||||
$this->previous_photo_url = $url;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setNextPhotoUrl($url)
|
|
||||||
{
|
|
||||||
$this->next_photo_url = $url;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function html_main()
|
public function html_main()
|
||||||
{
|
{
|
||||||
$this->photoNav();
|
$this->photoNav();
|
||||||
@ -35,8 +24,12 @@ class PhotoPage extends Template
|
|||||||
|
|
||||||
echo '
|
echo '
|
||||||
<div class="row mt-5">
|
<div class="row mt-5">
|
||||||
<div class="col-lg-8">
|
<div class="col-lg-9">
|
||||||
<div id="sub_photo" class="content-box">
|
<div id="sub_photo" class="content-box">';
|
||||||
|
|
||||||
|
$this->userActions();
|
||||||
|
|
||||||
|
echo '
|
||||||
<h2 class="entry-title">', $this->photo->getTitle(), '</h2>';
|
<h2 class="entry-title">', $this->photo->getTitle(), '</h2>';
|
||||||
|
|
||||||
$this->taggedPeople();
|
$this->taggedPeople();
|
||||||
@ -45,10 +38,9 @@ class PhotoPage extends Template
|
|||||||
echo '
|
echo '
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg-4">';
|
<div class="col-lg-3">';
|
||||||
|
|
||||||
$this->photoMeta();
|
$this->photoMeta();
|
||||||
$this->userActions();
|
|
||||||
|
|
||||||
echo '
|
echo '
|
||||||
</div>
|
</div>
|
||||||
@ -86,18 +78,23 @@ class PhotoPage extends Template
|
|||||||
</a>';
|
</a>';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setTag(Tag $tag)
|
||||||
|
{
|
||||||
|
$this->tag = $tag;
|
||||||
|
}
|
||||||
|
|
||||||
private function photoNav()
|
private function photoNav()
|
||||||
{
|
{
|
||||||
if ($this->previous_photo_url)
|
if ($previousUrl = $this->photo->getUrlForPreviousInSet($this->tag))
|
||||||
echo '
|
echo '
|
||||||
<a href="', $this->previous_photo_url, '#photo_frame" id="previous_photo"><i class="bi bi-arrow-left"></i></a>';
|
<a href="', $previousUrl, '#photo_frame" id="previous_photo"><i class="bi bi-arrow-left"></i></a>';
|
||||||
else
|
else
|
||||||
echo '
|
echo '
|
||||||
<span id="previous_photo"><i class="bi bi-arrow-left"></i></span>';
|
<span id="previous_photo"><i class="bi bi-arrow-left"></i></span>';
|
||||||
|
|
||||||
if ($this->next_photo_url)
|
if ($nextUrl = $this->photo->getUrlForNextInSet($this->tag))
|
||||||
echo '
|
echo '
|
||||||
<a href="', $this->next_photo_url, '#photo_frame" id="next_photo"><i class="bi bi-arrow-right"></i></a>';
|
<a href="', $nextUrl, '#photo_frame" id="next_photo"><i class="bi bi-arrow-right"></i></a>';
|
||||||
else
|
else
|
||||||
echo '
|
echo '
|
||||||
<span id="next_photo"><i class="bi bi-arrow-right"></i></span>';
|
<span id="next_photo"><i class="bi bi-arrow-right"></i></span>';
|
||||||
@ -106,52 +103,19 @@ class PhotoPage extends Template
|
|||||||
private function photoMeta()
|
private function photoMeta()
|
||||||
{
|
{
|
||||||
echo '
|
echo '
|
||||||
<div id="photo_exif_box" class="content-box clearfix">
|
<ul class="list-group photo_meta">';
|
||||||
<h3>EXIF</h3>
|
|
||||||
<dl class="photo_meta">';
|
|
||||||
|
|
||||||
if (!empty($this->exif->created_timestamp))
|
foreach ($this->metaData as $header => $body)
|
||||||
|
{
|
||||||
echo '
|
echo '
|
||||||
<dt>Date Taken</dt>
|
<li class="list-group-item">
|
||||||
<dd>', date("j M Y, H:i:s", $this->exif->created_timestamp), '</dd>';
|
<h4>', $header, '</h4>
|
||||||
|
', $body, '
|
||||||
|
</li>';
|
||||||
|
}
|
||||||
|
|
||||||
echo '
|
echo '
|
||||||
<dt>Uploaded by</dt>
|
</ul>';
|
||||||
<dd>', $this->photo->getAuthor()->getfullName(), '</dd>';
|
|
||||||
|
|
||||||
if (!empty($this->exif->camera))
|
|
||||||
echo '
|
|
||||||
<dt>Camera Model</dt>
|
|
||||||
<dd>', $this->exif->camera, '</dd>';
|
|
||||||
|
|
||||||
if (!empty($this->exif->shutter_speed))
|
|
||||||
echo '
|
|
||||||
<dt>Shutter Speed</dt>
|
|
||||||
<dd>', $this->exif->shutterSpeedFraction(), '</dd>';
|
|
||||||
|
|
||||||
if (!empty($this->exif->aperture))
|
|
||||||
echo '
|
|
||||||
<dt>Aperture</dt>
|
|
||||||
<dd>f/', number_format($this->exif->aperture, 1), '</dd>';
|
|
||||||
|
|
||||||
if (!empty($this->exif->focal_length))
|
|
||||||
echo '
|
|
||||||
<dt>Focal Length</dt>
|
|
||||||
<dd>', $this->exif->focal_length, ' mm</dd>';
|
|
||||||
|
|
||||||
if (!empty($this->exif->iso))
|
|
||||||
echo '
|
|
||||||
<dt>ISO Speed</dt>
|
|
||||||
<dd>', $this->exif->iso, '</dd>';
|
|
||||||
|
|
||||||
if (!empty($this->exif->software))
|
|
||||||
echo '
|
|
||||||
<dt>Software</dt>
|
|
||||||
<dd>', $this->exif->software, '</dd>';
|
|
||||||
|
|
||||||
echo '
|
|
||||||
</dl>
|
|
||||||
</div>';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function taggedPeople()
|
private function taggedPeople()
|
||||||
@ -246,9 +210,9 @@ class PhotoPage extends Template
|
|||||||
</script>';
|
</script>';
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setExif(EXIF $exif)
|
public function setMetaData(array $metaData)
|
||||||
{
|
{
|
||||||
$this->exif = $exif;
|
$this->metaData = $metaData;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function userActions()
|
public function userActions()
|
||||||
@ -257,13 +221,13 @@ class PhotoPage extends Template
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
echo '
|
echo '
|
||||||
<div id="user_actions_box" class="content-box">
|
<div class="float-end">
|
||||||
<h3>Actions</h3>
|
<a class="btn btn-primary" href="', $this->photo->getEditUrl(), '">
|
||||||
<a class="btn btn-primary" href="', $this->photo->getEditUrl(), '">Edit photo</a>
|
<i class="bi bi-pencil"></i> Edit</a>
|
||||||
<a class="btn btn-danger" href="', $this->photo->getDeleteUrl(), '&',
|
<a class="btn btn-danger" href="', $this->photo->getDeleteUrl(), '&',
|
||||||
Session::getSessionTokenKey(), '=', Session::getSessionToken(),
|
Session::getSessionTokenKey(), '=', Session::getSessionToken(),
|
||||||
'" onclick="return confirm(\'Are you sure you want to delete this photo?\');"',
|
'" onclick="return confirm(\'Are you sure you want to delete this photo?\');"',
|
||||||
'">Delete photo</a>
|
'"><i class="bi bi-pencil"></i> Delete</a></a>
|
||||||
</div>';
|
</div>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user
Maybe re-add the
f/
prefix?