Written by Manabu Bannai

Laravelで画像処理(アップロード/リサイズ/サムネイル)を行なう方法

Laravel PROGRAMMING

LaravelでLaravelで画像処理(アップロード/リサイズ/サムネイル)を行なう方法をまとめました。
Laravel学習をしている方の参考になれば幸いです。
ソースはgithubで公開しています。
manabubannai/Laravel_Image_Manipulation

Laravelで画像処理をするパッケージのインストール

intervention/image というパッケージを利用します。
intervention/image – Packagist

以下のコマンドでインストールします。

$ composer require intervention/image

つづいて、intervention/imageのセットアップを行ないます。
編集ファイル:app/config/app.php


// 124行目に以下を追加
'InterventionImageImageServiceProvider',

// 192行目に以下を追加
'Image' => 'InterventionImageFacadesImage',

以上でセットアップが完了です。かんたんですね( ◜◡‾)

Laravelで画像処理をするさまざまな方法

まずは、Web上から画像をもってきて表示してみます。
以下の画像を利用してみます。
テスト用画像
以下のプログラムを実行すると画像が取得されていることがわかります。


Route::get('/', function(){

  $image = Image::make(file_get_contents('http://goo.gl/uDTEzv'));

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

});

つぎに画像をリサイズしてみます。
以下のプログラムを実行してみてください。


Route::get('/', function(){

  $image = Image::make(file_get_contents('http://goo.gl/uDTEzv'));

  $image->resize(100,100);

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

});

幅だけを設定して、高さは自動処理にしたい場合は以下のように記述します。


$image->resize(100, null, function ($constraint) {
  $constraint->aspectRatio();
});

クロップしたい場合は以下のように記述します。

$image->crop(100, 100);

デフォルトでは中心部からクロップされますが、クロップ位置を調整した場合は以下のように記述します。


// 左上からクロップする
$image->crop(100, 100, 0, 0);

白黒にした場合は以下のように記述します。
こりゃ便利ですね。

$image->greyscale();

もちろんチェーンメソッドも使えます。
以下が例となります。

$image->crop(200, 200)->greyscale();

その他のコマンドは公式マニュアルからご覧ください。

» Intervention Image – Introduction

Laravelを使って画像をフォルダに保存する方法

まず、publicフォルダ内にimagesフォルダを作っておきます。
その後、以下のように記述します。


Route::get('/', function(){

  $image = Image::make(file_get_contents('http://goo.gl/uDTEzv'));

  $image->crop(200, 200)->greyscale()->save(public_path(). '/images/sample.jpg');

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

});

ここですこしリファクタリングします。


Route::get('/', function(){

  $image = Image::make(file_get_contents('http://goo.gl/uDTEzv'));
  $file = 'sample.jpg';
  $path = public_path() . '/images/';

  $image->save($path . $file) // 画像を保存する
        ->crop(200, 200) // 画像をクロップする
        ->greyscale() // 画像を白黒にする
        ->save($path . 'thumbnail-' . $file); // 加工した画像を保存する

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

});

Laravelを使ってフォームから画像をアップロードする方法

まずは、ルートに以下を記述します。

Route::resource('photos', 'PhotosController');

次に以下のコマンドを実行

$ php artisan controller:make PhotosController

するとPhotosControllerが出来上がるので以下を記述します。
編集ファイル:app/controllers/PhotosController.php


public function create(){
  return View::make('photos.create');
}

つぎにビューを作成します。
新規作成ファイル:app/views/photos.create.blade.php

Laravelで画像処理します

{{ Form::open(['route' => 'photos.store', 'files' => true]) }} {{ Form::hidden('user_id', Auth::user()->id) }} {{ Form::label('fileName', 'アップロード') }} {{ Form::file('fileName') }} {{ Form::submit('アップロードする') }} {{ Form::close() }}

つぎにPhotosControllerに以下を追記します。
編集ファイル:app/controllers/PhotosController.php


public function store(){
  // リクエストの全入力を取得する
  $input = Input::all();

  dd(Input::file('fileName'));
}

このままでは、Auth部分でエラーが発生するので、DBの作成を行います。
usersテーブルを作って、Laravelとコネクトしておいてください。
以下の写真のような簡易なものでOKです。
DBの作成

それでは、テストを行なってみましょう。
localhost:8000/photos/createにアクセスし、画像をアップロードします。
すると以下の結果が表示されます。

object(SymfonyComponentHttpFoundationFileUploadedFile)#9 (7) {
  ["test":"SymfonyComponentHttpFoundationFileUploadedFile":private]=>
  bool(false)
  ["originalName":"SymfonyComponentHttpFoundationFileUploadedFile":private]=>
  string(8) "jq01.png"
  ["mimeType":"SymfonyComponentHttpFoundationFileUploadedFile":private]=>
  string(9) "image/png"
  ["size":"SymfonyComponentHttpFoundationFileUploadedFile":private]=>
  int(46368)
  ["error":"SymfonyComponentHttpFoundationFileUploadedFile":private]=>
  int(0)
  ["pathName":"SplFileInfo":private]=>
  string(36) "/Applications/MAMP/tmp/php/php33b0p7"
  ["fileName":"SplFileInfo":private]=>
  string(9) "php33b0p7"
}

正常に動いていることが確認できたら、次にすすみましょう。
PhotosControllerコントローラーを作成していきます。
編集ファイル:app/controllers/PhotosController.php


public function store(){
  // リクエストの全入力を取得する
  $input = Input::all();

  // getClientOriginalName():アップロードしたファイルのオリジナル名を取得します
  $fileName = $input['fileName']->getClientOriginalName();

  // getRealPath():アップロードしたファイルのパスを取得します。
  $image = Image::make($input['fileName']->getRealPath());

  // 画像を保存する
  $image->save(public_path() . '/images/' . Auth::user()->name . '/' . $fileName);
}

Auth::user()->nameに注目してください。
現在は認証システムを構築していないのでこのままではエラーが起きます。
それをさけるために、routes.phpに以下を追記します。

Auth::loginUsingID(1);

これで、超簡易版の認証システムが完成しました。

それでは、プログラムを実行してみましょう。
しかし、エラーが起きることがわかります。
原因としては、Auth::user()->nameのフォルダを作っていなかったためです。
以下のように解決できます。


public function store(){
  // リクエストの全入力を取得する
  $input = Input::all();

  // getClientOriginalName():アップロードしたファイルのオリジナル名を取得します
  $fileName = $input['fileName']->getClientOriginalName();

  // getRealPath():アップロードしたファイルのパスを取得します。
  $image = Image::make($input['fileName']->getRealPath());

  // Auth::user()->nameのフォルダがあるかどうかを確認し、ない場合は新規作成する
  File::exists(public_path() . '/images/' . Auth::user()->name) or File::makeDirectory(public_path() . '/images/' . Auth::user()->name);

  // 画像をサーバーに保存する
  $image->save(public_path() . '/images/' . Auth::user()->name . '/' . $fileName);
}

これでほぼ完成ですが、最後にサムネイルの保存をしてみます。


$image->save(public_path() . '/images/' . Auth::user()->name . '/' . $fileName)
      ->resize(200, null, function ($constraint) {$constraint->aspectRatio();})
      ->greyscale()
      ->save(public_path() . '/images/' . Auth::user()->name . '/200-' . $fileName);

以上でサムネイルの保存ができました。
参考になれば幸いです( ◜◡‾)

番外編:画像のPathをDBに保存するコード


// こんな感じでOK
$post->image = 'images/'. $fileName;

※コード:manabubannai/Laravel_Image_Manipulation

※参考記事Image Manipulation