patterncsharpMinor
Comparing screen captures using unsafe / API calls
Viewed 0 times
callscomparingunsafecapturesusingscreenapi
Problem
After a week of searching and testing each approach via
I came to this method using the fastest way possible to capture screen into a bitmap and then to a
-
Is it possible to make it any faster using parallel features or any idea I have not taken into account? (As I am a newbie, 4 months of self learning.)
-
I mixed two or three versions of the copying function (portion of screen to memory
then convert captured/crop into
```
unsafe public static Bitmap NatUnsfBtmp(IntPtr hWnd, Size Ms)
{
Stopwatch swCap2Byte = new Stopwatch();
swCap2Byte.Start();
WINDOWINFO winInfo = new WINDOWINFO();
bool ret = GetWindowInfo(hWnd, ref winInfo);
if (!ret)
{
return null;
}
int height = Ms.Height;
int width = Ms.Width;
if (height == 0 || width == 0) return null;
Graphics frmGraphics = Graphics.FromHwnd(hWnd);
IntPtr hDC = GetWindowDC(hWnd); //gets the entire window
//IntPtr hDC = frmGraphics.GetHdc(); -- gets the client area, no menu bars, etc..
System.Drawing.Bitmap tmpBitmap = new System.Drawing.Bitmap(width, height, frmGraphics);
Bitmap bitmap = (Bitmap)Clipboard.GetDataObject().GetData(DataFormats.Bitmap);
Graphics bmGraphics = Graphics.FromImage(tmpBitmap);
IntPtr bmHdc = bmGraphics.GetHdc();
BitBlt(bmHdc, 0, 0, width, height, hDC, 0, 0, TernaryRasterOperations.SRCCOPY);
swCap2Byte.Stop();
string swCopiedFF = swCap2Byte.Elapsed.ToString().Remove(0, 5);
swCap2Byte.Restart();
#region ByteArr ============>>
BitmapData bData = tmpBitmap.LockBits(new Rectangle(new Point(), Ms),
ImageLockMode.ReadOnly,
PixelFormat.Format24bppRgb);
MyForm1.MyT.Cap.TestBigCapturedBtmp = tmpBitmap;
// number of bytes in the bitmap
int byteCount = bData.Stride * tmpBitmap.Height;
byte[] bmpBytes = new byte[byteCount];
// Copy the locked byte
Stopwatch, I came to this method using the fastest way possible to capture screen into a bitmap and then to a
byte[].-
Is it possible to make it any faster using parallel features or any idea I have not taken into account? (As I am a newbie, 4 months of self learning.)
-
I mixed two or three versions of the copying function (portion of screen to memory
then convert captured/crop into
byte[]). I might have left unnecessary lines of code, I would like to refine it (if and where needed).```
unsafe public static Bitmap NatUnsfBtmp(IntPtr hWnd, Size Ms)
{
Stopwatch swCap2Byte = new Stopwatch();
swCap2Byte.Start();
WINDOWINFO winInfo = new WINDOWINFO();
bool ret = GetWindowInfo(hWnd, ref winInfo);
if (!ret)
{
return null;
}
int height = Ms.Height;
int width = Ms.Width;
if (height == 0 || width == 0) return null;
Graphics frmGraphics = Graphics.FromHwnd(hWnd);
IntPtr hDC = GetWindowDC(hWnd); //gets the entire window
//IntPtr hDC = frmGraphics.GetHdc(); -- gets the client area, no menu bars, etc..
System.Drawing.Bitmap tmpBitmap = new System.Drawing.Bitmap(width, height, frmGraphics);
Bitmap bitmap = (Bitmap)Clipboard.GetDataObject().GetData(DataFormats.Bitmap);
Graphics bmGraphics = Graphics.FromImage(tmpBitmap);
IntPtr bmHdc = bmGraphics.GetHdc();
BitBlt(bmHdc, 0, 0, width, height, hDC, 0, 0, TernaryRasterOperations.SRCCOPY);
swCap2Byte.Stop();
string swCopiedFF = swCap2Byte.Elapsed.ToString().Remove(0, 5);
swCap2Byte.Restart();
#region ByteArr ============>>
BitmapData bData = tmpBitmap.LockBits(new Rectangle(new Point(), Ms),
ImageLockMode.ReadOnly,
PixelFormat.Format24bppRgb);
MyForm1.MyT.Cap.TestBigCapturedBtmp = tmpBitmap;
// number of bytes in the bitmap
int byteCount = bData.Stride * tmpBitmap.Height;
byte[] bmpBytes = new byte[byteCount];
// Copy the locked byte
Solution
There are a few things I see at a glance:
tags, you should be pulling that code out into a helper method. You
could probably split this method into several. Don't worry about
overhead of extra method calls -- the compiler will likely re-inline
them anyways.
- If you have to enclose a section of code within a method in region
tags, you should be pulling that code out into a helper method. You
could probably split this method into several. Don't worry about
overhead of extra method calls -- the compiler will likely re-inline
them anyways.
- Split the body of your if/else on "Big" and "Small" into a helper method that takes in a file name. That's the only difference I see in each block.
- There are a lot of lines where you are declaring and assigning variables. When you do that, it is likely more readable to declare as var, because you indicate what type it is immediately to the right of the assignment operator.
- Rather than converting your elapsed times with
ToString ().Remove ()calls, I would instead suggest storing them as TimeSpan types and using a string format in your message boxes.
- Move "Big", "Small", "testBig4BenchViaChaos.bar", and "testSmall4BenchViaChaos.bar" into constants.
- If this is just a utility that is not client-facing, move your other strings to constants. Otherwise, move them into a resx so they can be localized.
- Naming - you should use longer, more descriptive names. You are not saving much by using a name like OrgArr instead of the longer OriginalArray. You should also be consistent in capitalization. Some of your local variables are camel case, and some are pascal case. The standard for the framework is camel case for local variables.
- You are overwriting testBig4BenchViaChaos.bar with OrgArr, but then comparing the bytes in testBig4BenchViaChaos.bar with OrgArr. Am I missing something, or should this always return a match because the data is the same? Though, on that note, you are doing == with byte arrays, so you should really always mis-match due to object reference comparison.
- Your quickest way to compare the two byte arrays is probably going to be using a for loop (single-threaded) or possibly PLINQ using SequenceEqual. As always, benchmark to be sure because test results are worth a thousand expert opinions.
Context
StackExchange Code Review Q#15349, answer score: 6
Revisions (0)
No revisions yet.