Image PropertyItems和已释放的MemoryStream

本文关键字:MemoryStream 释放 PropertyItems Image | 更新日期: 2023-09-27 18:27:27

我正在使用MemoryStreambyte[]加载Image,并通过检查图像的ProperyItems来获取有关图像的信息。然而,在这样做的过程中,我注意到了一些奇怪的行为,图像的一些PropertyItems正在消失。经过多次调试,我终于发现这是由正在处理的MemoryStream引起的。

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");

输出:

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, 

因此,似乎至少有一些PropertyItems是由MemoryStream的内容直接支持的,解决方案是不处理它,还是我错了?

在调试这个问题的过程中,尽管我注意到了一些奇怪的事情,但如果我访问using块内的PropertyIdList(或与图像PropertyItems相关的任何东西),则在MemoryStream被处理后,PropertyItems不会消失。

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");

输出:

Outside using with PropertyIdList access, Image propertyIDs: 
254, 256, 257, 258, 259, 262, 269, 273, 274, 277, 278, 279, 282, 283, 284, 296,

我查看了Image类的源,PropertyIdList属性似乎没有保留PropertyItems数据的本地副本,那么在这种情况下,为什么在处理MemoryStream之后保留PropertyItems呢?

Image PropertyItems和已释放的MemoryStream

处理MemoryStream通常是一件非常无用的事情。它本身没有任何可丢弃的资源,它只是内存,已经由垃圾收集器管理。只有当你已经使用了BeginRead/Write()方法,但它们还没有完成,这才是重要的,这是你从未做过的

但是,它确实将CanRead()属性设置为false。这对从MemoryStream加载的位图对象来说是非常致命的。

当您继续使用位图时,接下来会发生什么是不可预测的。GDI+要求流保持可读性,它可以在以后使用它,以惰性的方式读取位图数据。最常见的情况是,当位图被绘制时,这往往会导致程序相当可靠地崩溃,并出现"一般错误"。

你发现了另一个角落的案例,似乎它只是认为没有更多的财产。这并不是那么神秘,你确实关闭了流,所以它不可能读取更多的属性。它没有为此生成异常是草率的,但对于GDI+来说并不罕见。

只要使用语句去掉,它就没有任何用处。如果您无论如何都在为处理流而烦恼,那么在不再使用位图对象之后,必须这样做。

因为您在using语句的范围之外创建了img2,所以处理流不会影响它。

CCD_ 21是图像而非CCD_ 22对象的方法。