Webp画像の真髄に迫る！！

皆様こんにちは、玉ちゃんです！！！！

いきなりですが皆様、画像の拡張子といえば何を思いつくでしょうか、pngやjpgなどでしょうかね？

いいえ、時代はwebpです。ウェッピーと読みます。

本日は、まだまだ馴染みないであろうWebpの真髄に迫っていこうと思います。

# Webpについて

> webp（ウェッピー）とは、Googleが開発した次世代画像フォーマットのことであり、2010年に公式発表されました。webpは画像の圧縮率が高く、表示速度の高速化に有利に働きます。

Google先生が開発いたしました。たまーにwebサイトから画像を保存したりするとwebp拡張子のことあります。（テンション上がります）

## ズバリwebp画像を利用するメリット

### １：画像サイズの軽量化

画質もpngやjpgに劣らない上に、可逆圧縮にも非可逆圧縮にも対応しています！そしてとにかく軽い、軽すぎるのです！！

Webpとjpegを比較した場合約25％程度は軽量化することが可能と言われています。

### ２：ページスピードの改善

画像サイズが軽量化されるということは、Webサイトのページスピードに直結するのです！既に使わん理由なし！！

### ３：SEO面での恩恵

Googleが公表する**The Page Experience Update**という検索アルゴリズムからすると、ページスピードといった、ユーザーに対する良質なエクスペリエンスはSEOの観点からもかなり重要視されています。

（昨今のSEOでは**Google Core Web Vitals**と呼ばれるWebサイトの応答性、表示速度、デザイン性などの総評から検索エンジンの順位を決定している。）

## Webpのデメリットは、、、？

### **非対応のブラウザが存在する**

![スクリーンショット 2022-12-05 11.14.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2705538/bdd6da25-2a1a-4a45-cbd9-1ea36f6d00f6.png)

上記の赤部分が22/12時点のwebp対応ブラウザとなっています。

SafariもmacOS 11 Big Sur以前では未対応ですが、市場に多く流通しているiPhoneはすべて対応済みと考えられます、、、

しかし！！上の画像の赤枠でWebサイトを閲覧している方々も存在しないわけではありません。というか、一定数確実にいます。

Webp対応していないブラウザでは、Webp画像を表示することはできない、、

わけではなく、未対応ブラウザに対してはpngもしくはjpg画像を表示してあげれば良いのです！そう！シンプルなのです！！

ということで、実際にブラウザごとの振り分けを行いましょう！！

## Webp対応ブラウザと未対応ブラウザ表示振り分け

今回は一番シンプルな、HTMLの<picture>タグを用いた対応策を紹介できればと思います。

```html
<picture>

  <source srcset=”sample.webp” type=”image/webp”>

  <img src=”sample.jpg“>

</picture>
```

`picture`タグは１つ以上の`source`タグと、１つ以上の`img`タグを子要素に含む必要があります。

ブラウザは、<source></source>を上から順番に検討し、条件に該当した画像を表示してすることとなります。

そのため、Webpに対応しているブラウザの場合は、sample.webpを表示し、

未対応ブラウザの場合にはsample.jpgを表示してくれるということになります。うん、賢い(^^)v

※（しかし、IEはそもそも`picture`タグに対応していないそうなので[こちら](https://scottjehl.github.io/picturefill/)をご参考に、、）

※（他にも、CSS側での切り分けのための「[Modernizr](https://modernizr.com/)」などのプラグインなども存在しています。）

## ちょっと待てい！！！

上記のように、シンプルに表示の切り分けを行うことができるのですが`picture`タグを利用するにはwebp拡張子の画像と、png/jpg画像の２つを用意しなくてはなりません。

これ、わざわざ、面倒じゃないですか？？？？？

## では、どうするか？？

**※今回はS3に画像を保存していること、DBに画像pathを保持していること(webp_pathカラムとそれ以外のpathカラム\[image_path\]の2つが存在している)、PHP7系以上を使用していることが前提です。**

簡潔ですが、利用するべき関数などを紹介できればと思います。

### １：S3に元々保存されているpng/jpg画像から、webp画像を作成する。

上記の逆のパターン（S3に保存されているwebp画像からpng/jpg画像を作成する）も対応する必要もありますね。今回は、単発のバッチ処理想定で行います。

**※gifの変換は行いません。**

**⁠※webp画像はpng画像に複製しています**

```php
$list = "DB内の画像path達"

foreach($list as $path) {            

  $path = "DBに保存されているpng/jpg/webpのパス";
  $path_info = pathinfo($path);

   // url化
   $image_url = config('config.works_image_url');
   $url = $image_url . $path;

    // 拡張子情報取得
    $extension = $path_info['extension'];

    $mime_type = null;

    switch($extension) {
      case 'jpg';
        $image = imagecreatefromjpeg($url);
        $mime_type = 'webp';
        break;
      case 'png';
        $image = imagecreatefrompng($url);
        $mime_type = 'webp';
        break;
      case 'webp';
        $image = imagecreatefromwebp($url);
        $mime_type = 'png';
        break;
     }
```

**ちょこっと解説**

*・pathinfo()を用いて、pathの情報を分解して取得しています。拡張子の情報もこれで一発で取得できます。*

*・imagecreatefrom〇〇系の関数は画像作成関数でして、pathをもとにGdimage オブジェクトを返します。ここで一度画像を作成しています。*

 *・$mime_typeに対して、後程変換するべき拡張子の情報を持たせています。*

下記もforeachの中で行ってください。

```php
if (!is_null($mime_type)) {

   //複製fileNameを作成 
   $fileName = $path_info['filename'] . '.'.$mime_type;

    // 仮保存tempフォルダ作成
    mkdir(base_path('仮保存用のフォルダまでのpath'));

    // 仮保存フォルダに画像パスを追加
    $tmp = base_path('仮保存用のフォルダまでのpath'.$fileName);

    $store_path = $path_info['dirname'];

    $baseName = $store_path . '/' .  $path_info['filename'];

    $copy_path = $baseName . '.' . $mime_type;

    // Palette imageに対応
    imagepalettetotruecolor($image);

    // テーブル選択
    $Table = "保存先のテーブル";
    if ($mime_type == 'webp') {
        // webp画像作成
        imagewebp($image,$tmp);

        // webp_pathカラムに追加
        $Table->webp_path = $copy_path;
        $Table->save();

    } elseif ($mime_type == 'png') {

        // png画像作成
        imagepng($image,$tmp);

        // Webpパスをwebp_pathカラムに移動
        $webp_path = $Table->image_path;
        $Table->webp_path = $webp_path;

        // pngパスで上書き
        $Table->image_path = $copy_path;
        $Table->save();
    }

    // S3に保存
    $file = new File($tmp);
    $s3_path = Storage::disk('s3')->putFileAs($store_path, $file, $fileName,'public');

    if (file_exists($tmp)) {
        // 画像削除
        unlink($tmp);
        //tempフォルダも削除
        rmdir(base_path('仮保存用のフォルダまでのpath'));
    }
}
```

**ちょこっと解説**

*・imagewebp()やimagepng()は第一引数に、Gdimageオブジェクト、第二引数に実体を保存するpathをあげることによって画像をファイルに出力してくれる関数です。*

*・S3に保存するためには、画像のpathのみではなく画像の実態が必要なので仮保存しています。*
*・最後にunlink()とrmdir()で仮保存していたフォルダごと削除します。（S3に保存できれば必要ないので）*

### ２：S3保存時にWebp画像を自動で作成しS3に保存する。

ここは、上記で行った処理とほぼ同じですので割愛させてください。（長くなりすぎちゃう、、）

### ３：最後に表示処理では上記の、タグを用いた表示を行ってください。

フロント側で、webpとpngもしくはjpgのS3のpathを渡してください。

```html
<picture>

  <source srcset=”S3内のwebp画像path” type=”image/webp”>

  <img src=”S3内のpng/jpg画像path“>

</picture>
```

ブラウザで確認するとwebp画像が表示されるようになったと思います。

## ⁠最後に

かなり長くなりましたが、表示処理の切り分けは至ってシンプルです。

Webpの恩恵を受けるためにも、特に画像を多く利用するwebサイトに関しては対応をお勧めします！！