SvgPath.Bounds returns incorrect Bounds
Description
SvgPath.Bounds returns different values depending on when it is queried.
Adapted from the SVGViewer sample:
private void RenderSvg(SvgDocument svgDoc) { var bounds = svgDoc.Bounds; System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(16, 16); svgDoc.Draw(bitmap); bounds = svgDoc.Bounds; }
The bounds initially returned are not the same as those returned after rendering.
The cause is in SvgPath.Path: in the the second call _path != null so that
else if (renderer == null)
{
// Calculate boundary including stroke width.
var radius = StrokeWidth * 2;
var bounds = _path.GetBounds();
_path.AddEllipse(bounds.Left - radius, bounds.Top - radius, 2 * radius, 2 * radius);
_path.AddEllipse(bounds.Right - radius, bounds.Bottom - radius, 2 * radius, 2 * radius);
}
is not executed.
Also incorrect is StrokeWidth * 2.
Example data
Any svg
Used Versions
OS Windows 10. .Net Framework 4.7.2 SVG v3.3.0
The current implementation is as follows.
renderer
null -> Boundary with stroke.
other -> Boundary without stroke.
This is implementation in history of this library.(I think that it should usually be calculated from GraphicsPath.)
renderer null -> Boundary with stroke. other -> Boundary without stroke.
The above is only true if _path == null if renderer != null has been executed then _path has been created so that renderer == null no longer does anything.
What kind of issue do you care about ?
In case of renderer == null, an inaccurate Boundary will be returned.
I require an accurate bounds as I need to crop to the images bounds. In my case the svgs have a 20x20 viewbox, the actual image is about 16x16 with a transparent frame. Currently the only method that works is to render the svg to 20x20 and read the pixel data to find the actual image.
For the most the svgs have a StrokeWidth==1 so that acquiring the Bounds with renderer==null and _path==null can return a Bounds>=20x20. If one compares that to the rendered image in say gimp it is clearly inaccurate. Acquiring the Bounds after rendering the image returns a Bounds 16x16. The latter can be correct as long as the StrokeWidth==1. If not then that is also wrong.
The issue I care about is that the Bounds is effectively always inaccurate.
Bounds does not return accurate values for users. (If anything, it's used for rendering.)
If you set the IsPathDirty property to true, you can control which value is returned.
Just curios. How can we get the correct bounds of a path object then?
@Shujee
https://github.com/svg-net/SVG/issues/1049#issuecomment-1491341504
Thanks @H1Gdev. That doesn't seem to work though. The function specified in that comment does not return anything, while Bounds property returns the same (incorrect) value before and after calling that function.
Passing the same path data to WPF (using Geometry.Parse(pathData).Bounds) returns correct bounds.
@Shujee
In that sense, it doesn't provide a way to get accurate bounds...