让前端飞

[63/100] 技术文章:nginx + lua + imag

2018-12-17  本文已影响6人  Alee文润

需求

在文章模块,上传的封面图片在不同的场景使用,可以任意的剪切不同大小的图片以供使用。类似xx.png_100x100.png的任意尺寸的图片。
本文通过nginx + lua + imageMagic的技术方案实现图片的剪切功能。在实现此功能的时候我们需要对nginx、lua、以及imageMagic有一个大致的了解。下面先分别介绍相关的知识,最后通过代码完成整个功能的搭建。

nginx基本知识

location指令的作用是根据用户请求的URI来执行不同的应用,也就是根据用户请求的网站URL进行匹配,匹配成功即进行相关的操作。
location的语法

location [ = | ~ | ~& | ^~] uri {...}
指令 || 匹配表示 || 匹配的网站网址 || 匹配uri后要执行的配置

=为精准匹配
~ 区分大小写
~*不区分大小写
^~ 表示不做正则表达式的检查。
常见采用~*不区分大小写的正则来匹配uri做一些配置。

正则基本知识

详细的正则知识查看这里 http://tool.oschina.net/uploads/apidocs/jquery/regexp.html
下面主要说常用到的几个表达式

\ 将下一个字符标记为一个特殊字符、或一个原义字符、或一个向后引用、或一个八进制转义符。例如,“n”匹配字符“n”。“\n”匹配一个换行符。串行“\\”匹配“\”而“\(”则匹配“(”。
^ 开始
$ 结束
* 匹配前面的子表达式零次或多次
+ 匹配前面的子表达式一次或多次
? 匹配前面的子表达式零次或一次
. 匹配除”\n“ 外的任何单个字符
\d 匹配一个数字
.+ 除\n 外的任意子表达式一次或多次

lua基本语法

先大致的了解下lua。内容摘自 http://www.runoob.com/lua/lua-tutorial.html

Lua 是一种轻量小巧的脚本语言,用标准C语言编写并以源代码形式开放, 其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。
Lua 特性
轻量级: 它用标准C语言编写并以源代码形式开放,编译后仅仅一百余K,可以很方便的嵌入别的程序里。
*可扩展: *Lua提供了非常易于使用的扩展接口和机制:由宿主语言(通常是C或C++)提供这些功能,Lua可以使用它们,就像是本来就内置的功能一样。
其它特性:

  • 支持面向过程(procedure-oriented)编程和函数式编程(functional programming);
  • 自动内存管理;只提供了一种通用类型的表(table),用它可以实现数组,哈希表,集合,对象;
  • 语言内置模式匹配;闭包(closure);函数也可以看做一个值;提供多线程(协同进程,并非操作系统所支持的线程)支持;
  • 通过闭包和table可以很方便地支持面向对象编程所需要的一些关键机制,比如数据抽象,虚函数,继承和重载等。

a = 5               -- 全局变量
local b = 5         -- 局部变量
~=                  --表示非运算
-- 流程控制
if(boolean_expression)
then
   --[ statement(s) will execute if the boolean expression is true --]
else if( boolean_expression 2)
   --[ Executes when the boolean expression 2 is true --]
else 
   --[ executes when the none of the above condition is true --]
end
-- 嵌套
if( 布尔表达式 1)
then
   --[ 布尔表达式 1 为 true 时执行该语句块 --]
   if(布尔表达式 2)
   then
      --[ 布尔表达式 2 为 true 时执行该语句块 --]
   end
end
-- 使用 .. 进行字符串连接
print("连接字符串",string1..string2..string3)

在大致了解了字符串、变量、流程控制后,我们就可以简单的实现lua中的代码了。

nginx、lua、imageMagic 安装

nginx 、lua、和imageMagic的安装可参照这篇文章。

代码实现细节

nginx中重点就是匹配url,当符合规则的url时进行图片生成和剪裁。
首先看我们要实现的图片规则,xxx.jpg_200x200f_q80.jpg.webp,我们需要通过url规则生成不同的图片尺寸和大小。
nginx中代码示例

location ~* ^(.+\.(jpg|jpeg|gif|png))_(\d+)x(\d+)(f?)\.(jpg|jpeg|gif|png)(\.webp)?$ {
            if (!-f $request_filename) {
                access_log /usr/local/nginx/logs/ImageResizer.log main;
                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 /home/leewr/mono/app$1;    # 设置原始图片路径,如:/document_root/1.gif
                set $width $3;    # 设置裁剪/缩放的宽度
                set $height $4;    # 设置裁剪/缩放的高度
                set $enforce $5; # 是否强制裁剪
                set $ext $6;    # 图片文件格式后缀
                set $webp $7; # 支持webp返回webp图片格式图片
                #content_by_lua_block {
                    #ngx.say(ngx.var.noresize)
                #}
                content_by_lua_file lua/ImageResizer.lua;
            }
        }

这里的正则我们分组匹配了以.+ 开始的任意字符然后是jpg,再是_ \d+x\d+ (f?) 零次或一次最后是jpg|jeg|gif|png结尾,最后是webp。
通过正则的匹配我们拿到$1, $2, $3等值并赋值给$width\$height等变量,最后在lua图片转换中调用,执行相关图片转换命令。
lua中代码简单实现

local sizeType
local command
if ngx.var.enforce == 'f'
then
    command = "convert "..ngx.var.request_filepath.." -resize "..ngx.var.width.."x"..ngx.var.height.."^ -gravity center -extent ".. ngx.var.width .. "x" .. ngx.var.height .." "..ngx.var.request_filepath.."_"..ngx.var.width.."x"..ngx.var.height..ngx.var.enforce.."."..ngx.var.ext
    sizeType = "f"
else
    command = "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.enforce .. "." .. ngx.var.ext
    sizeType = ""
end

-- local command = "convert  " ..ngx.var.request_filepath.." -resize ".. ngx.var.width .. "x" .. ngx.var.height .. ngx.var.enforce .. " +profile \"*\" " .. ngx.var.request_filepath .. "_" .. ngx.var.width .. "x" .. ngx.var.height .. ngx.var.enforce .. "." .. ngx.var.ext
if ngx.var.webp == ".webp"
then
    command = command ..ngx.var.webp
end
-- ngx.say(ngx.var.noresize)
os.execute(command)
ngx.exec(ngx.var.request_uri)

过程不复杂,当enforce为强制转换的时候设置command命令,当有webp格式转换的时候生成webp图片。最后调用os.execute()执行imageMagic命令进行转换。最后返回请求的图片地址,此时图片已经生成,图片正确显示。

总结

通过了nginx层我们实现了一个图片资源的尺寸转换裁剪功能。在往更深层一面思考,是否可以做更多?将资源的管理统一起来,形成一个独立的资源管理服务。所有的图片操作都采用统一的管理。

上一篇 下一篇

猜你喜欢

热点阅读