def number(num: int) -> Line: if 0 > num > 9999: raise RuntimeError( 'Cistercian numbers can only represent numbers from 0 to 9999') num_drawing = Group() num_drawing.add(zero()) if num != 0: for i, digit in enumerate(reversed(str(num))): digit_drawing = draw_functions[int(digit)]() offset = offsets[i] try: isnt_flat = bool(digit_drawing['y1'] - digit_drawing['y2']) except KeyError: isnt_flat = True if offset[1] and isnt_flat: offset = (offset[0], offset[1] - 10) digit_drawing.translate(offset) if i % 2 != 0: digit_drawing.scale((-1, 1)) digit_drawing.translate((-10, 0)) if i > 1: if isnt_flat: digit_drawing.scale((1, -1)) digit_drawing.translate((0, -10)) elif digit == '2': digit_drawing.translate((0, -20)) num_drawing.add(digit_drawing) num_drawing.translate((20, 20)) return num_drawing
def save(cls, image, filename, mosaic=False): # Use debug=False everywhere to turn off SVG validation, # which turns out to be obscenely expensive in this # library. DEBUG = False svg = svgwrite.Drawing(filename=filename, style='background-color: black;', size=(("%dpx" % (2 * image.r_outer), "%dpx" % (2 * image.r_outer))), debug=DEBUG) group = Group(debug=DEBUG) group.translate(image.r_outer, image.r_outer) for y, row in enumerate(image.pixels): ring = image.rings[y] theta = 2 * math.pi / len(row) r1 = ring.center + image.r_ring / 2 r2 = ring.center - image.r_ring / 2 for x, c in enumerate(row): if mosaic: path = Path(stroke='black', stroke_width=1, fill=cls.color_hex(c), debug=DEBUG) path.push((('M', 0, r2), ('L', 0, r1), ('A', r1, r1, 0, '0,0', (r1 * sin(theta), r1 * cos(theta))), ('L', r2 * sin(theta), r2 * cos(theta)), ('A', r2, r2, 0, '0,1', (0, r2)))) else: path = Path(stroke=cls.color_hex(c), stroke_width=image.r_pixel, fill='none', debug=DEBUG) path.push((('M', 0, ring.center), ('A', ring.center, ring.center, 0, '0,0', (ring.center * sin(theta), ring.center * cos(theta))))) path.rotate(180 - degrees(theta * (x + 1)), center=(0, 0)) group.add(path) svg.add(group) svg.save()
def save(cls, image, filename, mosaic=False): # Use debug=False everywhere to turn off SVG validation, # which turns out to be obscenely expensive in this # library. DEBUG = False svg = svgwrite.Drawing(filename=filename, style='background-color: black;', size=(("%dpx" % (2 * image.r_outer), "%dpx" % (2 * image.r_outer))), debug=DEBUG) group = Group(debug=DEBUG) group.translate(image.r_outer, image.r_outer) for y, row in enumerate(image.pixels): ring = image.rings[y] theta = 2 * math.pi / len(row) r1 = ring.center + image.r_ring / 2 r2 = ring.center - image.r_ring / 2 for x, c in enumerate(row): if mosaic: path = Path(stroke='black', stroke_width=1, fill=cls.color_hex(c), debug=DEBUG) path.push( (('M', 0, r2), ('L', 0, r1), ('A', r1, r1, 0, '0,0', (r1 * sin(theta), r1 * cos(theta))), ('L', r2 * sin(theta), r2 * cos(theta)), ('A', r2, r2, 0, '0,1', (0, r2)))) else: path = Path(stroke=cls.color_hex(c), stroke_width=image.r_pixel, fill='none', debug=DEBUG) path.push((('M', 0, ring.center), ('A', ring.center, ring.center, 0, '0,0', (ring.center * sin(theta), ring.center * cos(theta))))) path.rotate(180 - degrees(theta * (x + 1)), center=(0, 0)) group.add(path) svg.add(group) svg.save()
def new_drawing(filename='plot.svg', display_scale=1): from svgwrite.drawing import Drawing from svgwrite.container import Group size = 2 * PADDING + SCALE dwg = Drawing(filename, size=(size * display_scale, size * display_scale)) dwg.viewbox(minx=0, miny=0, width=size, height=size) add_stylesheet(dwg) canvas = Group(id='canvas') canvas.translate(PADDING, PADDING) canvas.scale(1, -1) canvas.translate(0, -SCALE) dwg.add(canvas) return dwg, canvas
def convert_font(): cwd = pathlib.Path.cwd() for root, dirs, files in os.walk('{}/exports'.format(cwd)): for name in files: source = os.path.join(root, name) target = 'fonts/{}.min.svg'.format(name.split('.')[0]) print(source) try: paths, attr = svg2paths(source) except Exception as e: print(e) continue try: xmin, xmax, ymin, ymax = bounding_box(paths) except Exception as e: print(e) continue dx = xmax - xmin dy = ymax - ymin viewbox = '{} {} {} {}'.format(xmin, ymin, dx, dy) attr = {'viewBox': viewbox, 'preserveAspectRatio': 'xMidYMid meet'} wsvg(paths=paths, svg_attributes=attr, filename=source) doc = SaxDocument(source) d = doc.get_pathd_and_matrix()[0] g = Group() dwg = svgwrite.Drawing(target) dwg.viewbox(minx=xmin, miny=ymin, width=dx, height=dy) dwg.add(g) g.scale(sx=1, sy=-1) g.translate(tx=0, ty=-dy - ymin * 2) g.add(dwg.path(d)) dwg.save() generate_pdf(target)
def encode(self, bits_data: List[int]): tattoo_bit_height = int(len(bits_data) / 8) x, y = 0, 0 xmin, xmax = 0, 0 ymin, ymax = 0, 0 tattoo = Group(id="tattoo") for j in range(tattoo_bit_height): for i in range(8): if x > xmax: xmax = x if y > ymax: ymax = y bit = bits_data.pop() if bit == 0: tattoo.add(Use("#zero", (x, y))) elif bit == 1: tattoo.add(Use("#one", (x, y))) else: raise RuntimeError() x, y = self.shift_bit(x, y) x, y = self.shift_byte(j, y) xmax += self.poly.inner_circle_radius * self.dimens.bit_radius * 2 ymax += self.poly.outer_circle_radius * self.dimens.bit_radius * 2 tattoo_width = xmax - xmin tattoo_height = ymax - ymin scaled_width_mm = 65 scale_factor = scaled_width_mm * 3.78 / tattoo_width scaled_height_mm = tattoo_height * scale_factor / 3.78 tattoo.scale(scale_factor) tattoo.translate( 3.78 * (210 - scaled_width_mm) / 2, 3.78 * (297 - scaled_height_mm) / 2 ) self.dwg.add(tattoo) self.dwg.save(pretty=True)
def nest(output, files, wbin, hbin, enclosing_rectangle=False): packer = newPacker() def float2dec(x): return _float2dec(x, 4) def bbox_paths(paths): bbox = None for p in paths: p_bbox = p.bbox() if bbox is None: bbox = p_bbox else: bbox = (min(p_bbox[0], bbox[0]), max(p_bbox[1], bbox[1]), min(p_bbox[2], bbox[2]), max(p_bbox[3], bbox[3])) return tuple(float2dec(x) for x in bbox) all_paths = {} for svg\ in files: paths, attributes = svg2paths(svg) bbox = bbox_paths(paths) for i in range(files[svg]): rid = svg + str(i) all_paths[rid] = {'paths': paths, 'bbox': bbox} print(rid) packer.add_rect(bbox[1] - bbox[0], bbox[3] - bbox[2], rid=rid) print('Rectangle packing...') while True: packer.add_bin(wbin, hbin) packer.pack() rectangles = {r[5]: r for r in packer.rect_list()} if len(rectangles) == len(all_paths): break else: print('not enough space in the bin, adding ') combineds = {} print('packing into SVGs...') for rid, obj in all_paths.items(): paths = obj['paths'] bbox = obj['bbox'] group = Group() width, height = (float2dec(bbox[1] - bbox[0]), float2dec(bbox[3] - bbox[2])) bin, x, y, w, h, _ = rectangles[rid] if bin not in combineds: svg_file = output if bin != 0: splitext = os.path.splitext(svg_file) svg_file = splitext[0] + '.%s' % bin + splitext[1] dwg = Drawing(svg_file, profile='tiny', size=('%smm' % wbin, '%smm' % hbin), viewBox="0 0 %s %s" % (wbin, hbin)) combineds[bin] = dwg combined = combineds[bin] if (width > height and w > h) or \ (width < height and w < h) or \ (width == height and w == h): rotate = 0 dx = -bbox[0] dy = -bbox[2] else: rotate = 90 dx = -bbox[2] dy = -bbox[0] for p in paths: path = Path(d=p.d()) path.stroke(color='red', width='1') path.fill(opacity=0) group.add(path) group.translate(x + dx, y + dy) group.rotate(rotate) combined.add(group) for combined in combineds.values(): if enclosing_rectangle: r = Rect(size=(wbin, hbin)) r.fill(opacity=0) r.stroke(color='lightgray') combined.add(r) print('SVG saving...') combined.save(pretty=True)
def make_svg(self, data): layers = data["layers"] _PROPORTION = 10 _SHIFT_PROP = _PROPORTION / 1.5 for f in self.forms: structures = [None] * len(f.id.split("_")) linkers = [] centers = {} order = {} maxW, maxH = 0, 0 for cx, x in enumerate(f.id.split("_")): order[x] = cx for cl, l in enumerate(layers): for cs, s in enumerate(l): name = f.id + "__" + s["id"] if s["type"] == "H": color = "cornflowerblue" if "ref" not in s else "gainsboro" shape = Circle( center = (s["shift_x"] * _SHIFT_PROP, s["shift_z"] * _SHIFT_PROP), r = 2.3 * _PROPORTION, id = name, fill = color, stroke="black", stroke_width = "2") elif s["type"] == "E": color = "indianred" if "ref" not in s else "salmon" rotate = f.get_ss_by_id(s["id"]).struc.goes_down() shape = Triangle(center = (s["shift_x"] * _SHIFT_PROP, s["shift_z"] * _SHIFT_PROP), rc = 2.3 * _PROPORTION, id = name, fill=color, stroke = "black", stroke_width = "2", rotate = rotate) else: color = "darkgreen" if "ref" not in s else "lightgreen" shape = Cross(center = (s["shift_x"] * _SHIFT_PROP, s["shift_z"] * _SHIFT_PROP), r = 2.3 * _PROPORTION, fill=color, stroke="black", stroke_width = "2", id = name) structures[order[s["id"]]] = shape centers[s["id"]] = [s["shift_x"] * _SHIFT_PROP, s["shift_z"] * _SHIFT_PROP] if s["shift_x"] * _SHIFT_PROP > maxW: maxW = s["shift_x"] * _SHIFT_PROP if s["shift_z"] * _SHIFT_PROP > maxH: maxH = s["shift_z"] * _SHIFT_PROP for cx, x in enumerate(f.id.split("_")): if cx == 0 or cx == len(f.id.split("_")) - 1: init = [0, 0] if (ord(x[0]) - 64) <= len(layers) / 2: init[1] = centers[x][1] - (2.3 * _PROPORTION * 2) else: init[1] = centers[x][1] + (2.3 * _PROPORTION * 2) if int(re.search("(\d+)", x).group(1)) <= len(layers[ord(x[0]) - 65]) / 2: init[0] = centers[x][0] - (2.3 * _PROPORTION * 2) else: init[0] = centers[x][0] + (2.3 * _PROPORTION * 2) if cx == 0: shape = Line(init, centers[x], stroke="darkblue", stroke_width = "4") elif cx == len(f.id.split("_")) - 1: shape = Line(centers[x], init, stroke="darkred", stroke_width = "4") linkers.append(shape) for cy, y in enumerate(f.id.split("_")): if cy == cx + 1: shape = Line(centers[x], centers[y], stroke="black", stroke_width = "4") linkers.append(shape) # Intercalate toplink = [] dowlink = [] if f.sslist[0].struc.goes_up(): dowlink = linkers[0:][::2] toplink = linkers[1:][::2] else: dowlink = linkers[1:][::2] toplink = linkers[0:][::2] g = Group() for x in dowlink: g.add(x) for x in structures: g.add(x) for x in toplink: g.add(x) g.translate(2.3 * _PROPORTION * 3, 2.3 * _PROPORTION * 3) d = Drawing(size = (maxW + ((2.3 * _PROPORTION * 3) * 2), maxH + ((2.3 * _PROPORTION * 3) * 2)), id = f.id + "__image") d.add(g) for x in data["forms"]: if x["id"] == f.id: x["svg"] = d.tostring()