LoginSignup
0
1

LaravelとLivewireを活用した画像保存法。アスペクト比とキャンバス余白の設定からS3へのアップロードまで

Posted at

実装したいこと

画像を保存した後、Tailwind CSSを使用して横幅と高さを指定すると、指定されたサイズに合わせて画像が不自然に引き伸ばされてしまいました。そこで、画像のアスペクト比を保持しつつ、指定した横幅と高さで自然に表示されるように設定しました。余白はグレーで埋めることにしました。
元の画像
スクリーンショット 2024-06-08 7.24.19.png

表示時は不自然に引き伸ばされてしまう

<img src="{{  $user->getFirstMediaUrl('images') }}" alt="user_image" class="w-[734px h-60">
スクリーンショット 2024-06-08 7.24.19.png

使用技術

実装

1.必要なものをインストール

Livewire

composer require livewire/livewire

laravel-medialibrary

composer require "spatie/laravel-medialibrary"

必要なマイグレーションを実行してデータベースを設定します。mediaテーブルが作成されます。

php artisan vendor:publish --provider="Spatie\MediaLibrary\MediaLibraryServiceProvider" --tag="migrations"
php artisan migrate

作成されたテーブル

カラム データ型 説明
id uuid PK
model_type string メディアが関連づけられているモデルのタイプ
model_id integer FK。 メディアが関連付けられているモデルのid
collection_name string メディアが属するコレクションの名前
name string ファイルの名前
file_name string 実際のファイル名
mime_type string ファイルのMIMEタイプ
disk string ファイルが保存されているディスクの名前
conversions_disk string 変換されたメディアファイルが保存されているディスクの名前を保存
size bigint ファイルのサイズ(バイト単位)
manipulations json メディアに適応された変換や操作の配列
custom_properites json 任意のプロパティ
responsive_images json レスポンシブ画像の生成に関するデータ
generated_conversions json 画像変換をJSON形式で保存
order_column integer 同じコレクション内でのメディアの順序

User モデルでメディアを扱うために、HasMedia インターフェイスと InteractsWithMedia トレイトを実装し、モデルにメディアを添付できるようにします。

Models.user.php
<?php

namespace App\Models;

use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia;
use Illuminate\Foundation\Auth\User as Authenticatable;


class User extends Authenticatable implements HasMedia
{
 use InteractsWithMedia;

intervention/image

composer require intervention/image

S3を利用してファイル操作を行うための

composer require league/flysystem-aws-s3-v3

手順1.画像加工処理

画像加工処理はintervention/imageのResize機能を使用します。
今回はリサイズと余白埋めをするためcontainを使用します。

引数

public Image::contain(int $width, int $height, $background = 'ffffff', string $position = 'center'): ImageInterface

使用例(公式から)

use Intervention\Image\ImageManager;
use Intervention\Image\Drivers\Gd\Driver;

// create new image instance (800 x 600)
$image = ImageManager::withDriver(Driver::class)->read('images/example.jpg');

// resize padded without upsizing
$image->contain(900, 600);

// padded resizing with grey background color
$image->contain(500, 500, 'efefef');

実際の使用方法

Livewire/UploadImage.php
    $manager = new ImageManager(new Driver());

    $image = $manager->read($this->newImage->get());

    // アスペクト比を変更せず、リサイズ。足りない箇所はグレーの背景で埋める
    $image->contain(734, 240, background: 'f5f5f5', position: 'center');
            

画像は以下のようになります
スクリーンショット 2024-06-08 7.24.19.png

手順2.画像保存処理

S3に保存するためにはLaravelのStorageファサードを使用し、保存後のファイルをspatie/laravel-medialibraryを用いてユーザーのメディアコレクションに登録します。

$filename = 'user/images/' . uniqid();
// S3に画像データを保存
Storage::disk('s3')->put($filename, $image->encode());
// 保存した画像のURLを取得
$full_path = Storage::disk('s3')->url($filename);

$user->clearMediaCollection('images');
$user->addMediaFromUrl($full_path)->toMediaCollection('images', 's3');

1.ファイル名の生成

$filename = 'user/images/' . uniqid();

ここでは、uniqid() 関数を使用して一意のIDを生成し、それをファイル名の一部として組み込んでいます。これにより、S3上でファイルが一意に識別され、他のファイルと名前が重複しないようになります。

2.S3にデータを保存

Storage::disk('s3')->put($filename, $image->encode());

指定された$filenameで画像データをS3に保存しています。ここで$image->encode()は、画像を適切な形式(通常はJPEGやPNG)にエンコードするために使用されます。Storage::disk('s3')は、ファイル操作のためのS3ディスクインスタンスを指定しています。

3.保存した画像のURLを取得

$full_path = Storage::disk('s3')->url($filename);

4.ユーザーのメディアコレクションをクリアし、新しい画像を追加

$user->clearMediaCollection('images');
$user->addMediaFromUrl($full_path)->toMediaCollection('images', 's3');

最初に、ユーザーのimagesメディアコレクションをクリアしています。これは、古い画像を削除し、新しい画像のみを保持するためです。その後、取得した画像のURLを使用して新しい画像をメディアコレクションに追加しています。toMediaCollection('images', 's3')は、画像をimagesコレクションに追加し、s3をディスクとして指定しています。

全体のコード

Livewire/UploadImage.php
<?php

namespace App\Livewire;

use Illuminate\Support\Facades\Storage;
use Livewire\Component;
use Livewire\WithFileUploads;

use Intervention\Image\ImageManager;
use Intervention\Image\Drivers\Gd\Driver;

class UploadImage extends Component
{
    use WithFileUploads;

    public $newImage;

    /**
     * バリデーションルール
     */
    protected $rules = [
        'newImage' => 'nullable|image',
    ];

    /**
     * 画像のアップロード処理
     */
    public function saveImages()
    {
        $this->validate();

        $user = auth()->user();

        $manager = new ImageManager(new Driver());

        // メイン画像の保存処理
        $image = $manager->read($this->newImage->get());

        // アスペクト比を変更せず、リサイズ。足りない箇所はグレーの背景で埋める
        $image->contain(734, 240, background: 'f5f5f5', position: 'center');

        $filename = 'user/images/' . uniqid();
        // S3に画像データを保存
        //加工した画像のエンコードを引数として渡す
        Storage::disk('s3')->put($filename, $image->encode());

        // 保存した画像のURLを取得
        $full_path = Storage::disk('s3')->url($filename);

        $user->clearMediaCollection('images');
        $user->addMediaFromUrl($full_path)->toMediaCollection('images', 's3');

        return redirect()->route('user.profile');
    }

     public function render()
    {
        return view('livewire.user.upload-image');
    }
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1