split.py revision 20e9b1f7cd4a3104e934c17ed5536a259054ad84
#!/usr/bin/env python
'''
Copyright (C) 2009 Karlisson Bezerra, contato@nerdson.com
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
'''
import inkex
class Split(inkex.Effect):
def __init__(self):
inkex.Effect.__init__(self)
self.OptionParser.add_option("-s", "--splittype",
action="store", type="string",
dest="split_type", default="word",
help="type of split")
self.OptionParser.add_option("-p", "--preserve",
action="store", type="inkbool",
dest="preserve", default="True",
help="Preserve original")
def split_lines(self, node):
"""Returns a list of lines"""
lines = []
count = 1
for n in node:
if not (n.tag == inkex.addNS("flowPara", "svg") or n.tag == inkex.addNS("tspan", "svg")):
if n.tag == inkex.addNS("textPath", "svg"):
inkex.debug("This type of text element isn't supported. First remove text from path.")
break
else:
continue
text = inkex.etree.Element(inkex.addNS("text", "svg"), node.attrib)
#handling flowed text nodes
if node.tag == inkex.addNS("flowRoot", "svg"):
try:
from simplestyle import parseStyle
fontsize = parseStyle(node.get("style"))["font-size"]
except:
fontsize = "12px"
fs = inkex.unittouu(fontsize)
#selects the flowRegion's child (svg:rect) to get @X and @Y
id = node.get("id")
flowref = self.xpathSingle('/svg:svg//*[@id="%s"]/svg:flowRegion[1]' % id)[0]
if flowref.tag == inkex.addNS("rect", "svg"):
text.set("x", flowref.get("x"))
text.set("y", str(float(flowref.get("y")) + fs * count))
count += 1
else:
inkex.debug("This type of text element isn't supported. First unflow text.")
break
#now let's convert flowPara into tspan
tspan = inkex.etree.Element(inkex.addNS("tspan", "svg"))
tspan.set(inkex.addNS("role","sodipodi"), "line")
tspan.text = n.text
text.append(tspan)
else:
from copy import copy
x = n.get("x") or node.get("x")
y = n.get("y") or node.get("y")
text.set("x", x)
text.set("y", y)
text.append(copy(n))
lines.append(text)
return lines
def split_words(self, node):
"""Returns a list of words"""
words = []
#Function to recursively extract text
def plain_str(elem):
words = []
if elem.text:
words.append(elem.text)
for n in elem:
words.extend(plain_str(n))
if n.tail:
words.append(n.tail)
return words
#if text has more than one line, iterates through elements
lines = self.split_lines(node)
if not lines:
return words
for line in lines:
#gets the position of text node
x = float(line.get("x"))
y = line.get("y")
#gets the font size. if element doesn't have a style attribute, it assumes font-size = 12px
try:
from simplestyle import parseStyle
fontsize = parseStyle(line.get("style"))["font-size"]
except:
fontsize = "12px"
fs = inkex.unittouu(fontsize)
#extract and returns a list of words
words_list = "".join(plain_str(line)).split()
prev_len = 0
#creates new text nodes for each string in words_list
for word in words_list:
tspan = inkex.etree.Element(inkex.addNS("tspan", "svg"))
tspan.text = word
text = inkex.etree.Element(inkex.addNS("text", "svg"), line.attrib)
tspan.set(inkex.addNS("role","sodipodi"), "line")
#positioning new text elements
x = x + prev_len * fs
prev_len = len(word)
text.set("x", str(x))
text.set("y", str(y))
text.append(tspan)
words.append(text)
return words
def split_letters(self, node):
"""Returns a list of letters"""
letters = []
words = self.split_words(node)
if not words:
return letters
for word in words:
x = float(word.get("x"))
y = word.get("y")
#gets the font size. If element doesn't have a style attribute, it assumes font-size = 12px
try:
import simplestyle
fontsize = simplestyle.parseStyle(word.get("style"))["font-size"]
except:
fontsize = "12px"
fs = inkex.unittouu(fontsize)
#for each letter in element string
for letter in word[0].text:
tspan = inkex.etree.Element(inkex.addNS("tspan", "svg"))
tspan.text = letter
text = inkex.etree.Element(inkex.addNS("text", "svg"), node.attrib)
text.set("x", str(x))
text.set("y", str(y))
x += fs
text.append(tspan)
letters.append(text)
return letters
def effect(self):
"""Applies the effect"""
split_type = self.options.split_type
preserve = self.options.preserve
#checks if the selected elements are text nodes
for id, node in self.selected.iteritems():
if not (node.tag == inkex.addNS("text", "svg") or node.tag == inkex.addNS("flowRoot", "svg")):
inkex.debug("Please select only text elements.")
break
else:
if split_type == "line":
nodes = self.split_lines(node)
elif split_type == "word":
nodes = self.split_words(node)
elif split_type == "letter":
nodes = self.split_letters(node)
for n in nodes:
node.getparent().append(n)
#preserve original element
if not preserve and nodes:
parent = node.getparent()
parent.remove(node)
b = Split()
b.affect()