Nginx笔记(五)----Nginx+Lua+GraphicsMagick实现图片自动裁剪/缩放、以及定时清理生成的缩略图

一、前言

在开发的过程中,在后台提交的图片没有做什么处理,然后APP,前端页面,获取到图片之后,自己通过控制宽高实现对图片的控制,在这种情况下,会出现,一张图片很大,原封不动的返回给客户端,浪费服务器带宽,请求响应变慢。这个时候我们就要在服务器端对图片进行处理,根据客户端的请求参数,返回相应的图片。

面临的问题
    ● 网站需求变更,需要更多不同尺寸的缩略图
    ● 有些图片的缩略图很少使用到,但还是存在了硬盘上,造成空间浪费

需求

   ● 根据请求参数动态裁剪图片保存到本地,裁剪后的图片和原图放在同一级目录

        例如原图地址的物理路径为:/static/images/uploads/2016/07/01.jpg

        按200x200裁剪后的图片物理路径为:/static/images/uploads/2016/07/01_200x200.jpg

   ● 只在第一次请求时裁剪,后面不裁剪,从本地取图片,如果本地没有图片再裁剪图片返回。

   ● 定时清理目录下的裁剪图,减少硬盘空间。

   ● 根据坐标裁剪图片中的某一块区域。

解决方法

由于我这里图片处理用的是nginx,所以,有以下两种解决方法:

1.Nginx自带的http_image_filter_module模块

2.Nginx搭配Lua+GraphicsMagick

Nginx 虽然有自带的 image filter module 实现此功能,但是有弊端:

● image filter module 使用的是 GD,GD 性能、效率、处理后的图片质量不如 GraphicsMagick、并且裁剪后也不会保存,这样每次请求过来都要重新裁剪,所以访问很慢。

● image filter module 没法真正生成裁剪/缩放后的图片,而是通过 Nginx 直接输出的,这样每次请求或缓存过期后都需要重新裁剪/缩放,这样无疑会增加 Nginx 负担

这里使用Lua+GraphicsMagick实现图片自由裁剪、把裁剪后的图片放到一个目录,并做好过期或定期删除,访问时就去判断,有裁剪后的就取,没有的再做裁剪。

但是这样也有个问题就是,用久了之后,会在本地硬盘产生很多缩略图,对硬盘造成浪费,所以需要定时的清理硬盘下的缩略图。

如果用Nginx来处理图片的话,就会有以下的优缺点:

▲ 优点

     ● 操作简单。通过简单配置,省去了后端裁剪程序的复杂性。
     ● 实时裁剪。可以实时访问在线裁剪图片。
     ● 灵活性强。后端程序裁剪图片时需要知道裁剪图片的尺寸和质量,使用nginx裁剪可以实时裁剪任意尺寸的图片。

不占用硬盘空间。

▲ 缺点
    ● 消耗CPU和内存,访问量大的时候就会给服务器带来很大的负担。(可以通过使用Nginx缓存和缓存服务器来解决)

    ● 功能不是很强大,支持的处理图片类型只包括JPEG, GIF, PNG, or WebP

二、搭建

由于我这里是先安装好了Nginx,所以就不安装Nginx了,用的版本是nginx/1.7.4,只安装一些必要的模块,步骤如下:

2.1、基础软件包安装

# yum -y install epel-release git
# yum install -y gcc gcc-c++ zlib zlib-devel openssl openssl-devel pcre pcre-devel
# yum install -y libpng libjpeg libpng-devel libjpeg-devel ghostscript libtiff libtiff-devel freetype freetype-devel readline-devel ncurses-devel libtermcap-devel ncurses-devel libevent-devel

2.2、下载相关软件

# cd /usr/local/src
# wget http://luajit.org/download/LuaJIT-2.0.4.tar.gz
# wget http://www.zlib.net/fossils/zlib-1.2.8.tar.gz
# wget http://www.lua.org/ftp/lua-5.3.1.tar.gz  
# wget ftp://ftp.graphicsmagick.org/pub/GraphicsMagick/1.3/GraphicsMagick-1.3.18.tar.gz

# yum install git
# git clone https://github.com/simpl/ngx_devel_kit.git
# git clone https://github.com/openresty/lua-nginx-module.git
# git clone https://github.com/simpl/ngx_devel_kit.git

2.3、编译安装Lua、GraphicsMagick

# tar -zxf LuaJIT-2.0.4.tar.gz
# tar -zxf zlib-1.2.8.tar.gz
# cd LuaJIT-2.0.4
# make 
# make install 
# export LUAJIT_LIB=/usr/local/lib
# export LUAJIT_INC=/usr/local/include/luajit-2.0
# ln -s /usr/local/lib/libluajit-5.1.so.2 /lib64/libluajit-5.1.so.2
  
# cd ..
# tar -zxvpf lua-5.3.1.tar.gz
# cd lua-5.3.1
# make linux && make install
  
# cd ..
# tar -zxvpf GraphicsMagick-1.3.18.tar.gz
# cd GraphicsMagick-1.3.18
# ./configure --prefix=/usr/local/GraphicsMagick --enable-shared
# make  && make install

2.4、Nginx动态添加模块

先查看nginx编译安装时安装了哪些模块

# nginx -V
nginx version: nginx/1.7.4
built by gcc 4.4.7 20120313 (Red Hat 4.4.7-16) (GCC)
TLS SNI support enabled
configure arguments: 
--prefix=/usr/local/nginx 
--with-pcre=/root/pcre-8.35 
--with-zlib=/root/zlib-1.2.8 
--with-openssl=/root/openssl-1.0.1i 
--with-http_ssl_module 
--with-http_sub_module 
--with-http_stub_status_module 

2.5、加入需要安装的模块,重新编译,在nginx的源码目录下,通过–add-module=xxx的方式添加以下模块

--add-module=/usr/local/src/lua-nginx-module
--add-module=/usr/local/src/ngx_devel_kit
完整的如下
./configure --prefix=/usr/local/nginx --with-pcre=/root/pcre-8.35 --with-zlib=/root/zlib-1.2.8 --with-openssl=/root/openssl-1.0.1i --with-http_ssl_module --with-http_sub_module --with-http_stub_status_module --add-module=/usr/local/src/lua-nginx-module --add-module=/usr/local/src/ngx_devel_kit

然后

# make    //千万不要make install,不然就真的覆盖了

然后可以通过nginx -V查看是否添加成功

2.6、替换nginx二进制文件,在nginx源码目录下执行以下命令

# cp /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx.bak
# cp ./objs/nginx /usr/local/nginx/sbin/

2.7、修改nginx配置文件

首先测试看能否访问图片:

location ~ .*\.(gif|jpg|jpeg|png)$ {    
	expires 24h;    
		root /home/nginx/html/;#指定图片存放路径  
		access_log /usr/local/nginx/logs/images.log;#日志存放路径    
		proxy_store on;    
		proxy_store_access user:rw group:rw all:rw;    
		proxy_temp_path         /usr/local/nginx/html;#图片访问路径    
		proxy_redirect          off;    
		proxy_set_header        Host 19;    
		client_max_body_size    10m;    
		client_body_buffer_size 1280k;    
		proxy_connect_timeout   900;    
		proxy_send_timeout      900;    
		proxy_read_timeout      900;    
		proxy_buffer_size       40k;    
		proxy_buffers           40 320k;    
		proxy_busy_buffers_size 640k;    
		proxy_temp_file_write_size 640k;    
		if ( !-e $request_filename)    
		{    
			 proxy_pass  http://127.0.0.1;#默认80端口    
		}    
}      
location / {  
  root  /home/nginx/html; #html访问路径 
  index index.html; #html文件名称 

} 

在html下上传图片然后访问: http://192.168.182.5/2018.jpeg


然后将上面的location匹配的图片改成如下所示:

location / {
		root   /home/nginx/html;
		index  index.html index.htm;
}

location ~* ^((\/manager)(\/\w+)(.+\.(jpg|jpeg|gif|png))_(\d+)x(\d+)\.(jpg|jpeg|gif|png))$ {
                root /home/nginx/html;
                if (!-f $request_filename) {    # 如果文件不存在时才需要裁剪
					add_header X-Powered-By 'Lua GraphicsMagick';    # 此 HTTP Header 无实际意义,用于测试
					add_header file-path $request_filename;    # 此 HTTP Header 无实际意义,用于测试
					#lua_code_cache off; # 在编写外部 Lua 脚本时,设置为 off Nginx 不会缓存 Lua,方便调试
					set $request_filepath /home/nginx/html$2/$3/$4;    # 设置原始图片路径,如:/manager/app/2018.jpeg
					set $width $6;    # 设置裁剪/缩放的宽度
					set $height $7;    # 设置裁剪/缩放的高度
					set $ext $5;    # 图片文件格式后缀
					content_by_lua_file lua/ImageResizer.lua;    # 加载外部 Lua 文件
                 }
}

其中的:

location / {
		root   /home/nginx/html;
		index  index.html index.htm;
}

匹配如下请求: 

http://192.168.182.5/2018.jpeg 

● 黄颜色的用来匹配:

http://192.168.182.5/manager/test/2014.jpeg_100x100.jpeg

这种请求。

● 红颜色root指定当前server的根目录,对应系统上的具体文件夹

● 绿颜色是设置ngx变量,变量值就是正则匹配的$匹配组的值,设置好变量后可以在lua脚本中使用


注意:

我在这里遇到了一些坑。。。上面的这个正则:

~* ^((\/manager)(\/\w+)(.+\.(jpg|jpeg|gif|png))_(\d+)x(\d+)\.(jpg|jpeg|gif|png))$

是用来匹配像我这种路径:

http://192.168.182.5/manager/test/2014.jpeg_100x100.jpeg

可以通过在线正则工具来检查:


注意要去掉前面的~*。

正则:

1、^: 匹配字符串的开始位置;
2、 $:匹配字符串的结束位置;
3、.*:   .匹配任意字符,*匹配数量0到正无穷;
4、\. 斜杠用来转义,\.匹配 .    特殊使用方法,记住记性了;
5、(值1|值2|值3|值4):或匹配模式,例:(jpg|gif|png|bmp)匹配jpg或gif或png或bmp

^ 匹配输入字符串的开始位置,除非在方括号表达式中使用,此时它表示不接受该字符集合。要匹配 ^ 字符本身,请使用 \^。
$ 匹配输入字符串结尾的位置。如果设置了 RegExp 对象的 Multiline 属性,$ 还会与 \n 或 \r 之前的位置匹配。
\. 斜杠用来转义,\.匹配.
[\w+]表示匹配数字、字母、下划线和加号本身字符
location ~* .(gif|jpg|jpeg)$ {
# 匹配任何已.gif、.jpg 或 .jpeg 结尾的请求
+ 匹配前面的子表达式一次或多次。要匹配 + 字符,请使用 \+。

我在这里调试了很久。。。可通过如下方式来调:

location ~* ^((\/manager)(\/\w+)(.+\.(jpg|jpeg|gif|png))_(\d+)+x(\d+)+\.(jpg|jpeg|gif|png))$ {
        set $para1 $1;
        set $para2 $2;
        set $para3 $3;
        set $para4 $4;
        set $para5 $5;
        set $para6 $6;
        set $para7 $7;
        set $para8 $8;
        set $para9 $9;
        content_by_lua_block {
                ngx.say(ngx.var.para1)
                ngx.say(ngx.var.para2)
                ngx.say(ngx.var.para3)
                ngx.say(ngx.var.para4)
                ngx.say(ngx.var.para5)
                ngx.say(ngx.var.para6)
                ngx.say(ngx.var.para7)
                ngx.say(ngx.var.para8)
                ngx.say(ngx.var.para9)
        }

}

打印在浏览器上如下:

/manager/test/2014.jpeg_100x100.jpeg
/manager
/test
/2014.jpeg
jpeg
100
100
jpeg

然后把打印值的变量修改到如下地方:

set $request_filepath /home/nginx/html$2/$3/$4;    # 设置原始图片路径,如:/manager/app/2018.jpeg
set $width $6;                                     # 设置裁剪/缩放的宽度
set $height $7;                                    # 设置裁剪/缩放的高度
set $ext $5;                                       # 图片文件格式后缀

2.8、创建lua脚本

在/usr/local/nginx/lua/目录下创建ImageResizer.lua文件

# cat /usr/local/nginx/lua/ImageResizer.lua 
local command = "/usr/local/GraphicsMagick/bin/gm convert   -auto-orient -strip " .. ngx.var.request_filepath .. " -resize " .. ngx.var.width .. "x" .. ngx.var.height .. " +profile \"*\" " .. ngx.var.request_filepath .. "_" .. ngx.var.width .. "x" .. ngx.var.height .. "." .. ngx.var.ext;
os.execute(command);    
ngx.exec(ngx.var.request_uri);

三、测试

然后通过命令重新加载Nginx配置文件

[[email protected] sbin]# ./nginx -s reload

访问以下连接:

http://192.168.1.5:7501/manager/test/2014.jpeg

效果如下所示:



然后再访问:

http://192.168.1.5:7501/manager/test/2014.jpeg_100x100.jpeg

效果如下所示



同时会在manager/test目录下多出个2014.jpeg_100x100.jpeg的图片。


最后就是通过脚本定时删除生成的图片了。


参考:

http://www.cnblogs.com/xy-nb/articles/Nginx-Lua-GraphicsMagick.html

http://www.hopesoft.org/blog/?p=1188

http://yanue.net/post-166.html


文章来源: Nginx笔记(五)----Nginx+Lua+GraphicsMagick实现图片自动裁剪/缩放、以及定时清理生成的缩略图

人吐槽 人点赞

猜你喜欢

发表评论

用户名: 密码:
验证码: 匿名发表

你可以使用这些语言

查看评论:Nginx笔记(五)----Nginx+Lua+GraphicsMagick实现图片自动裁剪/缩放、以及定时清理生成的缩略图