diff --git a/app/AlbumSources/IAlbumSource.php b/app/AlbumSources/IAlbumSource.php index c079100..72b4df5 100644 --- a/app/AlbumSources/IAlbumSource.php +++ b/app/AlbumSources/IAlbumSource.php @@ -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 diff --git a/app/AlbumSources/LocalFilesystemSource.php b/app/AlbumSources/LocalFilesystemSource.php index 2f994c0..7dcfd59 100644 --- a/app/AlbumSources/LocalFilesystemSource.php +++ b/app/AlbumSources/LocalFilesystemSource.php @@ -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)); diff --git a/app/Console/Commands/ProcessUploadCommand.php b/app/Console/Commands/ProcessUploadCommand.php index 8d08b46..b4b8053 100644 --- a/app/Console/Commands/ProcessUploadCommand.php +++ b/app/Console/Commands/ProcessUploadCommand.php @@ -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) diff --git a/app/Helpers/ImageHelper.php b/app/Helpers/ImageHelper.php new file mode 100644 index 0000000..ada15a2 --- /dev/null +++ b/app/Helpers/ImageHelper.php @@ -0,0 +1,79 @@ +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; + } +} \ No newline at end of file diff --git a/app/Photo.php b/app/Photo.php index 497757d..d9d62bd 100644 --- a/app/Photo.php +++ b/app/Photo.php @@ -25,7 +25,9 @@ class Photo extends Model 'taken_at', 'camera_make', 'camera_model', - 'camera_software' + 'camera_software', + 'width', + 'height' ]; /** diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index ad6906d..99ca2bc 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -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(); diff --git a/database/migrations/2016_09_02_220323_add_photo_metadata_columns.php b/database/migrations/2016_09_02_220323_add_photo_metadata_columns.php index a005f0a..ecda951 100644 --- a/database/migrations/2016_09_02_220323_add_photo_metadata_columns.php +++ b/database/migrations/2016_09_02_220323_add_photo_metadata_columns.php @@ -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'); }); } } diff --git a/resources/views/themes/bootstrap3/theme.json b/resources/views/themes/bootstrap3/theme.json index cf18c4f..943053c 100644 --- a/resources/views/themes/bootstrap3/theme.json +++ b/resources/views/themes/bootstrap3/theme.json @@ -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 + } + ] } \ No newline at end of file