将原始数据加载到位图 - 我做错了什么?

时间:2013-03-06 18:19:45

标签: c# .net image

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

good image

它是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);

但它产生了这个:

bad image

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

那么,我做错了什么?

2 个答案:

答案 0 :(得分:4)

问题是在位图中,一行的字节与下一行的字节之间存在间隙(更多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 :(得分:3)

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

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