From cd286253090d58e7e767f0073186a02accc327e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Kv=C3=A1=C4=8Dek?= Date: Mon, 26 Sep 2016 15:21:30 +0200 Subject: [PATCH] FEATURE: make thumbnails from uploaded image --- app/Helpers/FileManager.php | 7 +- app/Helpers/Template.php | 12 ++ app/Models/File.php | 35 ++++ app/Providers/GlobalViewDataProvider.php | 10 +- composer.json | 3 +- composer.lock | 181 +++++++++++++++++- config/.gitignore | 1 + config/app.php | 1 + config/image.php | 20 ++ .../content/formParts/appearance.blade.php | 2 +- .../admin/fileManager/filesTiles.blade.php | 2 +- 11 files changed, 262 insertions(+), 12 deletions(-) create mode 100644 config/image.php diff --git a/app/Helpers/FileManager.php b/app/Helpers/FileManager.php index 5ca5f8fc..01459d13 100644 --- a/app/Helpers/FileManager.php +++ b/app/Helpers/FileManager.php @@ -17,12 +17,7 @@ class FileManager switch ($type) { case 'image': - // try to check if file have thumbnail - if (file_exists(config('app.thumbnail_url') . '/' . $file->filename)) { - $url = config('app.thumbnail_url') . '/' . $file->filename; - } else { - $url = config('app.upload_url') . '/' . $file->filename; - } + $url = Template::thumbnail($file->filename); return '' . $file->description . ''; break; diff --git a/app/Helpers/Template.php b/app/Helpers/Template.php index fab3a803..07332d77 100644 --- a/app/Helpers/Template.php +++ b/app/Helpers/Template.php @@ -61,6 +61,18 @@ class Template return config('app.upload_url') . '/' . $filename; } + public static function thumbnail($filename) + { + // try to check if file have thumbnail + if (file_exists(config('app.thumbnail_path') . '/' . $filename)) { + $url = config('app.thumbnail_url') . '/' . $filename; + } else { + $url = self::upload($filename); + } + + return $url; + } + /** * Get path to given asset * diff --git a/app/Models/File.php b/app/Models/File.php index 1c7c39a0..6c171459 100644 --- a/app/Models/File.php +++ b/app/Models/File.php @@ -4,9 +4,13 @@ namespace App\Models; use App\Events\UploadFile; use App\Http\Requests\Request; +use Franzose\ClosureTable\Extensions\Str; use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Event; +use Illuminate\Support\Facades\File as FileFacade; +use Intervention\Image\Constraint; +use Intervention\Image\Facades\Image; use Symfony\Component\HttpFoundation\File\File as SymphonyFile; use Symfony\Component\HttpFoundation\File\UploadedFile; @@ -63,6 +67,12 @@ class File extends Model // save file into physical location (local FS) $uploadedFile = $file->move($destination, $filename); + // is uploaded file an image? + if (Str::startsWith($uploadedFile->getMimeType(), 'image')) { + // yes, create thumbnail + $this->createThumbnail($uploadedFile); + } + // insert record into database $id = $this->saveIntoDatabase($uploadedFile, $request, $file->getClientOriginalName()); @@ -118,4 +128,29 @@ class File extends Model return $newFile->id; } + + /** + * Create thumbnail of given image + * + * @param SymphonyFile $file + */ + private function createThumbnail(SymphonyFile $file) + { + // does thumbnail directory exist? + if (!is_dir(config('app.thumbnail_path'))) { + FileFacade::makeDirectory(config('app.thumbnail_path')); + } + + // get image instance + $image = Image::make(config('app.upload_path') . DIRECTORY_SEPARATOR . $file->getFilename()); + + // resize image and keep aspect ration + $image->resize(env('THUMBNAIL_WIDTH', 300), null, function (Constraint $constraint) { + $constraint->aspectRatio(); + $constraint->upsize(); + }); + + // save thumbnail with lower quality + $image->save(config('app.thumbnail_path') . DIRECTORY_SEPARATOR . $file->getFilename(), 75); + } } \ No newline at end of file diff --git a/app/Providers/GlobalViewDataProvider.php b/app/Providers/GlobalViewDataProvider.php index f201c027..e0e31da2 100644 --- a/app/Providers/GlobalViewDataProvider.php +++ b/app/Providers/GlobalViewDataProvider.php @@ -65,7 +65,7 @@ class GlobalViewDataProvider extends ServiceProvider return preg_replace($pattern, $code, $view); }); - // shortcut for loading uploaded images + // shortcut for loading uploaded files Blade::extend(function ($view) { $pattern = $this->createPattern('upload'); $code = ''; @@ -73,6 +73,14 @@ class GlobalViewDataProvider extends ServiceProvider return preg_replace($pattern, $code, $view); }); + // shortcut for loading thumbnails of uploaded images + Blade::extend(function ($view) { + $pattern = $this->createPattern('upload'); + $code = ''; + + return preg_replace($pattern, $code, $view); + }); + // shortcut for displaying Gravatar Blade::extend(function ($view) { $pattern = $this->createPattern('gravatar'); diff --git a/composer.json b/composer.json index 2a77208a..c45e56d7 100644 --- a/composer.json +++ b/composer.json @@ -13,7 +13,8 @@ "pingpong/menus": "^2.2", "watson/sitemap": "^2.0", "mcamara/laravel-localization": "^1.1", - "franzose/closure-table": "^4.1" + "franzose/closure-table": "^4.1", + "intervention/image": "^2.3" }, "require-dev": { "fzaninotto/faker": "~1.4", diff --git a/composer.lock b/composer.lock index cc93517b..a245d21e 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "34fec17afe62b99ed90d0f72d3536a7b", - "content-hash": "58f7e332f9be3faf1f8d481191cf1bb1", + "hash": "066078c74cc6b8d99111c0e9b4b385d6", + "content-hash": "1574402e32047ac8589b6fc08d6d744c", "packages": [ { "name": "classpreloader/classpreloader", @@ -704,6 +704,133 @@ ], "time": "2016-07-08 08:19:46" }, + { + "name": "guzzlehttp/psr7", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "64862e854f876bc5aee2996cab2f552db8586065" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/64862e854f876bc5aee2996cab2f552db8586065", + "reference": "64862e854f876bc5aee2996cab2f552db8586065", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "psr/http-message": "~1.0" + }, + "provide": { + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Schultze", + "homepage": "https://github.com/Tobion" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "request", + "response", + "stream", + "uri", + "url" + ], + "time": "2016-08-03 09:33:34" + }, + { + "name": "intervention/image", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/Intervention/image.git", + "reference": "4064a980324f6c3bfa2bd981dfb247afa705ec3c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Intervention/image/zipball/4064a980324f6c3bfa2bd981dfb247afa705ec3c", + "reference": "4064a980324f6c3bfa2bd981dfb247afa705ec3c", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "guzzlehttp/psr7": "~1.1", + "php": ">=5.4.0" + }, + "require-dev": { + "mockery/mockery": "~0.9.2", + "phpunit/phpunit": "3.*" + }, + "suggest": { + "ext-gd": "to use GD library based image processing.", + "ext-imagick": "to use Imagick based image processing.", + "intervention/imagecache": "Caching extension for the Intervention Image library" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.3-dev" + } + }, + "autoload": { + "psr-4": { + "Intervention\\Image\\": "src/Intervention/Image" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Oliver Vogel", + "email": "oliver@olivervogel.net", + "homepage": "http://olivervogel.net/" + } + ], + "description": "Image handling and manipulation library with support for Laravel integration", + "homepage": "http://image.intervention.io/", + "keywords": [ + "gd", + "image", + "imagick", + "laravel", + "thumbnail", + "watermark" + ], + "time": "2016-09-01 17:04:03" + }, { "name": "jakub-onderka/php-console-color", "version": "0.1", @@ -1632,6 +1759,56 @@ "description": "Support Component of Pingpong Sky Package", "time": "2016-01-07 08:23:04" }, + { + "name": "psr/http-message", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "time": "2016-08-06 14:39:51" + }, { "name": "psr/log", "version": "dev-master", diff --git a/config/.gitignore b/config/.gitignore index 2475f7d1..a6acbe5b 100644 --- a/config/.gitignore +++ b/config/.gitignore @@ -17,4 +17,5 @@ !services.php !session.php !sitemap.php +!image.php !view.php diff --git a/config/app.php b/config/app.php index 49291806..a451ec46 100644 --- a/config/app.php +++ b/config/app.php @@ -161,6 +161,7 @@ return [ App\Providers\SubmodulesManager::class, Franzose\ClosureTable\ClosureTableServiceProvider::class, \Watson\Sitemap\SitemapServiceProvider::class, + Intervention\Image\ImageServiceProvider::class, /* * Application Service Providers... */ diff --git a/config/image.php b/config/image.php new file mode 100644 index 00000000..b106809e --- /dev/null +++ b/config/image.php @@ -0,0 +1,20 @@ + 'gd' + +); diff --git a/resources/views/admin/content/formParts/appearance.blade.php b/resources/views/admin/content/formParts/appearance.blade.php index f11c96fc..375abcf0 100644 --- a/resources/views/admin/content/formParts/appearance.blade.php +++ b/resources/views/admin/content/formParts/appearance.blade.php @@ -18,7 +18,7 @@ - + @include('admin.snippets.hasError', ['field' => 'titlePhoto']) diff --git a/resources/views/admin/fileManager/filesTiles.blade.php b/resources/views/admin/fileManager/filesTiles.blade.php index 24d3af63..eee274d6 100644 --- a/resources/views/admin/fileManager/filesTiles.blade.php +++ b/resources/views/admin/fileManager/filesTiles.blade.php @@ -1,7 +1,7 @@
@forelse($files as $file) -
+
@include('admin.snippets.card', [ 'body' => ''.\App\Helpers\FileManager::getPreview($file).'', 'footerClass' => 'text-right',