在做网站尤其是以内容为主的过程中,常常会遇到一张图片各种地方都要引用,且每个引用的地方要求的图片尺寸都不一样的。对于小网站来说,这种需求通常是人工进行裁剪,然后在代码上分别引用。然而当网站图片越来越多的时候,这种办法的效率问题就凸显出来了,所以一般中大型的网站都会对这一类的图片做自动裁剪功能。本文介绍在centos6操作系统上,采用nginxluaGraphicsMagick工具简单实现图片的自动裁剪功能。其中nginx负责展示图片和调度lua脚本,GraphicsMagick负责对原图进行裁剪。

实现功能点如下:

1、输入原图地址,例如:http://192.168.1.19/img_6065.jpg后返回原图

2、输入图片地址,例如:http://192.168.1.19/img_6065.jpg_200x400.jpg 后,如果目录底下存在图片,则返回,如果不存在则根据需求对原图进行裁剪,其中200代表图片的宽,400代表图片的长。

3、图片的根目录为/static/images,裁剪后的图片和原图放在同一级目录,例如原图地址的物理路径为:/static/images/uploads/2016/07/01.jpg

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

 

一、基础软件包安装

1
2
3
4
5
# groupadd www
# useradd -g www www -s /bin/false
# 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

二、下载相关软件

其中nginx-http-concatecho-nginx-module模块非必须

1
2
3
4
5
6
7
8
9
10
11
# cd /usr/local/src
# wget http://nginx.org/download/nginx-1.8.0.tar.gz
# wget http://luajit.org/download/LuaJIT-2.0.4.tar.gz
# wget http://zlib.net/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
  
# git clone https://github.com/alibaba/nginx-http-concat.git
# git clone https://github.com/simpl/ngx_devel_kit.git
# git clone https://github.com/openresty/echo-nginx-module.git
# git clone https://github.com/openresty/lua-nginx-module.git

三、编译安装nginx、GraphicsMagick

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# tar -zxf nginx-1.8.0.tar.gz
# 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
  
# cd ..
# cd nginx-1.8.0
# ./configure --prefix=/usr/local/nginx \
--user=www \
--group=www \
--with-http_ssl_module \
--with-http_realip_module \
--with-http_sub_module \
--with-http_flv_module \
--with-http_dav_module \
--with-http_gzip_static_module \
--with-http_stub_status_module \
--with-http_addition_module \
--with-http_spdy_module \
--with-pcre \
--with-zlib=../zlib-1.2.8 \
--add-module=../nginx-http-concat \
--add-module=../lua-nginx-module \
--add-module=../ngx_devel_kit \
--add-module=../echo-nginx-module \
 --with-ld-opt=-Wl,-rpath,$LUAJIT_LIB 
 # make && make install

四、修改nginx配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
   server {
        listen       80;
        server_name  192.168.1.19;
        root /static/image;
  
        location /lua1 {
        default_type 'text/plain';
        content_by_lua 'ngx.say("hello, lua")';
        }
  
  
          location ~* ^(.+\.(jpg|jpeg|gif|png))_(\d+)x(\d+)\.(jpg|jpeg|gif|png)$ {
                root /static/image;
                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 /static/image/$1;    # 设置原始图片路径,如:/document_root/1.gif
                        set $width $3;    # 设置裁剪/缩放的宽度
                        set $height $4;    # 设置裁剪/缩放的高度
                        set $ext $5;    # 图片文件格式后缀
                        content_by_lua_file lua/ImageResizer.lua;    # 加载外部 Lua 文件
                }
  
  
        }
}

五、准备lua脚本

1
2
3
4
# 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);

六、测试

1
2
3
4
# cd /static/image/
# ls
# cd uploads/2016/07/21/
# ls

wKioL1eWyGmhp2LOAABrtKx0wvQ028.jpg-wh_50

wKiom1eWyGmRGVmZAAFLZJb2QrY830.jpg-wh_50

wKioL1eWyGzCIgluAAVldYxJx-A921.png-wh_50

wKiom1eWyG2w6PdcAAHwyhW-1yI343.png-wh_50

wKiom1eWyG2jCNXPAAFHDnbl9jI722.png-wh_50

wKioL1eWyG7zoWTlAACWV4Z7H7A678.jpg-wh_50

如果要做固定高宽模式裁切图片处理,例如:http://192.168.1.19/uploads/2016/07/21/1.jpg_-200.jpg 或http://192.168.1.19/uploads/2016/07/21/1.jpg_200-.jpg 这种需求,首先修改nginx配置文件如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
http {
    include       mime.types;
    default_type  application/octet-stream;
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    access_log  logs/access.log  main;
    sendfile        on;
    tcp_nopush     on;
    keepalive_timeout  65;
    gzip  on;
 
    server {
        listen       80;
        server_name  192.168.1.19;
        root /static/image;
 
        location /lua1 {
        default_type 'text/plain';
        content_by_lua 'ngx.say("hello, lua")';
        }
   set $upload_path /static/image;
    set $img_original_root  $upload_path;# original root;
    set $img_thumbnail_root $upload_path/cache/thumb;
    set $img_file $img_thumbnail_root$uri;
 
    # like:/xx/xx/xx.jpg_100-.jpg or /xx/xx/xx.jpg_-100.jpg
    location ~* ^(.+\.(jpg|jpeg|gif|png))_((\d+\-)|(\-\d+))\.(jpg|jpeg|gif|png)$ {
            root $img_thumbnail_root;    # root path for croped img
            set $img_size $3;
 
            if (!-f $img_file) {    # if file not exists
                    add_header X-Powered-By 'Nginx+Lua+GraphicsMagick By Yanue';  #  header for test
                    add_header file-path $request_filename;    #  header for test
                    set $request_filepath $img_original_root$1;    # origin_img full path:/document_root/1.gif
                    set $img_size $3;    # img width or height size depends on uri
                    set $img_ext $2;    # file ext
                    content_by_lua_file lua/autoSize.lua;    # load lua
            }
    }
 
    # like: /xx/xx/xx.jpg_100x100.jpg
    location ~* ^(.+\.(jpg|jpeg|gif|png))_(\d+)+x(\d+)+\.(jpg|jpeg|gif|png)$ {
            root $img_thumbnail_root;    # root path for croped img
 
            if (!-f $img_file) {    # if file not exists
                    add_header X-Powered-By 'Nginx+Lua+GraphicsMagick By Yanue';  #  header for test
                    add_header file-path $request_filename;    #  header for test
                    set $request_filepath $img_original_root$1;    # origin_img file path
                    set $img_width $3;    # img width
                    set $img_height $4;    # height
                    set $img_ext $5;    # file ext
                    content_by_lua_file lua/cropSize.lua;    # load lua
            }
    }
 
}
 
}

其次准备两个lua脚本,脚本包含在附件中。

测试效果如下:

wKiom1eXMc3S7kHBAACNxiClap4879.jpg-wh_50

wKioL1eXMc7wV8g2AACGH8po2sc829.jpg-wh_50

wKiom1eXMc-w83YjAABdJN_Ef1o807.jpg-wh_50


后记:

采用这种方式简单实现了需求,但是url中的图片高度和宽度没有限制,这个需要注意,还有长时间不用的缩略图如何清理也需要考虑。

 

参考文档,感谢作者分享!

http://my.oschina.net/eduosi/blog/169606

http://blog.ddtet.org/2014/03/graphicsmagick.html

https://github.com/yanue/nginx-lua-GraphicsMagick

http://www.111cn.net/sys/CentOS/55070.htm