Thumbnails are now being generated as part of the photo analysis routine

This commit is contained in:
Andy Heathershaw 2016-09-03 17:09:49 +01:00
parent d559d09d55
commit c2a65accdf
8 changed files with 158 additions and 6 deletions

View File

@ -16,6 +16,8 @@ interface IAlbumSource
*/ */
function getPathToPhoto(Album $album, Photo $photo); function getPathToPhoto(Album $album, Photo $photo);
function saveThumbnail(Album $album, Photo $photo, $thumbnailImageResource, $thumbnailInfo);
/** /**
* Saves an uploaded file to the container and returns the filename. * Saves an uploaded file to the container and returns the filename.
* @param Album $album The album containing the photo * @param Album $album The album containing the photo

View File

@ -21,6 +21,10 @@ class LocalFilesystemSource implements IAlbumSource
return sprintf('%s/%s', $this->getPathToAlbum($album), $photo->file_name); return sprintf('%s/%s', $this->getPathToAlbum($album), $photo->file_name);
} }
public function saveThumbnail(Album $album, Photo $photo, $thumbnailImageResource, $thumbnailInfo)
{
}
public function saveUploadedPhoto(Album $album, File $uploadedFile) public function saveUploadedPhoto(Album $album, File $uploadedFile)
{ {
$tempFilename = sprintf('%s/photo_%s', $this->getPathToAlbum($album), MiscHelper::randomString(20)); $tempFilename = sprintf('%s/photo_%s', $this->getPathToAlbum($album), MiscHelper::randomString(20));

View File

@ -4,6 +4,8 @@ namespace App\Console\Commands;
use App\Album; use App\Album;
use App\AlbumSources\IAlbumSource; use App\AlbumSources\IAlbumSource;
use App\Helpers\ImageHelper;
use App\Helpers\ThemeHelper;
use App\Photo; use App\Photo;
use App\Upload; use App\Upload;
use App\UploadPhoto; use App\UploadPhoto;
@ -14,6 +16,16 @@ class ProcessUploadCommand extends Command
{ {
const METADATA_VERSION = 1; const METADATA_VERSION = 1;
/**
* @var ImageHelper
*/
private $imageHelper;
/**
* @var ThemeHelper
*/
private $themeHelper;
/** /**
* The name and signature of the console command. * The name and signature of the console command.
* *
@ -33,9 +45,12 @@ class ProcessUploadCommand extends Command
* *
* @return void * @return void
*/ */
public function __construct() public function __construct(ImageHelper $imageHelper, ThemeHelper $themeHelper)
{ {
parent::__construct(); parent::__construct();
$this->imageHelper = $imageHelper;
$this->themeHelper = $themeHelper;
} }
/** /**
@ -49,7 +64,7 @@ class ProcessUploadCommand extends Command
['is_completed', false], ['is_completed', false],
['is_processing', false] ['is_processing', false]
]) ])
->orderBy('created_at', 'desc') ->orderBy('created_at')
->get(); ->get();
foreach ($uploadsToProcess as $upload) foreach ($uploadsToProcess as $upload)
@ -72,7 +87,6 @@ class ProcessUploadCommand extends Command
{ {
/** @var Photo $photo */ /** @var Photo $photo */
$photo = $uploadPhoto->photo; $photo = $uploadPhoto->photo;
$this->output->writeln(sprintf('Analysing photo #%d: %s', $photo->id, $photo->name));
/** @var Album $album */ /** @var Album $album */
$album = $photo->album; $album = $photo->album;
@ -80,8 +94,21 @@ class ProcessUploadCommand extends Command
$photoFile = $albumSource->getPathToPhoto($album, $photo); $photoFile = $albumSource->getPathToPhoto($album, $photo);
// Read and analyse Exif data
$this->output->writeln(sprintf('Analysing photo #%d: %s', $photo->id, $photo->name));
// Open the photo
$imageInfo = null;
$originalPhotoResource = $this->imageHelper->openImage($photoFile, $imageInfo);
$photo->width = $imageInfo[0];
$photo->height = $imageInfo[1];
$photo->mime_type = $imageInfo['mime'];
// Read the Exif data
$exifData = @exif_read_data($photoFile); $exifData = @exif_read_data($photoFile);
dump($exifData);
// For debugging:
//dump($exifData);
$photo->metadata_version = ProcessUploadCommand::METADATA_VERSION; $photo->metadata_version = ProcessUploadCommand::METADATA_VERSION;
$photo->taken_at = $this->metadataDateTime($exifData); $photo->taken_at = $this->metadataDateTime($exifData);
@ -89,6 +116,23 @@ class ProcessUploadCommand extends Command
$photo->camera_model = $this->metadataCameraModel($exifData); $photo->camera_model = $this->metadataCameraModel($exifData);
$photo->camera_software = $this->metadataCameraSoftware($exifData); $photo->camera_software = $this->metadataCameraSoftware($exifData);
$photo->save(); $photo->save();
// Generate thumbnails
$this->output->writeln('Generating thumbnails');
$themeInfo = $this->themeHelper->info();
$thumbnailsRequired = $themeInfo['thumbnails'];
foreach ($thumbnailsRequired as $thumbnail)
{
$this->imageHelper->generateThumbnail(
$originalPhotoResource,
$photo,
$albumSource,
$thumbnail
);
$this->output->writeln(sprintf('Thumbnail \'%s\' (%dx%d) created', $thumbnail['name'], $thumbnail['width'], $thumbnail['height']));
}
} }
private function metadataCameraMake(array $exifData) private function metadataCameraMake(array $exifData)

View File

@ -0,0 +1,79 @@
<?php
namespace App\Helpers;
use App\AlbumSources\IAlbumSource;
use App\Photo;
class ImageHelper
{
public function generateThumbnail(
$gdImageResource,
Photo $photo,
IAlbumSource $storage,
$thumbnailInfo
)
{
$thumbnailWidth = intval($thumbnailInfo['width']);
$thumbnailHeight = intval($thumbnailInfo['height']);
$thumbnailImageResource = imagecreatetruecolor($thumbnailWidth, $thumbnailHeight);
imagecopyresized(
$thumbnailImageResource,
$gdImageResource,
0,
0,
0,
0,
$thumbnailWidth,
$thumbnailHeight,
$photo->width,
$photo->height
);
$tempName = tempnam('/tmp', 'blue_twilight_thumbnail_');
rename($tempName, $tempName . '.jpg');
// TODO make thumbnail quality configurable
imagejpeg($thumbnailImageResource, $tempName . '.jpg', 90);
}
public function openImage($imagePath, &$imageInfo)
{
$imageInfo = getimagesize($imagePath);
$im = false;
$type = $imageInfo[2];
$allowedTypes = [
IMG_GIF,
IMG_PNG,
IMG_JPEG,
IMG_WBMP
];
if (!in_array($type, $allowedTypes))
{
return false;
}
switch ($type)
{
case IMG_GIF:
$im = imagecreatefromgif($imagePath);
break;
case IMG_JPEG:
$im = imagecreatefromjpeg($imagePath);
break;
case IMG_PNG:
$im = imagecreatefrompng($imagePath);
break;
case IMG_WBMP:
$im = imagecreatefromwbmp($imagePath);
break;
}
return $im;
}
}

View File

@ -25,7 +25,9 @@ class Photo extends Model
'taken_at', 'taken_at',
'camera_make', 'camera_make',
'camera_model', 'camera_model',
'camera_software' 'camera_software',
'width',
'height'
]; ];
/** /**

View File

@ -3,6 +3,7 @@
namespace App\Providers; namespace App\Providers;
use App\Facade\Theme; use App\Facade\Theme;
use App\Helpers\ImageHelper;
use App\Helpers\ThemeHelper; use App\Helpers\ThemeHelper;
use Illuminate\Database\QueryException; use Illuminate\Database\QueryException;
use Illuminate\Support\Facades\View; use Illuminate\Support\Facades\View;
@ -17,6 +18,10 @@ class AppServiceProvider extends ServiceProvider
*/ */
public function boot() public function boot()
{ {
$this->app->singleton('image', function($app)
{
return new ImageHelper();
});
$this->app->singleton('theme', function($app) $this->app->singleton('theme', function($app)
{ {
return new ThemeHelper(); return new ThemeHelper();

View File

@ -19,6 +19,8 @@ class AddPhotoMetadataColumns extends Migration
$table->string('camera_make')->nullable(); $table->string('camera_make')->nullable();
$table->string('camera_model')->nullable(); $table->string('camera_model')->nullable();
$table->string('camera_software')->nullable(); $table->string('camera_software')->nullable();
$table->integer('width')->nullable();
$table->integer('height')->nullable();
}); });
} }
@ -35,6 +37,8 @@ class AddPhotoMetadataColumns extends Migration
$table->dropColumn('camera_make'); $table->dropColumn('camera_make');
$table->dropColumn('camera_model'); $table->dropColumn('camera_model');
$table->dropColumn('camera_software'); $table->dropColumn('camera_software');
$table->dropColumn('width');
$table->dropColumn('height');
}); });
} }
} }

View File

@ -3,5 +3,17 @@
"version": "1.0", "version": "1.0",
"author": "Andy Heathershaw", "author": "Andy Heathershaw",
"author_email": "andy@andys.eu", "author_email": "andy@andys.eu",
"navbar_class": "navbar-inverse navbar-static-top" "navbar_class": "navbar-inverse navbar-static-top",
"thumbnails": [
{
"name": "fullsize",
"height": 600,
"width": 800
},
{
"name": "preview",
"height": 300,
"width": 400
}
]
} }