Skip to content

Problem setting viewbox value #239

@vanepp

Description

@vanepp

First and formost thank you for svgpathtools. It is the only python package I have found that will create a viewbox that matches that produced by Inkscape. That said this issue is abotu what may be a bug or may just be how viewbox calculation works. The viewobox is created by this code

from svgpathtools import Document, Path, polygon
from io import StringIO

...

def calculate_boundingbox(svg, pitch):
"""
Calculate the viewbox using svgpathtools. Returns the calculated viewbox
from the input svg string.
"""

doc = Document(StringIO(svg))
xmin, xmax, ymin, ymax = Path(*[seg for path in doc.paths()
                              for seg in path]).bbox()
doc = Document(StringIO(svg))
xmin, xmax, ymin, ymax = Path(*[seg for path in doc.paths()
                              for seg in path]).bbox()
# Adjust the output from svgpathtools to create the bounding box and
# viewbox.
if xmin < 0:
    if xmin > -0.01:
        # fp roundoff error increase to 0.
        xmin = 0
    else:
        # otherwise an error.
        logger.info(f'exited {utils.function_name()} on xmin < 0, {xmin}')
        sys.stderr.write(
                            f'Error: lower bound xmin less than 0, {xmin}'
                        )
        exit(1)

if xmin > 0:
    # if xmin is > 0 then there are stroke-widths involved so add the
    # offset xmax and set xmin to 0 to correct for the stroke-width by
    # making xmax  xmax + stroke-width, then set xmin to 0 as it should
    # be.
    xmax += xmin
    xmin = 0
    logger.debug(
                    f'{utils.function_name()}\n                         '
                    f'xmin "{xmin}", xmax "{xmax}"'
                )
if ymin < 0:
    if ymin > -0.01:
        # fp roundoff error increase to 0.
        ymin = 0
    else:
        # otherwise an error.
        logger.info(f'exited {utils.function_name()} on ymin < 0, {ymin}')
        sys.stderr.write(
                            f'Error: lower bound ymin less than 0, {ymin}'
                        )
        exit(1)

if ymin > 0:
    # if ymin is > 0 then there are stroke-widths involved so add the
    # offset ymax and set ymin to 0 to correct for the stroke-width by
    # making ymax  ymax + stroke-width, then set ymin to 0 as it should
    # be.
    ymax += ymin
    ymin = 0.0
    logger.debug(
                    f'{utils.function_name()}\n                         '
                    f'ymin "{ymin}", ymax "{ymax}"'
                )

# round the return values to 2 digits (all we should need)
xmax = round(xmax, 2)
ymax = round(ymax, 2)

logger.info(
            f'exited {utils.function_name()} returned\n                   '
            f'      "{xmax}", "{ymax}"'
           )

return xmax, ymax

Where the svg parameter to the call is an svg with a suitable viewbox and all the xml in a string identical to the listed svg above.

The additional code after the svgpathtools call adjusts for the stroke width for the viewbox if it is present. My svgs always origins at 0in 0in and is dimensioned  in inches to match the real world (as I am doing parts for an EDA program to make pcbs and schematic diagrams.) I think that may not be true in the general case, but it so far works for me. if the xmin or ymin value is smaller than the likely fp roundoff value set it to 0. If it is larger than the roundoff value, there is a stroke width present in the affected access and I need to add the value of the min value to the max value to account for the stroke-width. That so far appears to work fine. In one particular case I have a rectangle placed in a line that is within the bounding box. However with it there, the min/max values reduce a small amount and make the calculated viewbox too small. The effect looks like this in the svg rendered by Inkscape:

Image

which comes from this svg

Image

I reduced it to the minimal case (the 2 lines without the rectangle) and to my surprise that viewbox turns out correct.

Image

which comes from this svg

Image

When I add this rectangle (which is inside one of the lines to provide the end point for the connection wire, and which I think should not affect the viewbox) the reduction happens.

Image

which is in this svg

Image

The difference appears to be that the size of the terminal rectangle appears to be subtracted from the xmax value making the viewbox too small

Image

which produces this svg which works for what I need.

Image

So my question is is there something that can be done so the correct viewbox value will come out of svgpathtools without the need for the extra rectangle (or have I screwed up the svg in some way I am not seeing!)

Peter

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