GraphicsPath 和 OutOfMemoryException

发布于 2024-11-27 23:36:29 字数 304 浏览 4 评论 0 原文

我有以下情况

private bool IsPathVisible(Rectangle detectorRectangle, GraphicsPath path, Pen pen)
{
    path.Widen(pen);
    return IsPathVisible(detectorRectangle, path);
}

path 点是同一点时,我收到 OutOfMemoryException (使用 Widen 函数)。

我该如何管理它?

I have the following

private bool IsPathVisible(Rectangle detectorRectangle, GraphicsPath path, Pen pen)
{
    path.Widen(pen);
    return IsPathVisible(detectorRectangle, path);
}

When path points are the same point, I receive a OutOfMemoryException (using Widen function).

How can I manage it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

青柠芒果 2024-12-04 23:36:29

这是笔和加宽方法的错误。确保路径的起点和路径的终点不相同。

这是一个演示:

private void panel1_Paint(object sender, PaintEventArgs e)
{
  //This works:
  using (GraphicsPath path = new GraphicsPath())
  {
    path.AddLine(new Point(16, 16), new Point(20, 20));
    path.Widen(Pens.Black);
    e.Graphics.DrawPath(Pens.Black, path);
  }

  //This does not:
  using (GraphicsPath path = new GraphicsPath())
  {
    path.AddLine(new Point(20, 20), new Point(20, 20));
    path.Widen(Pens.Black);
    e.Graphics.DrawPath(Pens.Black, path);
  }
}

这是向 Microsoft 报告的位置: GraphicsPath.Widen 如果路径有一个点,则抛出 OutOfMemoryException

That's a bug with the pen and the widen method. Make sure your startpoint of the path and the endpoint of the path are not the same.

This is a demonstration:

private void panel1_Paint(object sender, PaintEventArgs e)
{
  //This works:
  using (GraphicsPath path = new GraphicsPath())
  {
    path.AddLine(new Point(16, 16), new Point(20, 20));
    path.Widen(Pens.Black);
    e.Graphics.DrawPath(Pens.Black, path);
  }

  //This does not:
  using (GraphicsPath path = new GraphicsPath())
  {
    path.AddLine(new Point(20, 20), new Point(20, 20));
    path.Widen(Pens.Black);
    e.Graphics.DrawPath(Pens.Black, path);
  }
}

Here is where it was reported to Microsoft: GraphicsPath.Widen throw OutOfMemoryException if the path has a single point

我乃一代侩神 2024-12-04 23:36:29

我也曾遭受过这种异常的困扰。建议如下:

  1. 在扩大之前保存点,以查看导致 OutOfMemoryException 的确切点:

    private bool IsPathVisible(矩形检测器矩形, GraphicsPath 路径, Pen pen)
    {
        var points = path.PathPoints.Clone() as PointF[];
        路径.加宽(笔);
        返回 IsPathVisible(探测器矩形, 路径);
    }
    

您可能会看到可能存在具有相同坐标的后续点。他们实际上造成了问题。

  1. 此外,GraphicsPath 可以由多个子路径组成。为了进行可靠的命中测试,我建议执行以下操作:

    public Region[] CreateRegionFromGraphicsPath(GraphicsPath 路径,Pen 加宽Pen)
    {
        var Regions = new List();
    
        var itPath = new GraphicsPathIterator(路径);
        itPath.Rewind();
        var curSubPath = new GraphicsPath();
    
        for (int i = 0; i < itPath.SubpathCount; i++)
        {
            bool 已关闭;
            itPath.NextSubpath(curSubPath, out isClosed);
    
            if (!isClosed && CanWiden(curSubPath)) curSubPath.Widen(wideningPen); // 加宽非闭合路径
    
            int 区域索引 = i / 100; // 最大区域扫描矩形数
    
            if (regions.Count 
    /// 确定加宽此图形路径是否不会导致异常
    /// 
    公共静态 bool CanWiden(GraphicsPath gp)
    {
        const floatregionPointsTolerance = 1e-8f;
        var pts = gp.PathPoints;
        if (pts.Length < 2) 返回 false;
        for (int i = 1; i < pts.Length; i++)
        {
            if (Math.Abs​​(pts[i-1].X - pts[i].X) 

然后您只需为区域调用 IsVisible 来查找是否有任何区域被命中

I've also been suffering from this exception. Recommendations are as following:

  1. Save the points before widening to see exact points that cause OutOfMemoryException:

    private bool IsPathVisible(Rectangle detectorRectangle, GraphicsPath path, Pen pen)
    {
        var points = path.PathPoints.Clone() as PointF[];
        path.Widen(pen);
        return IsPathVisible(detectorRectangle, path);
    }
    

What you might see is that there are probably consequent points that have the same coordinates. They are actually causing the problem.

  1. Also, GraphicsPath can consist of multiple subpaths. To make a reliable hit testing, I would recommend the following:

    public Region[] CreateRegionFromGraphicsPath(GraphicsPath path, Pen wideningPen)
    {
        var regions = new List<Region>();
    
        var itPath = new GraphicsPathIterator(path);
        itPath.Rewind();
        var curSubPath = new GraphicsPath();
    
        for (int i = 0; i < itPath.SubpathCount; i++)
        {
            bool isClosed;
            itPath.NextSubpath(curSubPath, out isClosed);
    
            if (!isClosed && CanWiden(curSubPath)) curSubPath.Widen(wideningPen); // widen not closed paths
    
            int regionIndex = i / 100; // max region scan rectangles count
    
            if (regions.Count < regionIndex + 1)
            {
                regions.Add(new Region(curSubPath));
            }
            else
            {
                regions[regionIndex].Union(curSubPath);
            }
        }
    
        curSubPath.Dispose();
        itPath.Dispose();
    
        return regions.ToArray();
    }
    
    /// <summary>
    /// Determines whether widening this graphics path will not lead to an exception
    /// </summary>
    public static bool CanWiden(GraphicsPath gp)
    {
        const float regionPointsTolerance = 1e-8f;
        var pts = gp.PathPoints;
        if (pts.Length < 2) return false;
        for (int i = 1; i < pts.Length; i++)
        {
            if (Math.Abs(pts[i-1].X - pts[i].X) < regionPointsTolerance && Math.Abs(pts[i-1].Y - pts[i].Y) < regionPointsTolerance) return false;
        }
        return true;
    }
    

Then you simply call IsVisible for regions to find if any of them is hit

弃爱 2024-12-04 23:36:29

如果路径 IsPoint,则不进行加宽操作。

<System.Runtime.CompilerServices.Extension()> _
Public Function IsPoint(ByVal path As System.Drawing.Drawing2D.GraphicsPath) As Boolean
    If path Is Nothing Then Throw New ArgumentNullException("path")

    If path.PathPoints.Count < 2 Then Return True

    If path.PathPoints(0) <> path.PathPoints(path.PathPoints.Count - 1) Then Return False

    For i = 1 To path.PathPoints.Count - 1
     If path.PathPoints(i - 1) <> path.PathPoints(i) Then Return False
    Next i

    ' if all the points are the same
    Return True
End Function 

if the path IsPoint, don't do Widen.

<System.Runtime.CompilerServices.Extension()> _
Public Function IsPoint(ByVal path As System.Drawing.Drawing2D.GraphicsPath) As Boolean
    If path Is Nothing Then Throw New ArgumentNullException("path")

    If path.PathPoints.Count < 2 Then Return True

    If path.PathPoints(0) <> path.PathPoints(path.PathPoints.Count - 1) Then Return False

    For i = 1 To path.PathPoints.Count - 1
     If path.PathPoints(i - 1) <> path.PathPoints(i) Then Return False
    Next i

    ' if all the points are the same
    Return True
End Function 
骑趴 2024-12-04 23:36:29

以下代码会导致 .Net 4.0(以及可能更高版本)中的 DrawPath 出现 OutOfMemory。
我设法使用 LineCap.Flat 而不是 LineCap.NoAnchor 绕过它:

public void TestDrawPath()
{
    PointF[] points = new PointF[13]
    {
        new PointF(0.491141558f, 1.53909028f),
        new PointF(0.491141558f, 1.55148673f),
        new PointF(0.4808829f, 1.56153619f),
        new PointF(0.468228281f, 1.56153619f),
        new PointF(0.4555736f, 1.56153619f),
        new PointF(0.445314974f, 1.55148673f),
        new PointF(0.445314974f, 1.53909028f),
        new PointF(0.445314974f, 1.52669382f),
        new PointF(0.4555736f, 1.51664436f),
        new PointF(0.468228281f, 1.51664436f),
        new PointF(0.4808829f, 1.51664436f),
        new PointF(0.491141558f, 1.52669382f),
        new PointF(0.491141558f, 1.53909028f)
    };
    byte[] types = new byte[13] { 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 131 };

    using (Bitmap bitmap = new Bitmap(2, 2))
    using (Graphics g = Graphics.FromImage(bitmap))
    {
        using (Pen pen = new Pen(Color.Black))
        using (GraphicsPath path = new GraphicsPath(points, types))
        {
            pen.StartCap = LineCap.NoAnchor;
            pen.EndCap = LineCap.NoAnchor;
            g.DrawPath(pen, path);
        }
    }
}

The following code causes OutOfMemory in DrawPath in .Net 4.0 (and possibly higher).
I was managed to bypass it using LineCap.Flat instead of LineCap.NoAnchor:

public void TestDrawPath()
{
    PointF[] points = new PointF[13]
    {
        new PointF(0.491141558f, 1.53909028f),
        new PointF(0.491141558f, 1.55148673f),
        new PointF(0.4808829f, 1.56153619f),
        new PointF(0.468228281f, 1.56153619f),
        new PointF(0.4555736f, 1.56153619f),
        new PointF(0.445314974f, 1.55148673f),
        new PointF(0.445314974f, 1.53909028f),
        new PointF(0.445314974f, 1.52669382f),
        new PointF(0.4555736f, 1.51664436f),
        new PointF(0.468228281f, 1.51664436f),
        new PointF(0.4808829f, 1.51664436f),
        new PointF(0.491141558f, 1.52669382f),
        new PointF(0.491141558f, 1.53909028f)
    };
    byte[] types = new byte[13] { 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 131 };

    using (Bitmap bitmap = new Bitmap(2, 2))
    using (Graphics g = Graphics.FromImage(bitmap))
    {
        using (Pen pen = new Pen(Color.Black))
        using (GraphicsPath path = new GraphicsPath(points, types))
        {
            pen.StartCap = LineCap.NoAnchor;
            pen.EndCap = LineCap.NoAnchor;
            g.DrawPath(pen, path);
        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文