使用nginx+lua+GraphicsMagick实现图片自动 裁剪

时间:2022-11-25 10:14:43

在做网站尤其是以内容为主的过程中,常常会遇到一张图片各种地方都要引用,且每个引用的地方要求的图片尺寸都不一样的。
一般中大型的网站都会对这一类的图片做自动裁剪功能。本文介绍在centos6操作系统上,采用nginx、lua和GraphicsMagick工具简单实现图片的自动裁剪功能。其中nginx负责展示图片和调度lua脚本,GraphicsMagick负责对原图进行裁剪。

一、基础软件包安装
groupadd www
useradd -g www www -s /bin/false
yum -y install epel-release git gcc gcc-c++ zlib zlib-devel openssl openssl-devel pcre pcre-devel libpng libjpeg libpng-devel libjpeg-devel ghostscript libtiff libtiff-devel freetype freetype-devel readline-devel ncurses-devel wget

二、下载相关软件
其中nginx-http-concat和echo-nginx-module模块非必须
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
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 zxvf lua-5.3.1.tar.gz
cd lua-5.3.1
make linux && make install
 
cd ..
tar zxvf 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日志目录
mkdir -p /data/logs
chmod +w /data/logs
chown -R www:www /data/logs


创建Nginx配置文件
在/usr/local/nginx/conf/目录中创建nginx.conf文件:
>/usr/local/nginx/conf/nginx.conf
vi /usr/local/nginx/conf/nginx.conf

  输入以下内容:
#####################################################################################################
user  www www;

worker_processes 8;

error_log  /data/logs/nginx_error.log  crit;

pid        /usr/local/nginx/nginx.pid;

#Specifies the value for maximum file descriptors that can be opened by this process.
worker_rlimit_nofile 65535;

events
{
  use epoll;
  worker_connections 65535;
}

http
{
  include       mime.types;
  default_type  application/octet-stream;

  #charset  gb2312;
      
  server_names_hash_bucket_size 128;
  client_header_buffer_size 32k;
  large_client_header_buffers 4 32k;
  client_max_body_size 8m;
      
  sendfile on;
  tcp_nopush     on;

  keepalive_timeout 60;

  tcp_nodelay on;

  fastcgi_connect_timeout 300;
  fastcgi_send_timeout 300;
  fastcgi_read_timeout 300;
  fastcgi_buffer_size 64k;
  fastcgi_buffers 4 64k;
  fastcgi_busy_buffers_size 128k;
  fastcgi_temp_file_write_size 128k;

  gzip on;
  gzip_min_length  1k;
  gzip_buffers     4 16k;
  gzip_http_version 1.0;
  gzip_comp_level 2;
  gzip_types       text/plain application/x-javascript text/css application/xml;
  gzip_vary on;

  #limit_zone  crawler  $binary_remote_addr  10m;
  include vhosts/*.conf;
}
#####################################################################################################

创建lua目录和lua脚本
mkdir /usr/local/nginx/lua
vi /usr/local/nginx/lua/cropSize.lua
#####################################################################################################
-- 根据输入长和宽的尺寸裁切图片

-- 检测路径是否目录
local function is_dir(sPath)
    if type(sPath) ~= "string" then return false end

    local response = os.execute("cd " .. sPath)
    if response == 0 then
        return true
    end
    return false
end

-- 文件是否存在
function file_exists(name)
    local f = io.open(name, "r")
    if f ~= nil then io.close(f) return true else return false end
end

-- 获取文件路径
function getFileDir(filename)
    return string.match(filename, "(.+)/[^/]*%.%w+$") --*nix system
end

-- 获取文件名
function strippath(filename)
    return string.match(filename, ".+/([^/]*%.%w+)$") -- *nix system
end

--去除扩展名
function stripextension(filename)
    local idx = filename:match(".+()%.%w+$")
    if (idx) then
        return filename:sub(1, idx - 1)
    else
        return filename
    end
end

--获取扩展名
function getExtension(filename)
    return filename:match(".+%.(%w+)$")
end

-- 开始执行
-- ngx.log(ngx.ERR, getFileDir(ngx.var.img_file));

local gm_path = '/usr/local/GraphicsMagick/bin/gm'

-- check image dir
if not is_dir(getFileDir(ngx.var.img_file)) then
    os.execute("mkdir -p " .. getFileDir(ngx.var.img_file))
end

--  ngx.log(ngx.ERR,ngx.var.img_file);
--  ngx.log(ngx.ERR,ngx.var.request_filepath);

-- 裁剪后保证等比缩图 (缺点:裁剪了图片的一部分)
-- gm convert cropSize.jpg -thumbnail 300x300^ -gravity center -extent 300x300 -quality 100 +profile "*" cropSize.jpg_300x300.jpg
if (file_exists(ngx.var.request_filepath)) then
    local cmd = gm_path .. ' convert  -auto-orient -strip ' .. ngx.var.request_filepath
    cmd = cmd .. " -thumbnail " .. ngx.var.img_width .. "x" .. ngx.var.img_height .. "^"
    cmd = cmd .. " -gravity center -extent " .. ngx.var.img_width .. "x" .. ngx.var.img_height

    -- 由于压缩后比较模糊,默认图片质量为100,请根据自己情况修改quality
    cmd = cmd .. " -quality " .. ngx.var.img_fill
    cmd = cmd .. " +profile \"*\" " .. ngx.var.img_file;
--  ngx.log(ngx.ERR, cmd);
    os.execute(cmd);
    ngx.exec(ngx.var.uri);
else
    ngx.exit(ngx.HTTP_NOT_FOUND);
end
#####################################################################################################


创建image.conf
touch /usr/local/nginx/conf/image.conf
vi /usr/local/nginx/conf/image.conf
###########################################################################################
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
{
        expires      30d;
}
###########################################################################################


创建js.conf
touch /usr/local/nginx/conf/js.conf
vi /usr/local/nginx/conf/js.conf
###########################################################################################
location ~ .*\.(js|css)?$
{
        expires      1d;
}
###########################################################################################

创建nginxcrop.conf
vi /usr/local/nginx/conf/nginxcrop.conf
###########################################################################################
    location /lua1 {
        default_type 'text/plain';
        content_by_lua 'ngx.say("hello, lua")';
    }
    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_100x100.jpg
    location ~* ^(.+\.(jpg|jpeg|gif|png))_+w(\d+)+h(\d+)+f(\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_fill $5;    # height
                    set $img_ext $2;    # file ext
                    content_by_lua_file lua/cropSize.lua;    # load lua
            }
    }


###########################################################################################

创建vhosts/a.conf
mkdir /usr/local/nginx/conf/vhosts
vi /usr/local/nginx/conf/vhosts/a.conf
###########################################################################################
server
{
    listen       80;
    charset  utf-8;
    server_name  192.168.1.50;
    index index.html index.htm index.php;
    root  /data/www/blog;  
    #设置图片路径 建议与root相同
    set $upload_path /data/www/blog;  
    #limit_conn   crawler  20;                             
    include       image.conf;
    include       js.conf;
    include       nginxcrop.conf;
    log_format  access  '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" $http_x_forwarded_for';
    access_log  /data/logs/access.log  access;
}
###########################################################################################

最后启动nginx
/usr/local/nginx/sbin/nginx

测试:
真实图片地址:http://192.168.0.25/images/xxx/xxx/a.jpg
访问裁剪地址:http://192.168.0.25/images/xxx/xxx/a.jpg_w200h150f70.jpg