【问题标题】:GDI+ generic error saving bitmap created from memory using LockBits使用 LockBits 从内存创建的 GDI+ 通用错误保存位图
【发布时间】:2020-06-17 18:16:24
【问题描述】:

根据我在 SO 和网络上的研究,保存位图时的 GDI+ 一般错误显然是一个常见问题。给出以下简化的 sn-p:

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 对象由函数调用返回。但是既然这个小例子已经失败了,我猜适配器没有问题。

非常感谢任何建议!

【问题讨论】:

  • 16 位灰度可能不是有效的 bmp 格式?
  • 说实话,我没有考虑过。切换到 8bpp 索引创建的文件没有任何错误。最终目标是将灰度 16bpp 图像保存为 PNG,但是将上面的替换为 bmp.Save(@"name.bmp", ImageFormat.Png); 也不起作用。
  • 您是否尝试过在保存时指定 ImageFormat.Bmp?看到这个答案:social.msdn.microsoft.com/Forums/vstudio/en-US/…
  • 还有你在什么平台上?如果 XP 则可能不支持保存 16BppGrayScale。
  • @Ben: Win7 64。还尝试指定ImageFormat.Bmp。请参阅我的最后一条评论,显然不支持 Format16bppGrayscale。但是,我仍然在努力将位图保存为 16bpp 的 PNG。

标签: c# gdi+ system.drawing


【解决方案1】:
   Bitmap bmp = new Bitmap(2048, 2048, PixelFormat.Format16bppGrayScale);

GDI+ 异常相当糟糕,您几乎没有希望诊断出这两个错误。较小的一个是您的 Save() 调用,它没有指定您要保存的 ImageFormat。默认是 PNG,而不是您希望的 BMP。

但核心是PixelFormat.Format16bppGrayScale。设计 GDI+ 时,早在 .NET 出现之前,每个人仍在使用 CRT 而不是 LCD 显示器。 CRT 非常擅长显示各种颜色。虽然不错,但目前还没有主流 CRT 能够显示 65536 种不同的灰色。最重要的是受视频适配器中的 DAC 限制,该芯片将数字像素值转换为 CRT 的模拟信号。能够以 100 MHz 或更高频率进行 16 位精度转换的 DAC 在技术上尚不可行。 Microsoft 押注于显示技术的改进,以便有朝一日使之成为可能,因此将 Format16bppGrayScale 指定为可能某天可用的像素格式。

那没有发生。相反,LCD 在颜色分辨率方面明显较差。典型的 LCD 面板只能解析 6 位颜色,而不是像素格式中可用的 8 位。达到 16 位色彩分辨率需要重大的技术突破。

所以他们猜错了,因为像素格式没有用,GDI+ 实际上没有可以编写 16bpp 灰度图像格式的图像编码器。无论您选择哪种 ImageFormat,尝试将其保存到磁盘时都会出现 Kaboom。

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

您需要购买支持客户所需图像格式的库。 Lead Tools 是该产品领域的一千磅重的大猩猩。

【讨论】:

  • 感谢您的详细回答,总是很高兴获得一些背景的解释。这里的重点是图像很少用于显示,而是通过软件进行分析。这些图像来自延时显微镜,16 位比 8 位提供了更多的选择。因此,如果我必须使用额外的库,WIC 会在这里工作(已经在相机适配器中链接它),还是我必须退回到 libpng?
  • 在这种情况下,您根本没有承诺支持的图像格式。明智的做法是以您自己的格式保存数据。例如,没有什么是 BinaryWriter 做不到的。
  • 16 位位图也可用于范围数据(例如 Kinect 生成的数据)
  • @simd 是否有任何库可以在 c# 中制作 16 位灰度图像?
【解决方案2】:

PixelFormat.Format32bppArgb 似乎在使用 GDI 的 Ubuntu 20 上为我工作。

var bitmapdata = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly,
                PixelFormat.Format32bppArgb);

我得到的错误是

System.ArgumentException: 'Parameter is not valid.'
at System.Drawing.SafeNativeMethods.Gdip.CheckStatus(Int32 status)
   at System.Drawing.Bitmap.LockBits(Rectangle rect, ImageLockMode flags, PixelFormat format, BitmapData bitmapData)
   at System.Drawing.Bitmap.LockBits(Rectangle rect, ImageLockMode flags, PixelFormat format)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-25
    • 1970-01-01
    • 1970-01-01
    • 2011-06-21
    • 2017-08-18
    • 2013-01-29
    相关资源
    最近更新 更多