Skip to content

Function to remove whitespace from svg #28

@pozitron57

Description

@pozitron57

I already wrote about whitespace in svg in #6, but I need zero whitespace.
Here is the function I use to remove all the whitespace from svg files generated by SchemDraw:

import inkex
import os

# This function processes an SVG file
def process_svg(svg_file):
    try:
        # Load the SVG file and get the root element
        svg_element = inkex.load_svg(svg_file).getroot()
        # Get the largest bounding box element
        _, largest_bbox_element = get_largest_geometric_bbox(svg_element)
    except:
        # If the SVG file cannot be loaded, print an error message
        print(f'Cannot load svg {svg_file}')
        return
    # Crop the SVG and save the processed file
    crop_and_save_processed_svg(svg_element, largest_bbox_element, svg_file)

# This function crops the SVG and saves it
def crop_and_save_processed_svg(svg_element, largest_bbox_element, svg_file):
    # Change the SVG canvas size according to the bounding box
    if largest_bbox_element and hasattr(largest_bbox_element, 'bounding_box'):
        bbox = largest_bbox_element.bounding_box()
        svg_element.set('width', str(bbox.width))
        svg_element.set('height', str(bbox.height))
        svg_element.set('viewBox', f'{bbox.left} {bbox.top} {bbox.width} {bbox.height}')
    # Write the changes to the same SVG file
    with open(svg_file, 'w') as output_file:
        output_file.write(svg_element.tostring().decode('utf-8'))
    # Define the actions for Inkscape command line
    my_actions = 'select-all;fit-canvas-to-selection;'
    export_actions = my_actions + f'export-type:svg;export-filename:{svg_file};export-do;'
    # Execute the Inkscape actions
    inkex.command.inkscape(svg_file, actions=export_actions)

# This function returns the largest geometric bounding box
def get_largest_geometric_bbox(svg_element):
    element_area = 0
    largest_bbox_element_id = None
    largest_bbox_element = None
    # Create a list of potential elements to check
    element_list = svg_element.xpath('//svg:path | //svg:polygon | //svg:polyline | //svg:rect | //svg:use | //svg:image')
    # Determine the largest bounding box
    for element in element_list:
        if hasattr(element, 'bounding_box'):
            bbox_area = float(element.bounding_box().width) * float(element.bounding_box().height)
            if bbox_area > element_area:
                element_area = bbox_area
                largest_bbox_element_id = element.get_id()
                largest_bbox_element = element
        else:
            continue
    return largest_bbox_element_id, largest_bbox_element

# Example usage
svg_file_name = 'filename.svg'
if not os.path.exists(svg_file_name):
    print(f'File Not Found: {svg_file_name}')
else:
    process_svg(svg_file_name)

It is not optimal as there is need for Inkscape installation.
Nevertheless I'd like SchemDraw to allow for this usage, something like d.save('filename.svg', crop=True).
It works for all my plots, but the elements I use are limited to a little part of basic elements,
hence more testing might be necessary.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions