设备无关位图字节数组到图像:参数无效

时间:2017-08-15 15:25:07

标签: c# bitmap binaryfiles com-interface

我正在使用提供COM接口的电子软件OMICRON MPD和MI。我正在通过COM接口提供的方法截取屏幕截图,并尝试将byte []保存到图像文件中。

我的代码:

byte[] rawImg = ...
MemoryStream mstream = new MemoryStream(rawImg);
ImageConverter imageConverter = new System.Drawing.ImageConverter();
System.Drawing.Image image = imageConverter.ConvertFrom(rawImg) as System.Drawing.Image; //error line
image.Save(@"path\img.jpg", System.Drawing.Imaging.ImageFormat.Jpeg);

我收到错误:

System.ArgumentException' occurred in System.Drawing.dll Parameter is not valid

我检查了字节数组的长度:

rawImg.Length
//897832

我可以使用以下内容将上述内存流保存到文件中:

using (FileStream file = new FileStream(@"path\img.txt", FileMode.Create, FileAccess.Write))
{
    mstream.WriteTo(file);
}

我不确定这意味着什么,但我该如何调试呢?错误在哪里?是我收到的数据是错误的还是C#代码将其保存为图像。

根据COM接口文档,rawImg是与设备无关的位图(格式与.BMP文件相同)。

尝试失败#1

ImageConverter imageConverter = new System.Drawing.ImageConverter();
            Image image = imageConverter.ConvertFrom(rawImg) as Image; //error line
            image.Save(@"path\img.bmp", System.Drawing.Imaging.ImageFormat.Bmp);

对于无效参数

给出与上述相同的错误

最终解决方案

我观看了一个名为“Hex To BMP:从头开始创建位图”的视频,它帮助我根据我得到的数据构建图像。

我收到的数据包含以字节为单位的图像数据,40字节的DIB标头,以及一些最初的27字节数据(我真的无法弄清楚它是什么)。为了将其翻译成图像,它在开头需要一个14字节的文件头,我手动构造如下:

byte[] fileHeader = { 0x42, 0x4d, 0x0c, 0xef, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00 };

请注意,十六进制文件大小(0x0c,0xef,0x82,0x00等于847760字节文件大小)是硬编码的(字节很容易变为动态)。 0x36是实际图像数据开始的位置,其在索引54处为十六进制36。

然后我只是通过偏移到DIB标题开始的位置来附加我原始数组中的数据,在我的例子中是27。

下面是原始数据的屏幕截图,其中包含最初的27个字节的未知数据,以及从索引27开始的DIB标题。

enter image description here

enter image description here

以上是我最终图像十六进制数据的屏幕截图。蓝色是14字节的文件头,红色是DIB头40字节,其余以绿色开头是图像数据。使用“.bmp”扩展名保存此数据并获得图像。

我的代码:

byte[] imgData, newImgData;
byte[] fileHeader = { 0x42, 0x4d, 0x0c, 0xef, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00 };
newImgData = new byte[847760];
BinaryFormatter bf = new BinaryFormatter();
string path2 = @"path\myImg.bmp";
using (MemoryStream ms = new MemoryStream())
{
  bf.Serialize(ms, value);
  mgData = ms.ToArray();

 }
 for(int i = 0; i < fileHeader.Count(); i++)
 {
       newImgData[i] = fileHeader[i];
 }

  int indx = 14;

  for (int i = 27; i < imgData.Count(); i++)
  {
       newImgData[indx] = imgData[i];
       indx++;
  }

  System.IO.File.WriteAllBytes(path2, newImgData.ToArray());

2 个答案:

答案 0 :(得分:2)

查看Notepad ++转储,看起来这只是32位/像素或4字节ARGB图像的原始字节。您应该能够使用Bitmap(Int32, Int32, Int32, PixelFormat, IntPtr)构造函数并传入原始字节。唯一的问题是找出图像的widthheightstridePixelFormat,但您应该能够通过一些实验来弄清楚这一点

这是一个例子,我制作了一个类似于你所显示的字节数组:

byte[] bytes = new byte[] {
    0,64,128,128,
    0,64,128,128,
    0,64,128,128,
    0,64,128,128,
    0,64,128,128,
    0,64,128,128,
    0,64,128,128,
    0,64,128,128,
};

unsafe
{
    fixed (byte* pBytes = bytes)
    {
        int width = 4; // Your width
        int height = 2; // Your height
        int stride = width * 4; // Your stride
        Bitmap bitmap = new Bitmap(width, height, stride, PixelFormat.Format32bppArgb, new IntPtr(pBytes));
        bitmap.Save(@"c:\temp\bitmap.png"); // Could save to another format like .jpg
    }
}

答案 1 :(得分:1)

请尝试代替您的代码片段:

byte[] rawImg = ...

MemoryStream mstream = new MemoryStream(rawImg);
File.WriteAllBytes("screen.bmp", mstream.ToArray());

尝试#2

我的第二个猜测,这可能是一个DIB文件格式,如果是真的,你应该能够打开&#34; screen.dib&#34;在大多数照片浏览者/编辑(如GIMP或其他人)中

byte[] rawImg = array;

File.WriteAllBytes("screen.dib", rawImg);