作为国内最早的一批PHP程序员,在图形库选用上从最早的GD切换到ImageMagick后再未更换过,其以强大的API,远胜GD的图文能力以及强劲的性能给我留下了深刻的映像。近来因疫情闲来无事,也算是与时俱进,玩起了OpenResty并打算造几个轮子,其中一个轮子需要进行图片处理,作为ImageMagick的忠实粉丝自然要探究一下Lua下的ImageMagick Binding。
我们先从包管理器开始,Lua的主流包管理名为Luarocks,在OpenResty下使用需要先行安装:
1 | 下载当前最新版Luarocks |
因为OpenResty作为一个集成了Nginx+lua-nginx-module+LuaJIT的独立发行版,为了使Luarocks安装的包可以匹配OpenResty并能被直接require,需要将其安装到OpenResty目录内并使用其内置的LuaJIT作为解释器。
接下来就可以看一下Luarocks提供了哪些与ImageMagick相关的包可供使用:
1 | luarocks search imagemagick |
一无所获,出乎意料,但Openresty还提供了一个包管理名为opm,试试看:
1 | root@test:/usr/local/openresty/bin# ./opm search imagemagick |
opm返回了一个结果,可以拿来试一下,但在这里需要注意的是,Lua不同于PHP/Python等语言,内置了丰富的三方模块并由成熟的社区/商业机构维护,普通用户开封即用。Lua的三方模块多是由开源爱好者基于自己的需求开发并贡献给他人使用,普遍缺乏全面的测试和长期维护,在选用时务必进行甄别。
opm索引的lua-resty-magick托管于Github,2018年1月22日创建了仓库,当天内提交了五次后便沉寂至今,没有任何Issue,版本停留在0.0.1,也仅仅只实现了五个方法的封装,可以视为一个荒废的项目。虽然基于LuaJIT的ffi接口可以快速地封装ImageMagick的C库函数,但作为非业务模块如果有现成的轮子又何必再去造呢,于是我又在Github上进行了一轮搜索(基于Recently updated排序),找到了下面两个有一定星数,最后一次更新不晚于2年的项目:
- leafo/magick 323 Stars & Updated on 7 Apr
- isage/lua-imagick 50 Stars & Updated on 3 Jul 2019
第一个项目是由搞出了MoonScript的大神leafo创建并维护,今年4月还修了一次内存泄露的bug。第二个项目由一位俄罗斯开发者维护,今年没有任何更新,但对Issue的处理很勤勉。两个项目都实现了对ImageMagick基本功能的OOP封装,但在实现方式上迥异,支持的功能也略有差别,如下表所示:
leafo/magick | isage/lua-imagick | |
---|---|---|
封装方式 | FFI | C Module |
封装库 | ImageMagick&GraphicsMagick | ImageMagick |
LuaJIT | ✔ | ✔ |
Luarocks | ✔ | × |
装载 | 文件&BLOB | 文件&BLOB |
裁剪 | ✔ | ✔ |
旋转 | ✔ | ✔ |
模糊 | ✔ | ✔ |
锐化 | ✔ | ✔ |
格式转换 | ✔ | ✔ |
比例缩放 | ✔ | ✔ |
缩略图 | ✔ | ✔ |
画板 | × | ✔ |
调色 | × | ✔ |
文字嵌入 | × | ✔ |
总体综合来看,isage/lua-imagick对ImageMagick的封装较leafo/magick更为完整,实现方式上来讲也比FFI性能更高,leafo/magick胜在可以用Luarocks安装,我们此前未能找到该模块是因为Luarocks命令行不支持关键词查找,但通过网站搜素可以匹配到。
如果对文字嵌入没有需求,leafo/magick足以满足一般的需求,我们先安装它:
1 | 安装MagicWand |
接着安装isage/lua-imagick:
1 | 如果没有camke需要先安装 |
如果cmake不能找到你的OpenResty安装目录,可以修改cmake/FindLuaJIT.cmake文件或:
1 | cmake -DLUA_LIBRARY=/path of your openresty/luajit/lib/ \ |
接下来来用load from png->resize->save to jpg来做一个基准测试,代码分别如下:
- magick1.lua
1 | local magick = require "magick.wand" --eafo/magick |
- magick2.lua
1 | local magick = require "imagick" --isage/lua-imagick |
运行结果:
1 | time /usr/local/openresty/bin/resty magick1.lua |
结果让人大跌眼镜,让我对LuaJIT的FFI刮目相看,isage/lua-imagick采用的C Module封装除了在内存占用方面少消耗130kb,速度方面比采用FFI封装的eafo/magick慢了整整25%,也许是基准测试中基本都是call函数,所有的计算和文件操作都是在C中完成,没有涉及到太多FFI占劣势的部分,比如Lua和C的数据交换。
总之, 通过测试更加印证了上面说过的话,如果对文字嵌入没有需求,leafo/magick足以满足一般的需求,而且可以跑得更快!