summaryrefslogtreecommitdiff
path: root/renderer/support/pogojig/inkscape/inkscape.py
blob: efe767710acc6a721a974f23589583d7d006f0ab (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
import os
import subprocess
import xml.etree.ElementTree as etree

def get_inkscape_layers(svg_path):
    document = etree.parse(svg_path)
    
    layers = []
    nodes = document.findall(
        '{http://www.w3.org/2000/svg}g[@{http://www.inkscape.org/namespaces/inkscape}groupmode="layer"]')
    
    for i in nodes:
        inkscape_name = i.get('{http://www.inkscape.org/namespaces/inkscape}label').strip()
        
        if inkscape_name.endswith(']'):
            export_name, args = inkscape_name[:-1].rsplit('[', 1)
            
            export_name = export_name.strip()
            args = args.strip()
            
            use_paths = 'p' in args
        else:
            use_paths = False
            export_name = inkscape_name
        
        layers.append(Layer(inkscape_name, export_name, use_paths))
    return layers


def _inkscape(svg_path, verbs):
    subprocess.run([os.environ.get('INKSCAPE', 'inkscape'), *(x for verb in verbs for x in ('--verb', verb)), svg_path])


class Layer(object):
    def __init__(self, inkscape_name, export_name, use_paths):
        self.inkscape_name = inkscape_name
        self.export_name = export_name
        self.use_paths = use_paths


class InkscapeCommandLine(object):
    def __init__(self, path):
        self._path = path
        self._layers = get_inkscape_layers(path)
        self._current_layer_index = None
        self._verbs = []
    
    def apply_to_document(self, *verb):
        self._verbs.extend(verb)
    
    def apply_to_layer(self, layer, *verb):
        self._go_to_layer(layer)
        self.apply_to_document(*verb)
    
    def select_all_in_layer(self, layer):
        self.apply_to_layer(layer, 'EditSelectAll')
    
    def apply_to_layer_content(self, layer, *verbs):
        self.select_all_in_layer(layer)
        self.apply_to_document(*verbs)
    
    def _go_to_layer(self, layer, with_selection=False):
        if self._current_layer_index is None:
            # Initialize to a known state. We cannot assume that any layer is
            #  selected and thus we need as many LayerPrev as we have layers.
            self._current_layer_index = len(self._layers)
            self._go_to_layer(self._layers[0])
        
        target_index = self._layers.index(layer)
        
        if with_selection:
            next_command = 'LayerMoveToNext'
            previous_command = 'LayerMoveToPrev'
        else:
            next_command = 'LayerNext'
            previous_command = 'LayerPrev'
        
        while self._current_layer_index != target_index:
            if self._current_layer_index < target_index:
                self.apply_to_document(next_command)
                self._current_layer_index += 1
            else:
                self.apply_to_document(previous_command)
                self._current_layer_index -= 1
        
        if with_selection:
            # When using LayerMoveToNext and LayerMoveToPrev, inkscape does
            # not reliably select the next/previous layer.
            self._current_layer_index = None
    
    def duplicate_layer(self, layer):
        self.apply_to_layer(layer, 'LayerDuplicate')

        # Inkscape 0.91 places a duplicated layer above (after) the selected
        # one and selects the new layer.
        new_layer = Layer(layer.inkscape_name + ' copy', layer.export_name, layer.use_paths)
        self._layers.insert(self._current_layer_index + 1, new_layer)
        
        # Whether the original or the new layer is selected after the operation
        # fluctuates between Inkscape versions.
        self._current_layer_index = None
        
        return new_layer
    
    def delete_layer(self, layer):
        self.apply_to_layer(layer, 'LayerDelete')
        
        # Inkscape 0.91 selects the layer above (after) the deleted layer.
        del self._layers[self._current_layer_index]
    
    def clear_layer(self, layer):
        self.select_all_in_layer(layer)
        self.apply_to_document('EditDelete')
    
    def move_content(self, source_layer, target_layer):
        self.select_all_in_layer(source_layer)
        self._go_to_layer(target_layer, True)
    
    def run(self):
        _inkscape(self._path, self._verbs)
    
    @property
    def layers(self):
        return list(self._layers)