<img src="/path/to/img.jpg" >
って書いてて、あなんかこの画像やっぱ重いなぁと思ったら
<img src="{{ resize('/path/to/img.jpg' ,200, 200) }}" >
<!-- /storage/cache/aerwsvv4w4cey75hf.jpg のように置換されます-->
って書き換えるだけで
- サムネイル生成(初回アクセス時のみ)
- 2回目以後のアクセスは、キャッシュ画像に直接アクセス
- サムネイルは、画像の更新や指定サイズの変更タイミングで自動更新
される実装です。
command
$ composer require intervention/image
$ php artisan storage:link
$ mkdir storage/app/public/cache
DynamicImage.php
<?php
namespace App\Services;
use Intervention\Image\Image;
/**
* Class DynamicThumb
* @package App\Services
*/
class DynamicImage
{
const CACHE_DIR = 'cache';
const IMG_QUALITY = 80;
/**
* resize処理
* @param string $imagePath
* @param array $query
* @return string|null
*/
public static function resize(string $imagePath, array $query): string
{
return self::execute($imagePath, __METHOD__, $query);
}
/**
* crop処理
* @param string $imagePath
* @param array $query
* @return string|null
*/
public static function crop(string $imagePath, array $query): string
{
return self::execute($imagePath, __METHOD__, $query);
}
/**
* fit処理
* @param string $imagePath
* @param array $query
* @return string|null
*/
public static function fit(string $imagePath, array $query): string
{
return self::execute($imagePath, __METHOD__, $query);
}
/**
* キャッシュがなければ生成して publicパスを返す
* @param string $imagePath
* @param string $action
* @param array $query
* @return string|null
*/
private static function execute(string $imagePath, string $action, array $query): ?string
{
if (!self::cacheExists($imagePath, $query)) {
$image = \Image::make(public_path($imagePath));
$action = $action . 'Image';
$image = $action($image, $query);
$image->save(self::getFullPathOfCacheImage($imagePath, $query), self::IMG_QUALITY);
}
return self::getPublicPathOfCacheImage($imagePath, $query);
}
/**
* キャッシュファイル存在するか?
* @param string $imagePath
* @param array $query
* @return bool
*/
private static function cacheExists(string $imagePath, array $query): bool
{
return file_exists(self::getFullPathOfCacheImage($imagePath, $query));
}
/**
* キャッシュディレクトリのpublicパス
* @return string
*/
private static function getPublicPathOfCacheDir(): string
{
return '/storage/' . self::CACHE_DIR . '/';
}
/**
* キャッシュディレクトリのフルパス
* @return string
*/
private static function getFullPathOfCacheDir(): string
{
return storage_path('app/public/' . self::CACHE_DIR) . '/';
}
/**
* キャッシュ画像のbaseName
* @param string $imagePath
* @param array $query
* @return string
*/
private static function getBaseNameOfCacheImage(string $imagePath, array $query): string
{
return md5(http_build_query([
'path' => $imagePath,
'query' => $query,
'modified' => filemtime(public_path($imagePath))
])) . '.jpg';
}
/**
* キャッシュ画像のpublicパス
* @param string $imagePath
* @param array $query
* @return string
*/
private static function getPublicPathOfCacheImage(string $imagePath, array $query): string
{
return self::getPublicPathOfCacheDir() . self::getBaseNameOfCacheImage($imagePath, $query);
}
/**
* キャッシュ画像のフルパス
* @param string $imagePath
* @param array $query
* @return string
*/
private static function getFullPathOfCacheImage(string $imagePath, array $query): string
{
return self::getFullPathOfCacheDir() . self::getBaseNameOfCacheImage($imagePath, $query);
}
/**
* $width x $height に収まるよう縮小
* @param Image $image
* @param array $query
* @return Image
*/
private static function resizeImage(Image $image, array $query): Image
{
$width = $height = null;
extract($query);
if ($image->width() < $image->height()) {
$image->resize($width, null, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
});
} else {
$image->resize(null, $height, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
});
}
return $image;
}
/**
* $position(top, center ,bottom)を起点に、$width x $height に収まるようトリミング
* @param Image $image
* @param array $query
* @return Image
*/
private static function fitImage(Image $image, array $query): Image
{
$width = $height = $position = null;
extract($query);
$image->fit($width, $height, function ($constraint) {
$constraint->upsize();
}, $position ?? 'center');
return $image;
}
/**
* $x x $yを起点に $width x $height で切り出す
* @param Image $image
* @param array $query
* @return Image
*/
private static function cropImage(Image $image, array $query): Image
{
$width = $height = $x = $y = null;
extract($query);
if ($x) {
$image->crop($width, $height, $x, $y);
} else {
$image->crop($width, $height);
}
return $image;
}
}
helpers.php
<?php
use App\Services\DynamicImage;
if(!function_exists('resize')){
function resize(string $basePath, int $width, int $height): string
{
return DynamicImage::resize($basePath, compact('width', 'height'));
}
}
if(!function_exists('crop')){
function crop(string $basePath, int $width, int $height, ?int $x = null, ?int $y = null): string
{
return DynamicImage::crop($basePath, compact('width', 'height', 'x', 'y'));
}
}
if(!function_exists('fit')){
function fit(string $basePath, int $width, int $height, ?string $position = null): string
{
return DynamicImage::fit($basePath, compact('width', 'height', 'position'));
}
}