def getBonds(svg,allowedColour=["#000000","#ff0000"]): """ Extract the bonds from the SVG file. """ paths, attributes = svgp.svg2paths(svg) bondList = [] for i_path,path in enumerate(paths): colour = attributes[i_path]["stroke"] isBond = (colour in allowedColour) and (len(path)>1) if isBond: segLen = [] for i,segment in enumerate(path): #print(i,segment,segment.length()) segLen.append(segment.length()) #print(segLen,segLen[0],segLen[-1]) if segLen[0]>segLen[-1]: ## Tail at start bondTail = path[0][0] bondHead = path[-2][1] else: bondTail = path[-1][1] bondHead = path[1][0] #print("Tail:",bondTail, "Head:", bondHead ) bondList.append([bondTail,bondHead]) return bondList
def load_svg_environment(svg_file, size=10, offset=1): paths = svgpathtools.svg2paths(svg_file, return_svg_attributes=False)[0] points = [] min_x = math.inf min_y = math.inf max_x = -math.inf max_y = -math.inf for path in paths: for line in path: if line.start.real < min_x: min_x = line.start.real if line.start.imag < min_y: min_y = line.start.imag if line.start.real > max_x: max_x = line.start.real if line.start.imag > max_y: max_y = line.start.imag scale = size - 2*offset for path in paths: for line in path: p_start_x = offset + scale * (line.start.real - min_x) / (max_x - min_x) p_start_y = offset + scale * (line.start.imag - min_y) / (max_y - min_y) p_start = [p_start_x, p_start_y] p_end_x = offset + scale * (line.end.real - min_x) / (max_x - min_x) p_end_y = offset + scale * (line.end.imag - min_y) / (max_y - min_y) p_end = [p_end_x, p_end_y] points += [[p_start, p_end]] obstacle = MultiLineString(points) return obstacle
def svg2inkml(svg_file, inkml_file): paths, attributes = svg2paths( svg_file ) # attributes contains all information about every path, directly extracted from the svg file with open(inkml_file, 'w') as f: # Initial data f.write('<ink xmlns=\"http://www.w3.org/2003/InkML\">\n' '\n' '<traceFormat>\n' ' <channel name=\"X\" type=\"decimal\"/>\n' ' <channel name=\"Y\" type=\"decimal\"/>\n' '</traceFormat>\n' '\n') # Trace data for i, v in enumerate(attributes): trace_id = i f.write('<trace id=\"' + str(trace_id) + '\">\n' + v['d'].replace(' L', ', ')[1:] + '\n</trace>\n\n') # Final data f.write('<annotation type="none"></annotation>\n' '\n' '</ink>')
def __init__(self, svg_file): self.svg_file = svg_file self.height = 0.0 # svg coordinate * scale == mm self.scale = 1.0 self.cairo = cairosvg.parser.Tree(url=self.svg_file) m = re.match('([0-9.]+)([a-zA-Z]*)', self.cairo['height']) if m == None: raise SystemExit, "failed to parse SVG height: %s" % c['height'] self.height = float(m.group(1)) if len(m.groups()) == 2: if m.group(2) == "mm": self.height = float(m.group(1)) elif m.group(2) == '': # no units on the height implies 96 dpi # 1 inch/96 units * 25.4 mm/1 inch = 25.4/96 mm/unit self.scale = 25.4/96 else: raise SystemExit, "unhandled SVG units '%s'" % m.group(2) else: raise SystemExit, "weird result from re" self.paths, self.attributes = svgpathtools.svg2paths(self.svg_file)
def extractObjects(self, resultdir): resultpath = resultdir + sep svgs = listdir(resultpath) pathno = 0 for svg in svgs: if '.svg' in svg: objfile = 'objects.txt' thefile = open(resultpath + objfile, 'w') paths, attributes = svg2paths(resultpath + svg) for path in paths: s = abs(path.area()) if pathno == 0: thefile.write('Chip %f\n' % (s)) else: thefile.write("o%s %f\n" % (pathno, s)) pathno += 1 lineno = 0 for line in path: lineno += 1 thefile.write( 'line%s: %.3f+%.3fi,%.3f+%.3fi\n' % (lineno, line.start.real, line.start.imag, line.end.real, line.end.imag)) thefile.close() logger = logging.getLogger('__main__') logger.info('svg file %s finished conversion.' % (svg))
def _get_ducts(self, svg_data): svg_path = svg_data paths, attributes = svg2paths(svg_path) size_source = self.get_img_size(self.image) size_svg = self.get_img_size(svg_path) scale = (np.array(size_source) / size_svg).mean(axis=0) #from svgpathtools import Path, Line, CubicBezier NUM_SAMPLES = 1000 paths_interpol = [] for path in paths: path_interpol = [] for i in range(NUM_SAMPLES): path_interpol.append(path.point(i / (float(NUM_SAMPLES) - 1))) paths_interpol.append( np.array([[j.real for j in path_interpol], [j.imag for j in path_interpol]]).T) for i in range(len(paths)): paths_interpol[i] = (np.concatenate( [paths_interpol[i], np.ones(NUM_SAMPLES)[:, None]], axis=1) @ np.array( [[scale, 0., 0.], [0., scale, 0.], [0., 0., 1.]]))[:, :-1] return { 'paths': paths_interpol, 'linetype': [attributes[i]['class'] for i in range(len(paths))] }
def parse_svg(filename, N=1000): """ return tuple of arrays X and Y representing coordinates from the svg file 'filename' N : number of data needed in X and Y """ path, _ = svg2paths(filename) path = path[0] X = np.zeros(N, dtype=float) Y = np.zeros(N, dtype=float) i = 0 for p in np.linspace(0.0, 1.0, N): point = path.point(p) X[i] = point.real Y[i] = point.imag i += 1 # Y is reversed. reversing Y = Y.max() - Y # centering origin X = X - X.max()/2.0 Y = Y - Y.max()/2.0 return X, Y
def read_svg(svg_path, scale=100.0, draw_mode=False): """ read svg, centralised and convert to stroke-3 format scale: stroke-3 output having max dimension [-scale, +scale] """ try: paths, path_attrs = svg2paths( svg_path, return_svg_attributes=False) # svg to paths lines = [] lens = [] for path_id, path in enumerate(paths): # get poly lines from path erase = False # path could be erased by setting stroke attribute to #fff (sketchy) path_attr = path_attrs[path_id] if 'stroke' in path_attr and path_attr['stroke'] == '#fff': erase = True # try: plen = int(path.length()) # except ZeroDivisionError: # plen = 0 if plen > 0 and not erase: lines.append( [path.point(i) for i in np.linspace(0, 1, max(2, plen))]) lens.append(plen) # convert to (x,y) coordinates lines = [ np.array([[real(x), imag(x)] for x in path]) for path in lines ] # get dimension of this drawing tmp = np.concatenate(lines, axis=0) w_max, h_max = np.max(tmp, axis=0) w_min, h_min = np.min(tmp, axis=0) w = w_max - w_min h = h_max - h_min max_hw = max(w, h) def group(line): out = np.array(line, dtype=np.float32) out[:, 0] = ((out[:, 0] - w_min) / max_hw * 2.0 - 1.0) * scale out[:, 1] = ((out[:, 1] - h_min) / max_hw * 2.0 - 1.0) * scale return out # normalised lines = [group(path) for path in lines] lines_simplified = [rdp(path, epsilon=1.5) for path in lines] # apply RDP algorithm strokes_simplified = lines_to_strokes( lines_simplified) # convert to 3-stroke format (dx,dy,pen_state) # scale_bound(strokes_simplified, 10) if draw_mode: draw_strokes3(strokes_simplified, 1.0) # no need to concat the origin point print('num points: {}'.format(len(strokes_simplified))) return np.array(strokes_simplified, dtype=np.float32) except Exception as e: print('Error encountered: {} - {}'.format(type(e), e)) print('Location: {}'.format(svg_path)) raise
def load_svg(path='fox.svg', num_samples=100) -> Tuple[np.ndarray, np.ndarray]: """ Load svg file, returning set of points and their inwards normals """ from svgpathtools import svg2paths paths, attributes = svg2paths(path) main_curve = paths[0] points = [] norms = [] for t in sorted(np.random.uniform(size=(num_samples, ))): pt = np.conj(main_curve.point(t)) pt_next = np.conj(main_curve.point((t + 1e-3) % 1.0)) grad = pt_next - pt grad = grad / abs(grad) points.append([pt.imag, pt.real]) norms.append([grad.real, -grad.imag]) points = np.array(points) norma = lambda x: (x - (np.max(x, 0) + np.min(x, 0))/2) / \ (np.max(x) - np.min(x)) * 4 points = norma(points) norms = np.array(norms) return points, norms
def read_flattened_svg(filename_in): paths, attributes = svg2paths(str(filename_in)) # now you can extract the path coordinates (complex plane) with # e.g. paths[0][0].control1.imag (for a CubicBezier # type path segment) point_clouds = [] num_intermediate_points = 10. for path in paths: xs = [] ys = [] print("---------------------------") print(path) for segment in path: xs.append(segment.start.real) ys.append(segment.start.imag) if type(segment) is CubicBezier: for i in np.arange(1., num_intermediate_points ): # This probably needs adjustment point = segment.point(i / num_intermediate_points) xs.append(point.real) ys.append(point.imag) xs.append(segment.end.real) ys.append(segment.end.imag) point_clouds.append(np.transpose([np.array(xs), np.array(ys)])) point_clouds = np.array(point_clouds) # disvg(paths, attributes=attributes) return point_clouds
def orderObjects(self, svgdir, printdir): svgpath = svgdir + sep printdir = printdir + sep svgs = listdir(svgpath) if len(listdir(printdir)) == 0: for svg in svgs: if '.svg' in svg: printfile = svg.replace('.svg', '.txt') thefile = open(printdir + printfile, 'w') paths, attributes = svg2paths(svgpath + svg) size = [0] * len(paths) for currentPath in paths: pathno = paths.index(currentPath) + 1 thefile.write("o%s (%s):" % (pathno, abs(currentPath.area()))) for path in (paths[:pathno - 1] + paths[pathno:]): objno = paths.index(path) + 1 if len(currentPath.intersect(path)) != 0: thefile.write(" o%s" % objno) if pathno < objno: if abs(currentPath.area()) > abs(path.area()): size[pathno - 1] = size[objno - 1] + 1 elif abs(currentPath.area()) < abs(path.area()): size[objno - 1] = size[pathno - 1] + 1 thefile.write("\n") minsize = min(size) thefile.write("\n") for i in range(0, len(size)): size[i] = size[i] - minsize for i in range(0, len(size)): thefile.write("%d: %d\n" % (i+1, size[i])) thefile.close()
def read_wavepaths(fname): """Read wave paths from svg file.""" # read paths paths, attributes = svg2paths(fname) X = [] Y = [] Z = [] for i, path in enumerate(paths): for line in path: # point = (line.real, line.imag) x1 = line.start.real y1 = line.start.imag x2 = line.end.real y2 = line.end.imag X.append(x1) X.append(x2) Y.append(y1) Y.append(y2) Z.append(i) Z.append(i) df = pd.DataFrame() df["x"] = X df["y"] = Y df["label"] = Z return df
def main(): parser = OptionParser(description="Circle generator for draw-fft p5js drawing web app.") parser.add_option("-i", "--image", dest="image_filename", help="Path to image to transform into circles. All bitmap file types are supported and vector images in SVG.") parser.add_option("-p", "--samples-count", type="int", default=1000, dest="samples_count", help="Number of samples extracted from input image") parser.add_option("-c", "--circles-count", type="int", default=100, dest="circles_count", help="Number of output circles (harmonics)") parser.add_option("-s", "--sample-scale", type="float", default=1.0, dest="sample_scale", help="Multiplication coefficient for x and y coordinates of given image)") parser.add_option("-a", "--amplitude-scale", type="float", default=1.0, dest="amplitude_scale", help="Multiplication coefficient for radius (amplitude) of circles") parser.add_option("-f", "--frequency-scale", type="float", default=1.0, dest="frequency_scale", help="Multiplication coefficient for frequency of circles") options, args = parser.parse_args() points = None if "svg" in options.image_filename.lower(): svg_paths, _ = svg2paths(options.image_filename) vector_path = path.concatpaths(svg_paths) time = np.linspace(0.0, 1.0, options.samples_count) points = np.asarray([vector_path.point(t) for t in time]).view(np.float).reshape(options.samples_count, 2) * options.sample_scale else: image = np.asarray(Image.open(options.image_filename).convert('L')) cloud = image_to_point_cloud(image, options.samples_count) path_indexes = solve_tsp(make_dist_matrix(cloud[0, :], cloud[1, :])) points = np.asarray(list(zip(cloud[0, path_indexes], cloud[1, path_indexes]))) * options.sample_scale circles_json = calculate_circles(points, scale=options.amplitude_scale, speed=options.frequency_scale, harmonics_length=options.circles_count) print(circles_json)
def loadfile(self, filename): drawobject = None if (filename == 'test'): if (len(sys.argv) > 2): self.config.numlines = int(sys.argv[2]) width = math.ceil(numlines**0.5) height = math.ceil(numlines**0.5) pixels = [[-1 * (x * (256 / numlines) - 255), 255] for x in range(0, int(math.ceil(numlines**0.5)**2))] drawobject = DrawObject(imagetype='PNG', height=height, width=width, pixels=pixels) elif (filename.split('.')[1] == 'png'): print('loading file: ', filename) img = Image.open(filename) width = img.size[0] height = img.size[1] pix_val = list(img.getdata()) pixels = [[x, a] for (x, _, _, a) in pix_val] drawobject = DrawObject(filename=filename.split('.')[0], imagetype='PNG', height=height, width=width, pixels=pixels) elif (filename.split('.')[1] == 'svg'): print('loading file: ', filename) paths, attributes = svg2paths(filename) drawobject = DrawObject(imagetype='SVG', paths=paths, attributes=attributes) return drawobject
def path_points_from_svg(svg_filename): svg_paths, attributes = svg2paths(svg_filename) SAMPLES_PER_PX = 0.05 # List of lists of points paths = [] for path, attr in zip(svg_paths, attributes): path_length = path.length() num_samples = int(path_length * SAMPLES_PER_PX) # New list to hold points for path current_path = [] if num_samples <= 1: continue for i in range(num_samples): position_on_path = i / float(num_samples - 1) pt = path.point(position_on_path) if pt == None: break x = pt.real y = pt.imag current_path.append((x, y)) # Only add paths that contain points if len(current_path) > 0: paths.append(current_path) return paths
def read_svg(fname): paths, attr = svg2paths(fname) l = [] for p in paths: x = np.array([c.start for c in p] + [p[-1].end]) l.append(np.c_[x.real, x.imag]) # was stored as complex number return l # list of curves
def __init__(self, svgfile: str, resolution: int = 100): Graph.__init__(self) paths, attributes = svg2paths(svgfile) # rather than add a new path for each svgpath, chain the svgpath points # together for a single path point_iterator = itertools.chain.from_iterable( self._svgpath_to_points(p) for p in paths) (self.start, _) = self.add_from_path(point_iterator)
def __init__(self, svgfile: str, resolution: int = 100): super().__init__() paths, attributes = svg2paths(svgfile) # now use methods provided by the path_data object # e.g. points can be extracted using # point = path_data.pos(pos_val) # where pos_val is anything between 0 and 1 self.add_from_paths(self._svgpath_to_points(p) for p in paths)
def loadVectorGraphic(filename): svg = None attributes = None try: svg, attributes = svgpathtools.svg2paths(filename) except Exception as e: print("Couldn't load SVG file. Perhaps it doesn't exist?") print(e.message) return svg, attributes
def test_path_single_line_segment(): # Given filepath = "resources/single_segment_trendline.svg" # When paths, _ = svg2paths(filepath) xlim, lines, trend = createcsvs.categorise_paths(paths) # Then assert len(trend) == 2
def test_path_only_individual_points(): # Given filepath = "resources/no_segment_trendline.svg" # When paths, _ = svg2paths(filepath) xlim, lines, trend = createcsvs.categorise_paths(paths) # Then assert len(trend) == 3
def test_path_with_point_at_end(): # Given filepath = "resources/endpoint.svg" # When paths, _ = svg2paths(filepath) xlim, lines, trend = createcsvs.categorise_paths(paths) # Then assert len(trend) == 26
def test_path_with_points_in_middle(): # Given filepath = "resources/midpoints.svg" # When paths, _ = svg2paths(filepath) xlim, lines, trend = createcsvs.categorise_paths(paths) # Then assert len(trend) == 9
def test_categorise_paths(): # Given filepath = "resources/nogaps.svg" # When paths, _ = svg2paths(filepath) xlim, lines, trend = createcsvs.categorise_paths(paths) # Then assert len(lines) == 3
def load_svg(path): """ """ paths, attributes = svg2paths(path) result = ddd.group2() for k, v in enumerate(attributes): #print(v) # v['d'] # print d-string of k-th path in SVG # Ex svgpath = 'M10 10 C 20 20, 40 20, 50 10Z' mpl_path = parse_path(v['d']) ''' import matplotlib.pyplot as plt fig = plt.figure(figsize=(200, 200)) ax = fig.add_subplot(111) ax.axis([0, 0, 200, 200]) collection = matplotlib.collections.PathCollection([mpl_path]) collection.set_transform(ax.transData) #patch = matplotlib.patches.PathPatch(mpl_path, facecolor="red", lw=2) ax.add_artist(collection) #ax.add_patch(patch) ax.set_xlim([0, 200]) ax.set_ylim([200, 0]) plt.show() ''' coords = mpl_path.to_polygons(closed_only=True) item = ddd.polygon(coords[0]).clean() #.convex_hull() for c in coords[1:]: ng = ddd.polygon(c).clean() #.convex_hull() #ng.show() #print (ng.geom.is_valid) #if not ng.geom.is_valid: continue if item.contains(ng): item = item.subtract(ng) else: item = item.union(ng) #result = ddd.group([ddd.polygon(c) for c in coords], empty=2) result.append(item) #result = result.scale([1.0 / (48 * 64), -1.0 / (48 * 64)]) #result = result.simplify(0.005) # #result.show() result = result.union().scale([1, -1]).clean(0) xmin, ymin, xmax, ymax = result.bounds() result = result.translate([0, -(ymin + ymax)]) #result = ddd.align.anchor(result, ddd.ANCHOR_CENTER) return result
def makePointFile(name): #Method 2 # name = "curvetest5.svg" #PGedits paths, attributes = svg2paths(name) for k, v in enumerate(attributes): if (k == 0): s = v['d'] # print(v['d']) #Print out the values #Get the numbers into a list strang = str(s) for t in strang.split(): num = re.findall(r"[-+]?\d*\.\d+|\d+", t) # print("Num:") # print(num) #print("***************") for x in num: try: l.append(float(x)) except ValueError: pass # print(l) f = open('testOut.txt', 'w') f.write("< d=") for y in l: f.write(str(y)) f.write(",") f.write("/>") f.close() #return l # Return the list of points #File Writing x = 0 f = open('testOut.txt', 'w') f.write("< d=") wSpace = str(s) #print("****") #print(wSpace) #print("*****") noSpace = wSpace.replace(" ", "s") noSpace = noSpace.replace("L", "s") noSpace = noSpace.replace("Ms", "M") noSpace = noSpace.replace("ms", "m") noSpace = noSpace.replace("scs", "c") noSpace = noSpace.replace("sss", "s") noSpace = noSpace.replace("css", "c") noSpace = noSpace.replace("ssc", "c") noSpace = noSpace.replace(",-", "-") f.write(noSpace) # print(noSpace) f.write("/>") f.close()
def bucket(): paths, attributes = svg2paths('sample.svg') total_area = 0 for i in range(len(attributes)): temp_list = attributes[i]["points"].split() att_list = [] for n in range(len(temp_list)): att_list.append(temp_list[n].split(",")) if len(att_list) == 4: total_area += (abs(int(att_list[0][0]) - int(att_list[2][0])) - 1) * abs(int(att_list[0][1]) - int(att_list[2][1])) return(total_area)
def _test_01(): import matplotlib.pyplot as plt import svgpathtools paths, attr = svgpathtools.svg2paths("porcupine-svgrepo-com.svg") X = np.hstack([np.array(curve[:-1]) for path in paths for curve in path]) X = np.conjugate(X) min_, L = np.quantile(X.real, (0, 1)) X += min_ """ x = np.linspace(0, 2 * np.pi, 200 + int(np.random.random() > 0.5)) trend = np.linspace(0, 5 * np.random.random(), x.size // 2) X = ( 0.3 * np.cos(1.5 * x + 0.5) + 0.7 * np.sin(3 * x) + 0.2 * np.sin(2 * np.pi / 0.5 * x) ) # X += 0.1 * np.random.randn(x.size) X[: x.size // 2] += trend X[(x.size + 1) // 2 :] += trend[-1] - trend L = 2 * np.pi """ ref_ab = FastFourierApproxAB(L=L) ref_ab_slow = SlowFourierApproxAB(L=L) ref_c = FastFourierApproxC(max_components=X.size, L=L) ref_c_slow = SlowFourierApproxC(max_components=X.size, L=L) approx_ab = ref_ab.transform(X) approx_ab_slow = ref_ab_slow.transform(X) approx_c = ref_c.transform(X) approx_c_slow = ref_c_slow.transform(X) # assert np.allclose(approx_ab, approx_ab_slow) # assert np.allclose(approx_ab, approx_c_slow) # assert np.allclose(approx_ab, approx_c) print( f"RMSE: {np.sqrt(np.mean(np.square(approx_ab[5:-5] - X[5:-5]))):.4f}") fig, (ax1, ax2) = plt.subplots(2, figsize=(10, 10)) ax1.set_title("AB Approximation") ax1.plot(X.real, X.imag, label="original") ax1.plot(approx_ab.real, approx_ab.imag, label="fast") ax1.plot(approx_ab_slow.real, approx_ab_slow.imag, label="slow") ax1.legend() ax2.set_title("C Approximation") ax2.plot(X.real, X.imag, label="original") ax2.plot(approx_c.real, approx_c.imag, label="fast") ax2.plot(approx_c_slow.real, approx_c.imag, label="slow") ax2.legend() plt.show()
def __init__(self, filePath): paths, attributes = svg2paths(filePath) self.xs = [] self.ys = [] self.all_xs = [] self.all_ys = [] for path in paths: self.parseSVG(path) self.all_xs.append(self.xs) self.all_ys.append(self.ys) self.xs = [] self.ys = []
def load_svg(filename): paths, attributes = svg2paths(filename) assert len(paths) == 1, "File must contain exactly one path." assert "style" in attributes[0].keys(), "Path must have inline style." assert "stroke" in attributes[0][ "style"], "Path must have stroke style attribute" hex_color = re.search("stroke:#(([0-9]|[A-F]|[a-f]){6});?", attributes[0]["style"])[1] rgb_color = tuple(bytearray.fromhex(hex_color)) return paths[0], rgb_color
def svg2normalvf(fn, l=None, sw=.1): paths, atts = svg2paths(fn) normalvf(paths, atts, l=l, sw=sw)