[Web] avifとwebpフォーマットを使ってイメージ最適化をする

[Web] avifとwebpフォーマットを使ってイメージ最適化をする

2023-03-24 hit count image

Pythonを使ってavifとwebpフォーマットのイメージを生成してLighthosueのServe images in next-gen formatsの問題を解決する方法について説明します。まlazy loadingを使ってイメージをロードしてDefer offscreen imagesの問題を解決する方法について説明します。

概要

GoogleChromeブラウザではウェブページの性能を測るためLighthouseと言う機能を提供してます。この機能を使うとウェブページの全般的な性能を確認することができるし、次のように問題点も確認ができます。

Optimization images - Lighthouse serve images in next-gen formats issue of images

今回のブログポストではウェブページでイメージフォーマットを最適化してServe images in next-gen formatsの問題を解決してイメージのlazy loadingDefer offscreen imagesの問題を解決する方法について説明します。

avifとwebpフォーマット

Serve images in next-gen formatsの問題を解決するためにはavifフォーマットまたはwebpフォーマットのイメージを提供する必要があります。avifwebpフォーマットのイメージはIE以外のモーダンブラウザは大体サポートしてるイメージフォーマットです。

Pythonでavifとwebpフォーマットイメージ生成

今回のブログポストではjpgpngフォーマットのイメージファイルをPythonを使ってavifwebpフォーマットのイメージを生成する方法について説明します。

Pythonを使ってavifwebpフォーマットのイメージを生成するためにはPillowpillow-avif-pluginライブラリをインストールする必要があります。次のコマンドを使ってPillowpillow-avif-pluginのライブラリをインストールします。

pip install Pillow pillow-avif-plugin

PillowPythonでイメージを扱う時使うライブラリで、pillow-avif-pluginPillowライブラリを使ってイメージのフォーマットを変更する時、avifフォーマットで保存できるようにするライブラリです。

ライブラリをインストールしたら、optimization_images.pyファイルを生成して次のように修正します。

import os
import glob
from PIL import Image
import pillow_avif

target_folder = './assets'
files = glob.glob(f'{target_folder}/**/*.jpg', recursive=True) + glob.glob(f'{target_folder}/**/*.png', recursive=True)

for f in files:
    print(f)
    title, ext = os.path.splitext(f)
    webp_file = title + '.webp'
    avif_file = title + '.avif'

    if os.path.isfile(webp_file) == False:
        img = Image.open(f)
        img.save(webp_file, format='webp')
        img.close()

    if os.path.isfile(avif_file) == False:
        img = Image.open(f)
        img.save(avif_file, format='AVIF' )
        img.close()

ソースコードを詳しくみてみましょう。

私はイメージファイルをassetsフォルダに保存して管理してます。もし、イメージファイルを他のフォルダで保存してる場合、下記の部分を修正してください。

...
target_folder = './assets'
...

イメージを保存したフォルダ中で全てのjpgpngフォーマットファイルを探します。

...
files = glob.glob(f'{target_folder}/**/*.jpg', recursive=True) + glob.glob(f'{target_folder}/**/*.png', recursive=True)
...

その後、全てのファイルを回しながらファイルフォーマットを変更します。ファイルフォーマットを変更したあtフォーマットに合わせてファイル名も変更するためos.pathを使ってファイル名を準備しました。

...
for f in files:
  title, ext = os.path.splitext(f)
  webp_file = title + '.webp'
  avif_file = title + '.avif'
  ...

そしたら、webpフォーマットのファイルが存在してるか確認して、存在しない場合は、既存ファイルをwebpフォーマットで変更して保存します。

...
for f in files:
    ...
    if os.path.isfile(webp_file) == False:
        img = Image.open(f)
        img.save(webp_file, format='webp')
        img.close()
    ...

同じに、avifファーマットのファイルが存在するか確認して、存在しない場合、既存のファイルをavifフォーマットで変更して保存します。

...
for f in files:
    ...
    if os.path.isfile(avif_file) == False:
        img = Image.open(f)
        img.save(avif_file, format='AVIF' )
        img.close()

これでjpgまたはpngフォーマットのイメージファイルをavifwebpフォーマットで変更するPythonスクリプトを作ってみました。

avifとwebpファイル生成

そしたら、このように作ったoptimization_images.pyファイルを実行してavifwebpフォーマットファイルを生成して身まあしょう。avifwebpフォーマットあいお生成するため次のコマンドを使ってPythonスクリプトを実行します。

python optimization_images.py

そしたら次のようにイメージファイルリストが確認できるし、avifwebpフォーマットのファイルが生成されることが確認できます。

...
./assets/images/category/flutter/2023/RefreshIndicator/refreshindicator_new_data_with_no_data.png
./assets/images/category/flutter/2023/RefreshIndicator/refreshindicator_pull_to_refresh.png
./assets/images/category/flutter/2023/RefreshIndicator/refreshindicator_no_data.png
./assets/images/category/flutter/2023/RefreshIndicator/listview.png
./assets/images/category/flutter/2023/RefreshIndicator/refreshindicator_refresh_no_data.png
./assets/images/category/flutter/2023/find_child_and_parent_widget/basic_app.png

pictureとsourceタグ

次は、このように生成したavifwebpフォーマットファイルをウェブページで使う方法について説明します。ウェブページで色んなフォーマットのイメージを使うためには<picture />タグと<source />タグを使う必要があります。イメージをロードする部分を、次のように<picture />タグと<source />タグを使ってavifwebpフォーマットをロードするように修正します。

<picture>
  <source srcset="example.avif" type="image/avif" />
  <source srcset="example.webp" type="image/webp" />
  <img src="example.png" alt="example file" />
</picture>

このように<picture /><source />タグを使うと、ブラウザがサポートするフォーマットのイメージをダウンロードして表示されるようになります。

loading lazy

Lighthouseを使ってイメージが多いウェブページを検査すると、Defer offscreen imagesの問題が出ることが確認できます。この問題を解決するためには<img />タグに次のようにloading="lazy"を追加します。

<picture>
  <source srcset="example.avif" type="image/avif" />
  <source srcset="example.webp" type="image/webp" />
  <img src="example.png" alt="example file" loading="lazy" />
</picture>

loading lazyについて詳しい内容は下記のリンクで確認できます。

完了

これでウェブページの性能を上げるため新しいイメージフォーマットであるavifwebpファイルを生成して、<picture /><srouce />タグを使ってイメージをローディングして最適化する方法についてみてみました。また、loading="lazy"を使ってイメージロードを最適化する方法についてもみてみました。

Lighthouseでよく発生する指摘事項なので、今回よく覚えておくと役に立つと思います。もし、ブラウザではなくローカルやCI環境でLighthouseを実行する方法を確認したい方は下記のリンクを参考してください。

私のブログが役に立ちましたか?下にコメントを残してください。それは私にとって大きな大きな力になります!

アプリ広報

今見てるブログを作成たDekuが開発したアプリを使ってみてください。
Dekuが開発したアプリはFlutterで開発されています。

興味がある方はアプリをダウンロードしてアプリを使ってくれると本当に助かります。

Posts