laravel パラメータ指定で簡単画像Resize＆Crop



`http://hoge.com/path/to/abc.jpg`
を
`http://hoge.com/path/to/abc.jpg.cnv?thumb=300x200` でサムネイル
`http://hoge.com/path/to/abc.jpg.cnv?crop=300x200` で切り出し
`http://hoge.com/path/to/abc.jpg.cnv?fit=300x200-top` で最適切り出し
したりします。


### 2019/01/23 追加

- サムネイルを無限生成できちゃうので、ファイル単位で制限を設定しましたー
- laravelのcache機構を導入しましたー 

@mikkame さんありがとございます

### 2019/01/24 追加

- cacheに関する記述追加


# 設定方法

## 初期設定

interventionインストール

```bash
$ php composer.phar require intervention/image #interventionインストール
```

.env の設定

```bash:.env
CACHE_DRIVER=array #ローカルでキャッシュを無効にする場合
CACHE_DRIVER=file #fileベースでキャッシュする場合
CACHE_DRIVER=redis #redisを使う場合
```


## ImageRouting.php

どこかに配置します。

```php:app/Services/ImageRouting.php
<?php

namespace App\Services;

use Cache;
use Illuminate\Http\Request;
use Intervention\Image\Image;

class ImageRouting
{
    /**
     * @param string $imagePath 画像のフルパス
     * @param Request $request
     * @param string $extension 識別用の拡張子
     * @param int $limit 生成件数制限
     * @param int $cacheDays キャッシュ保持期間
     * @return mixed
     */
    function __invoke(
        string $imagePath,
        Request $request,
        string $extension = '.cnv',
        int $limit = 10,
        int $cacheDays = 3
    )
    {
        $imagePath = str_replace($extension, '', $imagePath);

        $counterCache = md5($imagePath);
        $fileCache = md5(json_encode([$imagePath, $request->all()]));

        if (Cache::get($counterCache, 0) < $limit) {

            $image = Cache::remember($fileCache, 60 * 24 * $cacheDays,
                function () use ($request, $imagePath, $counterCache) {

                    $image = \Image::make(public_path($imagePath));

                    $image = $this->fitIfNeeded($image, $request);
                    $image = $this->cropIfNeeded($image, $request);
                    $image = $this->thumbnailIfNeeded($image, $request);

                    Cache::increment($counterCache);

                    return $image->response('jpg');
                });

            return $image;
        } else {
            abort(404);
        }
    }

    /**
     * hoge.cnv.jpg?fit=300x200-top (収まるようにトリミング)
     * @param $image
     * @param $request
     * @return Image
     */
    private function fitIfNeeded(Image $image, Request $request): Image
    {
        //chukyo.jpg_?fit=300x200-top (収まるようにトリミング)
        $fit = $request->f ?: $request->fit;
        if ($fit && preg_match('/([0-9]+)x([0-9]+)(:?-([-a-z]+))?/', $fit, $mc)) {

            $image->fit($mc[1], $mc[2], function ($constraint) {
                $constraint->upsize();
            }, !empty($mc[3]) ? $mc[3] : 'center');
        }

        return $image;
    }

    /**
     * hoge.cnv.jpg?crop=300x200 (切り出す)
     * @param $image
     * @param $request
     * @return Image
     */
    private function cropIfNeeded(Image $image, Request $request): Image
    {
        //chukyo.jpg_?crop=300x200 (切り出す)
        $crop = $request->c ?: $request->crop;
        if ($crop && preg_match('/([0-9]+)x([0-9]+)/', $crop, $mc)) {
            $image->crop($mc[1], $mc[2]);
        }

        return $image;
    }

    /**
     * hoge.cnv.jpg?thumb=300x200 (収まるように縮小)
     * @param Image $image
     * @param Request $request
     * @return Image
     */
    private function thumbnailIfNeeded(Image $image, Request $request): Image
    {
        $thumb = $request->t ?: $request->thumb;
        if ($thumb && preg_match('/([0-9]+)x([0-9]+)/', $thumb, $mc)) {

            if ($image->width() < $image->height()) {
                $image->resize($mc[1], null, function ($constraint) {
                    $constraint->aspectRatio();
                    $constraint->upsize();
                });
            } else {
                $image->resize(null, $mc[2], function ($constraint) {
                    $constraint->aspectRatio();
                    $constraint->upsize();
                });
            }
        }

        return $image;
    }
}
```

## routes/web.php に追加

```php:routes/web.php

use Illuminate\Http\Request;

Route::get('{imagePath}', function ($imagePath, Request $request, \App\Services\ImageRouting $service) {

    return $service($imagePath, $request);

})->where('imagePath', '(.*).cnv.(jpg|jpeg|png|gif)$');
```