Screenshot capture to byte array
Dear C# professionals.
Is this possible to optimize the code of screenshot capture and make it directly to byte array without intermediate bmp? The code I use now contains of two functions. First function CreateBitmapFromWindow accepts a pointer to the window and returns bitmap, corresponding to window rectangle. Second function translates bitmap to byte array via Marshal.Copy. I dont write unmanaged methods class here. Methods are standard and taken from msdn:
Code:
public Bitmap CreateBitmapFromWindow(IntPtr hwnd)
{
Rect rec;
IntPtr hDC;
Bitmap bmp;
//calculating window dimensions
UnmanagedMethods.GetWindowRect(hwnd, out rec);
//Here we get the handle to the window device context.
hDC = UnmanagedMethods.GetDCEx(hwnd, UnmanagedMethods.CreateRectRgn(rec.Left, rec.Top, rec.Right, rec.Bottom),UnmanagedMethods.DCX_WINDOW);
//Here we make a compatible device context in memory for window or screen device context.
IntPtr hMemDC = UnmanagedMethods.CreateCompatibleDC(hDC);
//We create a compatible bitmap of the screen size and using the screen device context.
IntPtr hBitmap = UnmanagedMethods.CreateCompatibleBitmap(hDC, rec.Right - rec.Left, rec.Bottom - rec.Top);
//Here we select the compatible bitmap in the memeory device
//context and keep the refrence to the old bitmap.
IntPtr hOld = UnmanagedMethods.SelectObject(hMemDC, hBitmap);
//We copy the Bitmap to the memory device context.
UnmanagedMethods.BitBlt(hMemDC, 0, 0, rec.Right - rec.Left, rec.Bottom - rec.Top, hDC, 0, 0, UnmanagedMethods.SRCCOPY);
//We select the old bitmap back to the memory device context.
UnmanagedMethods.SelectObject(hMemDC, hOld);
//We delete the memory device context.
UnmanagedMethods.DeleteDC(hMemDC);
//We release the screen device context.
UnmanagedMethods.ReleaseDC(hwnd, hDC);
//Image is created by Image bitmap handle and stored in local variable.
bmp = Image.FromHbitmap(hBitmap);
//Release the memory to avoid memory leaks.
UnmanagedMethods.DeleteObject(hBitmap);
//This statement runs the garbage collector manually.
GC.Collect();
return bmp;
}
//Second function translates bmp to byte array
public byte[] BMPToByteArray(Bitmap bmp)
{
Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
//I use only 24b BMPs
BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
IntPtr ptr = bmpData.Scan0;
int bytes = bmpData.Stride * bmp.Height;
byte[] rgbValues = new byte[bytes];
Marshal.Copy(ptr, rgbValues, 0, bytes);
bmp.UnlockBits(bmpData);
return rgbValues;
}
[StructLayout(LayoutKind.Sequential)]
public struct Rect
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
Re: Screenshot capture to byte array
What's wrong with using an intermediate Bitmap?
Re: Screenshot capture to byte array
I am looking for faster method of bmp extraction and analysis. My program should work at high cpu load and one screenshot operation from a window can take 500ms to complete. Bitmap analysis after extraction is near to instant. As a result program sees everything with delay, and during this delay window can change. I made measures of time consumption in CreateBitmapFromWindow block. It looks like there is no obvious bottleneck exist:
Thread synchronization lock (2x) - 16% - Monitors on the enter and exit of the function
CreateCompatibleBitmap - 15%
SelectObject (2x) - 23%
BitBlt - 36%
FromHBitMap - 6%
Garbage collector - 3%
BitBlt and Marshal.Copy functions make similar operation. Is there a way to copy bytes only one time?