在 Mac 上用 ImageMagick 转换 SVG

使用 ImageMagick

ImageMagick 是老牌的图片解决方案了,这次在 node.js 项目里本想用它的一个演进项目 GraphicsMagick,只可惜,在同样使用 gm 这个 npm 的情况下,GraphicsMagick 对中文的支持太不好了,于是在折腾一番后,还是选择放弃尝试新的事物,转为继续使用各方面技术支持更广泛的老大哥 ImageMagick。

我的需求是需要将 SVG 转为 Raster Graphics (位图),例如将如下 SVG 转为 JPG:

http://www.w3.org/TR/2009/WD-SVGCompositing-20090430/examples/over.svg

结果转换成 JPG 后,图片变成:

内容细节严重丢失,内嵌图片不见了。

经过各种参数调整,可问题依然。此时,查看官方文档发现一些问题:

ImageMagick 对 SVG 支持三种格式:MSVG, SVG, SVGZ。MSVG 为 ImageMagick 的内建库;SVG 和 SVGZ 则依赖其他一些库,比如,官方推荐的 RSVG。

于是用命令查看对 SVG 的支持情况:

1
convert -list format | grep SVG

返回

1
2
3
MSVG  SVG       rw+   ImageMagick's own SVG internal renderer
SVG SVG rw+ Scalable Vector Graphics (XML 2.7.8)
SVGZ SVG rw+ Compressed Scalable Vector Graphics (XML 2.7.8)

XML?!坑爹啊!果然不是 RSVG 库,还不是得很奇葩……

好吧!装库!

一堆问题

先安装 librsvg 库,在 Mac 下我目前采用 brew 解决包管理,所以:

1
brew install librsvg

结果报错,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
librsvg: Unsatisfied dependency: XQuartz
Homebrew does not package XQuartz. Installers may be found at:
https://xquartz.macosforge.org
cairo: Unsatisfied dependency: XQuartz
Homebrew does not package XQuartz. Installers may be found at:
https://xquartz.macosforge.org
pango: Unsatisfied dependency: XQuartz
Homebrew does not package XQuartz. Installers may be found at:
https://xquartz.macosforge.org
gtk+: Unsatisfied dependency: XQuartz 2.3.6
Homebrew does not package XQuartz. Installers may be found at:
https://xquartz.macosforge.org
Error: An unsatisfied requirement failed this build.

这才发现,原来 Mac 10.8 上没有 X11,好吧,安装一个,Apple 官方推荐的下载地址:

http://xquartz.macosforge.org/landing/

是 dmg 文件,如何安装就是不用说了。XQuartz 安装完之后,再次运行安装 librsvg 的命令就势如破竹了。

librsvg 安装好之后需要重新安装 ImageMagick,网上找到 —use-rsvg 这个参数,但结果是又一次坑爹了。一阵安装编译等待之后,依旧显示 (XML 2.7.8)!!!什么情况呢?重新进入无尽的搜索,最后是从 brew 源代码里找到当前 brew 版本中的正确参数 —with-librsvg。源码见:

https://github.com/mxcl/homebrew/blob/master/Library/Formula/imagemagick.rb

结果执行如下命令就成功了…

1
brew reinstall imagemagick --with-librsvg --with-webp

检验一下:

1
2
3
4
convert -list format | grep SVG
MSVG SVG rw+ ImageMagick's own SVG internal renderer
SVG SVG rw+ Scalable Vector Graphics (RSVG 2.36.3)
SVGZ SVG rw+ Compressed Scalable Vector Graphics (RSVG 2.36.3)

另外,如果此时还有问题,识别不到 RSVG 的话,请添加以下环境变量:

1
export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/opt/X11/lib/pkgconfig

而,如果是使用 port 的,命令如下:

1
port install imagemagick +rsvg

按理到这里为止,ImageMagick 已经可以正常通过 librsvg 来渲染 SVG 格式的图片了,但是在我的 Mac 环境里始终存在丢失 xlink 进来的外链 image 的问题。于是又进入了茫然……

不要妄自菲薄

为了解决 node.js 下使用 ImageMagick 来处理图片的问题,前后折腾了几个小时,当所有已知问题都解决的时候一切回到原点。很不甘,是哪儿弄错了?于是又折腾了几个小时……

由于使用场景和使用的细节已然是少数需求了,国内相关文字几乎为零,英文站点上的内容也极少。stackoverflow 上尽是提问的,回答了了,更多的是根本没有回答。

突然,因为连续几篇文字提到了 ImageMagick 的不同版本对于类似的 convert 时出现的 bug,于是我怀疑是我环境里 ImageMagick 版本的问题。立刻在服务器环境中进行了测试(ImageMagick 6.5.4-7 with RSVG 2.26.0 on CentOS)果然,一切正常了!OMG!

出错的是 ImageMagick 6.8.6-3 with RSVG 2.36.3 版本,貌似是 RSVG 的错误,具体哪里出错暂时无力再去验证。具体错误表现是:

  • xlink:href=”abc.png” 同目录丢失
  • xlink:href=”./abc.png” 相对路径丢失
  • xlink:href=”/path/to/abc.png” 绝对路径丢失
  • xlink:href=”data:image/png;base64,…=” 内嵌 Base64 格式正常

最后得到正确的图像输出:


此时,我想说,虽然常提“不要妄自菲薄”,但是做到还是挺难的。质疑问题需要的是锲而不舍的精神和精湛的技艺,我辈还不具备两者,还没勇气去怀疑知名软件库,真是还需努力!