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

原创
2013/10/17 16:40
阅读数 1.8W

一、背景

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

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

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

二、系统环境

  1. 操作系统



  2. CPU



  3. 内存



  4. 磁盘及分区



三、软件准备

四、软件安装

  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

    如果得到


    则,说明安装成功!!!
     

五、脚本编写

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 (大图)

        

        启用 poll 测试结果

        

        

        未启用 poll 测试结果

        

        


    B、GIF (小图)

        

        启用 poll 测试结果

        

        未启用 poll 测试结果

       
        

    C、JPEG(大图)

        

        启用 poll 测试结果

        

        

        未启用 poll 测试结果

        

        

    D、JPEG(小图)

        

        启用 poll 测试结果

        

        未启用 poll 测试结果

        

    E、PNG(大图)

        

        启用 poll 测试结果

        

        

        未启用 poll 测试结果

        

        

    F、PNG(小图)

        

        启用 poll 测试结果

        

        未启用 poll 测试结果

        


    G、照片原始图片

        
         启用 poll 测试结果

        

        

        未启用 poll 测试结果

         

         

展开阅读全文
打赏
7
189 收藏
分享
加载中
mark
2015/04/13 18:17
回复
举报

引用来自“开源中国董事会主席”的评论

引用来自“金三胖”的评论

谢谢,根据说明成功了。不过提两个问题下
1、正则中应该是 (\d+)x(\d+) 吧
2、ImageResizer.lua 中的 ".j" 多了个j,应该是 "." 。

嘿;-) 正则中是\d 来着呢 lua脚本中 没有.j 来着呢?
1、文中是 (\d+)+x(\d+)+ 2、.j是在 ngx.var.height .. ".j" .. ngx.var.ext 网页上显示不完全,我是通过Firebug查看的
2014/08/01 11:12
回复
举报

引用来自“金三胖”的评论

谢谢,根据说明成功了。不过提两个问题下
1、正则中应该是 (\d+)x(\d+) 吧
2、ImageResizer.lua 中的 ".j" 多了个j,应该是 "." 。

嘿;-) 正则中是\d 来着呢 lua脚本中 没有.j 来着呢?
2014/08/01 10:04
回复
举报
谢谢,根据说明成功了。不过提两个问题下
1、正则中应该是 (\d+)x(\d+) 吧
2、ImageResizer.lua 中的 ".j" 多了个j,应该是 "." 。
2014/08/01 03:34
回复
举报
13楼主写得很好,很有参考价值啊,赞
2014/05/09 09:26
回复
举报
我对GM很葱白!
2013/11/28 09:47
回复
举报

引用来自“chekun”的评论

引用来自“腾勇”的评论

引用来自“chekun”的评论

楼主 ab -c > 1呢

什么意思?

ab -c 3 -n 100 http://url/to//not/existed/thumb/image/file

这个你可以看看 apache ab 的参数说明
2013/11/28 09:44
回复
举报

引用来自“杨文”的评论

厉害啊

83过奖 过奖
2013/11/28 09:43
回复
举报
厉害啊
2013/11/28 09:05
回复
举报
牛逼,MARK
2013/10/24 11:34
回复
举报
更多评论
打赏
41 评论
189 收藏
7
分享
返回顶部
顶部