在我们平时的开发中,例如在做wordpress模板时,很多时候要在文章列表中显示一张文章的图片,由于文章图片的大小并不是可控的,而页面的设计为了美观,可能图片的尺寸是一定的,这个时候如果放原图的话,可能就会导致图片被拉伸或压缩,本来很好看的模板,但是用在实际中并不是太美观。 最近我也在工作中遇到这样的问题,这个时候就想起了阿里云的图片处理功能,之前见过,阿里云的图片缩放裁剪具体的内容可以查看http://help.aliyun.com/document_detail/oss/oss-img-guide/crop/auto-crop.html。
一、功能
今天我们只是简单实现这个功能,形式是这样, 比如有这样一张图片:http://test.vimer.club/vim.gif ,我希望得到的结果是这样,当我访问 http://test.vimer.club/vim.gif@330w_100h_75Q_c 时我得到一张330*100像素质量为75的裁剪图片,当我访问 http://test.vimer.club/vim.gif@330w_330h_75Q_r 时我得到一张330*330像素质量为75的等比例缩放图片。
二、原理
这里需要用到nginx的http_image_filter_module模块,这个模块可以很方便的实现缩略图功能,只是默认的情况下并不会安装,需要自己编译安装才能行。编译的时候./configure 增加 –with-http_image_filter_module 编译安装即可。具体http_image_filter_module的用法可以查看http://nginx.org/en/docs/http/ngx_http_image_filter_module.html。
三、初步实现:实时缩放裁剪
nginx配置:
# 等比缩放图片
location ~ (.+)\.(jpg|gif|png)@(\d+)w_(\d+)h_(\d+)Q_r$ {
set $w $3; #宽
set $h $4; #高
set $q $5; #图片质量
image_filter resize $w $h;
image_filter_jpeg_quality $q;
image_filter_buffer 5M;
try_files $1.$2 /img/notfound.jpg;
}
# 裁剪图片
location ~ (.+)\.(jpg|gif|png)@(\d+)w_(\d+)h_(\d+)Q_c$ {
set $w $3; #宽
set $h $4; #高
set $q $5; #图片质量
image_filter crop $w $h;
image_filter_jpeg_quality $q;
image_filter_buffer 5M;
try_files $1.$2 /img/notfound.jpg;
}
功能是实现了,这样实现有其优点,首先根据传入的参数即可生成各种尺寸图片,并且还不占用硬盘空间。但是这样实现需要消耗CPU,访问量大的时候就会给服务器带来极大的负担。所以如果访问量很大的话,最好将缩略图保存在硬盘上,或者在前端加上cache或者使用CDN。
四、实时生成缩略图存放在硬盘上
nginx配置:
location ~ (.+)\.(jpg|gif|png)@(\d+)w_(\d+)h_(\d+)Q_([rc])$ {
# 限制referer,防盗链
valid_referers test.vimer.club;
if ($invalid_referer) {return 404;}
set $w $3; #宽
set $h $4; #高
set $q $5; #图片质量
set $type $6;
set $image_path $1.$2; #真实图片地址
set $cache_path $1_$3w_$4h_$5Q_$6.$2; #临时文件地址
if ($type = 'r') {
set $type 'image-resize';
}
if ($type = 'c') {
set $type 'image-crop';
}
set $image_uri /$type$image_path?w=$w&h=$h&q=$q;
if (-f $document_root$cache_path) {
rewrite (.+)\.(jpg|gif|png)@(\d+)w_(\d+)h_(\d+)Q_([rc])$ $1_$3w_$4h_$5Q_$6.$2;
break;
}
if (!-f $document_root$cache_path) {
proxy_pass http://$server_name$image_uri;
break;
}
proxy_store $document_root$cache_path;
proxy_store_access user:rw group:rw all:r;
proxy_set_header Host $host;
expires 10d; # 设置图片过期时间10天
}
location ~ /image-resize(.+)\.(jpg|gif|png) {
rewrite /image-resize(.+)\.(jpg|gif|png)$ $1.$2 break;
image_filter resize $arg_w $arg_h;
image_filter_jpeg_quality $arg_q;
image_filter_buffer 5M;
try_files $1.$2 /img/notfound.jpg;
}
location ~ /image-crop(.+)\.(jpg|gif|png) {
rewrite /image-crop(.+)\.(jpg|gif|png)$ $1.$2 break;
image_filter crop $arg_w $arg_h;
image_filter_jpeg_quality $arg_q;
image_filter_buffer 5M;
try_files $1.$2 /img/notfound.jpg;
}
缩略图生成流程:
- 原图在 http://test.vimer.club/vim.gif 。我需要一份200×200的缩略图。
- 请求 http://test.vimer.club/vim.gif@200w_200h_75Q_r
- 判断referer,看是否合法,不合法则直接返回404
- 判断是否已生成了该格式文件,若已生成,则直接rewrite到该图上
- 若不存在则转到 http://test.vimer.club/image-resize/vim.gif?w=200&h=200&q=75
- 根据传入的参数对图片进行裁剪,并将裁剪后的文件存储为vim_200w_200h_75Q_r.gif
- 将图片返回
五、定时清理磁盘
定时清理磁盘我们用linux的crontab定时任务来进行清理。命令可以使用:
find ./ -type f -regex ".*_[0-9]+w_[0-9]+h_[0-9]+Q_\(r\|c\)\.\(jpg\|png\|gif\)" -atime +7 -delete
这个命令会把符合命名规则的文件,且7天未进行过访问的图片清理掉。定时执行可配置crontab:
0 3 * * * find ./ -type f -regex ".*_[0-9]+w_[0-9]+h_[0-9]+Q_\(r\|c\)\.\(jpg\|png\|gif\)" -atime +7 -delete