事实上ImageMagick是可以很好地支持svg的——当然,它只是将svg转成图片格式而不能反过来,毕竟它只是个图片处理工具。不论是在使用convert,identify还是mogrify等等时,只要操作的对象是一个.svg文件,那么ImageMagick就会启动这一机制。例如,当你使用identify查看一个.svg信息的时候,事实上你是在查看它转换后得到的一张.png图片:
> identify -verbose your.svg
Image: /var/folders/w9/fy0l4xgj3w73j4d71748v9nw0000gn/T/magick-481524PstlAlieWiB
Base filename: your.svg
Format: PNG (Portable Network Graphics)
Mime type: image/png
Class: DirectClass
...
ImageMagick主要有三种支持SVG的方式,包括内置(Internal)、内建(Build-in)和委托(Delegate)。
在高版本的ImageMagick中MSVG总是内置的;而稍早些的版本中,ImageMagick是混合了『内建』和『委托』两种方式来提供SVG的支持的。需要强调的是:
请尽量不要直接使用内置的MSVG。
内置的MSVG
ImageMagick的高版本内置了一个SVG渲染器。它有两种称谓,在代码中叫做IMAGEMAGICK_SVG
,例如在编译中提供相应的开关参数;而在用户级别的配置或接口中,它称为MSVG(这里的M是Magick的首字母)。它完整的名称是ImageMagick's own SVG internal renderer
,所以自有SVG(Own SVG)
、内部渲染器(internal renderer)
以及MSVG
其实指的都是同一个东西:
> convert -list format | grep SVG
MSVG SVG rw+ ImageMagick's own SVG internal renderer
SVG SVG rw+ Scalable Vector Graphics (XML 2.9.4)
SVGZ SVG rw+ Compressed Scalable Vector Graphics (XML 2.9.4)
注意这里的『XML 2.9.4』其实也是MSVG引擎的一部分,它实际上指的是libxml2
这个库的版本,因为MSVG是基于xml解析并自行渲染的svg引擎。
由于MSVG存在很多限制,所以ImageMagick『千万百计』地隐藏了它的存在——哈哈,其实没有这么夸张,它们是承认这个东西的存在并且提供官方支持的(在这里)。
在ImageMagick 6.6.7-10之后的版本中,MSVG总是缺省内置支持(WITH_IMAGEMAGICK_SVG
参数缺省打开),即使是在WITHOUT_X11
状态下,编译过程也只是给出WARN级别的警告。
而在此前( 但晚于v6.3.3-5之后的)版本中,如果WITHOUT_X11
,那么编译时将不会内置支持SVG。
任何情况下,如果你只是想启用MSVG(以避开其它引擎的影响),那么你可以在input文件名上加上"msvg:"前缀(v6.3.4以后)。例如:
> identify -verbose 'msvg:your.svg'
Image: your.svg
Base filename: b2t_8-2.svg
Format: MVG (Magick Vector Graphics)
Class: DirectClass
Geometry: 485x306+0+0
...
你也可以使用-draw
参数来开启一个MSVG的画板并操作它。例如(将这块画板作为源,转换成PNG格式输出):
# http://www.imagemagick.org/Usage/draw/#svg
> convert -size 10x6 xc:skyblue -fill black \
-draw 'color 6,3 point' -scale 100x60 draw_color_point.png
内建模式及其开启
如果ImageMagick在安装时包含librsvg模块,那么就会启用内建模式(所以Build-in SVG也往往直接称为RSVG)。一旦包含这个模块,那么它的优先级比内置的MSVG要高。
如果你是使用brew来安装的ImageMagick,那么你可以用:
> brew info imagemagick
...
Optional: fontconfig ✔, little-cms ✘, little-cms2 ✔, libwmf ✘, librsvg ✔ ...
来查看当前环境是否能支持rsvg。如上,librsvg
已经安装了,那么就可以通过安装参数来开启它(或使用brew reinstall
重新安装):
# 你可能需要先安装librsvg模块
# - brew install librsvg
> brew install imagemagick --with-librsvg
如果你不是使用brew,那么你可以使用如下命令来查看:
> convert -list configure | grep -Eoe '--with-rsvg(=[^\-]+)?'
--with-rsvg=no
如果没有rsvg的支持,那么你需要自己编译ImageMagick,相关的操作在这里。
如果你成功安装了rsvg支持,那么可以看到如下信息:
# build-in的delegate中包含了rsvg
> identify -version | grep --color rsvg
Delegates (built-in): bzlib cairo fontconfig freetype jng jpeg ltdl lzma png rsvg tiff xml zlib
# 或format中使用了rsvg来支持svg
> identify -list format | grep -i svg
convert -list format | grep -i svg
MSVG SVG rw+ ImageMagick's own SVG internal renderer
SVG SVG rw+ Scalable Vector Graphics (RSVG 2.40.17)
SVGZ SVG rw+ Compressed Scalable Vector Graphics (RSVG 2.40.17)
注1:一些资料中称需要使用
--use-rsvg
参数在编译中开启rsvg支持,这可能是一个被放弃的、早期的构建参数。注2:在brew中用的参数是
--with-librsvg
,而实际上编译时使用的是--with-rsvg
参数。这个转换操作是在brew安装用的formula文件中完成的。
委托模式的开启
通常情况下,ImageMagick会在内置的MSVG和内建模式(RSVG)之间选择一个;如果二者都没有,那么它会选择第三种,也就是委托模式。
你总是可以通过如下命令查看ImageMagick委托(外部程序)来进行的图形转换,包括SVG:
> convert -list delegate | grep 'svg'
...
svg => "rsvg-convert' -o '%o' '%i"
注:严格来说,前面说的内建模式事实上也是一种委托。只不过它是在编译时build-in的,所以在
--help
参数显示的信息中就能直接看到,并且会影响-format
显示的格式支持;而在-list delegate
所列举的委托关系中,却并不会出现。
由于只有MSVG和rsvg都不生效时才会开启委托模式,但高版本中ImageMagick中总是内置MSVG,所以是很难触发委托模式的。因此,如果你做这个尝试,那么你需要一个不内置MSVG的低版本ImageMagick,并且在编译中关闭--with-rsvg
选项。OK,这样你就可以看到ImageMagick调用了上述委托中的rsvg-convert
来进行转换。
当然,也有例外,因为其实还是有一个后门来做这件事的,这就是所谓的内部委托。
内部委托
准确地说法:MSVG这个内部渲染器提供了一个『内部委托(special internal delegates)』。这种内部委托与上面的rsvg-convert
采用的是类似机制,但是通过-list delegate
命令是无法查看到的——你得打开配置文件自己来找:
# 查看你的ImageMagick将读取哪些配置文件
> convert -debug all -list delegate 2>&1 | grep 'delegates.xml'
Searching for configure file: ...
...
Path: /usr/local/Cellar/imagemagick/7.0.5-9/etc/ImageMagick-7/delegates.xml
注意前面有一个搜索优先顺序的列表(你可能用得上),不过这里我们只需要关心最后这个Path
就好了。打开这个文件,查找svg:decode
,将stealth="True"
删除掉。现在你就可以看到它了:
> convert -list delegate | grep -Ee 'svg(:decode)? ='
svg => "rsvg-convert' -o '%o' '%i"
svg:decode => "inkscape' '%s' --export-png='%s' --export-dpi='%s' --export-background='%s' --export-background-opacity='%s' > '%s' 2>&1"
注:内部委托与一般的(外部程序的)委托模式处理逻辑是一样的,只是在高版本的ImageMagick用
svg:decode
替代了svg
这个入口而已。
是的,你应该已经注意到了,这个内部的委托指向了inkscape。你可以安装inkscape来支持这个委托。例如:
> brew cask install xquartz inkscape
接管内部委托
你也可以自己写个脚本来将操作转发到你的处理程序(类似于代理)。例如:
#!/bin/bash
DPI="${3##*=}"
rsvg-convert --format=png --output="${2##*=}" --dpi-x="${DPI%%,*}" --dpi-y="${DPI##*,}" --background-color="${4##*=}" "$1"
将这个脚本另存到搜索路径中,并命名为inkscape
,加上可执行权限。OK,你就看到svg:decode
的相关调用转发到你的脚本中,并交给rsvg-convert处理了。
注意:如果内部委托调用出错(程序退出代码大于0),那么ImageMagick将再次调用MSVG来完成处理。
当然,我们也可以把这个接管的脚本程序写得通用一点。比如将delegates.xml中的svg:decode
项修改到一个统一的模式(以后就可以不用改了,不过sv要注意其中的YOUR_SCRIPT_NAME
应该修改得与后面的脚本名一致):
<delegate decode="svg:decode" command=""YOUR_SCRIPT_NAME" "%s" "%s" "%s" "%s" "%s" > "%s" 2>&1"/>
然后安装自己的工具(下面以cairosvg这个工具为例,首先安装它):
# @see: http://cairosvg.org/
> pip3 install cairosvg
然后写调用脚本(YOUR_SCRIPT_NAME
):
#!/bin/bash
# in arguments:
# inFile outFile dpi bgColor bgOpacity
DPIX="${3%%,*}" # format - xRes,yRes
BGCOLOR="$4" # format - string, #xxxxxx, or rgb(r%,g%,b%)
cairosvg -f png -o "$2" -d "$DPIX" "$1"
最后将这个脚本另存、更名、更改可执行权限。
在你使用identify、convert等等工具处理svg时,都将调用上述脚本。所以,现在你可以随意用新的转换工具来替换MSVG了。
我的开源项目svg-provider是一个较完整的实现,其主要是在参数的处理上面进行了优化,并且可以适配更多的转换工具。