def get_offset(node, x=0, y=0): if node.firstChild is not None and is_path(node.firstChild): path_definition = node.firstChild.getAttribute("d") xmin, ymin, xmax, ymax = Path(path_definition).bbox() # use path's bounding box to get the center of the ayah marker x += Decimal(xmin + ((xmax - xmin) / 2)) y += Decimal(ymin + ((ymax - ymin) / 2)) try: transform = scour.svg_transform_parser.parse( node.getAttribute("transform")) while len(transform) > 0: tr, vals = transform.pop() if tr == "translate": x += vals[0] y += vals[1] if tr == "matrix": x = vals[0] * x + vals[2] * y + vals[4] y = vals[1] * y + vals[3] * y + vals[5] except NotFoundErr: pass except AttributeError: pass if node.parentNode is not None: return get_offset(node.parentNode, x, y) return x, y
def gen_placement(self): cx1, cy1, cx2, cy2 = self.boxes["canvas"] width = cx2 - cx1 + 10 height = cy2 - cy1 + 10 svg = """<svg width="%d" height="%d" xmlns="http://www.w3.org/2000/svg" >""" % (width, height) for b in self.boxes: if b == "canvas": continue shape = b if len(b) == 2: shape = shape[0] print("placing ", b, " with shape: ", shape) path = self.paths[shape] x1, y1, x2, y2 = self.boxes[b] w = x2 - x1 h = y2 - y1 print(x1, y1, x2, y2, w, h) sp = Path(path) sp = self.normalize(sp) sp = self.transform(sp, x1, y1, w, h) print("shape box:", sp.bbox()) d = sp.d() svg += """ <rect x="%d" y="%d" width="%d" height="%d" stroke="black" stroke-width="2" fill="none" />""" % (x1, y1, w, h) svg += """ <path style="fill:none" stroke="red" stroke-width="3" d="%s" />""" % d svg += "</svg>" with open("svg/layout.svg", "w") as fout: fout.write(svg)
def gen_raw_svg(self): """generate standard view of shapes""" for s in self.paths: shape_path = paths[s] sp = Path(shape_path) sp = self.normalize(sp) bb = sp.bbox() x1, y1, x2, y2 = bb dx = x2 - x1 dy = y2 - y1 sp = self.transform(sp, 20, 20, dx * 0.6, dy * 0.6) d = sp.d() db = "M 20,20 h %s v %s H 20 V 20 Z" % (dx * 0.6, dy * 0.6) svg = """<svg width="%d" height="%d" xmlns="http://www.w3.org/2000/svg" >""" % (dx, dy) svg += """ <path style="fill:none" stroke="black" stroke-width="3" d="%s" />""" % db svg += """ <path style="fill:none" stroke="red" stroke-width="3" d="%s" />""" % d svg += """" </svg>""" fname = "%s/raw_%s.svg" % (SVGDIR, s) with open(fname, "w") as fout: fout.write(svg)
def get_surah_header_positions(nodes): found = [] for node in nodes: if is_group(node): found.extend(get_surah_header_positions(node.childNodes)) if is_path(node): path_definition = node.getAttribute("d") xmin, ymin, xmax, ymax = Path(path_definition).bbox() width, height = xmax - xmin, ymax - ymin if round(width) in range(245, 250) and round(height) in range( 25, 30): x, y = get_offset(node.parentNode) found.append((x, y)) return found
def generate(self): if self.operation in ("Cut", "Engrave"): yield COMMAND_MODE_RAPID yield COMMAND_SET_ABSOLUTE yield COMMAND_SET_SPEED, self.speed yield COMMAND_SET_STEP, 0 yield COMMAND_SET_POWER, self.power if self.dratio is not None and self.dratio_custom: yield COMMAND_SET_D_RATIO, self.dratio else: yield COMMAND_SET_D_RATIO, None if self.acceleration is not None and self.acceleration_custom: yield COMMAND_SET_ACCELERATION, self.acceleration else: yield COMMAND_SET_ACCELERATION, None try: first = abs(self[0]).first_point yield COMMAND_MOVE, first[0], first[1] except (IndexError, AttributeError): pass yield COMMAND_MODE_PROGRAM for object_path in self: if isinstance(object_path, SVGImage): box = object_path.bbox() plot = Path( Polygon((box[0], box[1]), (box[0], box[3]), (box[2], box[3]), (box[2], box[1]))) yield COMMAND_PLOT, plot else: plot = abs(object_path) yield COMMAND_PLOT, plot yield COMMAND_MODE_RAPID elif self.operation in ("Raster", "Image"): yield COMMAND_MODE_RAPID yield COMMAND_SET_ABSOLUTE yield COMMAND_SET_SPEED, self.speed direction = self.raster_direction yield COMMAND_SET_POWER, self.power yield COMMAND_SET_D_RATIO, None if self.acceleration is not None and self.acceleration_custom: yield COMMAND_SET_ACCELERATION, self.acceleration else: yield COMMAND_SET_ACCELERATION, None crosshatch = False traverse = 0 if direction == 0: traverse |= X_AXIS traverse |= TOP elif direction == 1: traverse |= X_AXIS traverse |= BOTTOM elif direction == 2: traverse |= Y_AXIS traverse |= RIGHT elif direction == 3: traverse |= Y_AXIS traverse |= LEFT elif direction == 4: traverse |= X_AXIS traverse |= TOP crosshatch = True if self.raster_swing: traverse |= UNIDIRECTIONAL for svgimage in self: if not isinstance(svgimage, SVGImage): continue # We do not raster anything that is not classed properly. if self.operation == "Raster": step = self.raster_step else: try: step = int(svgimage.values['raster_step']) except (KeyError, ValueError): step = 1 yield COMMAND_SET_STEP, step image = svgimage.image width, height = image.size mode = image.mode if mode != "1" and mode != "P" and mode != "L" and mode != "RGB" and mode != "RGBA": # Any mode without a filter should get converted. image = image.convert("RGBA") mode = image.mode if mode == "1": def image_filter(pixel): return (255 - pixel) / 255.0 elif mode == "P": p = image.getpalette() def image_filter(pixel): v = p[pixel * 3] + p[pixel * 3 + 1] + p[pixel * 3 + 2] return 1.0 - v / 765.0 elif mode == "L": def image_filter(pixel): return (255 - pixel) / 255.0 elif mode == "RGB": def image_filter(pixel): return 1.0 - (pixel[0] + pixel[1] + pixel[2]) / 765.0 elif mode == "RGBA": def image_filter(pixel): return (1.0 - (pixel[0] + pixel[1] + pixel[2]) / 765.0) * pixel[3] / 255.0 else: raise ValueError # this shouldn't happen. m = svgimage.transform data = image.load() overscan = self.overscan if overscan is None: overscan = 20 else: try: overscan = int(overscan) except ValueError: overscan = 20 tx = m.value_trans_x() ty = m.value_trans_y() raster = RasterPlotter(data, width, height, traverse, 0, overscan, tx, ty, step, image_filter) yield COMMAND_MODE_RAPID x, y = raster.initial_position_in_scene() yield COMMAND_MOVE, x, y top, left, x_dir, y_dir = raster.initial_direction() yield COMMAND_SET_DIRECTION, top, left, x_dir, y_dir yield COMMAND_MODE_PROGRAM yield COMMAND_RASTER, raster if crosshatch: cross_traverse = traverse cross_traverse ^= Y_AXIS if traverse & Y_AXIS: cross_traverse ^= RIGHT if int(round( width)) & 1 and not traverse & UNIDIRECTIONAL: cross_traverse ^= BOTTOM else: cross_traverse ^= BOTTOM if int(round( height)) & 1 and not traverse & UNIDIRECTIONAL: cross_traverse ^= RIGHT cross_raster = RasterPlotter(data, width, height, cross_traverse, 0, overscan, tx, ty, step, image_filter) yield COMMAND_MODE_RAPID x, y = cross_raster.initial_position_in_scene() yield COMMAND_MOVE, x, y top, left, x_dir, y_dir = cross_raster.initial_direction() yield COMMAND_SET_DIRECTION, top, left, x_dir, y_dir yield COMMAND_MODE_PROGRAM yield COMMAND_RASTER, cross_raster yield COMMAND_MODE_RAPID
if args.verbose: # Debug the device. device.execute('Debug Device') kernel.execute('Debug Device') if args.input is not None: # load the given filename. import os kernel.load(os.path.realpath(args.input.name)) if args.path is not None: # Force the inclusion of the path. from svgelements import Path try: path = Path(args.path) path.stroke = Color('blue') kernel.elements.add_elem(path) except Exception: print("SVG Path Exception to: %s" % ' '.join(sys.argv)) if args.transform: # Transform any data loaded data from svgelements import Matrix m = Matrix(args.transform) for e in kernel.elements.elems(): e *= m try: e.modified() except AttributeError: pass
width="%d" height="%d" stroke="black" stroke-width="2" fill="none" />""" % (x1, y1, w, h) svg += """ <path style="fill:none" stroke="red" stroke-width="3" d="%s" />""" % d svg += "</svg>" with open("svg/layout.svg", "w") as fout: fout.write(svg) def get_logo_placement(self, size): """calculate scale and x,y to fit in circle of radius=size""" x1, y1, x2, y2 = boxes["canvas"] width = x2 - x1 height = y2 - y1 ar = width / height if __name__ == "__main__": l = Logo(1000) heart = paths["heart"] bbox = boxes["heart"] print(heart) p = Path(heart) print(p.d()) print(p.bbox()) x1, y1, x2, y2 = bbox print(x1, y1, x2, y2) l.gen_raw_svg() l.gen_placement()
def __init__(self, path_obj: se.Path, **kwargs): # Get rid of arcs path_obj.approximate_arcs_with_quads() self.path_obj = path_obj super().__init__(**kwargs)
if isinstance(v, bool): setattr(kernel.device, attr, bool(value)) elif isinstance(v, int): setattr(kernel.device, attr, int(value)) elif isinstance(v, float): setattr(kernel.device, attr, float(value)) elif isinstance(v, str): setattr(kernel.device, attr, str(value)) if args.input is not None: import os kernel.load(os.path.realpath(args.input.name)) if args.path is not None: from svgelements import Path kernel.elements.append(Path(args.path)) if args.verbose: kernel.device.execute('Debug Device') if args.transform: m = Matrix(args.transform) for e in kernel.elements: e *= m if args.mock: kernel.device.setting(bool, 'mock', True) kernel.device.mock = True if args.egv is not None: kernel.device.pipe.write(bytes(args.egv.replace('$', '\n') + '\n', "utf8"))
def entity_to_svg(elements, dxf, entity, scale): """ Entity to svg converts the ezdxf entity into a comparable svg element. This is used to convert the data into a format vpype reads and can process. :param elements: :param dxf: :param entity: :param scale: :return: """ element = None try: entity.transform_to_wcs(entity.ocs()) except AttributeError: pass if entity.dxftype() == "CIRCLE": element = Circle(center=entity.dxf.center, r=entity.dxf.radius) elif entity.dxftype() == "ARC": circ = Circle(center=entity.dxf.center, r=entity.dxf.radius) start_angle = Angle.degrees(entity.dxf.start_angle) end_angle = Angle.degrees(entity.dxf.end_angle) if end_angle < start_angle: end_angle += Angle.turns(1) element = Path(circ.arc_angle(start_angle, end_angle)) elif entity.dxftype() == "ELLIPSE": # TODO: needs more math, axis is vector, ratio is to minor. element = Ellipse( center=entity.dxf.center, # major axis is vector # ratio is the ratio of major to minor. start_point=entity.start_point, end_point=entity.end_point, start_angle=entity.dxf.start_param, end_angle=entity.dxf.end_param, ) elif entity.dxftype() == "LINE": # https://ezdxf.readthedocs.io/en/stable/dxfentities/line.html element = SimpleLine( x1=entity.dxf.start[0], y1=entity.dxf.start[1], x2=entity.dxf.end[0], y2=entity.dxf.end[1], ) elif entity.dxftype() == "POINT": element = Path(Move(entity.dxf.location)) + "z" elif entity.dxftype() == "POLYLINE": # https://ezdxf.readthedocs.io/en/stable/dxfentities/lwpolyline.html if entity.is_2d_polyline: if not entity.has_arc: if entity.is_closed: element = Polygon([(p[0], p[1]) for p in entity.points()]) else: element = Polyline([(p[0], p[1]) for p in entity.points()]) else: element = Path() bulge = 0 for e in entity: point = e.dxf.location if bulge == 0: element.line((point[0], point[1])) else: element += Arc( start=element.current_point, end=(point[0], point[1]), bulge=bulge, ) bulge = e.dxf.bulge if entity.is_closed: if bulge == 0: element.closed() else: element += Arc( start=element.current_point, end=element.z_point, bulge=bulge, ) element.closed() elif entity.dxftype() == "LWPOLYLINE": # https://ezdxf.readthedocs.io/en/stable/dxfentities/lwpolyline.html if not entity.has_arc: if entity.closed: element = Polygon(*[(p[0], p[1]) for p in entity]) else: element = Polyline(*[(p[0], p[1]) for p in entity]) else: element = Path() bulge = 0 for e in entity: if bulge == 0: element.line((e[0], e[1])) else: element += Arc(start=element.current_point, end=(e[0], e[1]), bulge=bulge) bulge = e[4] if entity.closed: if bulge == 0: element.closed() else: element += Arc( start=element.current_point, end=element.z_point, bulge=bulge, ) element.closed() elif entity.dxftype() == "HATCH": # https://ezdxf.readthedocs.io/en/stable/dxfentities/hatch.html element = Path() if entity.bgcolor is not None: Path.fill = Color(entity.bgcolor) for p in entity.paths: if p.path_type_flags & 2: for v in p.vertices: element.line(v[0], v[1]) if p.is_closed: element.closed() else: for e in p.edges: if type(e) == "LineEdge": # https://ezdxf.readthedocs.io/en/stable/dxfentities/hatch.html#ezdxf.entities.LineEdge element.line(e.start, e.end) elif type(e) == "ArcEdge": # https://ezdxf.readthedocs.io/en/stable/dxfentities/hatch.html#ezdxf.entities.ArcEdge circ = Circle( center=e.center, radius=e.radius, ) element += circ.arc_angle(Angle.degrees(e.start_angle), Angle.degrees(e.end_angle)) elif type(e) == "EllipseEdge": # https://ezdxf.readthedocs.io/en/stable/dxfentities/hatch.html#ezdxf.entities.EllipseEdge element += Arc( radius=e.radius, start_angle=Angle.degrees(e.start_angle), end_angle=Angle.degrees(e.end_angle), ccw=e.is_counter_clockwise, ) elif type(e) == "SplineEdge": # https://ezdxf.readthedocs.io/en/stable/dxfentities/hatch.html#ezdxf.entities.SplineEdge if e.degree == 3: for i in range(len(e.knot_values)): control = e.control_values[i] knot = e.knot_values[i] element.quad(control, knot) elif e.degree == 4: for i in range(len(e.knot_values)): control1 = e.control_values[2 * i] control2 = e.control_values[2 * i + 1] knot = e.knot_values[i] element.cubic(control1, control2, knot) else: for i in range(len(e.knot_values)): knot = e.knot_values[i] element.line(knot) elif entity.dxftype() == "IMAGE": bottom_left_position = entity.dxf.insert size = entity.dxf.image_size imagedef = entity.dxf.image_def_handle if not isinstance(imagedef, str): imagedef = imagedef.filename element = SVGImage( href=imagedef, x=bottom_left_position[0], y=bottom_left_position[1] - size[1], width=size[0], height=size[1], ) elif entity.dxftype() == "MTEXT": insert = entity.dxf.insert element = SVGText(x=insert[0], y=insert[1], text=entity.text) elif entity.dxftype() == "TEXT": insert = entity.dxf.insert element = SVGText(x=insert[0], y=insert[1], text=entity.dxf.text) elif entity.dxftype() == "SOLID" or entity.dxftype() == "TRACE": # https://ezdxf.readthedocs.io/en/stable/dxfentities/solid.html element = Path() element.move((entity[0][0], entity[0][1])) element.line((entity[1][0], entity[1][1])) element.line((entity[2][0], entity[2][1])) element.line((entity[3][0], entity[3][1])) element.closed() element.fill = Color("Black") elif entity.dxftype() == "SPLINE": element = Path() try: for b in entity.construction_tool().bezier_decomposition(): if len(element) == 0: element.move((b[0][0], b[0][1])) if len(b) == 4: element.cubic((b[1][0], b[1][1]), (b[2][0], b[2][1]), (b[3][0], b[3][1])) elif len(b) == 3: element.quad((b[1][0], b[1][1]), (b[2][0], b[2][1])) except (AttributeError, TypeError): # Fallback for rational b-splines. try: for bezier in entity.construction_tool( ).cubic_bezier_approximation(4): b = bezier.control_points if len(b) == 4: element.cubic( (b[1][0], b[1][1]), (b[2][0], b[2][1]), (b[3][0], b[3][1]), ) elif len(b) == 3: element.quad((b[1][0], b[1][1]), (b[2][0], b[2][1])) except (AttributeError, TypeError): # Fallback for versions of EZDXF prior to 0.13 element.move(entity.control_points[0]) for i in range(1, entity.dxf.n_control_points): element.line(entity.control_points[i]) if entity.closed: element.closed() elif entity.dxftype() == "INSERT": for e in entity.virtual_entities(): if e is None: continue entity_to_svg(elements, dxf, e, scale) return else: return # Might be something unsupported. layer = dxf.layers.get(entity.dxf.layer) # block = dxf.blocks.get(entity.dxf.block) if entity.rgb is not None: if isinstance(entity.rgb, tuple): element.stroke = Color(*entity.rgb) else: element.stroke = Color(entity.rgb) else: c = entity.dxf.color if c == ezdxf.const.BYLAYER: c = layer.color try: if c == ezdxf.const.BLACK: # Color 7 is black on light backgrounds, light on black. color = Color("black") else: color = Color(*int2rgb(DXF_DEFAULT_COLORS[c])) except: color = Color("black") element.stroke = color element.transform.post_scale(scale, -scale) element.values[SVG_ATTR_VECTOR_EFFECT] = SVG_VALUE_NON_SCALING_STROKE if isinstance(element, SVGText): elements.append(element) else: path = abs(Path(element)) if len(path) != 0: if not isinstance(path[0], Move): path = Move(path.first_point) + path elements.append(path)