2

I am working with a electronic software OMICRON MPD and MI that provides a COM Interface. I am taking a screenshot via the methods provided by COM Interface and attempting to save the byte[] to an image file.

My code:

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

I get the Error:

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

I have checked the length of the byte array:

rawImg.Length
//897832

I can save the above memory stream to a file using the following:

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

I am not sure what it means, but how do I debug this? Where is the error? Is it the data I am receiving that is erroneous or the C# code to save it as an image.

According to the COM Interface documentation, the rawImg is device-independent bitmap (the format is identical to a .BMP file).

Failed Attempt #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);

gives same error as above about invalid parameter

Final Solution

I watch a video called "Hex To BMP: Creating a Bitmap From Scratch", which helped me in constructing the image from the data I was getting.

I was receiving a data that had image data in bytes, the 40 bytes DIB Header, and some initial 27 bytes of data (I couldn't really make out what it is). For this to be translated into an image it needed a 14 bytes file header at the beginning, which I manually constructed like so:

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

Notice that the file size in hex (0x0c, 0xef, 0x82, 0x00 which equals 847760 bytes file size) is hard coded (byte can easily be made dynamic). 0x36 is where the actual image data begins which is at index 54 that is 36 in hex.

Then I just appended that data from my original array by offsetting to where the DIB Header begin which in my case was index 27.

Below is Screenshot of my raw data with the initial 27 bytes of unknown data and with DIB Header starting at index 27.

enter image description here

enter image description here

Above is a screenshot of my final image hex data. The blue is the file header of 14 bytes, red is DIB header 40 bytes, and rest starting with green is image data. Save this data with ".bmp" extension and you got a image.

My Code:

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());
Saad A
  • 1,135
  • 2
  • 21
  • 46

2 Answers2

2

Looking at the Notepad++ dump it appears this is just the raw bytes of 32 bit-per-pixel or 4 byte ARGB image. You should be able to use the Bitmap(Int32, Int32, Int32, PixelFormat, IntPtr) constructor and just pass in the raw bytes. The only issue will be figuring out the width, height, stride, and PixelFormat of the image but you should be able to figure that out with a little bit of experimentation.

Here's an example where I made a byte array similar to the one you've shown:

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
    }
}
tbridge
  • 1,754
  • 1
  • 18
  • 35
  • yes it does the trick without error however, as from the above discussion it very clear now that i am not getting the incorrect screenshot data from MPD 600 Com Interface. So the image is just blank! – Saad A Aug 15 '17 at 18:33
1

Try just istead of your code snippet something like this:

byte[] rawImg = ...

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

Attempt #2

My second guess, this could be a DIB file format, if it is true, you should be able to open "screen.dib" in most photo viewers/editors (like GIMP or others)

byte[] rawImg = array;

File.WriteAllBytes("screen.dib", rawImg);
komorra
  • 259
  • 1
  • 8
  • 20
  • it saves it as a image file but I can't view it in Windows Photo Viewer and when I tried to open it in GIMP, it says "Opening file failed, is not a valid BMP file" – Saad A Aug 15 '17 at 16:55
  • I think this goes with what @Zergatul said about rawImg not being a valid BMP. – Saad A Aug 15 '17 at 16:56