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 saveThumbnail(Album $album, Photo $photo, $thumbnailImageResource, $thumbnailInfo);
/**
* Saves an uploaded file to the container and returns the filename.
* @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);
}
public function saveThumbnail(Album $album, Photo $photo, $thumbnailImageResource, $thumbnailInfo)
{
}
public function saveUploadedPhoto(Album $album, File $uploadedFile)
{
$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\AlbumSources\IAlbumSource;
use App\Helpers\ImageHelper;
use App\Helpers\ThemeHelper;
use App\Photo;
use App\Upload;
use App\UploadPhoto;
@ -14,6 +16,16 @@ class ProcessUploadCommand extends Command
{
const METADATA_VERSION = 1;
/**
* @var ImageHelper
*/
private $imageHelper;
/**
* @var ThemeHelper
*/
private $themeHelper;
/**
* The name and signature of the console command.
*
@ -33,9 +45,12 @@ class ProcessUploadCommand extends Command
*
* @return void
*/
public function __construct()
public function __construct(ImageHelper $imageHelper, ThemeHelper $themeHelper)
{
parent::__construct();
$this->imageHelper = $imageHelper;
$this->themeHelper = $themeHelper;
}
/**
@ -49,7 +64,7 @@ class ProcessUploadCommand extends Command
['is_completed', false],
['is_processing', false]
])
->orderBy('created_at', 'desc')
->orderBy('created_at')
->get();
foreach ($uploadsToProcess as $upload)
@ -72,7 +87,6 @@ class ProcessUploadCommand extends Command
{
/** @var Photo $photo */
$photo = $uploadPhoto->photo;
$this->output->writeln(sprintf('Analysing photo #%d: %s', $photo->id, $photo->name));
/** @var Album $album */
$album = $photo->album;
@ -80,8 +94,21 @@ class ProcessUploadCommand extends Command
$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);
dump($exifData);
// For debugging:
//dump($exifData);
$photo->metadata_version = ProcessUploadCommand::METADATA_VERSION;
$photo->taken_at = $this->metadataDateTime($exifData);
@ -89,6 +116,23 @@ class ProcessUploadCommand extends Command
$photo->camera_model = $this->metadataCameraModel($exifData);
$photo->camera_software = $this->metadataCameraSoftware($exifData);
$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)

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',
'camera_make',
'camera_model',
'camera_software'
'camera_software',
'width',
'height'
];
/**

View File

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

View File

@ -19,6 +19,8 @@ class AddPhotoMetadataColumns extends Migration
$table->string('camera_make')->nullable();
$table->string('camera_model')->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_model');
$table->dropColumn('camera_software');
$table->dropColumn('width');
$table->dropColumn('height');
});
}
}

View File

@ -3,5 +3,17 @@
"version": "1.0",
"author": "Andy Heathershaw",
"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
}
]
}