[Python] Performing Union Operation using Inkscape Extension on 3 Groups But Weird Result

Discussão em 'Python' iniciado por Stack, Julho 13, 2025.

  1. Stack

    Stack Membro Participativo

    I made an extension to perform union operation on each selected group, but I got a weird result.

    For example, there are three selected groups of rectangles:

    [​IMG]

    After using the extension on them, only the first group gets converted into a union path, the rest get duplicated and they aren't in their original positions anymore:

    [​IMG]

    The expected result should be three union paths:

    [​IMG]

    Here's the extension (save it as "union_operation_on_each_selected_group.py"):

    import inkex
    import tempfile, os, shutil
    from uuid import uuid4
    from inkex import Group, Circle, Ellipse, Line, PathElement, Polygon, Polyline, Rectangle, Use
    from inkex.paths import Path
    from inkex.command import call
    from math import ceil
    from lxml import etree

    def process_svg(svg, action_string):

    temp_folder = tempfile.mkdtemp()

    # Create a random filename for svg
    svg_temp_filepath = os.path.join(temp_folder, f'original_{str(uuid4())}.svg')

    with open(svg_temp_filepath, 'w') as output_file:
    svg_string = svg.tostring().decode('utf-8')
    output_file.write(svg_string)

    processed_svg_temp_filepath = os.path.join(temp_folder, f'processed_{str(uuid4())}.svg')

    my_actions = '--actions='

    export_action_string = my_actions + f'export-filename:{processed_svg_temp_filepath};{action_string}export-do;'

    # Run the command line
    cmd_selection_list = inkex.command.inkscape(svg_temp_filepath, export_action_string)

    # Replace the current document with the processed document
    with open(processed_svg_temp_filepath, 'rb') as processed_svg:
    loaded_svg = inkex.elements.load_svg(processed_svg).getroot()

    shutil.rmtree(temp_folder)
    return loaded_svg

    def element_list_union(svg, element_list):

    group = None

    action_string = ''
    for element in element_list:
    group = element.getparent()
    action_string = action_string + f'select-by-id:{element.get_id()};'
    action_string = action_string + f'path-union;select-clear;'
    processed_svg = process_svg(svg, action_string)

    to_remove = []
    for child in group:
    to_remove.append(child)
    for item in to_remove:
    group.remove(item)

    for elem in processed_svg:
    group.add(elem)

    class UnionizeEachGroupMembers(inkex.EffectExtension):

    def add_arguments(self, pars):

    pars.add_argument("--selection_type_radio", type=str, dest="selection_type_radio", default='all')

    def effect(self):

    SELECTION_TYPE = self.options.selection_type_radio

    if SELECTION_TYPE == 'all':
    selection_list = self.svg.descendants()
    else:
    selection_list = self.svg.selected

    # Filter for only shapes
    selected_elements = selection_list.filter(inkex.ShapeElement)

    if len(selected_elements) < 1:
    inkex.errormsg('Please select at least one object / No Objects found')
    return

    for elem in selected_elements:
    if elem.tag == inkex.addNS('g', 'svg'): # Check if the tag is 'g' in the SVG namespace
    group = elem
    group_id = group.get_id()

    elements_to_union = [child for child in group if isinstance(child, (Circle, Ellipse, Line, PathElement, Polygon, Polyline, Rectangle, Use))]

    if len(elements_to_union) > 0:
    element_list_union(self.svg, elements_to_union)

    if __name__ == '__main__':
    UnionizeEachGroupMembers().run()


    And here's the .inx file:

    <?xml version="1.0" encoding="UTF-8"?>
    <inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
    <name>Union Operation on Each Selected Group</name>
    <id>union_operation_on_each_selected_group</id>

    <!-- Parameters Here -->

    <param name="selection_type_radio" type="optiongroup" appearance="radio" gui-text="Selection Type">
    <option value="selected">Selected Objects</option>
    <option value="all">All Objects</option>
    </param>

    <effect>
    <object-type>all</object-type>
    <effects-menu>
    <!-- <submenu name="Submenu Name"/>-->
    </effects-menu>
    </effect>
    <script>
    <command location="inx" interpreter="python">union_operation_on_each_selected_group.py</command>
    </script>
    </inkscape-extension>


    You can download the example file here:

    Example File

    Is it possible to get the expected result using an extension? How could I fix the extension?

    Continue reading...

Compartilhe esta Página