SVG icon indicating copy to clipboard operation
SVG copied to clipboard

SvgPath.Bounds returns incorrect Bounds

Open markus-bonk opened this issue 4 years ago • 9 comments

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

markus-bonk avatar Nov 03 '21 14:11 markus-bonk

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.)

H1Gdev avatar Nov 05 '21 11:11 H1Gdev

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.

markus-bonk avatar Nov 05 '21 12:11 markus-bonk

What kind of issue do you care about ?

In case of renderer == null, an inaccurate Boundary will be returned.

H1Gdev avatar Nov 05 '21 13:11 H1Gdev

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.

markus-bonk avatar Nov 05 '21 14:11 markus-bonk

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.

H1Gdev avatar Nov 05 '21 14:11 H1Gdev

Just curios. How can we get the correct bounds of a path object then?

Shujee avatar Mar 25 '23 01:03 Shujee

@Shujee

https://github.com/svg-net/SVG/issues/1049#issuecomment-1491341504

H1Gdev avatar Mar 31 '23 06:03 H1Gdev

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 avatar Mar 31 '23 06:03 Shujee

@Shujee

In that sense, it doesn't provide a way to get accurate bounds...

H1Gdev avatar Mar 31 '23 09:03 H1Gdev