-
Notifications
You must be signed in to change notification settings - Fork 149
Description
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:
which comes from this svg
I reduced it to the minimal case (the 2 lines without the rectangle) and to my surprise that viewbox turns out correct.
which comes from this svg
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.
which is in this svg
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
which produces this svg which works for what I need.
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



