実装したいこと
画像を保存した後、Tailwind CSSを使用して横幅と高さを指定すると、指定されたサイズに合わせて画像が不自然に引き伸ばされてしまいました。そこで、画像のアスペクト比を保持しつつ、指定した横幅と高さで自然に表示されるように設定しました。余白はグレーで埋めることにしました。
元の画像
表示時は不自然に引き伸ばされてしまう
<img src="{{ $user->getFirstMediaUrl('images') }}" alt="user_image" class="w-[734px h-60">

使用技術
実装
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
トレイトを実装し、モデルにメディアを添付できるようにします。
<?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');
実際の使用方法
$manager = new ImageManager(new Driver());
$image = $manager->read($this->newImage->get());
// アスペクト比を変更せず、リサイズ。足りない箇所はグレーの背景で埋める
$image->contain(734, 240, background: 'f5f5f5', position: 'center');
手順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をディスクとして指定しています。
全体のコード
<?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');
}