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 fontsize = word.style.get("font-size", "12px") fs = self.svg.unittouu(fontsize) # for each letter in element string for letter in word[0].text: tspan = Tspan() tspan.text = letter text = TextElement(**node.attrib) text.set("x", str(x)) text.set("y", str(y)) x += fs text.append(tspan) letters.append(text) return letters
def split_lines(self, node): """Returns a list of lines""" lines = [] count = 1 for elem in node: if isinstance(elem, TextPath): inkex.errormsg( "Text on path isn't supported. First remove text from path." ) break elif not isinstance(elem, (FlowPara, Tspan)): continue text = TextElement(**node.attrib) # handling flowed text nodes if isinstance(node, FlowRoot): fontsize = node.style.get("font-size", "12px") fs = self.svg.unittouu(fontsize) # selects the flowRegion's child (svg:rect) to get @X and @Y flowref = node.findone('svg:flowRegion')[0] if isinstance(flowref, Rectangle): 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 = Tspan() tspan.set("sodipodi:role", "line") tspan.text = elem.text text.append(tspan) else: from copy import copy x = elem.get("x") or node.get("x") y = elem.get("y") or node.get("y") text.set("x", x) text.set("y", y) text.append(copy(elem)) lines.append(text) return lines
def generateText(self, text, x, y, size): tspan = Tspan() tspan.text = text textElement = TextElement() textElement.set("x", str(x)) textElement.set("y", str(y)) # textElement.style = "font-size:50px; font-family:Metal Lord" textElement.style = "font-size:{}px;".format(size) textElement.append(tspan) return textElement
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 fontsize = line.style.get("font-size", "12px") fs = self.svg.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 = Tspan() tspan.text = word text = TextElement(**line.attrib) tspan.set('sodipodi:role', "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 add_fixedtext(self, node, x, y, text, anchor, angle, dy=0): new = node.add(Tspan()) new.set('sodipodi:role', 'line') s = {'text-align': 'center', 'vertical-align': 'bottom', 'text-anchor': anchor, 'font-size': str(self.options.fontsize), 'fill-opacity': '1.0', 'stroke': 'none', 'font-weight': 'normal', 'font-style': 'normal', 'fill': '#000000'} new.style = s new.set('dy', str(dy)) if text[-2:] == "^2": new.append(Tspan.superscript("2")) new.text = str(text)[:-2] else: new.text = str(text) node.set('x', str(x)) node.set('y', str(y)) node.set('transform', 'rotate(%s, %s, %s)' % (angle, x, y))
def test_path(self): """Test getting paths""" self.assertFalse(TextPath().get_path()) self.assertFalse(TextElement().get_path()) self.assertFalse(FlowRegion().get_path()) self.assertFalse(FlowRoot().get_path()) self.assertFalse(FlowPara().get_path()) self.assertFalse(FlowSpan().get_path()) self.assertFalse(Tspan().get_path())
def add_textonpath(self, node, x, y, text, _node, anchor, startOffset, dy=0): new = node.add(TextPath()) s = {'text-align': 'center', 'vertical-align': 'bottom', 'text-anchor': anchor, 'font-size': str(self.options.fontsize), 'fill-opacity': '1.0', 'stroke': 'none', 'font-weight': 'normal', 'font-style': 'normal', 'fill': '#000000'} new.style = s new.href = _node new.set('startOffset', startOffset) new.set('dy', str(dy)) # dubious merit # new.append(tp) if text[-2:] == "^2": new.append(Tspan.superscript("2")) new.text = str(text)[:-2] else: new.text = str(text) # node.set('transform','rotate(180,'+str(-x)+','+str(-y)+')') node.set('x', str(x)) node.set('y', str(y))
def effect(self): if len(self.svg.selected) == 0: inkex.errormsg("Please select some paths first.") exit() for id, node in self.svg.selected.items(): id = node.get('id') self.group = node.getparent().add(TextElement()) csp = node.path.transform(node.composed_transform()).to_superpath() bbox = node.bounding_box() tx, ty = bbox.center anchor = 'middle' node = self.group new = node.add(Tspan()) new.set('sodipodi:role', 'line') s = { 'text-align': 'center', 'vertical-align': 'bottom', 'text-anchor': 'middle', 'font-size': str(self.options.fontsize) + 'px', 'font-weight': self.options.fontweight, 'font-style': 'normal', 'font-family': self.options.font, 'fill': str(self.options.color) } new.set('style', str(inkex.Style(s))) new.set('dy', '0') if self.options.capitals: id = id.upper() new.text = id.replace(self.options.replaced, self.options.replacewith) node.set('x', str(tx)) node.set('y', str(ty)) node.set('transform', 'rotate(%s, %s, %s)' % (-int(self.options.angle), tx, ty))
def test_append_superscript(self): """Test adding superscript""" tap = TextPath() tap.append(Tspan.superscript('th')) self.assertEqual(len(tap), 1)
def writeSVG(self, unfolding, size, printNumbers): mesh = unfolding[0] isFoldingEdge = unfolding[1] glueNumber = unfolding[3] foldingDirection = unfolding[4] # Calculate the bounding box [xmin, ymin, boxSize] = findBoundingBox(unfolding[0]) if size > 0: boxSize = size strokewidth = 0.002 * boxSize dashLength = 0.008 * boxSize spaceLength = 0.02 * boxSize textDistance = 0.02 * boxSize textStrokewidth = 0.05 * strokewidth textLength = 0.001 * boxSize fontsize = 0.015 * boxSize # Generate a main group paperfoldPageGroup = self.document.getroot().add( inkex.Group(id=self.svg.get_unique_id("paperfold-page-"))) # Go over all edges of the grid for edge in mesh.edges(): # The two endpoints he = mesh.halfedge_handle(edge, 0) vertex0 = mesh.point(mesh.from_vertex_handle(he)) vertex1 = mesh.point(mesh.to_vertex_handle(he)) # Write a straight line between the two corners line = paperfoldPageGroup.add(inkex.PathElement()) #line.path = [ # ["M", [vertex0[0], vertex0[1]]], # ["L", [vertex1[0], vertex1[1]]] # ] line.set( 'd', "M " + str(vertex0[0]) + "," + str(vertex0[1]) + " " + str(vertex1[0]) + "," + str(vertex1[1])) # Colour depending on folding direction lineStyle = {"fill": "none"} if foldingDirection[edge.idx()] > 0: lineStyle.update({"stroke": self.options.color_mountain_cut}) line.set("id", self.svg.get_unique_id("mountain-cut-")) elif foldingDirection[edge.idx()] < 0: lineStyle.update({"stroke": self.options.color_valley_cut}) line.set("id", self.svg.get_unique_id("valley-cut-")) lineStyle.update({"stroke-width": str(strokewidth)}) lineStyle.update({"stroke-linecap": "butt"}) lineStyle.update({"stroke-linejoin": "miter"}) lineStyle.update({"stroke-miterlimit": "4"}) # Dotted lines for folding edges if isFoldingEdge[edge.idx()]: lineStyle.update({ "stroke-dasharray": (str(dashLength) + ", " + str(spaceLength)) }) if foldingDirection[edge.idx()] > 0: lineStyle.update( {"stroke": self.options.color_mountain_perforate}) line.set("id", self.svg.get_unique_id("mountain-perforate-")) if foldingDirection[edge.idx()] < 0: lineStyle.update( {"stroke": self.options.color_valley_perforate}) line.set("id", self.svg.get_unique_id("valley-perforate-")) else: lineStyle.update({"stroke-dasharray": "none"}) lineStyle.update({"stroke-dashoffset": "0"}) lineStyle.update({"stroke-opacity": "1"}) line.style = lineStyle # The number of the edge to be glued if not isFoldingEdge[edge.idx()]: # Find halfedge in the face halfEdge = mesh.halfedge_handle(edge, 0) if mesh.face_handle(halfEdge).idx() == -1: halfEdge = mesh.opposite_halfedge_handle(halfEdge) vector = mesh.calc_edge_vector(halfEdge) # normalize vector = vector / np.linalg.norm(vector) midPoint = 0.5 * (mesh.point(mesh.from_vertex_handle(halfEdge)) + mesh.point(mesh.to_vertex_handle(halfEdge))) rotatedVector = np.array([-vector[1], vector[0], 0]) angle = np.arctan2(vector[1], vector[0]) position = midPoint + textDistance * rotatedVector rotation = 180 / np.pi * angle if (printNumbers): text = paperfoldPageGroup.add( TextElement(id=self.svg.get_unique_id("number-"))) text.set("x", str(position[0])) text.set("y", str(position[1])) text.set("font-size", str(fontsize)) text.set("style", "stroke-width:" + str(textStrokewidth)) text.set( "transform", "rotate(" + str(rotation) + "," + str(position[0]) + "," + str(position[1]) + ")") tspan = text.add(Tspan()) tspan.set("x", str(position[0])) tspan.set("y", str(position[1])) tspan.set("style", "stroke-width:" + str(textStrokewidth)) tspan.text = str(glueNumber[edge.idx()]) return paperfoldPageGroup