Phew, first burden here is to explain what I'm looking for within a short title.
Basically, I want to improve my existing pixel draw bot. Main objective: It needs to be fast.
I am fairly content with its performance for now, but it can be better. What I am doing in a nutshell is very primitive; to sum it up:
- Get an image and process it to be black and white (by setting a specific ColorMatrix)
- Loop through every pixel in the image and decide to click the mouse, if it's black, and skip if not.
My main (performance) concerns right now that I am not sure how to solve:
- I am currently still clicking 500 times in a row for drawing a black line in the image for example, instead of clicking and dragging once from x1 to x2
- Use of System.Threading.Sleep(1): If I don't do that, the target application won't process and doesn't draw, except for a few pixels (testing in MS Paint). Shouldn't I be working with wait async etc.? I never quite learned how to successfully replace Sleep();
- I hear img.GetPixel(x, y) is a slow approach and should be replaced with Bitmap.LockBits()? Agreements, concerns?
- I'm importing RegisterHotKey via user32.dll and overriding WndProc to listen for a global system hotkey (to start the drawing process), could this also be better solved with native C# elements? I notice sometimes on building the solution, or while debugging that it takes up to a few seconds until my program runs initially.
Finally, the most important thing -- the codeZ:
Drawing:
void Draw()
{
Bitmap imgClipBoard = MakeBlackAndWhite((Bitmap)Clipboard.GetImage());
Point startPos = Cursor.Position;
ClickMouse(MouseButtons.Left, startPos.X, startPos.Y, true);
ClickMouse(MouseButtons.Left, startPos.X, startPos.Y, false);
for (int y = 0; y < img.Height; y++)
{
for (int x = 0; x < img.Width; x++)
{
Color c = img.GetPixel(x, y);
if (c.B == 0)
{
int drawX = startPos.X + x;
int drawY = startPos.Y + y;
MoveMouse(drawX, drawY);
ClickMouse(MouseButtons.Left, drawX, drawY, true);
ClickMouse(MouseButtons.Left, drawX, drawY, false);
Thread.Sleep(1);
}
if (Keyboard.IsKeyDown(Keys.Escape))
return;
}
}
}
What I am also wondering: Are there any more intelligent ways to redraw an image programmatically, than pixel by pixel? For instance, identifying paths (lines) in the image to trace with one stroke instead of looping from top to bottom and clicking pixels, or is this something very advanced already?
Edit #1:
Here is a demonstration in GIF format regarding my first performance concern: Click and drag is infinitely faster than clicking pixel by pixel (this test still using GetPixel()).
Edit #2
-- Snip --
Let's forget about LockBits() for now.
My main concern is: How can I scan each pixel "mass", either by line or ideally the entire picture, so I can tell my program: Okay, here is this black and white image: I don't want you to click hundreds of times in a row for each black pixel, but instead I want this logic: scan -> first black pixel -> hold down mouse -> keep going till you hit a white pixel -> release. Rinse and repeat.
Please check Edit 1 to see why I believe this to make sense: Much faster image printing!
This following test is too slow for my purposes! SEE ANIMATED GIF
Edit #3:
I expect a nice rectangle but get zigzags
private void DrawRect()
{
int x = Cursor.Position.X;
int y = Cursor.Position.Y;
for (int counter = 0; counter < 100; counter++)
{
MoveMouse(x, y + counter);
ClickMouse(MouseButtons.Left, x, y + counter, true);
Thread.Sleep(1);
MoveMouse(x + 100, y + counter);
Thread.Sleep(1);
}
Thread.Sleep(15);
ClickMouse(MouseButtons.Left, 0, 0, false);
}
I know it's because of the short sleep intervals, and if I increase them I get exactly what I want: I suspect that I will have to use wait async if I want this to run as fast as possible, without having to try out several numbers for the sleep delay.