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#

To determine whether the browser supports WebP format images, besides 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 the browser supports WebP; otherwise, it does not.

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 configuration file of Nginx to judge whether the requests ending with .jpg, .jpeg, and .png and with the request header Accept field containing image/webp should be processed as WebP files. 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 try it.

Preparation for Modification#

Install Lua module for Nginx#

Omitted

Install libwebp on the server#

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

Nginx.conf#

Because the if statement cannot judge multiple conditions at the same time, we define a variable and use if to modify its value. 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#

This file mainly works as follows: first, check if the corresponding WebP file exists. If it exists, directly redirect to the WebP file. If it does not exist, check if the original file exists. If it does not exist, return a 404 error. Then, call the libwebp method to generate the WebP file and 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 opening the same image address with a browser that does not support WebP (IE) and a browser that supports WebP (Chrome), we find that the response content returned by the server is different.

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

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.