2013-10-31 68 views
7

根据我在SO和Web上的研究,保存位图时的GDI +通用错误显然是一个常见问题。给定以下简化片段:GDI +使用LockBits从内存创建的通用错误保存位图

byte[] bytes = new byte[2048 * 2048 * 2]; 

for (int i = 0; i < bytes.Length; i++) 
{ 
    // set random or constant pixel data, whatever you want 
} 

Bitmap bmp = new Bitmap(2048, 2048, PixelFormat.Format16bppGrayScale); 
BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, 2048, 2048), ImageLockMode.ReadWrite, bmp.PixelFormat); 
System.Runtime.InteropServices.Marshal.Copy(bytes, 0, bmpData.Scan0, 8388608); 
bmp.UnlockBits(bmpData); 
bmp.Save(@"name.bmp"); 

这会导致0x80004005一般错误。据说通常的原因是对组件的锁定,但我在这里没有看到任何东西。我是否只是盲目的?我保存的路径存在,当然,只有一个空的bmp文件被创建(0B)。

背景:我从使用C++/CLI包装器传输到.NET的摄像头驱动程序获取像素数据,因此上述Bitmap对象通过函数调用返回。但由于这个小例子已经失败了,我猜这个适配器没有问题。

任何建议,非常感谢!

+0

16位灰度是不是一个有效的bmp格式可能? –

+0

老实说,我没有考虑过这一点。切换到8bpp索引创建文件没有任何错误。最终目标是将灰度16bpp图像保存为PNG,但用'bmp.Save(@“name.bmp”,ImageFormat.Png)替换上述内容;'也不起作用。 – simd

+0

保存时是否尝试过指定ImageFormat.Bmp?看到这个答案:http://social.msdn.microsoft.com/Forums/vstudio/en-US/10252c05-c4b6-49dc-b2a3-4c1396e2c3ab/action?threadDisplayName=writing-a-16bit-grayscale-image – Ben

回答

15
Bitmap bmp = new Bitmap(2048, 2048, PixelFormat.Format16bppGrayScale); 

GDI +的例外情况相当差,您将无法诊断出这两个错误。较小的一个是您的Save()调用,它不指定要保存的ImageFormat。默认是PNG,而不是你所希望的。

但核心之一是PixelFormat.Format16bppGrayScale。当GDI +被设计出来,早在.NET出现之前,每个人都在使用CRT而不是液晶显示器。 CRT显示色域相当不错。虽然好,但还没有主流CRT能够显示65536个不同的灰色。大部分都受到视频适配器中DAC的限制,该芯片将数字像素值转换为CRT的模拟信号。一个可以在100MHz或更高频率下以16位精度转换的DAC在技术上还不可行。微软在显示技术方面进行了冒险改进,以便有朝一日将如此指定的Format16bppGrayScale作为像素格式,可能有一天可用。

这没有发生。相反,LCD在色彩分辨率上明显更差。典型的LCD面板只能解析6位的颜色,而不是像素格式中的8位。获得16位色彩分辨率将需要重大的技术突破。

所以他们猜错了,由于像素格式没有用,GDI +实际上并没有一个图像编码器可以编写16bpp灰度图像格式。 Kaboom在尝试将其保存到磁盘时,无论您选择的ImageFormat如何。

实际使用16bpp灰度,放射成像使用该像素格式。用非常昂贵的显示器使其实际有用。然而,这样的设备不变地使用自定义图像格式,DICOM是通常的选择。 GDI +没有编解码器。

您需要购买一个支持客户想要的图像格式的图书馆。铅工具是该产品领域的千磅大猩猩。

+0

谢谢您的详细回答,总是很高兴为您解释一些背景知识。这里指的是图像不太适合用于显示,而是之后用软件进行分析。图像来自延时显微镜,16bit给我们的选项比8bit多得多。因此,如果我必须使用一个额外的库,那么WIC是否会在这里工作(已经在相机适配器中与它进行链接),还是必须回退到libpng? – simd

+3

在这种情况下,您完全不承诺支持的图像格式。这里要做的聪明的事情就是以自己的格式保存数据。例如,BinaryWriter无法做到这一点。 –

+1

16位位图对范围数据也很有用(例如Kinect生成的那样) – Eponymous