问题
I'm loading an Image
from a byte[]
using MemoryStream
and getting information about the image by inspecting it's ProperyItems
. In the process of doing this though, I noticed some odd behaviour where some of the image's PropertyItems
were disappearing. After much debugging I finally figured out that this was being caused by the MemoryStream
being disposed.
MemoryStream ms0 = new MemoryStream(imageBytes);
Image img0 = Image.FromStream(ms0);
Console.Out.WriteLine("Without using, Image propertyIDs: ");
foreach (int itemId in img0.PropertyIdList)
Console.Out.Write(itemId + ", ");
Console.Out.Write("\n");
Image img1 = null;
using (MemoryStream ms1 = new MemoryStream(imageBytes))
{
img1 = Image.FromStream(ms1);
}
Console.Out.WriteLine("Outside using, Image propertyIDs: ");
foreach (int itemId in img1.PropertyIdList)
Console.Out.Write(itemId + ", ");
Console.Out.Write("\n");
Output:
Without using, Image propertyIDs:
254, 256, 257, 258, 259, 262, 269, 273, 274, 277, 278, 279, 282, 283, 284, 296,
Outside using, Image propertyIDs:
254, 256, 257, 258, 259, 262, 274, 277, 278, 284, 296,
So it appears that at least some of the PropertyItems
are directly backed by the contents of the MemoryStream
and the solution is not to dispose it, or am I wrong?
In the process of debugging this issue though I've noticed something else odd, if I access the PropertyIdList
(or anything related to the images PropertyItems
) inside the using
block, the PropertyItems
won't disappear after the MemoryStream
is disposed.
Image img2 = null;
using (MemoryStream ms2 = new MemoryStream(imageBytes))
{
img2 = Image.FromStream(ms2);
int[] tmp = img2.PropertyIdList;
}
Console.Out.WriteLine("Outside using with PropertyIdList access, Image propertyIDs: ");
foreach (int itemId in img2.PropertyIdList)
Console.Out.Write(itemId + ", ");
Console.Out.Write("\n");
Output:
Outside using with PropertyIdList access, Image propertyIDs:
254, 256, 257, 258, 259, 262, 269, 273, 274, 277, 278, 279, 282, 283, 284, 296,
I looked at the source for the Image
class and the PropertyIdList
property doesn't appear to be retaining a local copy of the PropertyItems
data, so why are the PropertyItems
retained after the MemoryStream
is disposed in this situation?
回答1:
Disposing a MemoryStream is in general a fairly useless thing to do. It doesn't have any disposable resources itself, it is just memory and that's already managed by the garbage collector. It only matters if you've used the BeginRead/Write() methods and they are not yet completed, something you just never do.
It does however set the CanRead() property to false. And that's quite lethal to the Bitmap object you loaded from the MemoryStream.
What happens next, when you keep using the Bitmap, is fairly unpredictable. GDI+ requires that the stream stays readable, it may use it later, reading the bitmap data in a lazy fashion. Most typically when the bitmap gets painted and that tends to crash your program fairly reliably with a "generic error".
You found another corner case, seems it just thinks there are no more properties. This is not otherwise that mysterious, you really did close the stream so there are no more properties it could possibly read. That it doesn't generate an exception for that is sloppy but not uncommon for GDI+.
Just get rid of the using statement, it doesn't do anything useful. If you fret about disposing the stream anyway then you must do so after you won't use the Bitmap object anymore.
回答2:
Because you created img2
out of scope of using
statement so disposing stream does not affect it.
PropertyIdList
is a method of Image not MemoryStream
object.
来源:https://stackoverflow.com/questions/18215610/image-propertyitems-and-disposed-memorystream