-
April 20th, 2010, 10:49 PM
#1
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;
}
-
April 21st, 2010, 03:22 AM
#2
Re: Screenshot capture to byte array
What's wrong with using an intermediate Bitmap?
If you liked my post go ahead and give me an upvote so that my epee.... ahem, reputation will grow.
Yes; I have a blog too - http://the-angry-gorilla.com/
-
April 21st, 2010, 04:09 AM
#3
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?
Tags for this Thread
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|