【问题标题】:Loading raw data into a Bitmap - what have I done wrong?将原始数据加载到位图中 - 我做错了什么?
【发布时间】:2013-03-06 18:19:44
【问题描述】:

我正在使用 c sharp、.net 4(客户端配置文件,如果这很重要的话)并且我有一个包含图像原始数据的 byte 数组。具体来说,这张图片:

它是 SANE 测试后端的输出,格式在 SANE 网站here 上有完整描述。顺便说一下,我已经传入了参数:

  • 深度:8
  • 模式:颜色

它已经返回:

  • 格式:RGB
  • 深度:8
  • 行数:196
  • 每行像素:157
  • 每行字节数:471
  • 92316 字节长的字节流

因此,这些数字似乎是合理的 (196 * (157 * 471) = 92316) - 每个像素三个字节(24 位)。

通过阅读 SANE 文档,数据从左上角从左到右,从上到下按每个像素三个字节排序 - 就像这样(他们有更好的图片,抱歉这种 ASCIItastic 方法):

red,green,blue   red,green,blue  
--------------   --------------
    byte 1           byte 2       ...

因为我对这张图片非常了解,所以我认为将它加载到Bitmap 中会非常简单,我敲了这个:

var bmp = new Bitmap(157, 196, PixelFormat.Format24bppRgb);
BitmapData bmpData = bmp
    .LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height),
              ImageLockMode.ReadWrite,
              bmp.PixelFormat);
Marshal.Copy(data, 0, bmpData.Scan0, data.Length);
bmp.UnlockBits(bmpData);

但它产生了这个:

关闭,但没有雪茄,可以这么说。

那么,我做错了什么?

【问题讨论】:

    标签: c# .net image


    【解决方案1】:

    问题在于,在位图中,一行的字节与下一行的字节之间存在间隙(更多 here)。如果速度不是您最关心的问题,您可以更轻松地做到这一点SetPixel 和一个循环。

    编辑:
    与 SetPixel 相比,这将显着提高速度,但恐怕您仍然必须使用循环;)

    for(int i = 0; i < bmp.Height; i++) {
        Marshal.Copy(data, 
            i * bmp.Height,
            bmpData.Scan0 + i * bmpData.Stride,
            bmp.Width * 3);
    }
    

    请注意,我还没有测试过代码,但它应该足以给你这个想法。

    【讨论】:

    • 我希望它具有相当的性能 - 我认为图像很容易变得相当大,因此循环和设置像素对我来说并不是很理想,但感谢您的建议 - 我会保留它如果我找不到更好的方法。
    • 太棒了,谢谢 - 虽然使用您的信息运行它并不能很好地工作,但我想出了自己的,非常天真的方法,它确实会产生正确的结果
    • +1。 Stride 是获取每行大小的正确方法!
    【解决方案2】:

    位图需要将行填充到某个特定大小(4 字节,搜索 hor 格式详细信息,即 here)。

    因此,每行 157 个像素并不完全映射为位图位的二进制格式,您会看到下一行移动了一点。我认为您需要为每行分配 158*3 字节并将每一行从源(由于缺少填充而不是位图)格式复制到目标,用 0 填充每行的最后 3 个字节。

    【讨论】:

    • 我查看了来自@BlackBear 的 Stride 属性,并建议(至少对我而言)我应该使用它来填充行 - 在这种情况下,步幅长度为 158,所以我试着坚持每行末尾多了一个 0 字节,看起来是正确的
    猜你喜欢
    • 1970-01-01
    • 2017-12-27
    • 2013-02-24
    • 1970-01-01
    • 1970-01-01
    • 2017-08-03
    • 2023-03-21
    • 2015-06-02
    • 2013-08-23
    相关资源
    最近更新 更多