#41: Read and display more photographer-specific details
This commit is contained in:
parent
ab76fb6de5
commit
c258303700
@ -52,6 +52,50 @@ class MiscHelper
|
||||
return (int) $val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a decimal (e.g. 3.5) to a fraction (e.g. 7/2).
|
||||
* Adapted from: http://jonisalonen.com/2012/converting-decimal-numbers-to-ratios/
|
||||
*
|
||||
* @param float $decimal the decimal number.
|
||||
*
|
||||
* @return array|bool a 1/2 would be [1, 2] array (this can be imploded with '/' to form a string)
|
||||
*/
|
||||
public static function decimalToFraction($decimal)
|
||||
{
|
||||
if ($decimal < 0 || !is_numeric($decimal)) {
|
||||
// Negative digits need to be passed in as positive numbers
|
||||
// and prefixed as negative once the response is imploded.
|
||||
return false;
|
||||
}
|
||||
if ($decimal == 0) {
|
||||
return [0, 0];
|
||||
}
|
||||
|
||||
$tolerance = 1.e-4;
|
||||
|
||||
$numerator = 1;
|
||||
$h2 = 0;
|
||||
$denominator = 0;
|
||||
$k2 = 1;
|
||||
$b = 1 / $decimal;
|
||||
do {
|
||||
$b = 1 / $b;
|
||||
$a = floor($b);
|
||||
$aux = $numerator;
|
||||
$numerator = $a * $numerator + $h2;
|
||||
$h2 = $aux;
|
||||
$aux = $denominator;
|
||||
$denominator = $a * $denominator + $k2;
|
||||
$k2 = $aux;
|
||||
$b = $b - $a;
|
||||
} while (abs($decimal - $numerator / $denominator) > $decimal * $tolerance);
|
||||
|
||||
return [
|
||||
$numerator,
|
||||
$denominator
|
||||
];
|
||||
}
|
||||
|
||||
public static function getEnvironmentFilePath()
|
||||
{
|
||||
return sprintf('%s/.env', dirname(dirname(__DIR__)));
|
||||
|
@ -32,6 +32,9 @@ class Photo extends Model
|
||||
'height',
|
||||
'is_analysed',
|
||||
'raw_exif_data',
|
||||
'aperture_fnumber',
|
||||
'iso_number',
|
||||
'shutter_speed',
|
||||
'created_at',
|
||||
'updated_at'
|
||||
];
|
||||
|
@ -6,6 +6,7 @@ use App\Album;
|
||||
use App\AlbumSources\IAlbumSource;
|
||||
use App\Helpers\FileHelper;
|
||||
use App\Helpers\ImageHelper;
|
||||
use App\Helpers\MiscHelper;
|
||||
use App\Helpers\ThemeHelper;
|
||||
use App\Photo;
|
||||
use Symfony\Component\HttpFoundation\File\File;
|
||||
@ -68,18 +69,23 @@ class PhotoService
|
||||
$this->photo->mime_type = $imageInfo['mime'];
|
||||
|
||||
// Read the Exif data
|
||||
if (empty($this->photo->raw_exif_data))
|
||||
{
|
||||
$exifData = @exif_read_data($photoFile);
|
||||
$isExifDataFound = ($exifData !== false && is_array($exifData));
|
||||
|
||||
if (is_null($this->photo->raw_exif_data))
|
||||
{
|
||||
$this->photo->raw_exif_data = $isExifDataFound ? base64_encode(serialize($exifData)) : '';
|
||||
}
|
||||
else
|
||||
{
|
||||
$exifData = unserialize(base64_decode($this->photo->raw_exif_data));
|
||||
$isExifDataFound = ($exifData !== false && is_array($exifData));
|
||||
}
|
||||
|
||||
$angleToRotate = 0;
|
||||
|
||||
// If Exif data contains an Orientation, ensure we rotate the original image as such
|
||||
if ($isExifDataFound && isset($exifData['Orientation']))
|
||||
// If Exif data contains an Orientation, ensure we rotate the original image as such (providing we don't
|
||||
// currently have a metadata version - i.e. it hasn't been read and rotated already before)
|
||||
if ($isExifDataFound && isset($exifData['Orientation']) && is_null($this->photo->metadata_version))
|
||||
{
|
||||
switch ($exifData['Orientation'])
|
||||
{
|
||||
@ -117,6 +123,10 @@ class PhotoService
|
||||
$this->photo->camera_make = $this->metadataCameraMake($exifData, $this->photo->camera_make);
|
||||
$this->photo->camera_model = $this->metadataCameraModel($exifData, $this->photo->camera_model);
|
||||
$this->photo->camera_software = $this->metadataCameraSoftware($exifData, $this->photo->camera_software);
|
||||
$this->photo->aperture_fnumber = $this->metadataApertureFNumber($exifData, $this->photo->aperture_fnumber);
|
||||
$this->photo->iso_number = $this->metadataIsoNumber($exifData, $this->photo->iso_number);
|
||||
$this->photo->focal_length = $this->metadataFocalLength($exifData, $this->photo->focal_length);
|
||||
$this->photo->shutter_speed = $this->metadataExposureTime($exifData, $this->photo->shutter_speed);
|
||||
}
|
||||
|
||||
$this->photo->is_analysed = true;
|
||||
@ -288,6 +298,22 @@ class PhotoService
|
||||
@unlink($photoPath);
|
||||
}
|
||||
|
||||
private function calculateValueFromFraction($input)
|
||||
{
|
||||
$split = explode('/', $input);
|
||||
if (count($split) != 2)
|
||||
{
|
||||
return $split;
|
||||
}
|
||||
|
||||
$numerator = intval($split[0]);
|
||||
$denominator = intval($split[1]);
|
||||
|
||||
return $denominator == 0
|
||||
? 0
|
||||
: ($numerator / $denominator);
|
||||
}
|
||||
|
||||
private function downloadToTemporaryFolder()
|
||||
{
|
||||
$photoPath = tempnam(sys_get_temp_dir(), 'BlueTwilight_');
|
||||
@ -306,6 +332,23 @@ class PhotoService
|
||||
return $photoPath;
|
||||
}
|
||||
|
||||
private function metadataApertureFNumber(array $exifData, $originalValue = null)
|
||||
{
|
||||
if (isset($exifData['FNumber']))
|
||||
{
|
||||
$value = $this->calculateValueFromFraction($exifData['FNumber']);
|
||||
|
||||
if (intval($value) === $value)
|
||||
{
|
||||
return sprintf('f/%d', $value);
|
||||
}
|
||||
|
||||
return sprintf('f/%0.1f', $value);
|
||||
}
|
||||
|
||||
return $originalValue;
|
||||
}
|
||||
|
||||
private function metadataCameraMake(array $exifData, $originalValue = null)
|
||||
{
|
||||
if (isset($exifData['Make']))
|
||||
@ -355,4 +398,36 @@ class PhotoService
|
||||
|
||||
return preg_replace('/^([\d]{4}):([\d]{2}):([\d]{2})/', '$1-$2-$3', $dateTime);
|
||||
}
|
||||
|
||||
private function metadataExposureTime(array $exifData, $originalValue = null)
|
||||
{
|
||||
if (isset($exifData['ExposureTime']))
|
||||
{
|
||||
$decimal = $this->calculateValueFromFraction($exifData['ExposureTime']);
|
||||
$fraction = MiscHelper::decimalToFraction($decimal);
|
||||
return sprintf('%d/%d', $fraction[0], $fraction[1]);
|
||||
}
|
||||
|
||||
return $originalValue;
|
||||
}
|
||||
|
||||
private function metadataFocalLength(array $exifData, $originalValue = null)
|
||||
{
|
||||
if (isset($exifData['FocalLength']))
|
||||
{
|
||||
return $this->calculateValueFromFraction($exifData['FocalLength']);
|
||||
}
|
||||
|
||||
return $originalValue;
|
||||
}
|
||||
|
||||
private function metadataIsoNumber(array $exifData, $originalValue = null)
|
||||
{
|
||||
if (isset($exifData['ISOSpeedRatings']))
|
||||
{
|
||||
return $exifData['ISOSpeedRatings'];
|
||||
}
|
||||
|
||||
return $originalValue;
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class AddPhotographyPillarColumns extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('photos', function (Blueprint $table)
|
||||
{
|
||||
$table->string('aperture_fnumber', 20)->nullable(true);
|
||||
$table->string('iso_number', 20)->nullable(true);
|
||||
$table->string('shutter_speed', 20)->nullable(true);
|
||||
$table->string('focal_length', 20)->nullable(true);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('photos', function (Blueprint $table)
|
||||
{
|
||||
$table->dropColumn('aperture_fnumber');
|
||||
$table->dropColumn('iso_number');
|
||||
$table->dropColumn('shutter_speed');
|
||||
$table->dropColumn('focal_length');
|
||||
});
|
||||
}
|
||||
}
|
@ -7,9 +7,18 @@ return [
|
||||
'default' => 'Default',
|
||||
'slideshow' => 'Slideshow'
|
||||
],
|
||||
'aperture' => 'Aperture:',
|
||||
'back_to_album' => 'Back to :name',
|
||||
'camera_make' => 'Camera make:',
|
||||
'camera_model' => 'Camera model:',
|
||||
'camera_software' => 'Camera software:',
|
||||
'date_taken' => 'Date taken:',
|
||||
'file_name' => 'File name:',
|
||||
'focal_length' => 'Focal length:',
|
||||
'focal_length_units' => ':valuemm',
|
||||
'index_no_results_heading' => 'Start something amazing',
|
||||
'index_no_results_text' => 'This gallery is currently empty. If you are the owner of this gallery, you can create new albums and upload photos using the :admin_link.',
|
||||
'iso_rating' => 'ISO speed rating:',
|
||||
'label_intro' => 'All photos tagged with the label ":name".',
|
||||
'label_no_results_text' => 'No photos are tagged with the label ":name".',
|
||||
'label_no_results_text_2' => 'If you are an admin of this gallery, you can upload and tag photos in the :admin_link.',
|
||||
@ -25,6 +34,8 @@ return [
|
||||
'previous_button' => '« Previous Photo',
|
||||
'show_more_labels' => '... and :count other|... and :count others',
|
||||
'show_raw_exif_data' => 'Show all EXIF data',
|
||||
'shutter_speed' => 'Shutter speed:',
|
||||
'shutter_speed_units' => ':value sec.',
|
||||
'statistics' => [
|
||||
'album_by_photos' => 'Top 10 largest albums - number of photos',
|
||||
'album_by_size' => 'Top 10 largest albums - photo size (MB)',
|
||||
|
@ -21,7 +21,7 @@
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-8 content-body">
|
||||
<div class="col-md-8 content-body">
|
||||
@if ($is_original_allowed)
|
||||
<a href="{{ $photo->thumbnailUrl() }}">
|
||||
@endif
|
||||
@ -57,7 +57,7 @@
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div class="col-sm-4">
|
||||
<div class="col-md-4">
|
||||
<div class="card">
|
||||
<div class="card-header">Information about this photo:</div>
|
||||
<div class="card-body" style="padding: 0;">
|
||||
@ -70,37 +70,65 @@
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="metadata_name">File name:</td>
|
||||
<td class="metadata_name">@lang('gallery.file_name')</td>
|
||||
<td class="metadata_value">{{ $photo->file_name }}</td>
|
||||
</tr>
|
||||
|
||||
@if (strlen($photo->taken_at) > 0)
|
||||
@if (!empty($photo->taken_at))
|
||||
<tr>
|
||||
<td class="metadata_name">Date taken:</td>
|
||||
<td class="metadata_name">@lang('gallery.date_taken')</td>
|
||||
<td class="metadata_value">{{ date(UserConfig::get('date_format'), strtotime($photo->taken_at)) }}</td>
|
||||
</tr>
|
||||
@endif
|
||||
|
||||
@if (strlen($photo->camera_make) > 0)
|
||||
@if (!empty($photo->camera_make))
|
||||
<tr>
|
||||
<td class="metadata_name">Camera make:</td>
|
||||
<td class="metadata_name">@lang('gallery.camera_make')</td>
|
||||
<td class="metadata_value">{{ $photo->camera_make }}</td>
|
||||
</tr>
|
||||
@endif
|
||||
|
||||
@if (strlen($photo->camera_model) > 0)
|
||||
@if (!empty($photo->camera_model))
|
||||
<tr>
|
||||
<td class="metadata_name">Camera model:</td>
|
||||
<td class="metadata_name">@lang('gallery.camera_model')</td>
|
||||
<td class="metadata_value">{{ $photo->camera_model }}</td>
|
||||
</tr>
|
||||
@endif
|
||||
|
||||
@if (strlen($photo->camera_software) > 0)
|
||||
@if (!empty($photo->camera_software))
|
||||
<tr>
|
||||
<td class="metadata_name">Camera software:</td>
|
||||
<td class="metadata_name">@lang('gallery.camera_software')</td>
|
||||
<td class="metadata_value">{{ $photo->camera_software }}</td>
|
||||
</tr>
|
||||
@endif
|
||||
|
||||
@if (!empty($photo->iso_number))
|
||||
<tr>
|
||||
<td class="metadata_name">@lang('gallery.iso_rating')</td>
|
||||
<td class="metadata_value">{{ $photo->iso_number }}</td>
|
||||
</tr>
|
||||
@endif
|
||||
|
||||
@if (!empty($photo->focal_length))
|
||||
<tr>
|
||||
<td class="metadata_name">@lang('gallery.focal_length')</td>
|
||||
<td class="metadata_value">@lang('gallery.focal_length_units', ['value' => $photo->focal_length])</td>
|
||||
</tr>
|
||||
@endif
|
||||
|
||||
@if (!empty($photo->aperture_fnumber))
|
||||
<tr>
|
||||
<td class="metadata_name">@lang('gallery.aperture')</td>
|
||||
<td class="metadata_value">{{ $photo->aperture_fnumber }}</td>
|
||||
</tr>
|
||||
@endif
|
||||
|
||||
@if (!empty($photo->shutter_speed))
|
||||
<tr>
|
||||
<td class="metadata_name">@lang('gallery.shutter_speed')</td>
|
||||
<td class="metadata_value">@lang('gallery.shutter_speed_units', ['value' => $photo->shutter_speed])</td>
|
||||
</tr>
|
||||
@endif
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
Loading…
Reference in New Issue
Block a user