绘制图像时:System.Runtime.InteropServices.ExternalException:GDI 中发生一般错误

发布于 2024-08-12 07:41:49 字数 1614 浏览 2 评论 0原文

我有一个从面板创建的全局 Graphics 对象。定期从磁盘中拾取图像并使用 Graphics.DrawImage() 将图像绘制到面板中。它在几次迭代中工作得很好,然后我得到了以下有用的异常:

System.Runtime.InteropServices.ExternalException: A generic error occurred in GDI+.
at System.Drawing.Graphics.CheckErrorStatus(Int32 status)
at System.Drawing.Graphics.DrawImage(Image image, Int32 x, Int32 y)
at System.Drawing.Graphics.DrawImage(Image image, Point point)

当我完成处理图像对象时,我排除了内存泄漏。我知道图像没有损坏,并且可以正常读取,因为程序在面板停止显示之前可以正常执行一段时间。

我在使用 PictureBox 时遇到了同样的问题,但这次至少我得到了一个错误,而不是没有任何错误。

我检查了任务管理器中的 GDI 对象和 USER 对象,但当应用程序运行和不运行时,它们始终约为 65 个用户对象和 165 个 GDI 对象。

我确实需要尽快弄清楚这一点,但我不能在 .NET 系统库中设置断点并查看具体执行失败的位置。

提前致谢。

编辑:这是显示代码:

private void DrawImage(Image image)
{
  Point leftCorner = new Point((this.Bounds.Width / 2) - (image.Width / 2), (this.Bounds.Height / 2) - (image.Height / 2));
  _graphics.DrawImage(image, leftCorner);
}

图像加载代码:

private void LoadImage(string filename, ref Image image)
{
  MemoryStream memoryStream = DecryptImageBinary(Settings.Default.ImagePath + filename, _cryptPassword);

  image = Image.FromStream(memoryStream);

  memoryStream.Close();
  memoryStream.Dispose();
  memoryStream = null;
}

_image是全局的,其引用在LoadImage中更新。它们作为参数传递,因为我想仅从尽可能少的位置更改全局引用,并保持其他方法自包含。 _graphics 也是全局的。

我还有一个用于网站的 webBrowser 控件,我可以一次显示一张图像或一个网站。当有时间显示图像时,将执行以下代码:

webBrowser.Visible = false;
panel.Visible = true;
DrawImage(_image)
_image.Dispose();
_image = null;

_image 正在引用预加载的图像。

希望这有帮助。

I've got a global Graphics object created from a Panel. At regular intervals an image is picked up from the disk and drawn into the panel using Graphics.DrawImage(). It works fine for a few iterations and then I'm getting the following helpful exception:

System.Runtime.InteropServices.ExternalException: A generic error occurred in GDI+.
at System.Drawing.Graphics.CheckErrorStatus(Int32 status)
at System.Drawing.Graphics.DrawImage(Image image, Int32 x, Int32 y)
at System.Drawing.Graphics.DrawImage(Image image, Point point)

I ruled out memory leaks as I dispose of the image object when I'm done with it. I know that the images are not corrupted and can be read fine as the program executes fine for a while before the panel stops showing.

I ran into the same problem when using a PictureBox but this time at least I got an error instead of nothing.

I checked the GDI objects and USER objects in the Task Manager but they're always around 65 user objects and 165 GDI objects when the app works and when it doesn't.

I do need to get to the bottom of this as soon as and it's not like I can stick breakpoints in .NET System libraries and see where exactly execution fails.

Thanks in advance.

EDIT: This is the display code:

private void DrawImage(Image image)
{
  Point leftCorner = new Point((this.Bounds.Width / 2) - (image.Width / 2), (this.Bounds.Height / 2) - (image.Height / 2));
  _graphics.DrawImage(image, leftCorner);
}

the image load code:

private void LoadImage(string filename, ref Image image)
{
  MemoryStream memoryStream = DecryptImageBinary(Settings.Default.ImagePath + filename, _cryptPassword);

  image = Image.FromStream(memoryStream);

  memoryStream.Close();
  memoryStream.Dispose();
  memoryStream = null;
}

_image is global and its reference is updated in LoadImage. They are passed as parameters as I want to change the global references from as few places as possible only and keep the other methods self contained. _graphics is also global.

I've also got a webBrowser control for web sites and I either show an image or a website at one time. when there's time to display an image, the following code executes:

webBrowser.Visible = false;
panel.Visible = true;
DrawImage(_image)
_image.Dispose();
_image = null;

_image is referencing a pre-loaded image.

Hope this helps.

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

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

发布评论

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

评论(2

梦断已成空 2024-08-19 07:41:49

你的问题和我的想法很相似,但又不完全一样。当您加载图像时,您是从 MemoryStream 加载它。您必须在图像的生命周期内保持流打开,请参阅 MSDN Image.FromStream

您必须在图像的生命周期内保持流打开。

解决方案是在 FromImage 函数中复制图像:

private void LoadImage(string filename, ref Image image)
{
  using (MemoryStream memoryStream = DecryptImageBinary(Settings.Default.ImagePath + filename, _cryptPassword))
  {
      using (tmpImage = Image.FromStream(memoryStream))
      { 
         image = new Bitmap(tmpImage);
      }
  }

}

与我提到的处理问题类似,图像似乎可以工作,然后当底层流被垃圾收集时随机失败。

Your problem is similar to what I thought, but not quite. When you are loading the image, you are loading it from a MemoryStream. You have to keep the stream open for the lifetime of the image, see MSDN Image.FromStream.

You must keep the stream open for the lifetime of the Image.

The solution is to make a copy of your image in the FromImage function:

private void LoadImage(string filename, ref Image image)
{
  using (MemoryStream memoryStream = DecryptImageBinary(Settings.Default.ImagePath + filename, _cryptPassword))
  {
      using (tmpImage = Image.FromStream(memoryStream))
      { 
         image = new Bitmap(tmpImage);
      }
  }

}

Similar to the dispose problem I mentioned, the image will seem to work and then randomly fail when the underlying stream is garbage collected.

风月客 2024-08-19 07:41:49

如果没有更多的代码,这里还不足以正确诊断,但是,需要注意的一件事是,您可能已经在早些时候的某个时刻处理了绘图的图像,并且只有在垃圾收集器运行您的代码之后正在失败。您是否在任何地方使用克隆图像?我惊讶地了解到的一件事是,如果您直接执行 克隆图像,您不是克隆图像所依赖的底层位图,而是克隆图像结构,要创建图像的正确副本,您必须创建一个新图像:

var newImage = new Bitmap(img)

var newImage = oldImg.Clone();
oldImg.Dispose();
...
gr.DrawImage(newImage, new Rectangle(0,0,newImage.Width,newImage.Height);

将适用于虽然,但随后在某个随机点失败......

Without a little more code there is not enough to properly diagnose here, however, one thing to look at is that you may have disposed on the image your a drawing with at some point earlier and it is only after the garbage collector runs that your code is failing. Are you using cloned images anywhere? One thing I was suprised to learn is that if you do a straight clone of an image, you are not cloning the underlying bitmap that the image rely's upon, only the image structure, to create a proper copy of an image you have to create a new image:

var newImage = new Bitmap(img)

as

var newImage = oldImg.Clone();
oldImg.Dispose();
...
gr.DrawImage(newImage, new Rectangle(0,0,newImage.Width,newImage.Height);

will work for a while, but then fail at some random point...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文