どうもこんにちは。
先日、こんな問題が。
「iPhoneで撮影した写真をWebにアップロードして、ほかのPC等で見ると、なんか変。」
とのこと。
困りました。
調べると、こちらにたどりつきました。
https://qiita.com/RichardImaokaJP/items/385beb77eb39243e50a6
やれることは、
・表示時に回転を補正する
・アップロード時に回転を補正する
のふたつにひとつ。
表示時に補正するのは、表示している箇所が多いのと、ブラウザごとに解釈が違う(!)という
ところがあり、断念。
今回は、アップロード時に回転を補正する方向で話を進めます。
なお、例によってフレームワークはLaravel 5.8です。
目次
事前準備
PHPでの画像処理は数あれど、Laravelでやるなら「Intervention Image」一択、っぽい雰囲気だったので
これを使います。公式サイトはコチラ ⇒ Intervention Image – Introduction
みんな大好きGDや、みんな大好きImageMagickが使える環境であれば、特に不都合なく使えます(らしい)。
GD、ImageMagickのインストールおよびPHPの設定については割愛します。
確認
PHPのextensionがキチンと設定されているかの確認です。
・FileInfo
phpinfo();
で確認し、fileinfo support が enabled になっていることを確認しましょう。
・GD(GDをつかうなら)
php -r "var_dump(gd_info());"
で確認しましょう。
正しく設定されていれば、バージョン情報などが入った連想配列が返ってきます。
・ImageMagick(ImageMagickをつかうなら)
php -r "var_dump(Imagick::getVersion());"
で確認しましょう。
正しく設定されていれば、バージョン情報が入った連想配列が返ってきます。
Intervention Image をインストール
Composerでインストールします。
composer require intervention/image
ここはサラッと。
Laravelでやること
設定ファイル作成
まず、artisanコマンドで、設定ファイルをプロジェクトの中に作成します。
php artisan vendor:publish
どれを作るんだい?と聞かれる場合がありますので、適宜選択してください。
私の場合は、Intervention\Image\ImageServiceProviderLaravel5 を選びました。
コマンドが成功すると、プロジェクト配下に config/image.php が作成されるはずです。
GDを使う場合は変更しなくてもよい(デフォルトでgdが指定されている)のですが、
ImageMagickを使う場合はこいつを変更します。
1 2 3 |
//略 'driver' => 'imagick', //略 |
設定ファイル編集(config/app.php)
サービスプロバイダと、ファサードを登録します。
1 2 3 4 5 |
'providers' => [ // 略 Intervention\Image\ImageServiceProvider::class, // <= 追加 // 略 ], |
と
1 2 3 4 5 |
'aliases' => [ // 略 'Image' => Intervention\Image\Facades\Image::class, // <= 追加 // 略 ], |
です。
実装編
前提
今回、私の構築環境におけるファイルシステムドライバのデフォルトは”S3″にしています。
環境が異なる場合は、適宜読み替えてください。
本題
変更前)
こんな感じで、シンプルに保存をしていました。
1 |
Storage::putFile("path/to/file", $file, 'public'); |
変更後)
ローカルディスクに一時ファイルを作ってから、Storageファサードで保存、一時ファイルを消す、
という感じです(実はちょっと手こずりました)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
// 一時的にファイルを保存する。 $localDisk = Storage::disk('local'); $tmpFile = $localDisk->putFileAs('tmp', $file, Carbon::now()->timestamp . $file->hashName()); //一時ファイル名はご愛嬌 // インスタンスを作成 $image = Image::make($localDisk->path($tmpFile)); // 回転を補正して保存 $image->orientate()->save(); // 本体を保存 Storage::putFile("path/to/file", $tmpFile, 'public'); // インスタンス破棄 $image->destroy(); // 一時ファイル削除 $localDisk->delete($tmpFile); |
回転を補正するのは、$image->orientate()
で行います。
画像のサイズ変更や加工もここらあたりで行い、最後にsave()
します。
でないと反映されません。
本当は
1 |
Storage::putFile("path/to/file", $image, 'public'); |
のようなことをしたかったのですが、putFileの第2引数はIlluminate\Http\File
かIlluminate\Http\UploadedFile
しか
受け取ってくれなかったり、
1 2 |
$image = Image::make($file); $image->orientate()->save(); |
な感じにしようと思ったら、NotSupportedException(Encoding format(tmp) is not supported)
がthrowされてしまったり、
紆余曲折あったうえでのこんな処理です。
あと、
1 |
$image->destroy(); |
でファイルごと消してくれていたら最高だったんですが。。。
で、ファイルアップロード処理を実行すると、向きが正しく(と言っていいのだろうか?)
保存されていました。
最後に
いろいろ頑張ったのですが、実は先人がすでにこの領域に到達していました。
考え方は、ほぼ一緒でした。
https://qiita.com/fakefurcoronet/items/fe2861ca2846b7347418
きっと、似たようなことがPythonやRuby、Javaにもあるはずなので
なんかのタイミングで調べておこうと思いました。
しかし、またiPhoneかよ。。。どないなっとんねん、Appleはよ。。。
r.tanakaがお届けしました。