0

i was loooking for a faster solution to convert image to byte array using the regular method:

   public byte[] imageToByteArray(System.Drawing.Image imageIn)
 {
  MemoryStream ms = new MemoryStream();
  imageIn.Save(ms,System.Drawing.Imaging.ImageFormat.Gif);
  return  ms.ToArray();
 }

so i searched and found this one

public static byte[] BitmapToByteArray(Bitmap bitmap)
    {

        BitmapData bmpdata = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, bitmap.PixelFormat);
        int numbytes = bmpdata.Stride * bitmap.Height;

        numbytes = Math.Abs(numbytes);

        byte[] bytedata = new byte[numbytes];
        IntPtr ptr = bmpdata.Scan0;

        Marshal.Copy(ptr, bytedata, 0, numbytes);

        bitmap.UnlockBits(bmpdata);

        return bytedata;

    }

this is my call:

 `   private void Form1_Load(object sender, EventArgs e)
    {

       Bitmap curr = GetDesktopImage();

        byte[] buff = BitmapToByteArray(curr);


        }

than i got an expcetion arithmetic operation resulted in an overflow and i discoverd that numbofbytes was negative so it couldn't make the array so i used Math.Abs() but than i got another error on that line Marshal.Copy(ptr, bytedata, 0, numbytes); and the error : Attempted to read or write protected memory. This is often an indication that other memory is corrupt. why is it happening? GetDesktopImage() is a method i have that uses the gdi to take screenshots according to this and the method is actully (i tried to display on picturebox) but im facing weird errors when trying to convert to bytes..

this is GetDesktopImage()

 public static Bitmap GetDesktopImage()
    {
        //In size variable we shall keep the size of the screen.
        SIZE size;

        //Variable to keep the handle to bitmap.
        IntPtr hBitmap;

        IntPtr hDC = PlatformInvokeUSER32.GetDC(PlatformInvokeUSER32.GetDesktopWindow());

        IntPtr hMemDC = PlatformInvokeGDI32.CreateCompatibleDC(hDC);

        size.cx = PlatformInvokeUSER32.GetSystemMetrics(PlatformInvokeUSER32.SM_CXSCREEN);

        size.cy = PlatformInvokeUSER32.GetSystemMetrics(PlatformInvokeUSER32.SM_CYSCREEN);

        hBitmap = PlatformInvokeGDI32.CreateCompatibleBitmap(hDC, size.cx, size.cy);

        if (hBitmap != IntPtr.Zero)
        {

            IntPtr hOld = (IntPtr)PlatformInvokeGDI32.SelectObject(hMemDC, hBitmap);

            PlatformInvokeGDI32.BitBlt(hMemDC, 0, 0, size.cx, size.cy, hDC, 0, 0, PlatformInvokeGDI32.SRCCOPY);

            PlatformInvokeGDI32.SelectObject(hMemDC, hOld);

            PlatformInvokeGDI32.DeleteDC(hMemDC);

            PlatformInvokeUSER32.ReleaseDC(PlatformInvokeUSER32.GetDesktopWindow(), hDC);

            Bitmap bmp = System.Drawing.Image.FromHbitmap(hBitmap);

            PlatformInvokeGDI32.DeleteObject(hBitmap);

            GC.Collect();

            return bmp;
        }


        return null;
    }
  • Why do you need it to be faster than your first working method, are you trying to create video of the desktop using `GetDesktopImage()`? Also the reason `numbytes` is negative is likely because `bmpdata.Stride * bitmap.Height` is larger than a `int` can hold. – Scott Chamberlain Jun 29 '15 at 16:28
  • Side note: There is almost no chance that handling uncompressed image leads to overall better performance/memory usage. Screenshots are generally very compressible, so you may be forcing yourself to deal with 10-50x more memory than needed for compressed image. – Alexei Levenkov Jun 29 '15 at 16:37
  • @ScottChamberlain i dont think that's the reason because when i try to print the stride it's aleardy negative :( and no i dont want to make a video –  Jun 29 '15 at 18:47

1 Answers1

0

For the negative stride, the MSDN doc says:

The stride is the width of a single row of pixels (a scan line), rounded up to a four-byte boundary. If the stride is positive, the bitmap is top-down. If the stride is negative, the bitmap is bottom-up.

Your bitmap is bottom-up. Have a look at this nice explanation here: https://msdn.microsoft.com/en-us/library/windows/desktop/aa473780(v=vs.85).aspx

To copy the bytes, you need to calculate the starting address like in this answer: https://stackoverflow.com/a/17116072/200443.

If you want to reverse the bytes order, you need to copy one line at a time.

Community
  • 1
  • 1
Maxence
  • 12,868
  • 5
  • 57
  • 69