开发者

out of memory exception when use control.BackgroundImage = Image.FromStream(memStream);

I write a code that read a png image from file and show with control.

I want read image from stream and set

control.BackgroundImage = Image.FromStream(memStream);

but when use this code , occur "out of memory" exception. but when use

control.Image = Image.FromStream(memStream);

or

control.BackgroundImage = Image.FromFile(fileSource);

, that is work.

image开发者_JAVA技巧 file size is 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
  }
  }
 }

I think a bug in .net framework. please you help me?


Read the remarks on Image.FromStream on MSDN:

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

So if you remove the using around the creation of your MemoryStream your code works fine.

Of course you should preferrably dispose the MemoryStream once you no longer need the Image you created, although there is likely no harm in this case in not calling Dispose() and leaving it up to the GC to collect it once unused.

The fact that it seems to work with some of your code is likely pure luck and should not be considered a working solution. Always read the documentation to find out about quirks like this.


Giving some background to add to DeCaf's correct answer. GDI+ tries very hard to avoid copying the pixels of a bitmap. That's expensive, bitmaps taking dozens of megabytes is not unusual. When you load a bitmap from a file with the Bitmap constructor or Image.FromFile() then GDI+ creates a memory-mapped file. The pixels are paged-in on demand, only when needed. Very efficient but it puts a lock on the file. Clearly you were trying to avoid that in lock in this code.

You indeed avoid that lock by loading the bytes into memory yourself with a MemoryStream. But the same principle still applies, GDI+ still doesn't copy the pixels and only reads from the stream when it needs to. This goes wrong when you Dispose() the stream. Very hard to diagnose because the exception occurs later, typically when the bitmap needs to be drawn. It bombs in the painting code, you don't have any code to look at but Application.Run(). With a crappy exception message, GDI+ only has a handful of error codes. You are not out of memory, it only looks that way to GDI+, it cannot otherwise figure out why the stream suddenly isn't readable anymore.

At least part of the problem is caused by the very awkward implementation of MemoryStream.Dispose(). Dispose is meant to release unmanaged resources. A memory stream doesn't have any, it only owns memory. That's already taken care of by the garbage collector. Unfortunately they implemented it anyway. Not by actually disposing anything, since there's nothing to dispose, but by marking the MemoryStream unreadable. Which triggers the error in GDI+ when it tries to read while drawing the bitmap.

So simply remove the using statement to avoid disposing the MemoryStream to solve your problem. And don't fret about disposing it later when the bitmap is no longer in use. There's nothing to dispose, the garbage collector automatically frees the memory.


Two things which together resolved this intermittent issue, which has nothing to do with image size.

First, ensure that the image is in RGB mode and definitely not CMYK mode. In our experience, the RGB rendering is actually larger.

Second, erase (and dispose of if possible) any previous image in the image container before loading the new image, such as

Control.Image = Nothing

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜