banner
半米牙

半米牙的笔记

分享技术、记录生活
email

Browser WebP Image Adaptive Loading

Let the website adaptively load the corresponding format of images based on whether the browser supports WebP. If we judge it in the code, the workload will be huge because we need to modify the reference method of each image in the code. Is there a simpler and more efficient method? The answer is yes, and that is to modify the configuration of Nginx.

Main Idea#

How to determine whether the browser supports WebP format images? In addition to loading a 1x1 pixel WebP image in the front end to obtain the width, there is another method, which is to check the Accept field in the request header sent by the browser. If this field contains image/webp, it means that the browser supports WebP; otherwise, it does not support.

Request header Accept field of IE that does not support WebP:

webp1

Request header Accept field of Firefox that supports WebP:

webp2

Request header Accept field of Chrome that supports WebP:

webp4

Based on this, we can modify the Nginx configuration file to judge the requests with .jgp, .jpeg, and .png extensions and the request header Accept field containing image/webp. We write this judgment in a Lua file. In the Lua file, we first check if the corresponding WebP file exists. If it exists, we directly redirect to the WebP file. If it does not exist, we call the libwebp method to generate the WebP file and then redirect.

With this idea, let's give it a try.

Preparation for Modification#

Install Lua module for Nginx#

Omitted

Install libwebp on the server#

Reference: Nginx+Lua+libwebp for Automatic Server Image Conversion to WebP

Nginx.conf#

Because if cannot judge multiple conditions at the same time, we define a variable and modify its value with if. Finally, we judge whether all conditions are met based on the value of this variable.

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#

The main task of this file is to first check if the corresponding WebP file exists. If it exists, we directly redirect to the WebP file. If it does not exist, we call the libwebp method to generate the WebP file and then redirect.

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

Testing#

When we open the same image address with IE that does not support WebP and Chrome that supports WebP, we find that the response content returned by the server is different.

The response content for Chrome that supports WebP is an image in WebP format:

webp5

The response content for IE that does not support WebP is a regular jpg image:

webp6

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.