Tengine + Lua + GraphicsMagick 实现图片自动裁剪/缩放

一、背景

      随着互联网的快速发展、需求频繁变更、内容数量的俱增、时间的持续增长,图片数量也会越来越多。在实际需求中,会出现在若干个页面或同一个页面不同位置,展示同一条信息以及其缩略图。在这时,如果使用 CSS 控制图片显示的大小,对于那些与该位置不成比例的图片,缩小后就会出现图片变形。也不可能让编辑人员,对所有的图片进行 PS,这时候就产生了强烈的自动化裁剪、缩放图片的需求,来适应不同规格的缩略图。
      Nginx 虽然有自带的 image filter module 也能实现此功能,但是有弊端:

  • image filter module 使用的是 GD,GD 性能、效率、处理后的图片质量不如 GraphicsMagick

  • image filter module 没法真正生成裁剪/缩放后的图片,而是通过 Nginx 直接输出的,这样每次请求或缓存过期后都需要重新裁剪/缩放,这样无疑会增加 Nginx 负担

二、系统环境

  1. 操作系统



  2. CPU

    Tengine + Lua + GraphicsMagick 实现图片自动裁剪/缩放_第1张图片

  3. 内存



  4. 磁盘及分区

    Tengine + Lua + GraphicsMagick 实现图片自动裁剪/缩放_第2张图片

三、软件准备

  • Tengine:https://github.com/alibaba/tengine

  • Lua:http://www.lua.org/ftp/

  • LuaJIT: http://luajit.org/download.html

  • libjpeg、libjpeg-devel

  • libpng、libpng-devel

  • giflib、giflib-devel

  • freetype、freetype-devel

  • GraphicsMagick:http://sourceforge.net/projects/graphicsmagick/files/graphicsmagick/

四、软件安装

  1. readline&readline-devel(Lua 所需)

    yum install readline
    yum install readline-devel
  2. Lua

    • 进入 Lua 源码目录

    • make 会提示类似以下信息:

      make


    • make PLATFORM(例如你的操作系统是Linux,就执行:make linux,如果是 FreeBSD,就执行:make freebsd)

      make linux
      make install
  3. LuaJIT

    make
    make install
  4. Tengine

    • 进入 Tengine 源码目录

    • ./configure --prefix=/usr/local/Tengine --dso-path=/usr/local/Tengine/modules --with-http_realip_module --with-http_gzip_static_module --with-http_stub_status_module --with-http_concat_module --with-http_lua_module --with-openssl=/usr/local/src/openssl-1.0.1e --with-zlib=/usr/local/src/zlib-1.2.8 --http-proxy-temp-path=/var/tmp/Tengine/proxy_temp --http-fastcgi-temp-path=/var/tmp/Tengine/fastcgi_temp --http-uwsgi-temp-path=/var/tmp/Tengine/uwsgi_temp --http-scgi-temp-path=/var/tmp/Tengine/cgi_temp --http-client-body-temp-path=/var/tmp/Tengine/client_body_temp --http-log-path=/var/log/Tengine/access.log --error-log-path=/var/log/Tengine/error.log
      make
      make install
    • 红色加粗是关键部分,其余为我的其它配置,不是该问题讨论范围之内

    • 如果报有下面错误

      src/http/modules/lua/ngx_http_lua_log.c: 在函数‘ngx_http_lua_ngx_log’中:
      src/http/modules/lua/ngx_http_lua_log.c:40: 错误:‘LUA_GLOBALSINDEX’未声明(在此函数内第一次使用)
      src/http/modules/lua/ngx_http_lua_log.c:40: 错误:(即使在一个函数内多次出现,每个未声明的标识符在其
      src/http/modules/lua/ngx_http_lua_log.c:40: 错误:所在的函数内也只报告一次。)
      src/http/modules/lua/ngx_http_lua_log.c: 在函数‘ngx_http_lua_print’中:
      src/http/modules/lua/ngx_http_lua_log.c:81: 错误:‘LUA_GLOBALSINDEX’未声明(在此函数内第一次使用)

      时,是因为使用了不兼容的 Lua 的头文件,configure 需要加上

      --with-ld-opt="-Wl,-rpath,$LUAJIT_LIB"

      或者

      --with-luajit-inc=PATH             set LuaJIT headers path (where lua.h/lauxlib.h/... are located)
      --with-luajit-lib=PATH             set LuaJIT library path (where libluajit-5.1.{a,so} are located)
    • 如果在启动或者执行 Tengine 任意命令时,出现以上错误,那么就是,无法找到动态库 libluajit-5.1.so.2 ,64位系统貌似是去 /lib64 目录中寻找动态库的。
      那么解决办法就是,将 /usr/local/lib/libluajit-5.1.so.2 软连接到 /lib64 目录下:

      ln -s /usr/local/lib/libluajit-5.1.so.2 /lib64/libluajit-5.1.so.2
  5. libjpeg、libjpeg-devel

    yum install libjpeg
    yum install libjpeg-devel
  6. libpng、libpng-devel

    yum install libpng
    yum install libpng-devel
  7. giflib、giflib-devel

    yum install giflib
    yum install giflib-devel
  8. freetype、freetype-devel

    yum install freetype
    yum install freetype-devel
  9. GraphicsMagick

    ./configure --prefix=/usr/local/GraphicsMagick --enable-shared
    make
    make install

    执行

    /usr/local/GraphicsMagick/bin/gm version

    如果得到

    Tengine + Lua + GraphicsMagick 实现图片自动裁剪/缩放_第3张图片
    则,说明安装成功!!!
     

五、脚本编写

local command = "/usr/local/GraphicsMagick/bin/gm convert " .. 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;    // 调用 GraphicsMagick 进行图片转换,相关信息查看 GraphicsMagick 帮助文档
os.execute(command);    // 执行裁剪命令
ngx.exec(ngx.var.request_uri);    // 输出裁剪后的图片
// ngx.var.request_filepath、ngx.var.width、ngx.var.height 即 Nginx location 中设置的变量

六、配置

#group web;
user web;
worker_processes  12;

error_log  /var/log/Tengine/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

pid        /var/run/nginx.pid;

events {
        use   epoll;
        worker_connections  1024;
}

http {
    include       mime.types;
    default_type  html/html;
    charset       UTF-8;

    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  /var/log/Tengine/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    client_max_body_size 10M;

    gzip  on;

    gzip_min_length 1k;
gzip_buffers 5 12k;
    gzip_http_version 1.0;
    gzip_comp_level 2;
    gzip_vary on;
    gzip_types text/plain text/css text/xml application/xml application/atom+xml application/rss+xml application/xhtml+xml application/xml-dtd image/gif image/jpeg image/png ima
ge/x-icon image/bmp image/x-ms-bmp text/javascript application/x-javascript;

    include "vhosts.conf";
}


server {
        listen      80;
        server_name hostname;

        location / {
                root /document_root; # 站点根目录

                expires 1h;    # 缓存时间
                add_header Cache-Control max-age=3600; # 缓存时间

                access_log   /var/log/Tengine/host_access.log;
        }

        # 如果 url 格式如:xxxx.gif_数字x数字.gif
        location ~* ^(.+\.(jpg|jpeg|gif|png))_(\d+)x(\d+)\.(jpg|jpeg|gif|png)$ {
                root /document_root;    # 这里必须设置,否则根目录,即 $document_root 会是 Nginx 默认的 Nginx Root/html,在 Lua 中会得不到期望的值
                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 /document_root/$1;    # 设置原始图片路径,如:/document_root/1.gif
                        set $width $3;    # 设置裁剪/缩放的宽度
                        set $height $4;    # 设置裁剪/缩放的高度
                        set $ext $5;    # 图片文件格式后缀
                        content_by_lua_file /document_root/ImageResizer.lua;    # 加载外部 Lua 文件
                }
        }
}

七、测试

  1.     测试脚本(Lua,修改一下 /document_root/ImageResizer.lua 在做测试时生成随机图片)

    local command = "/usr/local/GraphicsMagick/bin/gm convert " .. ngx.var.request_filepath .. " -resize " .. ngx.var.width .. "x" .. ngx.var.height .. " +profile \"*\" " .. ngx.var.request_filepath .. "_" .. math.random(0, 100000000) .. ngx.var.width .. "x" .. ngx.var.height .. "." .. ngx.var.ext;
    os.execute(command);
    ngx.req.set_uri(ngx.var.request_uri, true);
  2. 测试网络环境局域网

  3. 测试工具: Apache AB

  4. 测试方法:

    ab -n 100 -c 1 image_url
  5. 测试结果(哎!前前后后、断断续续测试+整理内容,花了四五个小时)

    A、GIF (大图)

        Tengine + Lua + GraphicsMagick 实现图片自动裁剪/缩放_第4张图片

        启用 poll 测试结果

        Tengine + Lua + GraphicsMagick 实现图片自动裁剪/缩放_第5张图片

        Tengine + Lua + GraphicsMagick 实现图片自动裁剪/缩放_第6张图片

        未启用 poll 测试结果

        Tengine + Lua + GraphicsMagick 实现图片自动裁剪/缩放_第7张图片

        Tengine + Lua + GraphicsMagick 实现图片自动裁剪/缩放_第8张图片


    B、GIF (小图)

        Tengine + Lua + GraphicsMagick 实现图片自动裁剪/缩放_第9张图片

        启用 poll 测试结果

        Tengine + Lua + GraphicsMagick 实现图片自动裁剪/缩放_第10张图片

        未启用 poll 测试结果

        Tengine + Lua + GraphicsMagick 实现图片自动裁剪/缩放_第11张图片
        

    C、JPEG(大图)

        Tengine + Lua + GraphicsMagick 实现图片自动裁剪/缩放_第12张图片

        启用 poll 测试结果

        Tengine + Lua + GraphicsMagick 实现图片自动裁剪/缩放_第13张图片

        Tengine + Lua + GraphicsMagick 实现图片自动裁剪/缩放_第14张图片

        未启用 poll 测试结果

        Tengine + Lua + GraphicsMagick 实现图片自动裁剪/缩放_第15张图片

        Tengine + Lua + GraphicsMagick 实现图片自动裁剪/缩放_第16张图片

    D、JPEG(小图)

        Tengine + Lua + GraphicsMagick 实现图片自动裁剪/缩放_第17张图片

        启用 poll 测试结果

        Tengine + Lua + GraphicsMagick 实现图片自动裁剪/缩放_第18张图片

        未启用 poll 测试结果

        Tengine + Lua + GraphicsMagick 实现图片自动裁剪/缩放_第19张图片

    E、PNG(大图)

        Tengine + Lua + GraphicsMagick 实现图片自动裁剪/缩放_第20张图片

        启用 poll 测试结果

        Tengine + Lua + GraphicsMagick 实现图片自动裁剪/缩放_第21张图片

        Tengine + Lua + GraphicsMagick 实现图片自动裁剪/缩放_第22张图片

        未启用 poll 测试结果

        Tengine + Lua + GraphicsMagick 实现图片自动裁剪/缩放_第23张图片

        Tengine + Lua + GraphicsMagick 实现图片自动裁剪/缩放_第24张图片

    F、PNG(小图)

        Tengine + Lua + GraphicsMagick 实现图片自动裁剪/缩放_第25张图片

        启用 poll 测试结果

        Tengine + Lua + GraphicsMagick 实现图片自动裁剪/缩放_第26张图片

        未启用 poll 测试结果

        Tengine + Lua + GraphicsMagick 实现图片自动裁剪/缩放_第27张图片


    G、照片原始图片

        Tengine + Lua + GraphicsMagick 实现图片自动裁剪/缩放_第28张图片
         启用 poll 测试结果

        Tengine + Lua + GraphicsMagick 实现图片自动裁剪/缩放_第29张图片

        Tengine + Lua + GraphicsMagick 实现图片自动裁剪/缩放_第30张图片

        未启用 poll 测试结果

         Tengine + Lua + GraphicsMagick 实现图片自动裁剪/缩放_第31张图片

         Tengine + Lua + GraphicsMagick 实现图片自动裁剪/缩放_第32张图片

你可能感兴趣的:(lua,tengine,图片自动裁剪)