使用Nginx和Lua进行图片webp压缩处理

一般商品主图大小为800800(淘宝)或者750750(京东),即便以72*72的分辨率去做图,图片的大小也有几百k,对于移动端而已,图片过大,加载过慢,于是研究了下用Nginx和Lua进行图片webp压缩处理。以下我主要参考的几篇文章:
通过 Nginx-Lua 自动转换图片为 WebP 格式
nginx 之前端图片webp
centos yum 安装nginx 后增加模块
centos-nginx添加模块(无需重新编译)

下面进入正题:

安装libwebp

wget "http://downloads.webmproject.org/releases/webp/libwebp-0.6.0-linux-x86-64.tar.gz"
tar --strip-components 1 -xzvf libwebp*.gz -C /usr/local

测试是否安装成功

cwebp -q 75 test.png -o test.png.webp

为nginx添加lua模块

由于我本来就已经安装好了nginx,也不便停用,故只能为nginx添加lua模块。如果是全新安装nginx的同学,建议直接安装OpenResty,里面集成了nginx和lua。以下开始安装:

cd /root

wget https://github.com/openresty/lua-nginx-module/archive/v0.10.11.zip

unzip v0.10.11.zip

wget https://github.com/simpl/ngx_devel_kit/archive/v0.3.0.zip

unzip v0.3.0.zip

wget http://luajit.org/download/LuaJIT-2.0.5.zip

unzip LuaJIT-2.0.5.zip

cd LuaJIT-2.0.5

make

make install PREFIX=/usr/local/luajit

cat > /etc/ld.so.conf.d/luajit.conf<

由于我是用yum安装的nginx,查看现在的nginx版本,然后再重新编译。

nginx -V

nginx version: nginx/1.14.0
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-28) (GCC)
built with OpenSSL 1.0.2k-fips  26 Jan 2017
TLS SNI support enabled
configure arguments: --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib64/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -fPIC' --with-ld-opt='-Wl,-z,relro -Wl,-z,now -pie'

于是下载1.14.0版本:

$ wget http://nginx.org/download/nginx-1.14.0.tar.gz
$ tar xvzf nginx-1.14.0.tar.gz

然后重新编译

cd nginx-1.14.0
./configure --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib64/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -fPIC' --with-ld-opt='-Wl,-z,relro -Wl,-z,now -pie'  --add-module=/root/lua-nginx-module-0.10.11 --add-module=/root/ngx_devel_kit-0.3.0

$ make #千万别make install,否则就覆盖安装了

#备份旧的nginx程序

$ cp /usr/sbin/nginx /usr/sbin/nginx.bak

#把新的nginx程序覆盖旧的

$ cp objs/nginx /usr/sbin/nginx

#重启nginx
$ sudo systemctl restart nginx.service

图片压缩配置

新建webp.lua文件

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 newFile = ngx.var.request_filename;
local originalFile = newFile:sub(1, #newFile - 5); -- 去掉 .webp 的后缀
if not file_exists(originalFile) then -- 原文件不存在
   ngx.exit(404);
   return;
end

local cmdstr = "cwebp -q 20 " .. originalFile .. " -o " .. newFile; -- 转换原图片到 webp 格式,这里的质量是 20, 压缩比例为90%
cmdstr = string.gsub(cmdstr,"%$","\\$"); -- 处理字符串中含有dollar符号的
os.execute(cmdstr);

if file_exists(newFile) then -- 如果新文件存在(转换成功)
   ngx.exec(ngx.var.uri) -- Internal Redirect
else
   ngx.exit(404)
end

如果文件名中有$符号

修改img.conf配置,在server中添加

   # webp 压缩
   location ~* ^(.+\.(jpg|jpeg|gif|png))\.webp$ {
       set     $webp_root /mnt/www/img;
       root    $webp_root;
       set $filename $webp_root$uri;
       if (!-f $filename) {
           set $request_filepath $webp_root$1;
           content_by_lua_file "/etc/nginx/conf.d/webp.lua";
       }
   }

重启nginx即可访问了。

后续

经过上面的一波操作,我们终于可以使用webp压缩了。 不过,可惜的webp的google的标准,由于我们的图片要使用在微信小程序上,而iphone的微信小程序内置的浏览器不支持webp格式。于是只能放弃webp,下面使用的是GraphicsMagick压缩方式来替代。

安装GraphicsMagick

wget https://nchc.dl.sourceforge.net/project/graphicsmagick/graphicsmagick/1.3.31/GraphicsMagick-1.3.31.tar.xz
xz -d GraphicsMagick-1.3.31.tar.xz
tar -xvf GraphicsMagick-1.3.31.tar
cd GraphicsMagick-1.3.31
./configure
make
make install

修改lua文件

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 gmReqFile = ngx.var.request_filename; -- 原来访问地址
local originalFile = string.gsub(gmReqFile, "gm/",""); -- 去掉 gm 文件夹
local gmDir = string.match(originalFile, "(.+)/[^/]*%.%w+$") .. "/gm"; -- gm目录
--local imgName = string.match(originalFile, ".+/([^/]*%.%w+)$"); -- 文件名带原本的后缀
local imgName = string.match(originalFile, ".+/([^/]*)%.%w+$"); -- 文件名,无后缀
local gmFile = gmDir .. "/" .. imgName .. ".jpg";  -- 最终访问文件, 全部转为jpg
if file_exists(gmFile) then -- 如果压缩图已经存在
  ngx.exec(string.gsub(ngx.var.uri, "png","jpg"))
  --ngx.exec(ngx.var.uri)
end
if not file_exists(originalFile) then -- 原文件不存在
  ngx.exit(404);
  return;
end
local response = os.execute("cd " .. gmDir) -- 如果gm文件夹不存在
if response ~= 0 then
  os.execute("mkdir -p " .. gmDir);
end
local cmdstr = "gm convert -quality 75% " .. originalFile .. " " .. gmFile; -- 转换质量 75 % ,由于不同图片色彩不一样,压缩比例会不同,30%到90%
cmdstr = string.gsub(cmdstr,"%$","\\$"); -- 处理字符串中含有dollar符号的
os.execute(cmdstr);
if file_exists(gmFile) then -- 如果新文件存在(转换成功)
  ngx.exec(string.gsub(ngx.var.uri, "png","jpg"))
  --ngx.exec(ngx.var.uri)
else
  ngx.exit(404)
end

你可能感兴趣的:(架构之路)