def test_get_elements(self): """ Tests that elements passed to the constructor are used """ root = etree.Element("root") element1 = etree.SubElement(root, "path") element2 = etree.SubElement(root, "rect") extractor = PathsExtractor([element1, element2], to_mm, "wId") self.assertEqual(extractor.get_elements(), [element1, element2])
def test_remove_working_area(self): """ Tests that the working area is not considered among svg elements to use """ root = etree.Element("root") working_area = etree.SubElement(root, "svg", {"id": "wId"}) other_element = etree.SubElement(root, "path") extractor = PathsExtractor([working_area, other_element], to_mm, "wId") self.assertEqual(extractor.get_elements(), [other_element])
def place(self, nodes): max_line_width = self.unittouu('450mm') x_gap = y_gap = self.unittouu('10mm') x_start = self.unittouu('3mm') y_start = self.unittouu('1600mm') - self.unittouu('3mm') total_width = 0 total_height = 0 line_nodes = [] group = etree.SubElement(self.current_layer, addNS('g', 'svg')) for id, node, bbox in nodes: x, _, y, _ = bbox node_width = x_gap + self.width(bbox) # reached end of line, reset, move higher, start new group if total_width + node_width > max_line_width: group = etree.SubElement(self.current_layer, addNS('g', 'svg')) total_width = 0 total_height += self.height( self.computeBBox(line_nodes)) + y_gap line_nodes = [] group.append(node) x_dest = x_start + total_width y_dest = y_start - (total_height + self.height(bbox)) if node.tag == addNS('path', 'svg'): x_delta = x_dest - x y_delta = y_dest - y path = parsePath(node.attrib['d']) translatePath(path, x_delta, y_delta) node.attrib['d'] = formatPath(path) elif node.tag == addNS('g', 'svg'): x_delta = x_dest - x y_delta = y_dest - y translation_matrix = [[1.0, 0.0, x_delta], [0.0, 1.0, y_delta]] applyTransformToNode(translation_matrix, node) else: node.attrib['x'] = str(x_dest) node.attrib['y'] = str(y_dest) total_width += node_width line_nodes.append(node)
def test_closed_paths(self): """ Tests that closed paths are extracted correctly by repeating the first point at the end """ root = etree.Element("root") group = etree.SubElement(root, "{http://www.w3.org/2000/svg}g") etree.SubElement(group, "{http://www.w3.org/2000/svg}path", {'d': "M 70,800 l 125,-300 l 60,490 Z"}) extractor = PathsExtractor([group], to_mm, "wId") extractor.extract() self.assertEqual(len(extractor.paths()), 1) self.assertEqual(extractor.paths()[0], [(70.0, 800.0), (195.0, 500.0), (255.0, 990.0), (70.0, 800.0)])
def test_extract_paths_inside_group_keeping_transform(self): #pylint: disable=invalid-name """ Tests that extracted path from a group take the transformation into account """ root = etree.Element("root") group = etree.SubElement(root, "{http://www.w3.org/2000/svg}g", {'transform': "matrix(1,2,3,4,5,6)"}) etree.SubElement(group, "{http://www.w3.org/2000/svg}path", {'d': "M 10,20 L 50,30 L 20,70"}) extractor = PathsExtractor([group], to_mm, "wId") extractor.extract() self.assertEqual(extractor.paths()[0], [(75.0, 106.0), (145.0, 226.0), (235.0, 326.0)])
def test_extract_path_inside_groups(self): #pylint: disable=invalid-name """ Tests that a path inside a group is correctly extracted """ root = etree.Element("root") group = etree.SubElement(root, "{http://www.w3.org/2000/svg}g") etree.SubElement(group, "{http://www.w3.org/2000/svg}path", {'d': "M 70,800 l 125,-300 l 60,490"}) extractor = PathsExtractor([group], to_mm, "wId") extractor.extract() self.assertEqual(len(extractor.paths()), 1) self.assertEqual(extractor.paths()[0], [(70.0, 800.0), (195.0, 500.0), (255.0, 990.0)])
def test_extract_paths_inside_group_keeping_nested_transform(self): #pylint: disable=invalid-name """ Tests that extracted path from elements with nested transformation works correctly """ root = etree.Element("root") group = etree.SubElement(root, "{http://www.w3.org/2000/svg}g", {'transform': "translate(10,20)"}) subgroup = etree.SubElement(group, "{http://www.w3.org/2000/svg}g", {'transform': "matrix(1,2,3,4,5,6)"}) etree.SubElement(subgroup, "{http://www.w3.org/2000/svg}path", {'d': "M 10,20 L 50,30 L 20,70"}) extractor = PathsExtractor([group], to_mm, "wId") extractor.extract() self.assertEqual(extractor.paths()[0], [(85.0, 126.0), (155.0, 246.0), (245.0, 346.0)])
def add(self): if not self.options.deckname: raise inkcardsError( "You need to give the deck name you want to add a card to.") svg = self.document.getroot() nsmap = dict(svg.nsmap, inkcards=icNS) card = etree.SubElement(svg, addNS('card', 'inkcards'), nsmap=nsmap) card.attrib['id'] = self.uniqueId('card') card.attrib[addNS('deck', 'inkcards')] = self.options.deckname card.attrib[addNS('number', 'inkcards')] = self.nextCardNB(card.attrib[addNS( 'deck', 'inkcards')]) for lname in self.activeLayers: l = etree.SubElement(card, addNS('using', 'inkcards'), nsmap=nsmap) l.attrib[addNS('layer', 'inkcards')] = lname self.list()
def test_use_parent_transform_for_single_path_with_multiple_parents(self): #pylint: disable=invalid-name """ Tests that extracted path takes all the ancestors transformations into account """ root = etree.Element("root", {'transform': "scale(10)"}) parent = etree.SubElement(root, "{http://www.w3.org/2000/svg}g", {'transform': "translate(10,20)"}) element = etree.SubElement(parent, "{http://www.w3.org/2000/svg}path", { 'transform': "matrix(1,2,3,4,5,6)", 'd': "M 10,20 L 50,30 L 20,70" }) extractor = PathsExtractor([element], to_mm, "wId") extractor.extract() self.assertEqual(extractor.paths()[0], [(850.0, 1260.0), (1550.0, 2460.0), (2450.0, 3460.0)])
def __add_name(self, name, layer): if self.separate_sizes: parent = self.__get_layer(layer) else: parent = self.current_layer text_attribs = { 'style': self.text_style, 'transform': self.text_transform, 'x': str(0), 'y': str(0), addNS('linespacing', 'sodipodi'): str(self.line_spacing), } line_attribs = { 'x': str(0), 'y': str(0), addNS('role', 'sodipodi'): 'line', } # make all-caps and turn whitespace into linebreak lines = name.upper().split() # skip empty strings if len(lines) > 0: # add nodes to doucument tree text = etree.SubElement(parent, addNS('text', 'svg'), attrib=text_attribs) for line in lines: text_line = etree.SubElement(text, addNS('tspan', 'svg'), attrib=line_attribs) text_line.text = line # set coordinates for next line y = float(line_attribs['y']) line_attribs['y'] = str(y + self.delta_y) if self.separate_sizes: self.__sort_layers()
def test_upsert_does_not_create_duplicated_working_area(self): # pylint: disable=invalid-name """ Tests that upsert does not insert a new working area if it is already present """ generator = WorkingAreaGenerator(self.to_uu, "wId") root = etree.Element("root") etree.SubElement(root, "svg", {"id": "wId"}) generator.upsert(root) self.assertEqual(len(root), 1) self.assertEqual(root[0].tag, "svg") self.assertEqual(root[0].get("id"), "wId")
def fill_row(self, node): #max_line_width = self.svg.unittouu('450mm') #x_start = self.svg.unittouu('3mm') #y_start = self.svg.unittouu('1600mm') - self.svg.unittouu('3mm') #gap_x = gap_y = self.svg.unittouu('10mm') svg = self.document.getroot() x_start = 0 y_start = self.svg.unittouu(svg.attrib['height']) max_line_width = self.svg.unittouu(svg.get('width')) total_width = 0 total_height = self.total_height group = etree.SubElement(self.svg.get_current_layer(), addNS('g', 'svg')) bbox = node.bounding_box() x = bbox.left y = bbox.top node_width = self.options.gap_x + bbox.width while total_width + node_width < max_line_width: node_copy = deepcopy(node) group.append(node_copy) x_dest = x_start + total_width y_dest = y_start - (total_height + bbox.height) # translation logic if node_copy.tag == addNS('path', 'svg'): x_delta = x_dest - x y_delta = y_dest - y path = Path(node_copy.attrib['d']) path.translate(x_delta, y_delta, True) node_copy.attrib['d'] = str(Path(path)) elif node_copy.tag == addNS('g', 'svg'): x_delta = x_dest - x y_delta = y_dest - y translation_matrix = [[1.0, 0.0, x_delta], [0.0, 1.0, y_delta]] Transform(translation_matrix) * node_copy.transform else: node_copy.attrib['x'] = str(x_dest) node_copy.attrib['y'] = str(y_dest) total_width += node_width self.total_height += group.bounding_box().height + self.options.gap_y
def test_extract_paths_inside_groups_and_outside(self): #pylint: disable=invalid-name """ Tests that a mix of paths inside groups and outside are correctly extracted """ root = etree.Element("root") element = etree.SubElement(root, "{http://www.w3.org/2000/svg}path", {'d': "M 70,800 l 125,-300 l 60,390"}) group = etree.SubElement(root, "{http://www.w3.org/2000/svg}g") etree.SubElement(group, "{http://www.w3.org/2000/svg}path", {'d': "M 70,800 l 125,-300 l 60,490"}) etree.SubElement(group, "{http://www.w3.org/2000/svg}path", {'d': "M 60,700 l 127,-500 l 70,900"}) extractor = PathsExtractor([element, group], to_mm, "wId") extractor.extract() self.assertEqual(len(extractor.paths()), 3) self.assertEqual(extractor.paths()[0], [(70.0, 800.0), (195.0, 500.0), (255.0, 890.0)]) self.assertEqual(extractor.paths()[1], [(70.0, 800.0), (195.0, 500.0), (255.0, 990.0)]) self.assertEqual(extractor.paths()[2], [(60.0, 700.0), (187.0, 200.0), (257.0, 1100.0)])
def test_extract_svg_path_with_only_straight_lines(self): #pylint: disable=invalid-name """ Tests that svg paths are correctly extracted """ root = etree.Element("root") element = etree.SubElement(root, "{http://www.w3.org/2000/svg}path", {'d': "M 70,800 l 125,-300 l 60,490"}) extractor = PathsExtractor([element], to_mm, "wId") extractor.extract() self.assertEqual(len(extractor.paths()), 1) self.assertEqual(extractor.paths()[0], [(70.0, 800.0), (195.0, 500.0), (255.0, 990.0)])
def test_throw_exception_for_unrecognized_svg_element(self): #pylint: disable=invalid-name """ Tests that an exception is thrown for unrecognized svg elements """ root = etree.Element("root") element = etree.SubElement(root, "invalidElement") extractor = PathsExtractor([element], to_mm, "wId") with self.assertRaises(UnrecognizedSVGElement) as context_manager: extractor.extract() exception = context_manager.exception self.assertEqual(exception.element, "invalidElement")
def test_use_parent_transform_for_multiple_path(self): #pylint: disable=invalid-name """ Tests that extracted path takes the parent transformation into account """ root1 = etree.Element("root", {'transform': "translate(10,20)"}) element1 = etree.SubElement(root1, "{http://www.w3.org/2000/svg}path", { 'transform': "matrix(1,2,3,4,5,6)", 'd': "M 10,20 L 50,30 L 20,70" }) root2 = etree.Element("root", {'transform': "translate(5,10)"}) element2 = etree.SubElement(root2, "{http://www.w3.org/2000/svg}path", { 'transform': "matrix(1,2,3,4,5,6)", 'd': "M 10,20 L 50,30 L 20,70" }) extractor = PathsExtractor([element1, element2], to_mm, "wId") extractor.extract() self.assertEqual(extractor.paths()[0], [(85.0, 126.0), (155.0, 246.0), (245.0, 346.0)]) self.assertEqual(extractor.paths()[1], [(80.0, 116.0), (150.0, 236.0), (240.0, 336.0)])
def test_extract_multiple_paths_when_lines_interrupted(self): #pylint: disable=invalid-name """ Tests that multiple paths are generated when svg path is not continuos """ root = etree.Element("root") element = etree.SubElement( root, "{http://www.w3.org/2000/svg}path", {'d': "M 70,800 l 125,-300 l 60,490 M 100,100 L 200,200"}) extractor = PathsExtractor([element], to_mm, "wId") extractor.extract() self.assertEqual(len(extractor.paths()), 2) self.assertEqual(extractor.paths()[0], [(70.0, 800.0), (195.0, 500.0), (255.0, 990.0)]) self.assertEqual(extractor.paths()[1], [(100.0, 100.0), (200.0, 200.0)])
def test_closed_paths_with_multiple_paths(self): #pylint: disable=invalid-name """ Tests that closed paths are extracted correctly also when multiple subpaths are present """ root = etree.Element("root") element = etree.SubElement( root, "{http://www.w3.org/2000/svg}path", {'d': "M 70,800 l 125,-300 l 60,490 Z M 100,100 L 200,200"}) extractor = PathsExtractor([element], to_mm, "wId") extractor.extract() self.assertEqual(len(extractor.paths()), 2) self.assertEqual(extractor.paths()[0], [(70.0, 800.0), (195.0, 500.0), (255.0, 990.0), (70.0, 800.0)]) self.assertEqual(extractor.paths()[1], [(100.0, 100.0), (200.0, 200.0)])
def fill_row(self, node): max_line_width = self.unittouu('450mm') x_gap = y_gap = self.unittouu('10mm') x_start = self.unittouu('3mm') y_start = self.unittouu('1600mm') - self.unittouu('3mm') total_width = 0 total_height = self.total_height group = etree.SubElement(self.current_layer, addNS('g', 'svg')) bbox = computeBBox([node]) x, _, y, _ = bbox node_width = x_gap + self.width(bbox) while total_width + node_width < max_line_width: node_copy = deepcopy(node) group.append(node_copy) x_dest = x_start + total_width y_dest = y_start - (total_height + self.height(bbox)) # translation logic if node_copy.tag == addNS('path', 'svg'): x_delta = x_dest - x y_delta = y_dest - y path = parsePath(node_copy.attrib['d']) translatePath(path, x_delta, y_delta) node_copy.attrib['d'] = formatPath(path) elif node_copy.tag == addNS('g', 'svg'): x_delta = x_dest - x y_delta = y_dest - y translation_matrix = [[1.0, 0.0, x_delta], [0.0, 1.0, y_delta]] applyTransformToNode(translation_matrix, node_copy) else: node_copy.attrib['x'] = str(x_dest) node_copy.attrib['y'] = str(y_dest) total_width += node_width self.total_height += self.height(computeBBox(group)) + y_gap
def draw_rect(self, x, y, width, height): layer = self.current_layer style = { 'stroke': '#ff0000', 'stroke-width': '1', 'fill': 'none', } attribs = { 'style': formatStyle(style), 'x': str(x), 'y': str(y), 'width': str(width), 'height': str(height), } rect = etree.SubElement(layer, addNS('rect', 'svg'), attribs)
def test_automatically_close_open_paths_does_nothing_if_paths_closed(self): #pylint: disable=invalid-name """ Tests that nothing changes if closing paths is requested but paths are closed """ root = etree.Element("root") element = etree.SubElement( root, "{http://www.w3.org/2000/svg}path", { 'd': ("M 70,800 l 125,-300 l 60,490 Z " "M 100,100 L 200,200 L 100,100") }) extractor = PathsExtractor([element], to_mm, "wId") extractor.extract() self.assertEqual(len(extractor.paths()), 2) self.assertEqual(extractor.paths()[0], [(70.0, 800.0), (195.0, 500.0), (255.0, 990.0), (70.0, 800.0)]) self.assertEqual(extractor.paths()[1], [(100.0, 100.0), (200.0, 200.0), (100.0, 100.0)])
def test_automatically_close_open_paths(self): #pylint: disable=invalid-name """ Tests that open paths are automatically closed if requested """ root = etree.Element("root") element = etree.SubElement( root, "{http://www.w3.org/2000/svg}path", {'d': "M 70,800 l 125,-300 l 60,490 M 100,100 L 200,200"}) extractor = PathsExtractor([element], to_mm, "wId", auto_close_path=True) extractor.extract() self.assertEqual(len(extractor.paths()), 2) self.assertEqual(extractor.paths()[0], [(70.0, 800.0), (195.0, 500.0), (255.0, 990.0), (70.0, 800.0)]) self.assertEqual(extractor.paths()[1], [(100.0, 100.0), (200.0, 200.0), (100.0, 100.0)])
def paint(self, working_area): """ Draws the border in the working area :param working_area: the working area where the path is to be drawn :type working_area: an instance of the WirkingAreaGenerator """ self.working_area = working_area if self.border_is_to_be_drawn(): border_x = self.working_area.get_factor() * self.border.left() border_y = self.working_area.get_factor() * self.border.bottom() border_width = self.working_area.get_factor() * self.border.width() border_height = self.working_area.get_factor() * self.border.height() line_width = self.working_area.get_factor() * 0.25 etree.SubElement(self.working_area.get_element(), "rect", { 'x': str(border_x), 'y': str(border_y), 'width': str(border_width), 'height': str(border_height), 'style': ("stroke-width:{0};stroke-miterlimit:4;stroke-dasharray:0.25,0.25;" "stroke-dashoffset:0;fill:none").format(line_width)})
def __get_layer(self, label): root = self.document.getroot() # tidy up the label label = label.strip().upper() label = re.sub(' +', ' ', label) # no label, just return current layer if len(label) == 0: return self.current_layer # return layer if already exists for layer in root: if layer.get(addNS('label', 'inkscape'), default=None) == str(label): return layer # otherwise create new one layer_attrib = { addNS('groupmode', 'inkscape'): 'layer', addNS('label', 'inkscape'): str(label), } layer = etree.SubElement(root, addNS('g', 'svg'), attrib=layer_attrib) return layer
def test_flatten_path_if_requested(self): """ Tests that path is flattened if the constructor flatten parameter is not None """ root = etree.Element("root") element = etree.SubElement(root, "{http://www.w3.org/2000/svg}path", {'d': "dummy value to check"}) class FlattenMock: #pylint: disable=missing-docstring,too-few-public-methods def __init__(self, test): self.test = test def __call__(self, curve): #pylint: disable=missing-docstring self.test.assertEqual(curve, "dummy value to check") return [('M', (70.0, 800.0)), ('L', (195.0, 500.0)), ('L', (255.0, 990.0))] extractor = PathsExtractor([element], to_mm, "wId", FlattenMock(self)) extractor.extract() self.assertEqual(len(extractor.paths()), 1) self.assertEqual(extractor.paths()[0], [(70.0, 800.0), (195.0, 500.0), (255.0, 990.0)])
def split_fill_and_stroke(path_node): """Split a path into two paths, one filled and one stroked Returns a the list [fill, stroke], where each is the XML element of the fill or stroke, or None. """ style = simplestyle.parseStyle(path_node.get("style", "")) # If there is only stroke or only fill, don't split anything if "fill" in style.keys() and style["fill"] == "none": if "stroke" not in style.keys() or style["stroke"] == "none": return [None, None] # Path has neither stroke nor fill else: return [None, path_node] if "stroke" not in style.keys() or style["stroke"] == "none": return [path_node, None] group = path_node.makeelement(addNS("g", "svg")) fill = etree.SubElement(group, addNS("path", "svg")) stroke = etree.SubElement(group, addNS("path", "svg")) attribs = path_node.attrib if "d" in attribs.keys(): d = attribs["d"] del attribs["d"] else: raise AssertionError, "Cannot split stroke and fill of non-path element" if addNS("nodetypes", "sodipodi") in attribs.keys(): nodetypes = attribs[addNS("nodetypes", "sodipodi")] del attribs[addNS("nodetypes", "sodipodi")] else: nodetypes = None if "id" in attribs.keys(): path_id = attribs["id"] del attribs["id"] else: path_id = str(id(path_node)) if "style" in attribs.keys(): del attribs["style"] if "transform" in attribs.keys(): transform = attribs["transform"] del attribs["transform"] else: transform = None # Pass along all remaining attributes to the group for attrib_name in attribs.keys(): group.set(attrib_name, attribs[attrib_name]) group.set("id", path_id) # Next split apart the style attribute style_group = {} style_fill = {"stroke": "none", "fill": "#000000"} style_stroke = {"fill": "none", "stroke": "none"} for key in style.keys(): if key.startswith("fill"): style_fill[key] = style[key] elif key.startswith("stroke"): style_stroke[key] = style[key] elif key.startswith("marker"): style_stroke[key] = style[key] elif key.startswith("filter"): style_group[key] = style[key] else: style_fill[key] = style[key] style_stroke[key] = style[key] if len(style_group) != 0: group.set("style", simplestyle.formatStyle(style_group)) fill.set("style", simplestyle.formatStyle(style_fill)) stroke.set("style", simplestyle.formatStyle(style_stroke)) # Finalize the two paths fill.set("d", d) stroke.set("d", d) if nodetypes is not None: fill.set(addNS("nodetypes", "sodipodi"), nodetypes) stroke.set(addNS("nodetypes", "sodipodi"), nodetypes) fill.set("id", path_id + "-fill") stroke.set("id", path_id + "-stroke") if transform is not None: fill.set("transform", transform) stroke.set("transform", transform) # Replace the original node with the group path_node.getparent().replace(path_node, group) return [fill, stroke]