背景
在 Stack Overflow 上问了个问题然后尝试自己解决,发现除了在链接SVG上右键选择“嵌入图像”选项之外,并没有其他的解法。“嵌入图像”其实也不能解决问题,只是将原图转为 base64 格式,并不能实现子图内容可编辑。所幸 Inkscape 支持使用 Python 作为脚本开发扩展,最后还是转向了用自定义扩展解决问题。同时也发现国内关于 Inkscape 扩展开发的内容实在是凤毛麟角,故写下一点使用心得,希望能够抛砖引玉。入门相对来说还是容易的,即使教程不多,通过阅读源码,也能够了解到一些用法,在两天之内便能够写出一个简单的实现上述功能的扩展。
代码
伸手党可以直接访问我的仓库。
Inkscape 扩展开发教程资源示例:
原型
扩展原型来自 Inkscape 官方 Gitlab 仓库的《My First Effect Extension》教程,项目压缩包直接下载链接。跟着教程就能初步定制自己的扩展界面了。
debug
一旦按照上述教程将项目文件夹放到 Inkscape 指定的扩展目录并重启 Inkscape 使之识别以后,每当我们修改了代码,可以不必重启 Inkscape,只需要重新运行自己的扩展,代码的改变就能立马显现出来。
想查看自己扩展的运行信息,可以使用self.msg
这个函数将自己想 debug 的信息输出来,方便查错。
XPath
在SVG文件中查找特定节点可以用self.document.xpath
函数,第一个参数是 XPath 表达式字符串,第二个参数是inkex.NSS
,这个参数在下文会介绍。
xlink:href
链接SVG使用xlink:href
链接源图片,虽然对于一个节点,获取其属性可以使用类似node.attrib['id']
这样的方法,但是xlink:href
中冒号前面的xlink
属于“命名空间”,使用node.attrib['xlink:href']
是获取不到值的。其实xlink:href
全写是{http://www.w3.org/1999/xlink}href
,使用该键才能获取到其值。
inkex.NSS
inkex
是inkscape
+extension
的缩写,是一个 Python 的 Inkscape 扩展包。字典inkex.NSS
存储了SVG的命名空间,即SVG代码中下面这部分的字典化:
<svg
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
为了防止xlink
这个命名空间以后发生变化,可以不硬编码{http://www.w3.org/1999/xlink}href
,而是用'{{{0}}}href'.format(inkex.NSS['xlink'])
这样的方法来获取xlink:href
的全写。
tag
修改标签名可以通过类似element.tag = 'xxx'
这样的写法来修改,这里将标签名修改成了xxx
。不过要注意的是,这里同样需要带上svg
的命名空间,即element.tag = '{{{0}}}g'.format(inkex.NSS['svg'])
,这里将标签名修改成了群组,即svg:g
。
通过插件导入 SVG
从这里可以看到inkex.elements
下有个load_svg
函数,可以将 SVG 地址链接(可通过node.attrib['{{{0}}}href'.format(inkex.NSS['xlink'])]
获取)通过lxml
包转为 XML 节点对象,方便我们查询与引用、插入。在父元素下插入新的节点使用的是father.append(child)
这样的方式。
Image 对象转 Group 对象的注意事项
需要注意的是,将 image 标签转为 g 标签以后,x
、y
、width
、height
这些属性对 g 标签是无法生效的,需要转换为transform
属性,即设置该属性值为translate(x,y) scale(width/oWidth, height/oHeight)
,x
与y
、width
、height
从原 image 标签获取,oWidth
和oHeight
从 image 标签所引用的 SVG 图像的svg:svg
节点中获取。注意一开始获取到的值是字符串类型,需要转换为 float 类型才能进行运算;还要注意度量单位,这里我偷懒,默认我获取到的值的单位都是px
,不排除有些是mm
、cm
,自己注意写代码检测与转换。如此设置以后,便能得到与 image 标签一样的图像大小、位置效果,实现从 linked SVG 到 included SVG 的无缝转换。
便捷模块
Inkscape 除了 inkex 模块以外,还有一些便捷模块方便你的开发,如simpletransform
,可以将上述的 transform 由文本设置改为用函数设置(详情)。但由于官方 Wiki 的这则公告,我不打算使用这些便捷模块。