OpenResty(Nginx)+Lua+GraphicsMagick实现缩略图功能
一、背景说明
大多数网站基本都涉及到图片缩略图的处理,比如新闻配图、电商商品图等,特别是电商类网站,每个商品图对应多个不同尺寸的缩略图,用于不同的页面。
初期访问量少时,处理流程一般由web程序在上传成功后,同时生成相应缩略图。这种方式在访问量小,单机部署时没有问题。当访问量逐渐加大,服务器由单台变为多台时,这种方式扩展性较差。
以下有几种方案可以解决这个问题:
1、使用七牛、又拍云提供的云存储及数据处理服务,解决图片的处理、存储、多节点访问速度的问题,这种方式优点是方案成熟,相应的有一定费用和开发工作,另外有一些小概率的风险,比如云服务挂掉影响本站访问。
2、使用第三方的图片处理程序,比如zimg,点击查看使用手册,@招牌疯子开发。zimg的性能和扩展性不错,文档也很完善,会继续保持关注。
3、自己造轮子,根据自身业务,将生成缩略图功能独立出来,与web程序解耦。
我们采用的是第三种方案,参考了网友的基础代码,利用OpenResty(Nginx)+Lua+GraphicsMagick实现缩略图功能,图片上传及删除还是由web程序处理,缩略图由单独模块完成。目前可实现配置路径及缩略尺寸,无图片时显示默认图片,支持多种缩放方式等,后续可基于GraphicsMagick实现更多功能
二、相关规范
1、文件夹规划
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
img.hopesoft.org
|-- avatars
| `-- 001
| `-- 001.jpg
|-- default
| `-- notfound.jpg
|-- photos
| `-- 001
| `-- 001.jpg
`-- thumbnail
`-- photos
`-- 001
|-- 001_100x100.jpg
|-- 001_140x140.jpg
|-- 001_250x250.jpg
|-- 001_300x300.jpg
|-- 001_350x350.jpg
|-- 001_50x50.jpg
`-- abc_50x50.jpg
|
其中img.hopesoft.org为图片站点根目录,avatars和photos目录是原图目录,可根据目录设置不同的缩略图尺寸,default文件夹的notfound.jpg文件是在未找到原图时的默认图片,thumbnail文件夹用来存放缩略图,可定时清理。
2、链接地址
原图访问地址:http://img.hopesoft.org/photos/001/001.jpg
缩略图访问地址:http://img.hopesoft.org/photos/001/001_100x100.jpg,(请勿加thumbnail,这个是因为我们原来的原图和缩略图在同一个目录,后来将缩略图单独放了一个文件夹)
不同目录可设置不同的缩略图规则,如:
原图访问地址:http://img.xxx.com/mall/001/001.jpg
缩略图访问地址:http://img.xxx.com/mall/001/001.jpg_100x100.jpg (请勿加thumbnail)
3、访问流程
首先判断缩略图是否存在,如存在则直接显示缩略图;
如不存在则按以下流程处理:
- 判断缩略图链接与规则是否匹配,如不匹配,则404退出;如匹配跳至2
- 判断原图是否存在,如原图存在则跳至5,如不存在则进入下一步;
- 判断是否显示默认图片,如不显示则404退出;如显示则进入下一步
- 判断是否存在默认图片,如不存在则404退出;如存在则将默认图片代替原始图片,进入下一步;
- 拼接graphicsmagick命令,生成并显示缩略图
三、安装OpenResty
1、关于OpenResty(http://openresty.org/cn/)
OpenResty (也称为 ngx_openresty)是一个全功能的 Web 应用服务器,它打包了标准的 Nginx 核心,很多的常用的第三方模块,以及它们的大多数依赖项。
OpenResty 通过汇聚各种设计精良的 Nginx 模块,
从而将 Nginx 有效的变成一个强大的 Web 应用服务器,
这样, Web 开发人员可以使用 Lua 脚本语言调动 Nginx 支持的各种C以及Lua 模块,
快速构造出足以胜任 10K+ 并发连接响应的超高性能Web 应用系统。更多
2、安装OpenResty
注:drizzle-nginx-module模块和nginx-http-concat模块非必选项,各位可按需安装
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
|
#创建安装文件目录
mkdir -p /usr/local/src/nginx
cd /usr/local/src/nginx
#安装drizzle模块(访问mysql数据库模块,非必需,建议安装)
wget http://agentzh.org/misc/nginx/drizzle7-2011.07.21.tar.gz
tar zxvf drizzle7-2011.07.21.tar.gz
cd drizzle7-2011.07.21
./configure --without-server
make libdrizzle-1.0
make install-libdrizzle-1.0
cd ..
#下载openresty
wget http://openresty.org/download/ngx_openresty-1.4.2.7.tar.gz
tar zxvf ngx_openresty-1.4.2.7.tar.gz
#下载nginx-http-concat(合并静态文件请求模块,非必需,建议安装)
wget https://github.com/alibaba/nginx-http-concat/archive/master.zip
unzip master
mv nginx-http-concat-master/ ngx_openresty-1.4.2.7/bundle/nginx-http-concat
#安装openresty
cd ngx_openresty-1.4.2.7
./configure --with-luajit --with-http_drizzle_module --with-http_iconv_module --with-ld-opt="-Wl,-rpath,/usr/local/lib" --with-http_stub_status_module --with-http_ssl_module --with-http_sub_module --add-module=./bundle/nginx-http-concat/
gmake
gmake install
|
3、将OpenResty(Nginx)加入自启动
1
|
vi /etc/rc.d/init.d/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
60
61
62
63
64
65
66
67
68
69
|
#! /bin/sh
# chkconfig: 2345 55 25
# Description: Startup script for nginx webserver on Debian. Place in /etc/init.d and
# run 'update-rc.d -f nginx defaults', or use the appropriate command on your
# distro. For CentOS/Redhat run: 'chkconfig --add nginx'
### BEGIN INIT INFO
# Provides: nginx
# Required-Start: $all
# Required-Stop: $all
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: starts the nginx web server
# Description: starts nginx using start-stop-daemon
### END INIT INFO
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DESC="nginx daemon"
NAME=nginx
DAEMON=/usr/local/openresty/nginx/sbin/$NAME
CONFIGFILE=/usr/local/openresty/nginx/conf/$NAME.conf
PIDFILE=/usr/local/openresty/nginx/logs/$NAME.pid
SCRIPTNAME=/etc/init.d/$NAME
set -e
[ -x "$DAEMON" ] || exit 0
do_start() {
$DAEMON -c $CONFIGFILE || echo -n "nginx already running"
}
do_stop() {
kill -INT `cat $PIDFILE` || echo -n "nginx not running"
}
do_reload() {
kill -HUP `cat $PIDFILE` || echo -n "nginx can't reload"
}
case "$1" in
start)
echo -n "Starting $DESC: $NAME"
do_start
echo "."
;;
stop)
echo -n "Stopping $DESC: $NAME"
do_stop
echo "."
;;
reload|graceful)
echo -n "Reloading $DESC configuration..."
do_reload
echo "."
;;
restart)
echo -n "Restarting $DESC: $NAME"
do_stop
do_start
echo "."
;;
*)
echo "Usage: $SCRIPTNAME {start|stop|reload|restart}" >&2
exit 3
;;
esac
exit 0
|
把nginx加入chkconfig,并设置开机启动
1
2
|
chkconfig --add nginx
chkconfig nginx on
|
启动、停止、查看状态
1
2
3
|
service nginx start
service nginx stop
service nginx status
|
四、安装GraphicsMagick
1、安装
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
60
|
#创建安装目录
mkdir -p /usr/local/src/graphicsmagick
cd /usr/local/src/graphicsmagick
#下载graphicsmagick
wget http://sourceforge.net/projects/graphicsmagick/files/graphicsmagick/1.3.18/GraphicsMagick-1.3.18.tar.gz/download
tar zxvf GraphicsMagick-1.3.18.tar.gz
#下载libjpeg
wget ftp://ftp.pl.freebsd.org/vol/rzm1/GraphicsMagick/delegates/libjpeg-6b.tar.gz
rpm -qa | grep libjpeg
rpm -qa | grep libjpeg | xargs rpm -e --nodeps --allmatches
tar zxvf libjpeg-6b.tar.gz
cd libjpeg-6b
./configure
make
make install
ln -s /usr/local/lib/libjpeg* /lib/
ln -s /usr/local/lib/libjpeg* /lib64/
cd ..
#安装libpng
rpm -qa | grep libpng
rpm -qa | grep libpng | xargs rpm -e --nodeps --allmatches
wget ftp://ftp.pl.freebsd.org/vol/rzm1/GraphicsMagick/delegates/libpng-1.2.49.tar.gz
tar zxvf libpng-1.2.49.tar.gz
cd libpng-1.2.49
./configure
make
make install
ln -s /usr/local/lib/libpng* /lib/
ln -s /usr/local/lib/libpng* /lib64/
cd ../
#安装freetype
wget ftp://ftp.pl.freebsd.org/vol/rzm1/GraphicsMagick/delegates/freetype-2.4.10.tar.gz
tar zxvf freetype-2.4.10.tar.gz
cd freetype-2.4.10
./configure
make install
ln -s /usr/local/lib/freetype* /lib/
ln -s /usr/local/lib/freetype* /lib64/
cd ..
#安装GraphicsMagick
cd GraphicsMagick-1.3.18
./configure --prefix=/usr/local/graphicsmagick-1.3.18
make
make install
#编辑profile文件
vi /etc/profile
#末尾增加以下内容
export GMAGICK_HOME="/usr/local/graphicsmagick-1.3.18"
export PATH="$GMAGICK_HOME/bin:$PATH"
LD_LIBRARY_PATH=$GMAGICK_HOME/lib:$LD_LIBRARY_PATH
export LD_LIBRARY_PATH
#保存退出,运行以下命令立即生效配置
source /etc/profile
|
下载libjpeg、libpng、freetype链接如失效可访问:http://www.filewatcher.com/m/libjpeg-6b.tar.gz.961981-0.html
2、用法
原始图片是input.jpg,尺寸:160×120
1)只缩小不放大
1
|
gm convert input.jpg -resize "500x500>" output_1.jpg
|
加了>,表示只有当图片的宽与高,大于给定的宽与高时,才进行“缩小”操作。
生成的图片大小是:160×120,未进行操作
如果不加>,会导致图片被比等放大。
2)等比缩图 (缺点:产生白边)
1
|
gm convert input.jpg -thumbnail "100x100" output_1.jpg
|
生成的图片大小是:100×75
3)非等比缩图,按给定的参数缩图(缺点:长宽比会变化)
1
|
gm convert input.jpg -thumbnail "100x100!" output_2.jpg
|
生成的图片大小是:100×100
4)裁剪后保证等比缩图 (缺点:裁剪了图片的一部分)
1
|
gm convert input.jpg -thumbnail "100x100^" -gravity center -extent 100x100 output_3.jpg
|
生成的图片大小是:100×100,还保证了比例。不过图片经过了裁剪,剪了图片左右两边才达到1:1
5)填充后保证等比缩图 (缺点:要填充颜色,和第一种方法基本一样)
1
|
gm convert input.jpg -thumbnail "100x100" -background gray -gravity center -extent 100x100 output_4.jpg
|
生成的图片大小是:100×100,还保证了比例,同时没有对图片进行任何裁剪,缺失的部分按指定颜色进行填充。
6)裁剪、填充相结合 (缺点:最差的方法)
1
|
gm convert input.jpg -thumbnail "10000@ -background gray -gravity center -extent 100x100 output_5.jpg
|
生成的图片大小是:100×100,这次保证了大小和比例,其中的10000就是100×100的乘积,同时在填充和裁剪之间做了一个平衡。
7)位深度32 转为24
IE6,7,8不支持显示“位深度32”的图片,但IE9、火狐、谷歌浏览器就可以显示。
使用GM,把“位深度32”的图片转换为“位深度24”的图片
输入图片zzz.jpg就是“位深度32”的图片,输出图片 zzz_out.jpg就是“位深度24”的图片
1
|
gm convert -resize 100x100 -colorspace RGB zzz.jpg zzz_out.jpg
|
转完后,图片的颜色会有轻微变化。
更多请参考:http://elf8848.iteye.com/blog/382528
五、相关配置及脚本
1、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
|
user www www;
worker_processes 1;
# 日志级别调试时可设为notice,生产环境请设为error
error_log /usr/local/openresty/nginx/logs/error.log notice;
events
{
use epoll;
worker_connections 51200;
}
http
{
lua_package_path '/usr/local/openresty/nginx/lua/?.lua;;';
server {
listen 80;
server_name img.hopesoft.org;
root /home/wwwroot/img.hopesoft.org;
#/thumbnail目录下的图片请求不经过缩略图模块
location ^~ /thumbnail/ {
}
#对类似_100x100.gif/jpg/png/jpeg进行缩略图处理
location ~* _([0-9]+)x([0-9]+)\.(gif|jpg|png|jpeg)$ { #匹配文件名规则
root /home/wwwroot/img.hopesoft.org; #站点根目录
set $image_root /home/wwwroot/img.hopesoft.org; #图片目录
set $thumbnail_root /home/wwwroot/img.hopesoft.org/thumbnail; #缩略图存放目录
#如果缩略图文件存在,直接返回
set $file $thumbnail_root$uri;
if (-f $file) {
rewrite ^/(.*)$ /thumbnail/$1 last;
}
#如果缩略图文件不存在,则应用缩略图模块处理
if (!-f $file) {
rewrite_by_lua_file lua/thumbnail.lua;
}
}
}
include vhost/*.conf;
}
|
2、Lua脚本
/usr/local/openresty/nginx/lua/thumbnail.lua
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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
|
-- nginx thumbnail module
-- last update : 2014/8/21
-- version : 0.4.1
local c = require 'config'
--[[
uri :链接地址,如/goods/0007/541/001_328x328.jpg
ngx_img_root :图片根目录
ngx_thumbnail_root:缩略图根目录
img_width :缩略图宽度
img_width :缩略图高度
img_size :缩略图宽x高
img_crop_type :缩略图裁剪类型
cur_uri_reg_model :缩略图uri正则规则
]]
local |
全部评论
请发表评论