def lmove(vector_data, sources, dest): """Move the content of one or more layer(s) to another layer. SOURCES can be a single layer ID, the string 'all' (to copy all non-empty layers, or a coma-separated, whitespace-free list of layer IDs. DEST can be a layer ID or the string 'new', in which case a new layer with the lowest available ID will be created. Layer(s) left empty after the move are then discarded and may thus be reused by subsequent commands using 'new' as destination layer. If a layer is both in the source and destination, its content is not duplicated. Examples: Merge layer 1 and 2 to layer 1 (the content of layer 1 is not duplicated): vpype [...] lmove 1,2 1 [...] # merge layer 1 and 2 to layer 1 """ src_lids = multiple_to_layer_ids(sources, vector_data) dest_lid = single_to_layer_id(dest, vector_data) if dest_lid in src_lids: src_lids.remove(dest_lid) for lid in src_lids: vector_data.add(vector_data.pop(lid), dest_lid) return vector_data
def vpype_flow_imager(document, layer, filename, noise_coeff, n_fields, min_sep, max_sep, min_length, max_length, max_size, seed, flow_seed, search_ef, test_frequency, field_type, transparent_val, transparent_mask, edge_field_multiplier, dark_field_multiplier, kdtree_searcher, cmyk): """ Generate flowline representation from an image. The generated flowlines are in the coordinates of the input image, resized to have dimensions at most `--max_size` pixels. """ if kdtree_searcher: searcher_class = KDTSearcher else: searcher_class = HNSWSearcher target_layer = vp.single_to_layer_id(layer, document) img = cv2.imread(filename, cv2.IMREAD_UNCHANGED) logger.debug(f"original img.shape: {img.shape}") with tmp_np_seed(seed): if cmyk: img_layers = split_cmyk(img.copy()) else: img_layers = [img] alpha = get_alpha_channel(img) for layer_i, img_layer in enumerate(img_layers): logger.info(f"computing layer {layer_i+1}") numpy_paths = draw_image( img_layer, alpha, mult=noise_coeff, n_fields=n_fields, min_sep=min_sep, max_sep=max_sep, min_length=min_length, max_length=max_length, max_img_size=max_size, flow_seed=flow_seed, search_ef=search_ef, test_frequency=test_frequency, field_type=field_type, transparent_val=transparent_val, transparent_mask=transparent_mask, edge_field_multiplier=edge_field_multiplier, dark_field_multiplier=dark_field_multiplier, searcher_class=searcher_class, ) lc = vp.LineCollection() for path in numpy_paths: lc.append(path[:, 0] + path[:, 1] * 1.j) document.add(lc, target_layer + layer_i) return document
def lmove(document, sources, dest, prob: Optional[float]): """Move the content of one or more layer(s) to another layer. SOURCES can be a single layer ID, the string 'all' (to copy all non-empty layers, or a coma-separated, whitespace-free list of layer IDs. DEST can be a layer ID or the string 'new', in which case a new layer with the lowest available ID will be created. Layer(s) left empty after the move are then discarded and may thus be reused by subsequent commands using 'new' as destination layer. The `--prob` option controls the probability with which each path is moved. With a value lower than 1.0, some paths will not be moved to DEST, which may be used to achieve random coloring effects. If a layer is both in the source and destination, its content is not duplicated. Examples: Merge layer 1 and 2 to layer 1 (the content of layer 1 is not duplicated): vpype [...] lmove 1,2 1 [...] # merge layer 1 and 2 to layer 1 """ src_lids = multiple_to_layer_ids(sources, document) dest_lid = single_to_layer_id(dest, document) if dest_lid in src_lids: src_lids.remove(dest_lid) for lid in src_lids: if prob is not None: # split lines with provided probability remaining_lines = LineCollection() moving_lines = LineCollection() for line in document.layers[lid]: if random.random() < prob: moving_lines.append(line) else: remaining_lines.append(line) if len(remaining_lines) > 0: document.layers[lid] = remaining_lines else: document.pop(lid) if len(moving_lines) > 0: document.add(moving_lines, dest_lid) else: document.add(document.pop(lid), dest_lid) return document
def lcopy(document, sources, dest, prob: Optional[float]): """Copy the content of one or more layer(s) to another layer. SOURCES can be a single layer ID, the string 'all' (to copy all non-empty layers, or a coma-separated, whitespace-free list of layer IDs. DEST can be a layer ID or the string 'new', in which case a new layer with the lowest available ID will be created. If a layer is both in the source and destination, its content is not duplicated. The `--prob` option controls the probability with which each path is copied. With a value lower than 1.0, some paths will not be copied to DEST, which may be used to achieve random coloring effects. Examples: Copy layer 1 to a new layer: vpype [...] lcopy 1 new [...] # duplicate layer 1 Make a new layer with a merged copy of layer 1 and 2: vpype [...] lcopy 1,2 new [...] # make new layer with merged copy of layer 1 and 2 Add a merged copy of all layers to layer 1. If layer 1 previously had content, this \ content is not duplicated: vpype [...] lcopy all 1 [...] """ src_lids = multiple_to_layer_ids(sources, document) dest_lid = single_to_layer_id(dest, document) if dest_lid in src_lids: src_lids.remove(dest_lid) lc = LineCollection() for lid in src_lids: if prob is not None: for line in document[lid]: if random.random() < prob: lc.append(line) else: lc.extend(document[lid]) if len(lc) > 0: document.add(lc, dest_lid) return document
def lcopy(vector_data, sources, dest): """Copy the content of one or more layer(s) to another layer. SOURCES can be a single layer ID, the string 'all' (to copy all non-empty layers, or a coma-separated, whitespace-free list of layer IDs. DEST can be a layer ID or the string 'new', in which case a new layer with the lowest available ID will be created. If a layer is both in the source and destination, its content is not duplicated. Examples: Copy layer 1 to a new layer: vpype [...] lcopy 1 new [...] # duplicate layer 1 Make a new layer with a merged copy of layer 1 and 2: vpype [...] lcopy 1,2 new [...] # make new layer with merged copy of layer 1 and 2 Add a merged copy of all layers to layer 1. If layer 1 previously had content, this content is not duplicated: vpype [...] lcopy all 1 [...] """ src_lids = multiple_to_layer_ids(sources, vector_data) dest_lid = single_to_layer_id(dest, vector_data) if dest_lid in src_lids: src_lids.remove(dest_lid) lc = LineCollection() for lid in src_lids: lc.extend(vector_data[lid]) vector_data.add(lc, dest_lid) return vector_data
def read( vector_data: VectorData, file, single_layer: bool, layer: Optional[int], quantization: float, no_simplify: bool, ) -> VectorData: """Extract geometries from a SVG file. By default, the `read` command attempts to preserve the layer structure of the SVG. In this context, top-level groups (<svg:g>) are each considered a layer. If any, all non-group, top-level SVG elements are imported into layer 1. The following logic is used to determine in which layer each SVG top-level group is imported: - If a `inkscape:label` attribute is present and contains digit characters, it is stripped of non-digit characters the resulting number is used as target layer. If the resulting number is 0, layer 1 is used instead. - If the previous step fails, the same logic is applied to the `id` attribute. - If both previous steps fail, the target layer matches the top-level group's order of appearance. Using `--single-layer`, the `read` command operates in single-layer mode. In this mode, all geometries are in a single layer regardless of the group structure. The current target layer is used default and can be specified with the `--layer` option. This command only extracts path elements as well as primitives (rectangles, ellipses, lines, polylines, polygons). Other elements such as text and bitmap images are discarded, and so is all formatting. All curved primitives (e.g. bezier path, ellipses, etc.) are linearized and approximated by polylines. The quantization length controls the maximum length of individual segments. By default, an implicit line simplification with tolerance set to quantization is executed (see `linesimplify` command). This behaviour can be disabled with the `--no-simplify` flag. Examples: Multi-layer import: vpype read input_file.svg [...] Single-layer import: vpype read --single-layer input_file.svg [...] Single-layer import with target layer: vpype read --single-layer --layer 3 input_file.svg [...] Multi-layer import with specified quantization and line simplification disabled: vpype read --quantization 0.01mm --no-simplify input_file.svg [...] """ if single_layer: vector_data.add( read_svg(file, quantization=quantization, simplify=not no_simplify), single_to_layer_id(layer, vector_data), ) else: if layer is not None: logging.warning( "read: target layer is ignored in multi-layer mode") vector_data.extend( read_multilayer_svg(file, quantization=quantization, simplify=not no_simplify)) return vector_data
def read( document: Document, file, single_layer: bool, layer: Optional[int], quantization: float, simplify: bool, parallel: bool, no_crop: bool, display_size: Tuple[float, float], display_landscape: bool, ) -> Document: """Extract geometries from a SVG file. By default, the `read` command attempts to preserve the layer structure of the SVG. In this context, top-level groups (<svg:g>) are each considered a layer. If any, all non-group, top-level SVG elements are imported into layer 1. The following logic is used to determine in which layer each SVG top-level group is imported: - If a `inkscape:label` attribute is present and contains digit characters, it is \ stripped of non-digit characters the resulting number is used as target layer. If the \ resulting number is 0, layer 1 is used instead. - If the previous step fails, the same logic is applied to the `id` attribute. - If both previous steps fail, the target layer matches the top-level group's order \ of appearance. Using `--single-layer`, the `read` command operates in single-layer mode. In this mode, \ all geometries are in a single layer regardless of the group structure. The current target \ layer is used default and can be specified with the `--layer` option. This command only extracts path elements as well as primitives (rectangles, ellipses, lines, polylines, polygons). Other elements such as text and bitmap images are discarded, and so is all formatting. All curved primitives (e.g. bezier path, ellipses, etc.) are linearized and approximated by polylines. The quantization length controls the maximum length of individual segments. Optionally, a line simplification with tolerance set to quantization can be applied on the SVG's curved element (e.g. circles, ellipses, arcs, bezier curves, etc.). This is enabled with the `--simplify` flag. This process reduces significantly the number of segments used to approximate the curve while still guaranteeing an accurate conversion, but may increase the execution time of this command. The `--parallel` option enables multiprocessing for the SVG conversion. This is recommended ONLY when using `--simplify` on large SVG files with many curved elements. By default, the geometries are cropped to the SVG boundaries defined by its width and length attributes. The crop operation can be disabled with the `--no-crop` option. In general, SVG boundaries are determined by the `width` and `height` of the top-level <svg> tag. However, the some SVG may have their width and/or height specified as percent value or even miss them altogether (in which case they are assumed to be set to 100%). In these cases, vpype considers by default that 100% corresponds to a A4 page in portrait orientation. The options `--display-size FORMAT` and `--display-landscape` can be used to specify a different format. Examples: Multi-layer import: vpype read input_file.svg [...] Single-layer import: vpype read --single-layer input_file.svg [...] Single-layer import with target layer: vpype read --single-layer --layer 3 input_file.svg [...] Multi-layer import with specified quantization and line simplification enabled: vpype read --quantization 0.01mm --simplify input_file.svg [...] Multi-layer import with cropping disabled: vpype read --no-crop input_file.svg [...] """ width, height = display_size if display_landscape: width, height = height, width if single_layer: lc, width, height = read_svg( file, quantization=quantization, crop=not no_crop, simplify=simplify, parallel=parallel, default_width=width, default_height=height, ) document.add(lc, single_to_layer_id(layer, document)) document.extend_page_size((width, height)) else: if layer is not None: logging.warning("read: target layer is ignored in multi-layer mode") document.extend( read_multilayer_svg( file, quantization=quantization, crop=not no_crop, simplify=simplify, parallel=parallel, default_width=width, default_height=height, ) ) return document