Laravelで画像を圧縮する手順（ImageManager使用）

# 手順
# 1. Intervention Image をインストール
まず、Intervention Image ライブラリをインストールします。
```bash
composer require intervention/image
```

# 2-1. 画像の圧縮処理を実装(新規アップロード)：サービスクラス
✅の箇所
```/Applications/MAMP/htdocs/Laravel/collections/app/Service/Admin/CollectionService.php
namespace App\Service\Admin;
use App\Models\Collection;
use App\Models\CollectionImage;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Intervention\Image\ImageManager; // ✅
use Intervention\Image\Encoders\JpegEncoder; // ✅
use Intervention\Image\Drivers\Gd\Driver; // ✅


  public static function storeRequestImage($request, $collection)
  {
      $orderData = json_decode($request->input('image_order'), true) ?? [];
      $sessionTmpImages = $request->input('tmp_images');

      // ✅ `ImageManager`を`gd`ドライバー指定で作成
      $manager = new ImageManager(new Driver());

      // 🔹 通常アップロードされた画像の保存
      if($request->hasFile('image_path') && is_null($sessionTmpImages)) {
          $uploadedFiles = $request->file('image_path');
  
          foreach($uploadedFiles as $imagePath) {
              $fileName = trim($imagePath->getClientOriginalName()); // アップロードファイル名取得
              $order = collect($orderData)->first(fn($item) => str_starts_with($item['uniqueId'], $fileName)); // position取得
              $imageName = time() . '_' . uniqid() . '.' . $imagePath->getClientOriginalExtension(); // テーブル保存用

              // ✅ 拡張子を取得(小文字変換)
              $extension = strtolower($imagePath->extension());

              // ✅ 画像に合わせた拡張子選択
              switch ($extension) {
                  case 'png':
                      $encoder = new PngEncoder(9); // PNG 圧縮
                      break;
                  case 'webp':
                      $encoder = new WebpEncoder(80); // WebP 圧縮
                      break;
                  default:
                      $encoder = new JpegEncoder(75); // それ以外はJPEG（品質75）
              }

              // ✅ 画像を圧縮
              $compressedImage = $manager->read($imagePath->getRealPath())->encode($encoder);

              // ✅ 圧縮画像を保存
              Storage::disk('public')->put('collection_images/' . $imageName, (string)$compressedImage);
  
              CollectionImage::create([
                  'collection_id' => $collection->id,
                  'image_path' => $imageName,
                  'position' => $order ? $order['position'] : 0
              ]);
          }
      }
```


# 2-2. 画像の圧縮処理を実装(セッション+ストレージのアップロード)：リクエストクラス
✅の箇所
```/Applications/MAMP/htdocs/Laravel/collections/app/Http/Requests/CollectionRequest.php
<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\Facades\Storage;
use Intervention\Image\ImageManager; // ✅
use Intervention\Image\Drivers\Gd\Driver; // ✅
use Intervention\Image\Encoders\JpegEncoder; // ✅
use Intervention\Image\Encoders\PngEncoder; // ✅
use Intervention\Image\Encoders\WebpEncoder; // ✅

class CollectionRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array<string, mixed>
     */
    public function rules()
    {
        return [
            'title' => ['required', 'string', 'max:50'],
            'description' => ['nullable', 'string', 'max:10000'],
            'url_qiita' => ['nullable', 'url', 'max:500'],
            'url_webapp' => ['nullable', 'url', 'max:500'],
            'url_github' => ['nullable', 'url', 'max:500'],
            'is_public' => ['required', 'boolean'],
            'position' => ['required', 'integer'],
            'image_path' => ['nullable'],
            'image_order' => ['nullable'],
        ];
    }

    protected function failedValidation(\Illuminate\Contracts\Validation\Validator $validator)
    {
        // ✅ GDドライバーで ImageManager を作成
        $manager = new ImageManager(new Driver());

        $tmpImagePaths = session('tmp_images', []);
        $fileNames = session('file_names', []);
        $imageOrder = session('image_order', []);

        // フォームの hidden input から画像順序データを取得
        if($this->has('image_order')) {
            $imageOrder = json_decode($this->input('image_order'), true);
        }

        if ($this->hasFile('image_path')) {
            $images = $this->file('image_path');

            foreach ($images as $image) {
                // $base64Image = 'data:image/' . $image->extension() . ';base64,' . base64_encode(file_get_contents($image->getRealPath()));
                $fileName = $image->getClientOriginalName(); // ファイル名取得
                $extension = strtolower($image->extension()); // 拡張子を取得(小文字変換)

                // ✅ 画像に合わせた拡張子を選択
                switch ($extension) {
                    case 'png':
                        $encoder = new PngEncoder(9); // PNG 圧縮
                        break;
                    case 'webp':
                        $encoder = new WebpEncoder(80); // WebP 圧縮
                        break;
                    default:
                        $encoder = new JpegEncoder(75); // それ以外はJPEG（品質75）
                }

                // ✅ 画像を圧縮
                $compressedImage = $manager->read($image->getRealPath())->encode($encoder);

                $tmpImageName = time() . '_' . uniqid() . '.' . $extension;
                Storage::disk('public')->put("tmp/{$tmpImageName}", (string)$compressedImage);

                $tmpImagePaths[] = "tmp/{$tmpImageName}";
                $fileNames[] = $fileName;

                // `imageOrder` に `fileName` がすでに存在するかチェック
                $foundIndex = array_search($fileName, array_column($imageOrder, 'fileName'));

                if ($foundIndex !== false) {
                    // すでに `imageOrder` に登録済みなら `src` を更新
                    $imageOrder[$foundIndex]['src'] = "tmp/{$tmpImageName}";
                } else {
                    // 新規画像の場合
                    $imageOrder[] = [
                        'fileName' => $fileName,
                        'src' => "tmp/{$tmpImageName}",
                    ];
                }
            }
        }

        // セッションに保存
        Session::put('tmp_images', $tmpImagePaths);
        Session::put('file_names', $fileNames);
        Session::put('image_order', $imageOrder);

        parent::failedValidation($validator);
    }
}
```