
九保すこひです(フリーランスのITコンサルタント、エンジニア)
さてさて、突然ですがみなさん「webp(うぇっぴー)」って聞いたことあるでしょうか。
webp
とは、軽量の新画像形式(jpeg
やpng
などの仲間)のことで、なんと、開発したグーグルによると、可逆形式ではpng
の26%
、不可逆形式では25〜34%
もファイルサイズを減らすことができると紹介されています。
そのため、たくさん画像を使うサイトでは高速化のためにwebp
を使うことが有効といっていいんですが、実はそれほど普及しているイメージはなかったりもします。
なぜかというと、Can I useを見てもらえば分かりやすいですがIE
とSafari
がwebp
をサポートしていないからなんですね(うーん、大人の事情もからんでいそうですね・・・)
ただ、それでもブラウザのシェアを考えるとGoogle Chrome
が圧倒的なので、画像をメインにしているサイトだとブラウザによってwebp
とJPEG
などその他の画像形式を切り替えることで、サイトの高速化と負荷軽減を実現することができます。
そこで!
今回は、Laravel
にアップロードされた画像からwebp
とjpeg
形式の2画像をつくり、ブラウザによって自動的に切り替えをする方法をご紹介します。
ぜひ皆さんのお役に立てると嬉しいです
開発環境: Laravel 6.x、Vue 2.6
目次 [非表示]
前提として
GDを使う場合、以下のようにwebp
がサポートされていると表示されている必要があります。(PHP 5.5
以上か7
)
Imagemagick
の場合はlibwebp
がコンパイルされている必要があります。
画像パッケージをインストールする
実際にコードを書いていく前に、PHP
で画像を簡単に操作できる有名パッケージintervention
をインストールしておきましょう。
composer require intervention/image
※ なお、intervention
のより詳しい使い方は完全網羅!Intervention Image(PHP)で画像を編集する全実例を参考にしてみてください。
Laravelに画像をアップロードする機能をつくる
では、ここからが実際にプログラムを書いていく作業になります。
ルートをつくる
まずはルートをつくります。
routes/web.php
を開いて以下を追加してください。
Route::get('webp/create', 'WebpController@create');
Route::post('webp', 'WebpController@store');
コントローラーをつくる
続いてコントローラーです。
以下のコマンドを実行してください。
php artisan make:controller WebpController
すると、app/Http/Controllers/WebpController.php
というファイルが作成されるので、中身を以下のように変更してください。
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
class WebpController extends Controller
{
public function create() {
return view('webp/create');
}
public function store(Request $request) {
$result = false;
if($request->hasFile('image')) {
$path = $request->image->path();
$image = \Image::make($path);
$uuid = Str::uuid();
// Webpを作成
$webp_path = public_path('images/webp/'. $uuid .'.webp');
$image->save($webp_path);
// JPEGを作成
$jpeg_path = public_path('images/jpeg/'. $uuid .'.jpg');
$image->save($jpeg_path);
$result = true;
}
return ['result' => $result];
}
}
この中で重要なのがstore()
です。
このメソッドではAjax
を通して送信されてくる画像を取得し、それぞれwebp
とjpeg
形式の画像を作成しています。
なお、保存されるフォルダはpublic/images/webp
とpublic/images/jpeg
ですが、今回はテストなのでこれらのフォルダには777
(全てOK)の権限を与えています。
ただ、これはセキュリティ上良いとはいえないので、気になる方はstorageをpublic化しておくことをおすすめします。
※ また、バリデーションもついていませんのでご注意ください。
ビューをつくる
最後に画像をアップロードするフォームのビュー(HTML)を作成します。
resources/views/webp/create.blade.php
というファイルを作成して中身を以下のように変更してください。
<html>
<head>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" rel="stylesheet">
</head>
<body class="p-4">
<div id="app" class="container">
<div class="row">
<div class="col-4">
<div class="form-group">
<input class="form-control" type="file" accept="image/*" @change="onFileChange">
</div>
<button class="btn btn-primary" type="button" @click="onSubmit">画像をアップロードする</button>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.0"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.19.0/axios.min.js"></script>
<script>
new Vue({
el: '#app',
data: {
imageFile: null
},
methods: {
onFileChange(e) {
// 選択された画像を変数で保持する
this.imageFile = e.target.files[0];
},
onSubmit() {
// 画像をアップロード
const url = '/webp';
let formData = new FormData();
formData.append('image', this.imageFile);
axios.post(url, formData)
.then(response => {
if(response.data.result) {
alert('アップロードが完了しました。');
}
});
}
}
});
</script>
</body>
</html>
この中で重要なのは、まず画像が選択されたときに実行されるonFileChange()
です。
このメソッドの中では、選択された画像ファイルの情報をいったんimageFile
という変数の中に格納しています。
そして、次に「画像をアップロードする」ボタンをクリックしたときに実行されるonSubmit()
です。
選択された画像は、axios
でAjax
送信することになりますが、通常の入力値を送信する書き方とは違ってFormData
を使っていることに注意してください。
FormData
へのデータ追加はappend()
を使います。
これで、画像ファイルを送信すると自動的にwebp
とjpeg
画像が作成されるようになりました。
なお、webp
のファイルサイズがどれだけ圧縮できるかをチェックしたかったので以下のpng
画像をアップロードして試してみました
(ファイルサイズは、92.8 KB)
結果としては、
- jpeg ・・・ 58.5 KB
- webp ・・・ 29.4 KB
となりました。
なんと、Webp
の方はJPEG
ファイルの半分ほどのサイズです
これは高速化には大きな影響があると思われます。
webpとjpegを切り替えて表示する
では、ここからはアップロードされた画像(webp
, jpeg
)をブラウザによって切り替えて表示する方法をご紹介します。
HTML 5を使う
以下のようにHTML 5
の<picture>
タグを使うことで、ブラウザがwebp
対応している場合はwebp
を、そうでない場合はjpeg
など他の形式の画像を読み込むというように自動的に切り替えることができます。
<picture>
<!-- WebpのURL -->
<source type="image/webp" srcset="/images/webp/*****.webp">
<!-- JpegのURL -->
<img src="/images/jpeg/*****.jpg">
</picture>
コンポーネントをつくる
ただし、毎回毎回先ほどのタグを作成するのは面倒だったりします。
そこで、次のようなコンポーネントをつくっておくと便利でしょう。
Bladeテンプレート
resources/views/components/webp.blade.php
というファイルを作成して中身を以下のように変更します。
<picture>
<source type="image/webp" srcset="{{ $src }}">
<img src="{{ $alt }}">
</picture>
使い方はこのようになります。
@component('components.webp')
@slot('src', '/images/webp/*****.webp')
@slot('alt', '/images/jpeg/*****.jpg')
@endcomponent
Vueコンポーネント
Vueコンポーネントの場合は次のようになります。
Vue.component('v-webp', {
props: ['src', 'alt'],
template: '<picture>'+
'<source type="image/webp" :srcset="src">'+
'<img :src="alt">'+
'</picture>'
});
使い方はこのようになります。
<v-webp
src="/images/webp/*****.webp"
alt="/images/jpeg/*****.jpg"></v-webp>
これで自動切り替えが簡単になると思います。
お疲れ様でした
おわりに
ということで今回は軽量な画像形式のwebp
をつくる&使う方法をご紹介しましたが、実際にwebp
の画像がいかに軽量になるかを知ることになりました。
ただ、webp
はまだまだメジャーになるには道半ばで、windows 10
&Ubuntu 18.04
で確認しましたが、通常の画像ソフトでは見ることができずGoogle Chrome
で開く必要がありました。
そのため、インターネット上には「webpをjpegに変換する」というオンライン・サービスもあったりするようです。
とはいっても、フリーの画像ソフトGimp
がwebp
をサポートしたという動きもありますし、なによりGoogle
が開発したというのは大きいかもしれません。(たまにGoogle
は「はい、やめまーす♪」ってなるのも事実ですが)
ということでページの高速表示のためにwebp
も検討してみてはいかがでしょうか。
ではでは〜♪