Preface
Duplicate layer using inkscape extension.
Here we are going to learn to alter XML tree.
Preparation
Put your replacable text in a layer named Template
.
This template layer is belong to to level layer called Container
.
Now, also consider to have a look at the XML properties:
Notice that there is a child the text
,
and a grandchild the tspan
.
We are going to alter the text inside the tspan
.
Duplicate Layer Extension
Artefacts
We need two files.
duplicate_layer.inx
duplicate_layer.py
Duplicate Layer XML
<?xml version="1.0" encoding="UTF-8"?>
<inkscape-extension
xmlns="http://www.inkscape.org/namespace/inkscape/extension">
<name>Duplicate Layers</name>
<id>epsi.duplicate</id>
<effect>
<object-type>all</object-type>
<effects-menu>
<submenu name="Epsi"/>
</effects-menu>
</effect>
<script>
<command location="inx"
interpreter="python">duplicate_layer.py</command>
</script>
</inkscape-extension>
Duplicate Layer Python
Now we are ready to go to the coding part using python.
The structure of the extension is shown as below.
#!/usr/bin/env python
import inkex
import sys, copy
class DuplicateLayer(inkex.EffectExtension):
...
if __name__ == '__main__':
DuplicateLayer().run()
Notice that we need to import copy
for object duplication.
Effect Method
This is the main method in our inkscape extension.
def effect(self):
all_layers = self.get_layers()
container = self.find_layer(all_layers,'Container')
source_layer = self.find_layer(all_layers, 'Template')
self.duplicate_layer(
container, source_layer,
'Zeta Mataharani', 'Zeta Mataharani, MD')
We are using hardcoded layer name,
such as Container
and Template
.
I will explain the duplicate_layer
method, later.
For now, we discuss the result first.
Result
Disclaimer: I’have been using the Mataharani
name,
as example mockup for more than one decades.
even my home wifi SSID is Mataharani
.
The name Zeta Mataharani
will be used for layer name
and the Zeta Mataharani, MD
will be used for display text in tspan
.
Now, consider go back to see how the code works under the hood.
Consider begin with the get_layers
method,
then duplicate_layer
method, and the rest following.
Finding Layers
Consider begin with the get_layers
method,
then duplicate_layer
method, and the rest following.
Get Layers
It is simply list comprehension. Or to be exact, dict comprehension.
This look for any layer object.
def get_layers(self):
return {g
for g in self.svg.xpath('//svg:g')
if g.get('inkscape:groupmode') == 'layer'
}
We will be using this as:
def effect(self):
all_layers = self.get_layers()
container = self.find_layer(all_layers,'Container')
source_layer = self.find_layer(all_layers, 'Template')
So how to find the layer?
First Occurence
This is just about finding first occurence of layer label.
def find_layer(self, layers, label_name):
for layer in layers:
name = layer.get('inkscape:label')
if name == label_name:
return layer
return None
I’m not sure about my code. This above works, but I guess there is better way to do this. After all this is not a javascript DOM library.
Duplicate Layer
Deepcopy
The main course is just a deepcopy
new_layer = copy.deepcopy(source_layer)
container.append(new_layer)
Then append it to Container
layer.
Alter Name and Visibility
But I begin to think about, changing the layer label and the visibility. So I have this code
def duplicate_layer(self, container, source_layer, layer_label):
new_layer = copy.deepcopy(source_layer)
new_layer.label = layer_label
new_layer.style = 'display:none'
container.append(new_layer)
Alter Text
And more feature, change the tspan
text.
The Template
layer might has one or a few TextElement
,
but each TextElement
only has one tspan
.
for node in new_layer:
if isinstance(node, inkex.TextElement):
tspan = node[0]
tspan.text = text_span
Final Method
Finally we have this
def duplicate_layer(self, container, source_layer, layer_label, text_span):
new_layer = copy.deepcopy(source_layer)
new_layer.label = layer_label
new_layer.style = 'display:none'
container.append(new_layer)
for node in new_layer:
if isinstance(node, inkex.TextElement):
tspan = node[0]
tspan.text = text_span
Complete Code
For your comfort, this below is the complete code.
#!/usr/bin/env python
import inkex
import sys, copy
class DuplicateLayer(inkex.EffectExtension):
def get_layers(self):
return {g
for g in self.svg.xpath('//svg:g')
if g.get('inkscape:groupmode') == 'layer'
}
def find_layer(self, layers, label_name):
for layer in layers:
name = layer.get('inkscape:label')
if name == label_name:
return layer
return None
def duplicate_layer(self, container, source_layer, layer_label, text_span):
new_layer = copy.deepcopy(source_layer)
new_layer.label = layer_label
new_layer.style = 'display:none'
container.append(new_layer)
for node in new_layer:
if isinstance(node, inkex.TextElement):
tspan = node[0]
tspan.text = text_span
def effect(self):
all_layers = self.get_layers()
container = self.find_layer(all_layers,'Container')
source_layer = self.find_layer(all_layers, 'Template')
self.duplicate_layer(
container, source_layer,
'Zeta Mataharani', 'Zeta Mataharani, MD')
if __name__ == '__main__':
DuplicateLayer().run()
Looks not pretty useful? Wogh.. you should read the next automation part. This short code above really save my working hours.
What is Next ?
Consider continue reading [ Inkscape Automation - Part One ].
Thank you for reading.