Nginx的http_image_filter插件可以方便地对图片进行缩放、裁剪、转换格式等等。官方文档:http://nginx.org/en/docs/http/ngx_http_image_filter_module.html
官方的filer包含以下几种:
image_filter off;
image_filter test;
image_filter size;
image_filter rotate 90 | 180 | 270;
image_filter resize width height;
image_filter crop width height;
其中crop为裁剪,只保留图片居中的部分。例如原图:http://127.0.0.1/uploads/36.jpg
裁剪后:http://127.0.0.1/crop/a/200_80/uploads/36.jpg
而我现在想要的效果是保留图片的上面部分,从上往下裁剪。而nginx不支持这种,所以修改了一下插件的源码,添加一种裁剪方法:croptop。
我用的是v1.5.3版本的nginx源码。修改代码 src/http/modules/ngx_http_image_filter_module.c:
$ diff ngx_http_image_filter_module.c ngx_http_image_filter_module.c.bak 21d20 < #define NGX_HTTP_IMAGE_CROP_TOP 6 825,835d823 < } else if (conf->filter == NGX_HTTP_IMAGE_CROP_TOP) { < < resize = 0; < < if ((ngx_uint_t) dx > ctx->max_width) { < dy = dy * ctx->max_width / dx; < dy = dy ? dy : 1; < dx = ctx->max_width; < resize = 1; < } < 927c915 < --- > 977,1012d964 < if (conf->filter == NGX_HTTP_IMAGE_CROP_TOP) { < < src = dst; < < if ((ngx_uint_t) dy > ctx->max_height) { < oy = dy - ctx->max_height; < ox = 0; < dst = ngx_http_image_new(r, dx - ox, dy - oy, colors); < < if (dst == NULL) { < gdImageDestroy(src); < return NULL; < } < < ox /= 2; < oy = 0; < < ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, < "image crop: %d x %d @ %d x %d", < dx, dy, ox, oy); < < if (colors == 0) { < gdImageSaveAlpha(dst, 1); < gdImageAlphaBlending(dst, 0); < } < < gdImageCopy(dst, src, 0, 0, ox, oy, dx - ox, ctx->max_height); < < if (colors) { < gdImageTrueColorToPalette(dst, 1, 256); < } < < gdImageDestroy(src); < } < } < 1383,1385d1334 < < } else if (ngx_strcmp(value[i].data, "croptop") == 0) { < imcf->filter = NGX_HTTP_IMAGE_CROP_TOP;
可根据此更改制作path包:
$ diff ngx_http_image_filter_module.c ngx_http_image_filter_module.c.bak > image_filter.patch $ patch ngx_http_image_filter_module.c image_filter.patch
nginx 配置:
location ~ /croptop/([^/]+)/(\d+)_(\d+)/(.*)$ { set $md5 $1; set $width $2; set $height $3; set $img_path $4; set $imguri http://127.0.0.1/$img_path; proxy_pass $imguri; image_filter croptop $width $height; image_filter_jpeg_quality 85; }
编译nginx:
sudo apt-get install openssl-dev sudo apt-get install openssl sudo apt-get install libssl0.9.8 sudo apt-get install libssl-dev sudo apt-get install libpcre3 libpcre3-dev sudo apt-get install libgd2-xpm-dev sudo apt-get install libgeoip-dev ./configure --prefix=/usr/local/nginx --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log \ --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi \ --http-log-path=/var/log/nginx/access.log --http-proxy-temp-path=/var/lib/nginx/proxy \ --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi \ --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --with-pcre-jit --with-debug \ --with-http_addition_module --with-http_dav_module --with-http_geoip_module --with-http_gzip_static_module \ --with-http_image_filter_module --with-http_stub_status_module --with-http_ssl_module --with-http_sub_module \ --with-http_xslt_module --with-ipv6 --with-sha1=/usr/include/openssl --with-md5=/usr/include/openssl \ --with-mail --with-mail_ssl_module
访问新方法来裁剪图片 http://127.0.0.1/croptop/a/200_80/uploads/36.jpg,效果如下图:
原crop裁剪方法有个问题,就是当图片原宽度比裁剪宽度小的时候,比如原 232 x 350,要裁剪成 250 x 250,那么裁剪后变成 165 x 250,也就是它会把高350压缩成 250,宽度等比缩放到 165,而165比我们要的250要小,所以就不再裁剪了。
我想要的效果是,宽度小于250,就不缩放,直接按 232 x 232来裁剪出一个正方形。于是添加了一个自定义裁剪类型square,代码如下:
$ diff ngx_http_image_filter_module.c ngx_http_image_filter_module.c.bak 21,22d20 < #define NGX_HTTP_IMAGE_CROP_TOP 6 < #define NGX_HTTP_IMAGE_SQUARE 7 826,850d823 < } else if (conf->filter == NGX_HTTP_IMAGE_CROP_TOP) { < < resize = 0; < < if ((ngx_uint_t) dx > ctx->max_width) { < dy = dy * ctx->max_width / dx; < dy = dy ? dy : 1; < dx = ctx->max_width; < resize = 1; < } < < } else if (conf->filter == NGX_HTTP_IMAGE_SQUARE) { < < resize = 0; < < if ((ngx_uint_t) dx > ctx->max_width) { < dy = dy * ctx->max_width / dx; < dy = dy ? dy : 1; < dx = ctx->max_width; < resize = 1; < } else { < ctx->max_width = dx; < ctx->max_height = dx; < } < 942,950d914 < < if (conf->filter == NGX_HTTP_IMAGE_CROP || conf->filter == NGX_HTTP_IMAGE_SQUARE) { < < if (conf->filter == NGX_HTTP_IMAGE_SQUARE) { < if ((ngx_uint_t)dy < ctx->max_width){ < ctx->max_width = dy; < ctx->max_height = dy; < } < } 951a916 > if (conf->filter == NGX_HTTP_IMAGE_CROP) { 1000,1035d964 < if (conf->filter == NGX_HTTP_IMAGE_CROP_TOP) { < < src = dst; < < if ((ngx_uint_t) dy > ctx->max_height) { < oy = dy - ctx->max_height; < ox = 0; < dst = ngx_http_image_new(r, dx - ox, dy - oy, colors); < < if (dst == NULL) { < gdImageDestroy(src); < return NULL; < } < < ox /= 2; < oy = 0; < < ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, < "image crop: %d x %d @ %d x %d", < dx, dy, ox, oy); < < if (colors == 0) { < gdImageSaveAlpha(dst, 1); < gdImageAlphaBlending(dst, 0); < } < < gdImageCopy(dst, src, 0, 0, ox, oy, dx - ox, ctx->max_height); < < if (colors) { < gdImageTrueColorToPalette(dst, 1, 256); < } < < gdImageDestroy(src); < } < } < 1407,1409d1335 < } else if (ngx_strcmp(value[i].data, "croptop") == 0) { < imcf->filter = NGX_HTTP_IMAGE_CROP_TOP; < 1412,1414d1337 < < } else if (ngx_strcmp(value[i].data, "square") == 0) { < imcf->filter = NGX_HTTP_IMAGE_SQUARE;