def _merge_transform(self, node, transform): """Propagate style and transform to remove inheritance Originally from https://github.com/nikitakit/svg2sif/blob/master/synfig_prepare.py#L370 """ # Compose the transformations if node.tag == addNS("svg", "svg") and node.get("viewBox"): vx, vy, vw, vh = [self._get_dimension(x) for x in node.get("viewBox").split()] dw = self._get_dimension(node.get("width", vw)) dh = self._get_dimension(node.get("height", vh)) t = ("translate(%f, %f) scale(%f, %f)" % (-vx, -vy, dw / vw, dh / vh)) this_transform = simpletransform.parseTransform( t, transform) this_transform = simpletransform.parseTransform( node.get("transform"), this_transform) del node.attrib["viewBox"] else: this_transform = simpletransform.parseTransform(node.get( "transform"), transform) # Set the node's transform attrib node.set("transform", simpletransform.formatTransform(this_transform))
def match( p1, p2, a1, a2 ): x = 0 y = 1 # distances dp = [ p2[x]-p1[x], p2[y]-p1[y] ] da = [ a2[x]-a1[x], a2[y]-a1[y] ] # angles angle_p = math.atan2( dp[x], dp[y] ) angle_a = math.atan2( da[x], da[y] ) # radians #rp = math.sqrt( dp[x]*dp[x] + dp[y]*dp[y] ) #ra = math.sqrt( da[x]*da[x] + da[y]*da[y] ) rp = math.hypot( dp[x], dp[y] ) ra = math.hypot( da[x], da[y] ) # scale scale = ra / rp # transforms in the order they are applied t1 = simpletransform.parseTransform( "translate(%f,%f)"%(-p1[x],-p1[y]) ) #t2 = simpletransform.parseTransform( "rotate(%f)"%(-angle_p) ) #t3 = simpletransform.parseTransform( "scale(%f,%f)"%(scale,scale) ) #t4 = simpletransform.parseTransform( "rotate(%f)"%angle_a ) t2 = rotateTransform(-angle_p) t3 = scaleTransform( scale, scale ) t4 = rotateTransform( angle_a ) t5 = simpletransform.parseTransform( "translate(%f,%f)"%(a1[x],a1[y]) ) # transforms in the order they are multiplied t = t5 t = simpletransform.composeTransform( t, t4 ) t = simpletransform.composeTransform( t, t3 ) t = simpletransform.composeTransform( t, t2 ) t = simpletransform.composeTransform( t, t1 ) # return the combined transform return t
def getHpgl(self): # dryRun to find edges groupmat = [[self.mirrorX * self.scaleX * self.viewBoxTransformX, 0.0, 0.0], [0.0, self.mirrorY * self.scaleY * self.viewBoxTransformY, 0.0]] groupmat = simpletransform.composeTransform(groupmat, simpletransform.parseTransform('rotate(' + self.options.orientation + ')')) self.vData = [['', -1.0, -1.0], ['', -1.0, -1.0], ['', -1.0, -1.0], ['', -1.0, -1.0]] self.processGroups(self.doc, groupmat) if self.divergenceX == 'False' or self.divergenceY == 'False' or self.sizeX == 'False' or self.sizeY == 'False': raise Exception('NO_PATHS') # live run self.dryRun = False if self.options.center: self.divergenceX += (self.sizeX - self.divergenceX) / 2 self.divergenceY += (self.sizeY - self.divergenceY) / 2 elif self.options.useToolOffset: self.options.offsetX += self.options.toolOffset self.options.offsetY += self.options.toolOffset groupmat = [[self.mirrorX * self.scaleX * self.viewBoxTransformX, 0.0, - self.divergenceX + self.options.offsetX], [0.0, self.mirrorY * self.scaleY * self.viewBoxTransformY, - self.divergenceY + self.options.offsetY]] groupmat = simpletransform.composeTransform(groupmat, simpletransform.parseTransform('rotate(' + self.options.orientation + ')')) self.vData = [['', -1.0, -1.0], ['', -1.0, -1.0], ['', -1.0, -1.0], ['', -1.0, -1.0]] # store first hpgl commands self.hpgl = 'IN;SP%d' % self.options.pen # add precut if self.options.useToolOffset and self.options.precut: self.processOffset('PU', 0, 0) self.processOffset('PD', 0, self.options.toolOffset * 8) # start conversion self.processGroups(self.doc, groupmat) # shift an empty node in in order to process last node in cache self.processOffset('PU', 0, 0) # add return to zero point self.hpgl += ';PU0,0;' return self.hpgl
def parse_gradient(self, node, d): if node.tag == addNS("linearGradient", "svg"): gradient_id = node.get("id", str(id(node))) x1 = float(node.get("x1", "0.0")) x2 = float(node.get("x2", "0.0")) y1 = float(node.get("y1", "0.0")) y2 = float(node.get("y2", "0.0")) mtx = simpletransform.parseTransform(node.get("gradientTransform")) link = node.get(addNS("href", "xlink"), "#")[1:] spread_method = node.get("spreadMethod", "pad") if link == "": stops = self.parse_stops(node, d) d.add_linear_gradient(gradient_id, [x1, y1], [x2, y2], mtx, stops=stops, spread_method=spread_method) else: d.add_linear_gradient(gradient_id, [x1, y1], [x2, y2], mtx, link=link, spread_method=spread_method) elif node.tag == addNS("radialGradient", "svg"): gradient_id = node.get("id", str(id(node))) cx = float(node.get("cx", "0.0")) cy = float(node.get("cy", "0.0")) r = float(node.get("r", "0.0")) fx = float(node.get("fx", "0.0")) fy = float(node.get("fy", "0.0")) mtx = simpletransform.parseTransform(node.get("gradientTransform")) link = node.get(addNS("href", "xlink"), "#")[1:] spread_method = node.get("spreadMethod", "pad") if link == "": stops = self.parse_stops(node, d) d.add_radial_gradient(gradient_id, [cx, cy], r, [fx, fy], mtx, stops=stops, spread_method=spread_method) else: d.add_radial_gradient(gradient_id, [cx, cy], r, [fx, fy], mtx, link=link, spread_method=spread_method)
def effect(self): self.getselected() if self.selected: for id, shape in self.selected.items(): self.recursiveFuseTransform(shape, parseTransform(None)) else: self.recursiveFuseTransform(self.document.getroot(), parseTransform(None))
def recursivelyTraverseSvg(self, nodeList=None, matCurrent=[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]], parent_visibility='visible' ): """ Based on the Eggbot extension for Inkscape. Recursively traverse the svg file to plot out all the paths. Keeps track of the composite transformation that should be applied to each path. Handles path, group. Doesn't yet handle line, text, rect, polyline, polygon, circle, ellipse and use (clone) elements. Unhandled elements should be converted to paths in Inkscape. Probably want to avoid paths with holes inside. """ if not nodeList: nodeList = self.svgRoot # get svg document width and height width, units_width = self.parseLengthAndUnits(nodeList.get("width")) height, units_height = self.parseLengthAndUnits(nodeList.get("height")) if units_width != units_height: print "Weird, units for SVG root document width and height differ..." print nodeList.get("width") print nodelist.get("height") sys.exit(1) # set initial viewbox from document root viewbox = nodeList.get("viewBox") print "Document size: %f x %f (%s)" % (width, height, units_width) if viewbox: vinfo = viewbox.strip().replace(',', ' ').split(' ') if (vinfo[2] != 0) and (vinfo[3] != 0): sx = width / float(vinfo[2]) sy = height / float(vinfo[3]) matCurrent = simpletransform.parseTransform("scale(%f, %f) translate(%f, %f)" % (sx, sy, -float(vinfo[0]), -float(vinfo[1]))) print "Initial transformation matrix:", matCurrent for node in nodeList: # Ignore invisible nodes v = node.get('visibility', parent_visibility) if v == 'inherit': v = parent_visibility if v == 'hidden' or v == 'collapse': pass # first apply the current matrix transform to this node's transform matNew = simpletransform.composeTransform( matCurrent, simpletransform.parseTransform(node.get("transform")) ) if node.tag in [self.svgQName("g"), "g"]: print "group tag - Might not be handled right!" self.recursivelyTraverseSvg( list(node), matNew, v ) elif node.tag in [self.svgQName("path")]: self.plotPath( node, matNew ) else: print "Other tag: '%s'" % node.tag
def effect(self): object2path.ObjectToPath.effect(self) transformMatrix = [[1,0,0],[0,1,0]] dims = self.determine_dims(transformMatrix) [x,y,X,Y] = dims width = X - x height = Y - y # Longest side is vertical if width > height: scale = 480.0 / height if scale * width > 999.0: inkex.errormsg("Plot area is to large (%f > 999)." % scale*height) exit() transformMatrix = parseTransform('translate(%f,%f)' % (-x,-y)) transformMatrix = composeTransform(parseTransform('rotate(-90)'), transformMatrix) transformMatrix = composeTransform(parseTransform('scale(%f,%f)' % (scale,scale)), transformMatrix) else: scale = 480.0 / width if scale * height > 999.0: inkex.errormsg("Plot area is to large (%f > 999)." % scale*height) exit() transformMatrix = parseTransform('translate(%f,%f)' % (-x,-y)) transformMatrix = composeTransform(parseTransform('rotate(180)'), transformMatrix) transformMatrix = composeTransform(parseTransform('translate(%f,0)' % width), transformMatrix) transformMatrix = composeTransform(parseTransform('scale(%f,%f)' % (-scale,scale)), transformMatrix) transformMatrix = composeTransform(parseTransform('translate(480,0)'), transformMatrix) paths = [] for [path, node] in self.processPaths(transformMatrix): color = (0, 0, 0) style = node.get('style') if style: style = simplestyle.parseStyle(style) if 'stroke' in style: if style['stroke'] and style['stroke'] != 'none': color = simplestyle.parseColor(style['stroke']) points = [] for point in self.processPath(path): points.append(point) paths.append({'color':color, 'points':points}) dims = self.determine_dims(transformMatrix) if self.options.debug: print >>sys.stderr, "VC1520 debug info" print >>sys.stderr, "-----------------" print >>sys.stderr, "plot area: minX:%d, minY:%d, maxX:%d, maxY:%d" % tuple(dims) print >>sys.stderr, "nr paths: %d" % len(paths) i = 0 print >>sys.stderr, "path;color;points" for path in paths: print >>sys.stderr, "%d;%s;%d" % (i,self.find_color(path['color']),len(path['points'])) i += 1 for path in paths: print >>sys.stderr, path else: self.plot(paths, dims[1])
def translateElement(self, node, x, y, relative=False): # Grab transform attribute if it exists. transform = node.get("transform", "") # Compute the nodes bounding box box = list(simpletransform.computeBBox([node])) pos_x = box[0] pos_y = box[2] # rotation center is not a breeze to calculate from the matrix, so thanks inkscape ;) origin_x = float(node.get(inkex.addNS("transform-center-x", "inkscape"), 0)) origin_y = float(node.get(inkex.addNS("transform-center-y", "inkscape"), 0)) origin_x = origin_x + (box[1] / 2) origin_y = (origin_y * -1) + (box[3] / 2) if transform == "": # If there is no transform attribute on the node we add one node.attrib["transform"] = "" # simpletransform returns a multi dim array of matrix values transform = simpletransform.parseTransform(transform) transformObject = self.normalizeMatrix(transform) inkex.debug(transformObject) # offset_x = (transform[0][2]-pos_x) # offset_y = (transform[1][2]-pos_y) offset_x = pos_x * -1 offset_y = pos_y * -1 inkex.debug([offset_x, offset_y]) transform = simpletransform.parseTransform( ("translate(" + str(offset_x) + " " + str(offset_y) + ")"), transform ) transformObject = self.normalizeMatrix(transform) inkex.debug(transformObject) inkex.debug(transform) if relative == False: matrix = simpletransform.formatTransform(transform) node.set("transform", matrix) inkex.debug(matrix) else: simpletransform.applyTransformToNode(transform, node)
def process_group(self, group): if group.get(inkex.addNS('groupmode', 'inkscape')) == 'layer': style = group.get('style') if style: style = simplestyle.parseStyle(style) if style.has_key('display'): if style['display'] == 'none': return layer = group.get(inkex.addNS('label', 'inkscape')) layer = layer.replace(' ', '_') if layer in self.layers: self.layer = layer trans = group.get('transform') if trans: self.groupmat.append( simpletransform.composeTransform( self.groupmat[-1], simpletransform.parseTransform(trans))) for node in group: if node.tag == inkex.addNS('g', 'svg'): self.process_group(node) elif node.tag == inkex.addNS('use', 'svg'): self.process_clone(node) else: self.process_shape(node, self.groupmat[-1]) if trans: self.groupmat.pop()
def process_clone(self, node): trans = node.get('transform') x = node.get('x') y = node.get('y') mat = [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]] if trans: mat = simpletransform.composeTransform(mat, simpletransform.parseTransform(trans)) if x: mat = simpletransform.composeTransform(mat, [[1.0, 0.0, float(x)], [0.0, 1.0, 0.0]]) if y: mat = simpletransform.composeTransform(mat, [[1.0, 0.0, 0.0], [0.0, 1.0, float(y)]]) # push transform if trans or x or y: self.groupmat.append(simpletransform.composeTransform(self.groupmat[-1], mat)) # get referenced node refid = node.get(inkex.addNS('href','xlink')) refnode = self.getElementById(refid[1:]) if refnode is not None: if refnode.tag == inkex.addNS('g','svg'): self.process_group(refnode) elif refnode.tag == inkex.addNS('use', 'svg'): self.process_clone(refnode) else: self.process_shape(refnode, self.groupmat[-1]) # pop transform if trans or x or y: self.groupmat.pop()
def process_group(self, group): if group.get(inkex.addNS('groupmode', 'inkscape')) == 'layer': style = group.get('style') if style: style = simplestyle.parseStyle(style) if style.has_key('display'): if style['display'] == 'none' and self.options.layer_option and self.options.layer_option=='visible': return layer = group.get(inkex.addNS('label', 'inkscape')) if self.options.layer_name and self.options.layer_option and self.options.layer_option=='name' and not layer.lower() in self.options.layer_name: return layer = layer.replace(' ', '_') if layer in self.layers: self.layer = layer trans = group.get('transform') if trans: self.groupmat.append(simpletransform.composeTransform(self.groupmat[-1], simpletransform.parseTransform(trans))) for node in group: if node.tag == inkex.addNS('g','svg'): self.process_group(node) elif node.tag == inkex.addNS('use', 'svg'): self.process_clone(node) else: self.process_shape(node, self.groupmat[-1]) if trans: self.groupmat.pop()
def effect(self): self.dxf_insert_code('999', '"DXF R12 Output" (www.mydxf.blogspot.com)') self.dxf_add(r12_header) scale = 25.4 / 90.0 h = self.unittouu(self.getDocumentHeight()) path = '//svg:path' for node in self.document.getroot().xpath(path, namespaces=inkex.NSS): layer = node.getparent().get(inkex.addNS('label', 'inkscape')) if layer == None: layer = 'Layer 1' d = node.get('d') p = cubicsuperpath.parsePath(d) t = node.get('transform') if t != None: m = simpletransform.parseTransform(t) simpletransform.applyTransformToPath(m, p) m = [[scale, 0, 0], [0, -scale, h * scale]] simpletransform.applyTransformToPath(m, p) if re.search('drill$', layer, re.I) == None: #if layer == 'Brackets Drill': self.dxf_path_to_lines(layer, p) else: self.dxf_path_to_point(layer, p) self.dxf_add(r12_footer)
def process_clone(self, node): trans = node.get('transform') x = node.get('x') y = node.get('y') mat = [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]] if trans: mat = simpletransform.composeTransform( mat, simpletransform.parseTransform(trans)) if x: mat = simpletransform.composeTransform( mat, [[1.0, 0.0, float(x)], [0.0, 1.0, 0.0]]) if y: mat = simpletransform.composeTransform( mat, [[1.0, 0.0, 0.0], [0.0, 1.0, float(y)]]) # push transform if trans or x or y: self.groupmat.append( simpletransform.composeTransform(self.groupmat[-1], mat)) # get referenced node refid = node.get(inkex.addNS('href', 'xlink')) #print(refid,node.get('id'),node.get('layer')) refnode = self.getElementById(refid[1:]) if refnode is not None: if refnode.tag == inkex.addNS( 'g', 'svg') or refnode.tag == inkex.addNS('switch', 'svg'): self.process_group(refnode) elif refnode.tag == inkex.addNS('use', 'svg'): #print(refnode,'1') self.process_clone(refnode) else: self.process_shape(refnode, self.groupmat[-1]) # pop transform if trans or x or y: self.groupmat.pop()
def _merge_clippath(self, node, clippathurl): if (clippathurl): node_transform = simpletransform.parseTransform( node.get("transform")) if (node_transform): # Clip-paths on nodes with a transform have the transform # applied to the clipPath as well, which we don't want. So, we # create new clipPath element with references to all existing # clippath subelements, but with the inverse transform applied inverse_node_transform = simpletransform.formatTransform( self._invert_transform(node_transform)) new_clippath = inkex.etree.SubElement( self.xpathSingle('//svg:defs'), 'clipPath', {'clipPathUnits': 'userSpaceOnUse', 'id': self.uniqueId("clipPath")}) clippath = self.getElementById(clippathurl[5:-1]) for c in (clippath.iterchildren()): inkex.etree.SubElement( new_clippath, 'use', {inkex.addNS('href', 'xlink'): '#' + c.get("id"), 'transform': inverse_node_transform, 'id': self.uniqueId("use")}) # Set the clippathurl to be the one with the inverse transform clippathurl = "url(#" + new_clippath.get("id") + ")" # Reference the parent clip-path to keep clipping intersection # Find end of clip-path chain and add reference there node_clippathurl = node.get("clip-path") while (node_clippathurl): node = self.getElementById(node_clippathurl[5:-1]) node_clippathurl = node.get("clip-path") node.set("clip-path", clippathurl)
def mergeTransform(self, doc, matrix): # get and merge two matrixes into one trans = doc.get('transform') if trans: return simpletransform.composeTransform(matrix, simpletransform.parseTransform(trans)) else: return matrix
def effect(self): paths = [] for id, node in self.selected.iteritems(): if node.tag == '{http://www.w3.org/2000/svg}path': paths.append(node) if len(paths) == 2: break else: sys.stderr.write('Need 2 paths selected\n') return pts = [cubicsuperpath.parsePath(paths[i].get('d')) for i in (0, 1)] for i in (0, 1): if 'transform' in paths[i].keys(): trans = paths[i].get('transform') trans = simpletransform.parseTransform(trans) simpletransform.applyTransformToPath(trans, pts[i]) verts = [] for i in range(0, min(map(len, pts))): comp = [] for j in range(0, min(len(pts[0][i]), len(pts[1][i]))): comp.append([pts[0][i][j][1][-2:], pts[1][i][j][1][-2:]]) verts.append(comp) if self.options.mode.lower() == 'lines': line = [] for comp in verts: for n, v in enumerate(comp): line += [('M', v[0])] line += [('L', v[1])] ele = inkex.etree.Element('{http://www.w3.org/2000/svg}path') paths[0].xpath('..')[0].append(ele) ele.set('d', simplepath.formatPath(line)) ele.set( 'style', 'fill:none;stroke:#000000;stroke-opacity:1;stroke-width:1;') elif self.options.mode.lower() == 'polygons': g = inkex.etree.Element('{http://www.w3.org/2000/svg}g') g.set( 'style', 'fill:#000000;stroke:#000000;fill-opacity:0.3;stroke-width:2;stroke-opacity:0.6;' ) paths[0].xpath('..')[0].append(g) for comp in verts: for n, v in enumerate(comp): nn = n + 1 if nn == len(comp): nn = 0 line = [] line += [('M', comp[n][0])] line += [('L', comp[n][1])] line += [('L', comp[nn][1])] line += [('L', comp[nn][0])] line += [('L', comp[n][0])] ele = inkex.etree.Element( '{http://www.w3.org/2000/svg}path') g.append(ele) ele.set('d', simplepath.formatPath(line))
def copy_pattern(self, x, y): p = copy.deepcopy(self.ptrn) cx = float(self.ptrn.get('cx')) cy = float(self.ptrn.get('cy')) transformation = 'translate(' + str(x - cx) + ', ' + str(y - cy) + ')' transform = simpletransform.parseTransform(transformation) simpletransform.applyTransformToNode(transform, p) self.current_layer.append(p)
def mergeTransform(self, doc, matrix): # get and merge two matrixes into one trans = doc.get('transform') if trans: return simpletransform.composeTransform( matrix, simpletransform.parseTransform(trans)) else: return matrix
def effect(self): pts = [] for node in self.selected.itervalues(): if node.tag == inkex.addNS('path','svg'): guide = node pts = get_n_points_from_path(node, 2) if len(pts) == 2: (x0, y0), (x1, y1) = pts theta = atan2(y1-y0, x1-x0)*180./pi length = ((x1-x0)**2 + (y1-y0)**2)**0.5 label = inkex.etree.SubElement(self.current_layer, 'g') labeltag = inkex.etree.SubElement(label, 'g') if theta <= -90.0 or theta > 90.0: text, tw, th = self.make_text(anchor='end') applyTransformToNode(parseTransform('rotate(180.0)'), text) else: text, tw, th = self.make_text(anchor='start') fs = float(self.options.font_size) kh = 1.05 h = kh*fs pad = (h - fs)*0.5 + 0.04*tw w = tw + pad*2 x = -pad + 0.07*fs y = -0.5*h box = self.make_box(x, y, w, h, r=0.25*min(w, h)) labeltag.append(box) labeltag.append(text) transform = 'translate(%f, 0.0)'% (length,) applyTransformToNode(parseTransform(transform), labeltag) leader = self.make_double_line(length+x) label.append(leader) transform = 'translate(%f, %f) rotate(%f)'%(x0, y0, theta) applyTransformToNode(parseTransform(transform), label) guide.getparent().remove(guide)
def get_transform(self): data = self.node.get("transform") if not data: return matrix = parseTransform(data) m11, m21, dx = matrix[0] m12, m22, dy = matrix[1] return m11, m12, m21, m22, dx, dy
def recursiveFuseTransform(self, node, transf=[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]): transf = composeTransform(transf, parseTransform(node.get("transform", None))) if 'transform' in node.attrib: del node.attrib['transform'] if 'style' in node.attrib: style = node.attrib.get('style') style = simplestyle.parseStyle(style) update = False if 'stroke-width' in style: try: stroke_width = self.unittouu(style.get('stroke-width').strip()) # pixelsnap ext assumes scaling is similar in x and y # and uses the x scale... # let's try to be a bit smarter stroke_width *= math.sqrt(transf[0][0]**2 + transf[1][1]**2) style['stroke-width'] = str(stroke_width) update = True except AttributeError: pass if update: style = simplestyle.formatStyle(style) node.attrib['style'] = style node = ApplyTransform.objectToPath(node) if 'd' in node.attrib: d = node.get('d') p = cubicsuperpath.parsePath(d) applyTransformToPath(transf, p) node.set('d', cubicsuperpath.formatPath(p)) elif node.tag in [inkex.addNS('polygon', 'svg'), inkex.addNS('polyline', 'svg')]: points = node.get('points') points = points.strip().split(' ') for k,p in enumerate(points): if ',' in p: p = p.split(',') p = [float(p[0]),float(p[1])] applyTransformToPoint(transf, p) p = [str(p[0]),str(p[1])] p = ','.join(p) points[k] = p points = ' '.join(points) node.set('points', points) elif node.tag in [inkex.addNS('rect', 'svg'), inkex.addNS('text', 'svg'), inkex.addNS('image', 'svg'), inkex.addNS('use', 'svg')]: node.set('transform', formatTransform(transf)) for child in node.getchildren(): self.recursiveFuseTransform(child, transf)
def process_shape(self, node, mat): rgb = (0, 0, 0) # stroke color fillcolor = None # fill color stroke = 1 # pen width in printer pixels # Very NB : If the pen width is greater than 1 then the output will Not be a vector output ! style = node.get('style') if style: style = simplestyle.parseStyle(style) if style.has_key('stroke'): if style['stroke'] and style['stroke'] != 'none' and style[ 'stroke'][0:3] != 'url': rgb = simplestyle.parseColor(style['stroke']) if style.has_key('stroke-width'): stroke = self.unittouu( style['stroke-width']) / self.unittouu('1px') stroke = int(stroke * self.scale) if style.has_key('fill'): if style['fill'] and style['fill'] != 'none' and style['fill'][ 0:3] != 'url': fill = simplestyle.parseColor(style['fill']) fillcolor = fill[0] + 256 * fill[1] + 256 * 256 * fill[2] color = rgb[0] + 256 * rgb[1] + 256 * 256 * rgb[2] if node.tag == inkex.addNS('path', 'svg'): d = node.get('d') if not d: return p = cubicsuperpath.parsePath(d) elif node.tag == inkex.addNS('rect', 'svg'): x = float(node.get('x')) y = float(node.get('y')) width = float(node.get('width')) height = float(node.get('height')) p = [[[x, y], [x, y], [x, y]]] p.append([[x + width, y], [x + width, y], [x + width, y]]) p.append([[x + width, y + height], [x + width, y + height], [x + width, y + height]]) p.append([[x, y + height], [x, y + height], [x, y + height]]) p.append([[x, y], [x, y], [x, y]]) p = [p] else: return trans = node.get('transform') if trans: mat = simpletransform.composeTransform( mat, simpletransform.parseTransform(trans)) simpletransform.applyTransformToPath(mat, p) hPen = mygdi.CreatePen(0, stroke, color) mygdi.SelectObject(self.hDC, hPen) self.emit_path(p) if fillcolor is not None: brush = LOGBRUSH(0, fillcolor, 0) hBrush = mygdi.CreateBrushIndirect(addressof(brush)) mygdi.SelectObject(self.hDC, hBrush) mygdi.BeginPath(self.hDC) self.emit_path(p) mygdi.EndPath(self.hDC) mygdi.FillPath(self.hDC) return
def recursivelyTraverseSvg(self, aNodeList, matCurrent=[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]): for node in aNodeList: # first apply the current matrix transform to this node's transform matNew = composeTransform(matCurrent, parseTransform(node.get("transform"))) if node.tag == inkex.addNS('g', 'svg') or node.tag == 'g': self.recursivelyTraverseSvg(node, matNew) elif node.tag == inkex.addNS('symbol', 'svg') or node.tag == 'symbol': if (self.useTagNestLevel > 0): self.recursivelyTraverseSvg(node, matNew) elif node.tag == inkex.addNS('a', 'svg') or node.tag == 'a': self.recursivelyTraverseSvg(node, matNew) elif node.tag == inkex.addNS('use', 'svg') or node.tag == 'use': refid = node.get(inkex.addNS('href', 'xlink')) if refid is not None: # [1:] to ignore leading '#' in reference path = '//*[@id="%s"]' % refid[1:] refnode = node.xpath(path) if refnode is not None: x = float(node.get('x', '0')) y = float(node.get('y', '0')) # Note: the transform has already been applied if (x != 0) or (y != 0): t = parseTransform('translate(%f,%f)' % (x, y)) matNew2 = composeTransform(matNew, t) else: matNew2 = matNew self.useTagNestLevel = self.useTagNestLevel + 1 self.recursivelyTraverseSvg(refnode, matNew2) self.useTagNestLevel = self.useTagNestLevel - 1 else: continue else: continue elif node.tag == inkex.addNS('image', 'svg') or node.tag == 'image': self.gcode += self.imageToGcode(node, matNew) else: continue
def effect(self): pts = [] for node in self.selected.itervalues(): if node.tag == inkex.addNS('path', 'svg'): guide = node pts = get_n_points_from_path(node, 2) if len(pts) == 2: (x0, y0), (x1, y1) = pts theta = atan2(y1 - y0, x1 - x0) * 180. / pi length = ((x1 - x0)**2 + (y1 - y0)**2)**0.5 label = inkex.etree.SubElement(self.current_layer, 'g') labeltag = inkex.etree.SubElement(label, 'g') if theta <= -90.0 or theta > 90.0: text, tw, th = self.make_text(anchor='end') applyTransformToNode(parseTransform('rotate(180.0)'), text) else: text, tw, th = self.make_text(anchor='start') fs = float(self.options.font_size) kh = 1.05 h = kh * fs pad = (h - fs) * 0.5 + 0.04 * tw w = tw + pad * 2 x = -pad + 0.07 * fs y = -0.5 * h box = self.make_box(x, y, w, h, r=0.25 * min(w, h)) labeltag.append(box) labeltag.append(text) transform = 'translate(%f, 0.0)' % (length, ) applyTransformToNode(parseTransform(transform), labeltag) leader = self.make_double_line(length + x) label.append(leader) transform = 'translate(%f, %f) rotate(%f)' % (x0, y0, theta) applyTransformToNode(parseTransform(transform), label) guide.getparent().remove(guide)
def process_shape(self, node, mat): rgb = (0, 0, 0) style = node.get('style') if style: style = simplestyle.parseStyle(style) if style.has_key('stroke'): if style['stroke'] and style['stroke'] != 'none' and style[ 'stroke'][0:3] != 'url': rgb = simplestyle.parseColor(style['stroke']) hsl = coloreffect.ColorEffect.rgb_to_hsl(coloreffect.ColorEffect(), rgb[0] / 255.0, rgb[1] / 255.0, rgb[2] / 255.0) self.closed = 0 # only for LWPOLYLINE self.color = 7 # default is black if hsl[2]: self.color = 1 + (int(6 * hsl[0] + 0.5) % 6) # use 6 hues if node.tag == inkex.addNS('path', 'svg'): d = node.get('d') if not d: return if (d[-1] == 'z' or d[-1] == 'Z'): self.closed = 1 p = cubicsuperpath.parsePath(d) elif node.tag == inkex.addNS('rect', 'svg'): self.closed = 1 x = float(node.get('x')) y = float(node.get('y')) width = float(node.get('width')) height = float(node.get('height')) p = [[[x, y], [x, y], [x, y]]] p.append([[x + width, y], [x + width, y], [x + width, y]]) p.append([[x + width, y + height], [x + width, y + height], [x + width, y + height]]) p.append([[x, y + height], [x, y + height], [x, y + height]]) p.append([[x, y], [x, y], [x, y]]) p = [p] else: return trans = node.get('transform') if trans: mat = simpletransform.composeTransform( mat, simpletransform.parseTransform(trans)) simpletransform.applyTransformToPath(mat, p) for sub in p: for i in range(len(sub) - 1): s = sub[i] e = sub[i + 1] if s[1] == s[2] and e[0] == e[1]: if (self.options.POLY == 'true'): self.LWPOLY_line([s[1], e[1]]) else: self.dxf_line([s[1], e[1]]) elif (self.options.ROBO == 'true'): self.ROBO_spline([s[1], s[2], e[0], e[1]]) else: self.dxf_spline([s[1], s[2], e[0], e[1]])
def effect(self): """ This method is called first, and sets up the self.commands list for later output. """ svg = self.document.getroot() # find document width and height, used to scale down self.doc_width = inkex.unittouu(svg.get('width')) self.doc_height = inkex.unittouu(svg.get('height')) # add header self.commands.append("^DF;") self.commands.append("! 1;") self.commands.append("H;") self.commands.append("@ %d %d;" % (self.options.z_down, self.options.z_up)) self.commands.append("V {0};F {0};\n".format(self.options.feed_rate_moving)) self.commands.append("Z 0 0 %d;" % self.options.z_up) # mostly borrowed from hgpl_output.py lastX = 0 lastY = 0 # find paths in layers i = 0 layerPath = '//svg:g[@inkscape:groupmode="layer"]' for layer in svg.xpath(layerPath, namespaces=inkex.NSS): i += 1 nodePath = ('//svg:g[@inkscape:groupmode="layer"][%d]/descendant::svg:path') % i for node in svg.xpath(nodePath, namespaces=inkex.NSS): # these next lines added from this patch to fix the transformation issues - http://launchpadlibrarian.net/36269154/hpgl_output.py.patch # possibly also want to try this code: https://bugs.launchpad.net/inkscape/+bug/600472/+attachment/1475310/+files/hpgl_output.py transforms = node.xpath("./ancestor-or-self::svg:*[@transform]",namespaces=inkex.NSS) matrix = [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]] for parenttransform in transforms: newmatrix = simpletransform.parseTransform(parenttransform.get("transform")) matrix = simpletransform.composeTransform(matrix, newmatrix) d = node.get('d') if len(simplepath.parsePath(d)): p = cubicsuperpath.parsePath(d) simpletransform.applyTransformToPath(matrix, p) # this line is also from the transform-fixing patch mentioned above cspsubdiv.cspsubdiv(p, self.options.flat) for sp in p: first = True for csp in sp: if first: x, y = self.conv_coords(csp[1][0], self.doc_height - csp[1][1]) self.commands.append("Z %d %d %d;" % (x, y, self.options.z_up)) self.commands.append("V {0};F {0};".format(self.options.feed_rate_cutting)) first = False x, y = self.conv_coords(csp[1][0], self.doc_height - csp[1][1]) self.commands.append("Z %d %d %d;" % (x, y, self.options.z_down)) lastX = x lastY = y self.commands.append("V {0};F {0};".format(self.options.feed_rate_moving)) self.commands.append("Z %d %d %d;" % (lastX, lastY, self.options.z_up)) self.commands.append("Z 0 0 %d;" % self.options.z_up) self.commands.append("H;")
def scaleRoot(self, svg): """Scale all top-level elements in SVG root.""" # update viewport widthNumber = self.parse_length(svg.get('width'))[0] heightNumber = self.convert_length(*self.parse_length(svg.get('height')))[0] widthDoc = widthNumber * self.factor_a * self.unitExponent heightDoc = heightNumber * self.factor_a * self.unitExponent if svg.get('height'): svg.set('height', str(heightDoc)) if svg.get('width'): svg.set('width', str(widthDoc)) # update viewBox if svg.get('viewBox'): viewboxstring = re.sub(' +|, +|,',' ', svg.get('viewBox')) viewboxlist = [float(i) for i in viewboxstring.strip().split(' ', 4)] svg.set('viewBox','{} {} {} {}'.format(*[(val * self.factor_a) for val in viewboxlist])) # update guides, grids if self.options.switcher == "1": # FIXME: dpi96to90 only? self.scaleGuides(svg) self.scaleGrid(svg) for element in svg: # iterate all top-level elements of SVGRoot # init variables tag = etree.QName(element).localname width_scale = self.factor_a height_scale = self.factor_a if tag in GRAPHICS_ELEMENTS or tag in CONTAINER_ELEMENTS: # test for specific elements to skip from scaling if is_3dbox(element): if check_3dbox(svg, element, width_scale, height_scale): continue if is_text_on_path(element): if check_text_on_path(svg, element, width_scale, height_scale): continue if is_use(element): if check_use(svg, element, width_scale, height_scale): continue # relative units ('%') in presentation attributes for attr in ['width', 'height']: self.scale_attr_val(element, attr, ['%'], 1.0 / self.factor_a) for attr in ['x', 'y']: self.scale_attr_val(element, attr, ['%'], 1.0 / self.factor_a) # set preserved transforms on top-level elements if width_scale != 1.0 and height_scale != 1.0: mat = simpletransform.parseTransform( 'scale({},{})'.format(width_scale, height_scale)) simpletransform.applyTransformToNode(mat, element)
def parseGroup(self,node,parent): #inkex.debug(self.debug_tab + 'Parsing group' + node.get('id')) self.debug_tab += ' ' matrix_list = [] self.parsing_context = 'g' transform = node.get('transform','') id = node.get('id') if(transform!=''): transform = simpletransform.parseTransform(node.get('transform','')) transform = self.matrixToList(transform) transform = self.normalizeMatrix(transform) label = str(node.get(inkex.addNS('label', 'inkscape'),'')) elements = node.xpath('./*',namespaces=inkex.NSS) #box = simpletransform.computeBBox(elements) #box = list(box) if box != None else [] box =list(simpletransform.computeBBox([node])) box[1] = (box[1]-box[0]) box[3] = (box[3]-box[2]) origin_x = float(node.get(inkex.addNS('transform-center-x', 'inkscape'),0)) origin_y = float(node.get(inkex.addNS('transform-center-y', 'inkscape'),0)) origin_x = origin_x + ( box[1] / 2) origin_y = (origin_y * -1) + ( box[3] / 2) group = { 'id':id, 'name':label, 'label':label, 'svg':'g', 'transform':transform, 'origin':{ 'x':origin_x, 'y':origin_y, }, 'box':box, 'elements':[] } parent.append(group) self.parse_stack.append(group) #inkex.debug('Loop through all grouped elements') for child in elements: self.parseElement(child,group["elements"]) self.debug_tab = self.debug_tab[:-4] self.parsing_context = '' self.parse_stack.pop()
def get_transforms(self,g): root = self.document.getroot() trans = [] while (g!=root): if 'transform' in g.keys(): t = g.get('transform') t = simpletransform.parseTransform(t) trans = simpletransform.composeTransform(t,trans) if trans != [] else t g=g.getparent() return trans
def i2d_affine(self, node): m2 = simpletransform.parseTransform(node.get('transform')) while True: node = node.getparent() if node is None: break viewBox = node.get('viewBox') t1 = node.get('transform') if viewBox: viewBox = [float(i) for i in viewBox.split()] doc_width = self.unittouu(node.get('width', viewBox[2])) doc_height = self.unittouu(node.get('height', viewBox[3])) m1 = [[doc_width / viewBox[2], 0, -viewBox[0]], [0, doc_height / viewBox[3], -viewBox[1]]] elif t1: m1 = simpletransform.parseTransform(t1) else: continue m2 = simpletransform.composeTransform(m1, m2) return m2
def test_simpletransform(self): """Test simpletransform API""" import simpletransform self.assertEqual(simpletransform.parseTransform('scale(10)'), [[10, 0, 0], [0, 10, 0]]) self.assertEqual(simpletransform.parseTransform('translate(2,3)'), [[1, 0, 2], [0, 1, 3]]) self.assertEqual( simpletransform.parseTransform('translate(2,3) rotate(90)'), [approx([0, -1, 2]), approx([1, 0, 3])]) m = simpletransform.formatTransform([[0, -1, 2], [1, 0, 3]]) self.assertEqual(re.sub(r',', ' ', re.sub(r'\.0*\b', '', m)), 'matrix(0 1 -1 0 2 3)') self.assertEqual( simpletransform.invertTransform([[1, 0, 2], [0, 1, 3]]), [[1, 0, -2], [0, 1, -3]]) self.assertEqual( simpletransform.composeTransform([[1, 0, 2], [0, 1, 3]], [[0, -1, 0], [1, 0, 0]]), [[0, -1, 2], [1, 0, 3]]) pt = [4, 5] self.assertEqual( simpletransform.applyTransformToPoint([[0, -1, 2], [1, 0, 3]], pt), None) self.assertEqual(pt, [-3, 7]) self.assertEqual(simpletransform.boxunion([3, 5, 2, 4], [4, 6, 1, 3]), (3, 6, 1, 4)) self.assertEqual(simpletransform.cubicExtrema(1, 2, 3, 4), (1, 4)) # TODO need cubic superpath self.assertTrue(simpletransform.applyTransformToPath) self.assertTrue(simpletransform.roughBBox) self.assertTrue(simpletransform.refinedBBox) # TODO need node self.assertTrue(simpletransform.fuseTransform) self.assertTrue(simpletransform.composeParents) self.assertTrue(simpletransform.applyTransformToNode) self.assertTrue(simpletransform.computeBBox) self.assertTrue(simpletransform.computePointInNode)
def get_transform_values(self): """ Returns the entries a, b, c, d, e, f of self._node's transformation matrix depending on the transform applied. If no transform is defined all values returned are zero See: https://www.w3.org/TR/SVG11/coords.html#TransformMatrixDefined """ a = b = c = d = e = f = 0 if 'transform' in self._node.attrib: (a,c,e),(b,d,f) = st.parseTransform(self._node.attrib['transform']) return a, b, c, d, e, f
def processTree(self, node): ''' Recursively walk the SVG tree and randomize all rock/pebble symbols on the way ''' # Is this a symbol reference? if node.tag == inkex.addNS('use', 'svg'): # Is this one of our rock/pebble symbols? m = re.match('#(gr|un|)?([ra])b([0-9]+)[a-z]', str(node.get(inkex.addNS("href", "xlink")))) if m: # Add translation, if present x = float(node.get("x")) y = float(node.get("y")) if x <> 0 or y <> 0: node.set("x", "0") node.set("y", "0") currentTr = node.get("transform") if currentTr == None: currentTr = "" node.set("transform", currentTr + (" translate(%.6f, %.6f) " % (x, y))) # Get current symbol transform tr = SpeleoTransform.getTotalTransform(node) # Move it back to 0,0 for rotation simpletransform.applyTransformToNode(SpeleoTransform.invertTransform(tr), node) # Select a new, random symbol ID (matching the symbol family) new_id = m.group(1) + m.group(2) + "b" + m.group(3) + random.choice("abcdefghij") # Make sure the new symbol type is with us if self.ensureSymbol(new_id): node.set(inkex.addNS("href", "xlink"), "#" + new_id) # If not, we just leave the type as it is. # Apply random rotation simpletransform.applyTransformToNode(simpletransform.parseTransform("rotate(" + str(random.randint(0, 359)) + ")"), node) # Return the symbol to where it was simpletransform.applyTransformToNode(tr, node) # For compatibility with old maps, using speleoUIS3 if (node.tag == inkex.addNS('tspan', 'svg') or node.tag == inkex.addNS('text', 'svg')) and node.text: if len(node.text) == 1: if node.text in string.ascii_lowercase: node.text = random.choice(string.ascii_lowercase) elif node.text in string.ascii_uppercase: node.text = random.choice(string.ascii_uppercase) if (node.text in string.ascii_letters): node.set("rotate", str(random.randint(0, 359))) # Recurse! for child in node: self.processTree(child);
def effect(self): paths = [] for id, node in self.selected.iteritems(): if node.tag == '{http://www.w3.org/2000/svg}path': paths.append(node) if len(paths) == 2: break else: sys.stderr.write('Need 2 paths selected\n') return pts = [cubicsuperpath.parsePath(paths[i].get('d')) for i in (0,1)] for i in (0,1): if 'transform' in paths[i].keys(): trans = paths[i].get('transform') trans = simpletransform.parseTransform(trans) simpletransform.applyTransformToPath(trans, pts[i]) verts = [] for i in range(0, min(map(len, pts))): comp = [] for j in range(0, min(len(pts[0][i]), len(pts[1][i]))): comp.append([pts[0][i][j][1][-2:], pts[1][i][j][1][-2:]]) verts.append(comp) if self.options.mode.lower() == 'lines': line = [] for comp in verts: for n,v in enumerate(comp): line += [('M', v[0])] line += [('L', v[1])] ele = inkex.etree.Element('{http://www.w3.org/2000/svg}path') paths[0].xpath('..')[0].append(ele) ele.set('d', simplepath.formatPath(line)) ele.set('style', 'fill:none;stroke:#000000;stroke-opacity:1;stroke-width:1;') elif self.options.mode.lower() == 'polygons': g = inkex.etree.Element('{http://www.w3.org/2000/svg}g') g.set('style', 'fill:#000000;stroke:#000000;fill-opacity:0.3;stroke-width:2;stroke-opacity:0.6;') paths[0].xpath('..')[0].append(g) for comp in verts: for n,v in enumerate(comp): nn = n+1 if nn == len(comp): nn = 0 line = [] line += [('M', comp[n][0])] line += [('L', comp[n][1])] line += [('L', comp[nn][1])] line += [('L', comp[nn][0])] line += [('L', comp[n][0])] ele = inkex.etree.Element('{http://www.w3.org/2000/svg}path') g.append(ele) ele.set('d', simplepath.formatPath(line))
def process_group(self, group): ############################################## ### Get color set at group level stroke_group = group.get('stroke') ############################################## ### Handle 'style' data style = group.get('style') if style: declarations = style.split(';') for i,decl in enumerate(declarations): parts = decl.split(':', 2) if len(parts) == 2: (prop, val) = parts prop = prop.strip().lower() if prop == 'stroke': stroke_group = val.strip() if prop == 'display' and val == "none": #group display is 'none' return without processing group return ############################################## if group.get(inkex.addNS('groupmode', 'inkscape')) == 'layer': style = group.get('style') if style: style = simplestyle.parseStyle(style) if 'display' in style: if style['display'] == 'none': #layer display is 'none' return without processing layer return layer = group.get(inkex.addNS('label', 'inkscape')) layer = layer.replace(' ', '_') if layer in self.layers: self.layer = layer trans = group.get('transform') if trans: self.groupmat.append(simpletransform.composeTransform(self.groupmat[-1], simpletransform.parseTransform(trans))) for node in group: if node.tag == inkex.addNS('g','svg') or node.tag == inkex.addNS('switch','svg'): self.process_group(node) elif node.tag == inkex.addNS('use', 'svg'): self.process_clone(node) elif node.tag == inkex.addNS('style', 'svg'): if node.get('type')=="text/css": self.parse_css(node.text) elif node.tag == inkex.addNS('defs', 'svg'): for sub in node: if sub.tag == inkex.addNS('style','svg'): self.parse_css(sub.text) else: self.process_shape(node, self.groupmat[-1], group_stroke = stroke_group) if trans: self.groupmat.pop()
def effect(self): for id, node in self.selected.iteritems(): if node.tag == '{http://www.w3.org/2000/svg}path': path=node break else: sys.stderr.write('Need one path selected\n') return pts = cubicsuperpath.parsePath(path.get('d')) if 'transform' in path.keys(): trans = path.get('transform') trans = simpletransform.parseTransform(trans) simpletransform.applyTransformToPath(trans, pts[i]) gtext = inkex.etree.SubElement(path.xpath('..')[0], inkex.addNS('g','svg'), {} ) gdots = inkex.etree.SubElement(path.xpath('..')[0], inkex.addNS('g','svg'), {} ) size = 10 if 'style' in path.attrib: style=path.get('style') if style!='': styles=style.split(';') for i in range(len(styles)): if styles[i].startswith('stroke-width'): if ( styles[i].endswith('px') or styles[i].endswith('cm') ) : size=float(styles[i][len('stroke-width:'):-2])*2 else: size=float(styles[i][len('stroke-width:'):])*2 # if len(pts[0])>2: # size = math.sqrt(math.pow(pts[0][0][0][0]-pts[0][1][0][0],2)+math.pow(pts[0][0][0][1]-pts[0][1][0][1],2))/10 it = 0 for sub in pts: for p in sub: if it == 0: style = { 'stroke': 'none', 'fill': 'black' } x0 = p[0][0] y0 = p[0][1] circ_attribs = {'id':'pt0','style':simplestyle.formatStyle(style),'cx':str(x0), 'cy':str(y0),'r':str(size)} circle = inkex.etree.SubElement(gdots, inkex.addNS('circle','svg'), circ_attribs ) else: clone_attribs = { 'x':'0', 'y':'0', 'transform':'translate(%f,%f)' % (p[0][0]-x0,p[0][1]-y0) } clone = inkex.etree.SubElement(gdots, inkex.addNS('use','svg'), clone_attribs ) xlink = inkex.addNS('href','xlink') clone.set(xlink, '#pt0') text_style = { 'font-size':'%dpx' % (size*2.4), 'fill':'black', 'font-family':'DejaVu Sans', 'text-anchor':'middle' } text_attribs = { 'x':str(p[0][0]), 'y':str(p[0][1]-size*1.8), 'style':simplestyle.formatStyle(text_style) } text = inkex.etree.SubElement(gtext, inkex.addNS('text','svg'), text_attribs) tspan = inkex.etree.SubElement(text , 'tspan', {inkex.addNS('role','sodipodi'): 'line'}) tspan.text = '%d' % ( it+1 ) it+=1
def to_patches(self, last_patch=None): patches = [] source_node = get_clone_source(self.node) if source_node.tag not in EMBROIDERABLE_TAGS: return [] clone = copy(source_node) # set id clone_id = 'clone__%s__%s' % (self.node.get('id', ''), clone.get('id', '')) clone.set('id', clone_id) # apply transform transform = get_node_transform(self.node) applyTransformToNode(transform, clone) # set fill angle. Use either # a. a custom set fill angle # b. calculated rotation for the cloned fill element to look exactly as it's source param = INKSTITCH_ATTRIBS['angle'] if self.clone_fill_angle is not None: angle = self.clone_fill_angle else: # clone angle clone_mat = parseTransform(clone.get('transform', '')) clone_angle = degrees(atan(-clone_mat[1][0]/clone_mat[1][1])) # source node angle source_mat = parseTransform(source_node.get('transform', '')) source_angle = degrees(atan(-source_mat[1][0]/source_mat[1][1])) # source node fill angle source_fill_angle = source_node.get(param, 0) angle = clone_angle + float(source_fill_angle) - source_angle clone.set(param, str(angle)) elements = self.clone_to_element(clone) for element in elements: patches.extend(element.to_patches(last_patch)) return patches
def effect(self): paths = [] for id, node in self.selected.iteritems(): if node.tag == "{http://www.w3.org/2000/svg}path": paths.append(node) if len(paths) == 2: break else: sys.stderr.write("Need 2 paths selected\n") return pts = [cubicsuperpath.parsePath(paths[i].get("d")) for i in (0, 1)] for i in (0, 1): if "transform" in paths[i].keys(): trans = paths[i].get("transform") trans = simpletransform.parseTransform(trans) simpletransform.applyTransformToPath(trans, pts[i]) verts = [] for i in range(0, min(map(len, pts))): comp = [] for j in range(0, min(len(pts[0][i]), len(pts[1][i]))): comp.append([pts[0][i][j][1][-2:], pts[1][i][j][1][-2:]]) verts.append(comp) if self.options.mode.lower() == "lines": line = [] for comp in verts: for n, v in enumerate(comp): line += [("M", v[0])] line += [("L", v[1])] ele = inkex.etree.Element("{http://www.w3.org/2000/svg}path") paths[0].xpath("..")[0].append(ele) ele.set("d", simplepath.formatPath(line)) ele.set("style", "fill:none;stroke:#000000;stroke-opacity:1;stroke-width:1;") elif self.options.mode.lower() == "polygons": g = inkex.etree.Element("{http://www.w3.org/2000/svg}g") g.set("style", "fill:#000000;stroke:#000000;fill-opacity:0.3;stroke-width:2;stroke-opacity:0.6;") paths[0].xpath("..")[0].append(g) for comp in verts: for n, v in enumerate(comp): nn = n + 1 if nn == len(comp): nn = 0 line = [] line += [("M", comp[n][0])] line += [("L", comp[n][1])] line += [("L", comp[nn][1])] line += [("L", comp[nn][0])] line += [("L", comp[n][0])] ele = inkex.etree.Element("{http://www.w3.org/2000/svg}path") g.append(ele) ele.set("d", simplepath.formatPath(line))
def compose_parent_transforms(node, mat): # This is adapted from Inkscape's simpletransform.py's composeParents() # function. That one can't handle nodes that are detached from a DOM. trans = node.get('transform') if trans: mat = simpletransform.composeTransform(simpletransform.parseTransform(trans), mat) if node.getparent() is not None: if node.getparent().tag in [SVG_GROUP_TAG, SVG_LINK_TAG]: mat = compose_parent_transforms(node.getparent(), mat) return mat
def get_transforms(self,g): root = self.document.getroot() trans = [] while (g!=root): if 'transform' in g.keys(): t = g.get('transform') t = simpletransform.parseTransform(t) trans = simpletransform.composeTransform(t,trans) if trans != [] else t print_(trans) g=g.getparent() return trans
def _ungroup(self, node): node_parent = node.getparent() node_index = list(node_parent).index(node) node_style = simplestyle.parseStyle(node.get("style")) node_transform = simpletransform.parseTransform(node.get("transform")) node_clippathurl = node.get('clip-path') for c in reversed(list(node)): self._merge_transform(c, node_transform) self._merge_style(c, node_style) self._merge_clippath(c, node_clippathurl) node_parent.insert(node_index, c) node_parent.remove(node)
def copy_interior(self, basename,status, newbasename,newstatus, dx): current = self.getElementById(basename+'-'+status) if current != None: new = copy.deepcopy(current) new.set('id', newbasename+'-'+newstatus) if new.attrib.has_key('transform'): mat = simpletransform.parseTransform(new.get('transform')) mat[0][2] = mat[0][2]+dx else: mat = [[1,0,dx],[0,1,0]] new.set('transform', simpletransform.formatTransform(mat)) current.getparent().append(new)
def recursiveFuseTransform(self, node, transf=[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]): transf = composeTransform(transf, parseTransform(node.get("transform", None))) if 'transform' in node.attrib: del node.attrib['transform'] node = self.objectToPath(node) if 'd' in node.attrib: d = node.get('d') p = cubicsuperpath.parsePath(d) applyTransformToPath(transf, p) node.set('d', cubicsuperpath.formatPath(p)) self.scaleStrokeWidth(node, transf) elif node.tag in [ inkex.addNS('polygon', 'svg'), inkex.addNS('polyline', 'svg') ]: points = node.get('points') points = points.strip().split(' ') for k, p in enumerate(points): if ',' in p: p = p.split(',') p = [float(p[0]), float(p[1])] applyTransformToPoint(transf, p) p = [str(p[0]), str(p[1])] p = ','.join(p) points[k] = p points = ' '.join(points) node.set('points', points) self.scaleStrokeWidth(node, transf) elif node.tag in [ inkex.addNS('rect', 'svg'), inkex.addNS('text', 'svg'), inkex.addNS('image', 'svg'), inkex.addNS('use', 'svg'), inkex.addNS('circle', 'svg') ]: node.set('transform', formatTransform(transf)) else: # e.g. <g style="..."> self.scaleStrokeWidth(node, transf) for child in node.getchildren(): self.recursiveFuseTransform(child, transf)
def compose_parent_transforms(node, mat): # This is adapted from Inkscape's simpletransform.py's composeParents() # function. That one can't handle nodes that are detached from a DOM. trans = node.get('transform') if trans: mat = simpletransform.composeTransform( simpletransform.parseTransform(trans), mat) if node.getparent() is not None: if node.getparent().tag == inkex.addNS('g', 'svg'): mat = compose_parent_transforms(node.getparent(), mat) return mat
def _get_transforms(self, g): root = self.document.getroot() trans = [[1, 0, 0], [0, 1, 0]] while (g != root): if 'transform' in g.keys(): t = g.get('transform') t = simpletransform.parseTransform(t) trans = simpletransform.composeTransform( t, trans) if trans != [] else t self._log.debug("Found transform: " % trans) g = g.getparent() return trans
def push_transformation(self, element): """ Extracts the transformation of an svg element If the element has no transformation resets to unit :param element: the element from which the transformation has to be extracted :type element: an svg element (lxml.etree.Element object) :raises: UnrecognizedSVGElement if the element is not recognized """ self.transform_stack.append( simpletransform.parseTransform(element.get("transform"), self.current_transform()))
def get_viewbox_transform(node): # somewhat cribbed from inkscape-silhouette doc_width, doc_height = get_doc_size(node) viewbox = node.get('viewBox').strip().replace(',', ' ').split() dx = -float(viewbox[0]) dy = -float(viewbox[1]) transform = simpletransform.parseTransform("translate(%f, %f)" % (dx, dy)) try: sx = doc_width / float(viewbox[2]) sy = doc_height / float(viewbox[3]) scale_transform = simpletransform.parseTransform("scale(%f, %f)" % (sx, sy)) transform = simpletransform.composeTransform(transform, scale_transform) except ZeroDivisionError: pass return transform
def get_transform_list(self, node, cummulative = []): #For each node, get all the 'transform' attributes up the node tree transform_list = cummulative try: transform_list = transform_list + [simpletransform.parseTransform(node.attrib['transform']), ] except KeyError as e: pass #If parent exists, recurse if node.getparent() != None: transform_list = self.get_transform_list(node.getparent(), transform_list) return transform_list
def process_shape(self, node, mat): rgb = (0,0,0) # stroke color fillcolor = None # fill color stroke = 1 # pen width in printer pixels # Very NB : If the pen width is greater than 1 then the output will Not be a vector output ! style = node.get('style') if style: style = simplestyle.parseStyle(style) if style.has_key('stroke'): if style['stroke'] and style['stroke'] != 'none' and style['stroke'][0:3] != 'url': rgb = simplestyle.parseColor(style['stroke']) if style.has_key('stroke-width'): stroke = self.unittouu(style['stroke-width']) stroke = int(stroke*self.scale) if style.has_key('fill'): if style['fill'] and style['fill'] != 'none' and style['fill'][0:3] != 'url': fill = simplestyle.parseColor(style['fill']) fillcolor = fill[0] + 256*fill[1] + 256*256*fill[2] color = rgb[0] + 256*rgb[1] + 256*256*rgb[2] if node.tag == inkex.addNS('path','svg'): d = node.get('d') if not d: return p = cubicsuperpath.parsePath(d) elif node.tag == inkex.addNS('rect','svg'): x = float(node.get('x')) y = float(node.get('y')) width = float(node.get('width')) height = float(node.get('height')) p = [[[x, y],[x, y],[x, y]]] p.append([[x + width, y],[x + width, y],[x + width, y]]) p.append([[x + width, y + height],[x + width, y + height],[x + width, y + height]]) p.append([[x, y + height],[x, y + height],[x, y + height]]) p.append([[x, y],[x, y],[x, y]]) p = [p] else: return trans = node.get('transform') if trans: mat = simpletransform.composeTransform(mat, simpletransform.parseTransform(trans)) simpletransform.applyTransformToPath(mat, p) hPen = mygdi.CreatePen(0, stroke, color) mygdi.SelectObject(self.hDC, hPen) self.emit_path(p) if fillcolor is not None: brush = LOGBRUSH(0, fillcolor, 0) hBrush = mygdi.CreateBrushIndirect(addressof(brush)) mygdi.SelectObject(self.hDC, hBrush) mygdi.BeginPath(self.hDC) self.emit_path(p) mygdi.EndPath(self.hDC) mygdi.FillPath(self.hDC) return
def process_shape(self, node, mat): readStrokeWidth = not self.options.ignoreStrokeWidth color = None # stroke color fillcolor = None # fill color stroke = 1 # pen width in printer pixels # Very NB : If the pen width is greater than 1 then the output will Not be a vector output ! node_style = node.get('style') if node_style: style = self.groupstyle.copy() style.update(simplestyle.parseStyle(node_style)) if style.has_key('stroke'): if style['stroke'] and style['stroke'] != 'none' and style[ 'stroke'][0:3] != 'url': rgb = simplestyle.parseColor(style['stroke']) color = rgb[0] + 256 * rgb[1] + 256 * 256 * rgb[2] if readStrokeWidth and style.has_key('stroke-width'): stroke = self.unittouu( style['stroke-width']) / self.unittouu('1px') stroke = int(stroke * self.scale) if style.has_key('fill'): if style['fill'] and style['fill'] != 'none' and style['fill'][ 0:3] != 'url': fill = simplestyle.parseColor(style['fill']) fillcolor = fill[0] + 256 * fill[1] + 256 * 256 * fill[2] if node.tag == inkex.addNS('path', 'svg'): d = node.get('d') if not d: self.not_converted.append(node.get('id')) return p = cubicsuperpath.parsePath(d) elif node.tag == inkex.addNS('rect', 'svg'): x = float(node.get('x')) y = float(node.get('y')) width = float(node.get('width')) height = float(node.get('height')) p = self.printer.rectangle_path(x, y, width, height) elif node.tag == inkex.addNS('defs', 'svg') or node.tag == inkex.addNS( 'metadata', 'svg'): # ignore svg:defs and svg:metadata return elif node.tag.startswith('{' + inkex.NSS['svg']) == False: # ignore non-SVG elements return else: self.not_converted.append(node.get('id')) return trans = node.get('transform') if trans: mat = simpletransform.composeTransform( mat, simpletransform.parseTransform(trans)) simpletransform.applyTransformToPath(mat, p) self.printer.draw_path(p, color, stroke, fillcolor)
def process_shape(self, node, mat): rgb = (0,0,0) style = node.get('style') if style: style = simplestyle.parseStyle(style) if style.has_key('stroke'): if style['stroke'] and style['stroke'] != 'none' and style['stroke'][0:3] != 'url': rgb = simplestyle.parseColor(style['stroke']) hsl = coloreffect.ColorEffect.rgb_to_hsl(coloreffect.ColorEffect(),rgb[0]/255.0,rgb[1]/255.0,rgb[2]/255.0) self.closed = 0 # only for LWPOLYLINE self.color = 7 # default is black if hsl[2]: #self.color = 1 + (int(6*hsl[0] + 0.5) % 6) # use 6 hues self.color = 1 + (int(10*hsl[0] + 0.5) % 10) # use 6 hues if node.tag == inkex.addNS('path','svg'): d = node.get('d') if not d: return if (d[-1] == 'z' or d[-1] == 'Z'): self.closed = 1 p = cubicsuperpath.parsePath(d) elif node.tag == inkex.addNS('rect','svg'): self.closed = 1 x = float(node.get('x')) y = float(node.get('y')) width = float(node.get('width')) height = float(node.get('height')) p = [[[x, y],[x, y],[x, y]]] p.append([[x + width, y],[x + width, y],[x + width, y]]) p.append([[x + width, y + height],[x + width, y + height],[x + width, y + height]]) p.append([[x, y + height],[x, y + height],[x, y + height]]) p.append([[x, y],[x, y],[x, y]]) p = [p] else: return trans = node.get('transform') if trans: mat = simpletransform.composeTransform(mat, simpletransform.parseTransform(trans)) simpletransform.applyTransformToPath(mat, p) for sub in p: for i in range(len(sub)-1): s = sub[i] e = sub[i+1] if s[1] == s[2] and e[0] == e[1]: if (self.options.POLY == 'true'): self.LWPOLY_line([s[1],e[1]]) else: self.dxf_line([s[1],e[1]]) elif (self.options.ROBO == 'true'): self.ROBO_spline([s[1],s[2],e[0],e[1]]) else: self.dxf_spline([s[1],s[2],e[0],e[1]])
def effect(self): """This is the main entry point""" # based partially on the restack.py extension if self.selected: # TODO check for non-path elements? # TODO it seems like the order of selection is not consistent # for each selected item - TODO make this be all objects, everywhere # I can think of two options: # 1. Iterate over all paths in root, then iterate over all layers, and their paths # 2. Some magic with xpath? (would this limit us to specific node types?) objlist = [] for id_, node in self.selected.iteritems(): transform = node.get('transform') if transform: transform = simpletransform.parseTransform(transform) item = (id_, self.get_start_end(node, transform)) objlist.append(item) # sort / order the objects sort_order, air_distance_default, air_distance_ordered = find_ordering_naive( objlist) air_distance_default = float(air_distance_default) air_distance_ordered = float(air_distance_ordered) for id_ in sort_order: # There's some good magic here, that you can use an # object id to index into self.selected. Brilliant! self.current_layer.append(self.selected[id_]) if air_distance_default > 0: # don't divide by zero. :P improvement_pct = 100 * ( (air_distance_default - air_distance_ordered) / air_distance_default) inkex.errormsg( gettext.gettext( "Selected paths have been reordered and optimized for quicker EggBot plotting.\n\n" "Original air-distance: {0:f}\n" "Optimized air-distance: {1:f}\n" "Distance reduced by: {2:1.2f}%\n\n" "Have a nice day!".format(air_distance_default, air_distance_ordered, improvement_pct))) else: inkex.errormsg( gettext.gettext( "Unable to start. Please select multiple distinct paths. :)" ))
def __init__(self, layerElement): ''' ''' transform = layerElement.get( "transform" ) if not transform is None: matrix = simpletransform.parseTransform( transform ) dx = matrix[ 0 ][ 2 ] dy = matrix[ 1 ][ 2 ] else: dx = 0 dy = 0 self._transformX = dx self._transformY = dy
def getPaths(layer,flat=1.0): "return list of lists of float pairs" paths = [] for item in layer.getchildren(): if item.tag == inkex.addNS('g', 'svg'): transform = simpletransform.parseTransform(item.get('transform')) for i in item.getchildren(): if i.tag == inkex.addNS('path','svg'): paths.append(Path(i, flat, transform)) if item.tag == inkex.addNS('path','svg'): paths.append(Path(item, flat)) return paths
def rect_bounding_box(rect, box=None): """Get the bounding box of an SVG rectangle. :param rect: The XML node defining the object. :param box: The existing :class:`bounds.BoundingBox` if available. :return: A :class:`bounds.BoundingBox` encompassing the object. """ # Get the position and dimension of the rectangle x = float(rect.get('x', 0)) y = float(rect.get('y', 0)) width = float(rect.get('width')) height = float(rect.get('height')) # Width and height can't be negative if width < 0: raise ValueError(_('Width of rect object cannot be negative.')) if height < 0: raise ValueError(_('Height of rect object cannot be negative.')) # Width or height of zero disables rendering if width == 0 or height == 0: return box # Create the four points bl = [x, y] br = [x + width, y] tr = [x + width, y + height] tl = [x, y + height] # Get the transform transform = rect.get('transform', None) if transform: transform = simpletransform.parseTransform(transform) simpletransform.applyTransformToPoint(transform, bl) simpletransform.applyTransformToPoint(transform, br) simpletransform.applyTransformToPoint(transform, tr) simpletransform.applyTransformToPoint(transform, tl) # Extend the box if box is None: box = BoundingBox(bl[0], bl[0], bl[1], bl[1]) else: box.extend(bl) box.extend(br) box.extend(tr) box.extend(tl) # And done. return box
def handleViewBox( self ): ''' Set up the document-wide transform in the event that the document has an SVG viewbox ''' if self.getDocProps(): viewbox = self.document.getroot().get( 'viewBox' ) if viewbox: vinfo = viewbox.strip().replace( ',', ' ' ).split( ' ' ) if ( vinfo[2] != 0 ) and ( vinfo[3] != 0 ): sx = self.docWidth / float( vinfo[2] ) sy = self.docHeight / float( vinfo[3] ) self.docTransform = simpletransform.parseTransform( 'scale(%f,%f)' % (sx, sy) )