GraphicsPath和OutOfMemoryException

时间:2011-08-03 14:06:21

标签: .net gdi+

我有以下

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

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

我该如何管理?

4 个答案:

答案 0 :(得分:6)

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

这是一个示范:

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 throw OutOfMemoryException if the path has a single point

答案 1 :(得分:1)

我也遭受过这种例外。建议如下:

  1. 在加宽之前保存点以查看导致OutOfMemoryException的确切点:

    private bool IsPathVisible(Rectangle detectorRectangle, GraphicsPath path, Pen pen)
    {
        var points = path.PathPoints.Clone() as PointF[];
        path.Widen(pen);
        return IsPathVisible(detectorRectangle, path);
    }
    
  2. 您可能会看到,可能有后续点具有相同的坐标。他们实际上是造成了这个问题。

    1. 此外,GraphicsPath可以包含多个子路径。为了进行可靠的命中测试,我建议如下:

      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;
      }
      
    2. 然后你只需为区域调用IsVisible来查找是否有任何一个被击中

答案 2 :(得分:0)

如果路径为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 

答案 3 :(得分:0)

以下代码导致.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);
        }
    }
}