我编写了一个代码,用于从文件中读取png图像并显示控件 我想要从流中读取图像并设置
control.BackgroundImage = Image.FromStream(memStream);
但使用此代码时,会出现“内存不足”异常。但是在使用时
control.Image = Image.FromStream(memStream);
或
control.BackgroundImage = Image.FromFile(fileSource);
,这就是工作。
图片文件大小为5KB。
if (System.IO.File.Exists(imgSource))
{
using (FileStream localFileStream = new FileStream(imgSource, FileMode.Open))
{
using (MemoryStream memStream = new MemoryStream())
{
int bytesRead;
byte[] buffer = new byte[1024];
while ((bytesRead = localFileStream.Read(buffer, 0, buffer.Length)) > 0)
{
memStream.Write(buffer, 0, bytesRead);
}
retIMG = Image.FromStream(memStream);
pictureBox1.Image = retIMG; // is work
label1.Image = retIMG; // is work
button1.Image = retIMG; // is work
button1.BackgroundImage = retIMG; // don't work
groupBox1.BackgroundImage = retIMG; // don't work
panel1.BackgroundImage = retIMG; // don't work
}
}
}
我认为.net框架中存在一个错误。 请你帮帮我?
答案 0 :(得分:8)
阅读MSDN上Image.FromStream
上的评论:
您必须在图像的生命周期内保持流打开。
因此,如果您在创建using
周围删除MemoryStream
,则代码可以正常运行。
当你不再需要你创建的MemoryStream
时,你应该优先处理Image
,尽管在不调用Dispose()
并留下它的情况下可能没有任何伤害到GC时,一旦未使用就收集它。
它似乎与你的一些代码一起使用的事实可能是纯粹的运气,不应被视为一个有效的解决方案。请务必阅读文档以了解有关这样的怪癖。
答案 1 :(得分:7)
给予一些背景以添加DeCaf的正确答案。 GDI +非常努力地避免复制位图的像素。这是昂贵的,占用几十兆字节的位图并不罕见。当您使用Bitmap构造函数或Image.FromFile()从文件加载位图时,GDI +会创建一个内存映射文件。仅在需要时才按需分页像素。效率很高但它会锁定文件。很明显,你试图避免锁定此代码。
您确实通过使用MemoryStream将字节加载到内存中来避免该锁定。但是同样的原则仍然适用,GDI +仍然不会复制像素,只在需要时从流中读取。 Dispose()流时会出错。很难诊断因为以后发生异常,通常需要绘制位图时。它在绘画代码中炸弹,你没有任何代码可以看,但Application.Run()。有了一个糟糕的异常消息,GDI +只有一些错误代码。你不内存不足,它只能看到GDI +的方式,否则无法弄清楚为什么流突然不再可读了。
至少部分问题是由MemoryStream.Dispose()的非常笨拙的实现引起的。 Dispose旨在释放非托管资源。内存流没有任何内存流,它只拥有内存。这已经被垃圾收集器处理了。不幸的是他们无论如何实施了它不是通过实际处理任何东西,因为没有什么可以处理,而是通过标记MemoryStream不可读。在绘制位图时尝试读取时会触发GDI +中的错误。
因此,只需删除 using 语句,以避免处理MemoryStream来解决您的问题。并且不要担心以后在不再使用位图时将其处理掉。没有什么可以处理的,垃圾收集器会自动释放内存。
答案 2 :(得分:0)
两件事共同解决了这个间歇性问题,与图像大小无关。
首先,确保图像处于RGB模式,而绝对不是CMYK模式。根据我们的经验,RGB渲染实际上更大。
在加载新图像之前,第二次擦除(如果可能的话)图像容器中的任何先前图像,例如
Control.Image =没什么