背景
在 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 的這則公告,我不打算使用這些便捷模塊。