Exemple #1
0
def read_svg(
    filename: str, quantization: float, simplify: bool = False, return_size: bool = False
) -> Union["LineCollection", Tuple["LineCollection", float, float]]:
    """Read a SVG file an return its content as a :class:`LineCollection` instance.

    All curved geometries are chopped in segments no longer than the value of *quantization*.
    Optionally, the geometries are simplified using Shapely, using the value of *quantization*
    as tolerance.

    Args:
        filename: path of the SVG file
        quantization: maximum size of segment used to approximate curved geometries
        simplify: run Shapely's simplify on loaded geometry
        return_size: if True, return a size 3 Tuple containing the geometries and the SVG
            width and height

    Returns:
        imported geometries, and optionally width and height of the SVG
    """

    doc = svg.Document(filename)
    width, height, scale_x, scale_y, offset_x, offset_y = _calculate_page_size(doc.root)
    lc = _convert_flattened_paths(
        doc.flatten_all_paths(), quantization, scale_x, scale_y, offset_x, offset_y, simplify,
    )

    if return_size:
        if width is None or height is None:
            _, _, width, height = lc.bounds()
        return lc, width, height
    else:
        return lc
Exemple #2
0
def main () :
    for i in range(50) : 
        doc = svg.Document(None)
        doc.set_viewbox('0 0 100 100')
        person = Person()
        doc = person.addToDocument(doc)
        with open(f'./Data/body{i+1}.svg', 'wb') as fd: 
            fd.write(etree.tostring(doc.tree.getroot(), encoding='utf8', method='xml'))
Exemple #3
0
def shrink_svg(svgfilepath, shrinkBorder):
    """
    Shrink the SVG canvas to the size of the drawing
    """
    document = svgpathtools.Document(svgfilepath)
    paths = document.paths()
    if len(paths) == 0:
        return
    bbox = paths[0].bbox()
    for x in paths:
        bbox = merge_bbox(bbox, x.bbox())
    bbox = list(bbox)
    bbox[0] -= ki2svg(mm2ki(shrinkBorder))
    bbox[1] += ki2svg(mm2ki(shrinkBorder))
    bbox[2] -= ki2svg(mm2ki(shrinkBorder))
    bbox[3] += ki2svg(mm2ki(shrinkBorder))
    svg = document.tree
    root = svg.getroot()
    root.attrib["viewBox"] = "{} {} {} {}".format(bbox[0], bbox[2],
                                                  bbox[1] - bbox[0],
                                                  bbox[3] - bbox[2])
    root.attrib["width"] = str(ki2mm(svg2ki(bbox[1] - bbox[0]))) + "mm"
    root.attrib["height"] = str(ki2mm(svg2ki(bbox[3] - bbox[2]))) + "mm"
    document.save(svgfilepath)
Exemple #4
0
def read_multilayer_svg(
    filename: str,
    quantization: float,
    simplify: bool = False,
    return_size: bool = False
) -> Union["VectorData", Tuple["VectorData", float, float]]:
    """Read a multilayer SVG file and return its content as a :class:`VectorData` instance
    retaining the SVG's layer structure.

    Each top-level group is considered a layer. All non-group, top-level elements are imported
    in layer 1.

    Groups are matched to layer ID according their `inkscape:label` attribute, their `id`
    attribute or their appearing order, in that order of priority. Labels are stripped of
    non-numeric characters and the remaining is used as layer ID. Lacking numeric characters,
    the appearing order is used. If the label is 0, its changed to 1.

    All curved geometries are chopped in segments no longer than the value of *quantization*.
    Optionally, the geometries are simplified using Shapely, using the value of *quantization*
    as tolerance.

    Args:
        filename: path of the SVG file
        quantization: maximum size of segment used to approximate curved geometries
        simplify: run Shapely's simplify on loaded geometry
        return_size: if True, return a size 3 Tuple containing the geometries and the SVG
            width and height

    Returns:
         imported geometries, and optionally width and height of the SVG
    """

    doc = svg.Document(filename)

    width, height, scale_x, scale_y, offset_x, offset_y = _calculate_page_size(
        doc.root)

    vector_data = VectorData()

    # non-group top level elements are loaded in layer 1
    top_level_elements = doc.flatten_all_paths(
        group_filter=lambda x: x is doc.root)
    if top_level_elements:
        vector_data.add(
            _convert_flattened_paths(
                top_level_elements,
                quantization,
                scale_x,
                scale_y,
                offset_x,
                offset_y,
                simplify,
            ),
            1,
        )

    for i, g in enumerate(doc.root.iterfind("svg:g", SVG_NAMESPACE)):
        # compute a decent layer ID
        lid_str = re.sub(
            "[^0-9]", "",
            g.get("{http://www.inkscape.org/namespaces/inkscape}label") or "")
        if not lid_str:
            lid_str = re.sub("[^0-9]", "", g.get("id") or "")
        if lid_str:
            lid = int(lid_str)
            if lid == 0:
                lid = 1
        else:
            lid = i + 1

        vector_data.add(
            _convert_flattened_paths(
                flatten_group(g, g),
                quantization,
                scale_x,
                scale_y,
                offset_x,
                offset_y,
                simplify,
            ),
            lid,
        )

    if return_size:
        if width is None or height is None:
            _, _, width, height = vector_data.bounds() or 0, 0, 0, 0
        return vector_data, width, height
    else:
        return vector_data
def extract_lines(filepath, page_dir):
    doc = svgpathtools.Document(filepath)
    content_group = doc.get_group([None, "content"])

    # bounds are in the format (xmin, xmax, ymin, ymax)
    page_bounds = doc.paths_from_group(content_group)[0].bbox()

    line_height = (page_bounds[3] - page_bounds[2]) / 15

    lines = {}
    debug_lines = {}
    debug_nodes = {}
    for line_number in range(1, 16):
        lines[line_number] = svgpathtools.Path()
        debug_lines[line_number] = svgpathtools.Path()
        debug_nodes[line_number] = []

    full_path = svgpathtools.Path()
    for doc_path in doc.paths():
        for sub_path in doc_path:
            full_path.append(sub_path)

    indeterminate_paths = []
    for _path in full_path.d().split("M"):
        if len(_path.strip()) > 0:
            glyph_path = svgpathtools.parse_path(f"M{_path}")
            line_number = detect_line_number(glyph_path.bbox(), page_bounds[2],
                                             line_height)
            if line_number:
                for path_command in glyph_path:
                    lines[line_number].append(path_command)
            else:
                indeterminate_paths.append(glyph_path)

    indeterminate_paths = [
        indeterminate_path_info(p, page_bounds[2], line_height)
        for p in indeterminate_paths
    ]
    indeterminate_num = len(indeterminate_paths)
    print(f"Found {indeterminate_num} indeterminate paths")

    indeterminate_paths.sort(key=lambda x: x[2])

    for i, indeterminate_path in enumerate(indeterminate_paths):
        start_time = time.time()
        determination = detect_indeterminate_line(indeterminate_path, lines)
        if determination[0]:
            if determination[1]:
                debug_nodes[determination[0]].append(determination[1])
            for path_command in indeterminate_path[0]:
                lines[determination[0]].append(path_command)
                debug_lines[determination[0]].append(path_command)
        print(
            f"Completed {i+1}/{indeterminate_num} path determations in {time.time() - start_time:.2} seconds"
        )

    attribs = {"fill": "#000000", "fill-rule": "evenodd"}

    debug_attribs = {
        "stroke": "#FF0000",
        "stroke-width": "0.5",
        "fill-opacity": "0"
    }

    svg_attribs = {
        "xml:space": "preserve",
        "viewBox": "0 0 345 50",
        "width": "",
        "height": ""
    }

    for svg_line in lines.items():
        if len(svg_line[1]) == 0:
            continue

        line_number = svg_line[0]
        y_pos = floor(svg_line[1].bbox()[2])
        svg_attribs["viewBox"] = f"0 {y_pos} 345 50"
        filename = path.join(page_dir, f"{line_number}.svg")

        _paths = [svg_line[1]]
        _attribs = [attribs]
        _nodes = []
        if debug_mode:
            _nodes = debug_nodes[line_number]
            if len(debug_lines[line_number]) > 0:
                _paths.append(debug_lines[line_number])
                _attribs.append(debug_attribs)

        svgpathtools.wsvg(_paths,
                          filename=filename,
                          attributes=_attribs,
                          svg_attributes=svg_attribs,
                          nodes=_nodes)

    if debug_mode:
        filename = path.join(page_dir, "debug.svg")
        debug_paths = [full_path]
        svg_attribs["viewBox"] = "0 0 345 550"
        _attribs = [attribs]
        for line in range(1, 16):
            debug_paths.append(
                debug_overlay_path(page_bounds[2], line_height, line))
            _attribs.append(debug_attribs)

        svgpathtools.wsvg(
            debug_paths,
            filename=filename,
            attributes=_attribs,
            svg_attributes=svg_attribs,
        )