banner
半米牙

半米牙的笔记

分享技术、记录生活
email

浏览器 WebP 画像の自動適応読み込み

ウェブサイトは、ブラウザが WebP をサポートしているかどうかに基づいて、適切な形式の画像を自動的に読み込むようにすることができます。コードで判断すると、非常に手間がかかるため、すべての画像の参照方法を変更する必要があります。簡単で効率的な方法はありますか?答えはあります。それは Nginx の設定を変更することです。

主なアイデア#

ブラウザが WebP 形式の画像をサポートしているかどうかを判断する方法は、1x1 ピクセルの WebP 画像をフロントエンドで読み込んで幅を取得する方法だけでなく、リクエストヘッダの Accept フィールドを確認する方法もあります。 Accept フィールドにimage/webpが含まれている場合、ブラウザは WebP をサポートしています。それ以外の場合は、サポートしていません。

WebP をサポートしない IE のリクエストヘッダ Accept フィールド:

webp1

WebP をサポートする Firefox のリクエストヘッダ Accept フィールド:

webp2

WebP をサポートする Chrome のリクエストヘッダ Accept フィールド:

webp4
これに基づいて、Nginx の設定ファイルを変更し、拡張子が **.jgp.jpeg.pngで終わるリクエスト ** かつリクエストヘッダ Accept フィールドにimage/webpが含まれるリクエストに対して WebP ファイルを判断することができます。この判断は Lua ファイルに記述します。Lua ファイルでは、対応する WebP ファイルが存在するかどうかをまず判断し、存在する場合は直接 WebP ファイルにリダイレクトし、存在しない場合は libwebp メソッドを呼び出して WebP ファイルを生成し、その後にリダイレクトします。

このアイデアを試してみましょう。

変更の準備#

Nginx に Lua モジュールをインストールする#

省略

サーバーに libwebp をインストールする#

参考:Nginx+Lua+libwebp でサーバーの画像を自動的に WebP に変換する

Nginx.conf#

if 文では複数の条件を同時に判断することができないため、変数を定義し、if 文で変数の値を変更し、最後にその変数の値に基づいてすべての条件を満たすかどうかを判断します。

location /img {
    set  $cwebp_flag 0;

    if ($uri ~ \.(png|jpg|jpeg)$) {
        set  $cwebp_flag '${cwebp_flag}1';
    }

    if ($http_accept ~ image/webp) {
        set  $cwebp_flag '${cwebp_flag}1';
    }

    if ($cwebp_flag = 011) {
        content_by_lua_file  lua/imgProcess.lua;
    }
}

imgProcess.lua#

このファイルの主な役割は、まず対応する WebP ファイルが存在するかどうかを判断し、存在する場合は直接 WebP ファイルにリダイレクトし、存在しない場合は libwebp メソッドを呼び出して WebP ファイルを生成し、その後にリダイレクトすることです。

function file_exists(name)
	local f=io.open(name,"r");
    if f~=nil then io.close(f) return true else return false end
end
 
local originalFile = ngx.var.request_filename;
local newFile = ngx.var.request_filename .. ".webp";

if not file_exists(newFile) then
  if not file_exists(originalFile) then
    ngx.exit(404);
    return;
  end

  os.execute("cwebp -q 75 " .. originalFile  .. " -o " .. newFile); 

  if file_exists(newFile) then
    ngx.header.vary = 'accept, accept-encoding';
    ngx.header.x_webp = 'generate';
    ngx.header.real_source_url = ngx.var.uri .. ".webp";
    ngx.header.content_type = "image/webp";
    return ngx.exec(ngx.var.uri .. ".webp");
  else
    ngx.exit(500);
    return;
  end
else
  ngx.header.vary = 'accept, accept-encoding';
  ngx.header.x_webp = 'read';
  ngx.header.real_source_url = ngx.var.uri .. ".webp";
  ngx.header.content_type = "image/webp";
  return ngx.exec(ngx.var.uri .. ".webp");
end

テスト#

WebP をサポートしない IE と WebP をサポートする Chrome で同じ画像のアドレスを開くと、サーバーから返される応答内容が異なることがわかります。

WebP をサポートする Chrome の応答内容は WebP 形式の画像です:

webp5

WebP をサポートしない IE の応答内容は通常の jpg 画像です:

webp6

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。