Code

5e9de002bfa48d4e1e92a78453491a6607e21bbe
[inkscape.git] / share / extensions / split.py
1 #!/usr/bin/env python 
2 '''
3 Copyright (C) 2009 Karlisson Bezerra, contato@nerdson.com
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 '''
20 import inkex
22 class Split(inkex.Effect):
23     def __init__(self):
24         inkex.Effect.__init__(self)
25         self.OptionParser.add_option("-s", "--splittype", 
26                         action="store", type="string", 
27                         dest="split_type", default="word", 
28                         help="type of split")
29         self.OptionParser.add_option("-p", "--preserve", 
30                         action="store", type="inkbool", 
31                         dest="preserve", default="True", 
32                         help="Preserve original")
35     def split_lines(self, node):
36         """Returns a list of lines"""
38         lines = []
39         count = 1
40         
41         for n in node:
42             if not (n.tag == inkex.addNS("flowPara", "svg") or n.tag == inkex.addNS("tspan", "svg")):
43                 if n.tag == inkex.addNS("textPath", "svg"):
44                     inkex.debug("This type of text element isn't supported. First remove text from path.")
45                     break
46                 else:
47                     continue
48            
49             text = inkex.etree.Element(inkex.addNS("text", "svg"), node.attrib)
50             
51             #handling flowed text nodes
52             if node.tag == inkex.addNS("flowRoot", "svg"):
53                 try:
54                     from simplestyle import parseStyle
55                     fontsize = parseStyle(node.get("style"))["font-size"]
56                 except:
57                     fontsize = "12px"
58                 fs = inkex.unittouu(fontsize)
59                 
60                 #selects the flowRegion's child (svg:rect) to get @X and @Y
61                 id = node.get("id")
62                 flowref = self.xpathSingle('/svg:svg//*[@id="%s"]/svg:flowRegion[1]' % id)[0]
63                 
64                 if flowref.tag == inkex.addNS("rect", "svg"):
65                     text.set("x", flowref.get("x"))
66                     text.set("y", str(float(flowref.get("y")) + fs * count))
67                     count += 1
68                 else:
69                     inkex.debug("This type of text element isn't supported. First unflow text.")
70                     break
71                 
72                 #now let's convert flowPara into tspan
73                 tspan = inkex.etree.Element(inkex.addNS("tspan", "svg"))
74                 tspan.set(inkex.addNS("role","sodipodi"), "line")
75                 tspan.text = n.text
76                 text.append(tspan)
77             
78             else:
79                 from copy import copy
80                 x = n.get("x") or node.get("x")
81                 y = n.get("y") or node.get("y")
83                 text.set("x", x)
84                 text.set("y", y)
85                 text.append(copy(n))
86             
87             lines.append(text)
89         return lines
92     def split_words(self, node):
93         """Returns a list of words"""
94         
95         words = []
97         #Function to recursively extract text
98         def plain_str(elem):
99             words = []
100             if elem.text:
101                 words.append(elem.text)
102             for n in elem:
103                 words.extend(plain_str(n))
104                 if n.tail:
105                     words.append(n.tail)
106             return words
107         
108         #if text has more than one line, iterates through elements
109         lines = self.split_lines(node)
110         if not lines:
111             return words
113         for line in lines:
114             #gets the position of text node
115             x = float(line.get("x"))
116             y = line.get("y")
117             
118             #gets the font size. if element doesn't have a style attribute, it assumes font-size = 12px
119             try:
120                 from simplestyle import parseStyle
121                 fontsize = parseStyle(line.get("style"))["font-size"]
122             except:
123                 fontsize = "12px"
124             fs = inkex.unittouu(fontsize)
126             #extract and returns a list of words
127             words_list = "".join(plain_str(line)).split()
128             prev_len = 0
129             
130             #creates new text nodes for each string in words_list
131             for word in words_list:
132                 tspan = inkex.etree.Element(inkex.addNS("tspan", "svg"))
133                 tspan.text = word
134                 
135                 text = inkex.etree.Element(inkex.addNS("text", "svg"), line.attrib)
136                 tspan.set(inkex.addNS("role","sodipodi"), "line")
137                 
138                 #positioning new text elements
139                 x = x + prev_len * fs
140                 prev_len = len(word)
141                 text.set("x", str(x))
142                 text.set("y", str(y))
143                 
144                 text.append(tspan)
145                 words.append(text)
146         
147         return words
150     def split_letters(self, node):
151         """Returns a list of letters"""
153         letters = []
154         
155         words = self.split_words(node)
156         if not words:
157             return letters
159         for word in words:
160             
161             x = float(word.get("x"))
162             y = word.get("y")
163            
164             #gets the font size. If element doesn't have a style attribute, it assumes font-size = 12px
165             try:
166                 import simplestyle
167                 fontsize = simplestyle.parseStyle(word.get("style"))["font-size"]
168             except:
169                 fontsize = "12px"
170             fs = inkex.unittouu(fontsize)
172             #for each letter in element string
173             for letter in word[0].text:
174                 tspan = inkex.etree.Element(inkex.addNS("tspan", "svg"))
175                 tspan.text = letter
177                 text = inkex.etree.Element(inkex.addNS("text", "svg"), node.attrib)
178                 text.set("x", str(x))
179                 text.set("y", str(y))
180                 x += fs
181                 
182                 text.append(tspan)
183                 letters.append(text)
184         return letters
187     def effect(self):
188         """Applies the effect"""
190         split_type = self.options.split_type
191         preserve = self.options.preserve
192        
193         #checks if the selected elements are text nodes
194         for id, node in self.selected.iteritems():
195             if not (node.tag == inkex.addNS("text", "svg") or node.tag == inkex.addNS("flowRoot", "svg")):
196                 inkex.debug("Please select only text elements.")
197                 break
198             else:
199                 if split_type == "line":
200                     nodes = self.split_lines(node)
201                 elif split_type == "word":
202                     nodes = self.split_words(node)
203                 elif split_type == "letter":
204                     nodes = self.split_letters(node)
205                 
206                 for n in nodes:
207                     node.getparent().append(n)
208                         
209                 #preserve original element
210                 if not preserve and nodes:
211                     parent = node.getparent()
212                     parent.remove(node)
214 b = Split()
215 b.affect()