using System; using System.Collections.Generic; using System.Linq; using System.Drawing; using System.Drawing.Imaging; using System.IO; using System.Runtime.InteropServices; using System.Windows.Forms; namespace BotIt { [ClassInterface(ClassInterfaceType.AutoDual)] public class DetectImageAndClick { [Flags] private enum MouseEvents { LeftDown = 0x00000002, LeftUp = 0x00000004, MiddleDown = 0x00000020, MiddleUp = 0x00000040, Move = 0x00000001, Absolute = 0x00008000, RightDown = 0x00000008, RightUp = 0x00000010 } public const int KEYEVENTF_EXTENDEDKEY = 0x0001; //key down public const int KEYEVENTF_KEYUP = 0x0002; //key up public const int VK_SNAPSHOT = 0x2C; //VirtualKey code for print key [DllImport("user32.dll")] private static extern void keybd_event(byte vVK, byte bScan, int dwFlags, int dwExtraInfo); [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool GetCursorPos(out MousePoint lpMousePoint); [DllImport("user32.dll")] private static extern void mouse_event(int dwFlags, int dx, int dy, int dwData, int dwExtraInfo); private MousePoint GetCursorPosition() { var gotPoint = GetCursorPos(out MousePoint currentMousePoint); if (!gotPoint) { currentMousePoint = new MousePoint(0, 0); } return currentMousePoint; } private void MouseEvent(MouseEvents value) { MousePoint position = GetCursorPosition(); mouse_event ((int)value, position.X, position.Y, 0, 0) ; } [StructLayout(LayoutKind.Sequential)] public struct MousePoint { public int X; public int Y; public MousePoint(int x, int y) { X = x; Y = y; } } public Bitmap CaptureScreenGfx() { var image = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, PixelFormat.Format32bppArgb); var gfx = Graphics.FromImage(image); gfx.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y, 0, 0, Screen.PrimaryScreen.Bounds.Size, CopyPixelOperation.SourceCopy); image.Save("Output.PNG", ImageFormat.Png); return image; } private void PrintScreen() { keybd_event(VK_SNAPSHOT, 0, KEYEVENTF_EXTENDEDKEY, 0); keybd_event(VK_SNAPSHOT, 0, KEYEVENTF_KEYUP, 0); } public Bitmap CaptureScreenPrtSc() { PrintScreen(); if (Clipboard.ContainsImage()) { using (Image img = Clipboard.GetImage()) { img.Save("ClipBoard.PNG", ImageFormat.Png); return new Bitmap(img); } } return default; } public bool FindAndClick(string FilePathToPNG, bool Click = true) { if (null == FilePathToPNG) { return false; } if (!File.Exists(FilePathToPNG)) { return false; } using (var needle = new Bitmap(FilePathToPNG)) { using (var haystack = CaptureScreenPrtSc()) { var haystackArray = GetPixelArray(haystack); var needleArray = GetPixelArray(needle); foreach (var firstLineMatchPoint in FindMatch(haystackArray.Take(haystack.Height - needle.Height), needleArray[0])) { if (IsNeedlePresentAtLocation(haystackArray, needleArray, firstLineMatchPoint, 1)) { if (Click) { var MatchPoint = firstLineMatchPoint; MatchPoint.X -= needle.Width / 4; MatchPoint.Y -= needle.Height / 4; Cursor.Position = MatchPoint; MouseEvent(MouseEvents.LeftDown); MouseEvent(MouseEvents.LeftUp); } return true; } } return false; } } } private int[][] GetPixelArray(Bitmap bitmap) { var result = new int[bitmap.Height][]; var bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); for (int y = 0; y < bitmap.Height - 1; y++) { result[y] = new int[bitmap.Width]; Marshal.Copy(bitmapData.Scan0 + y * bitmapData.Stride, result[y], 0, result[y].Length); } bitmap.UnlockBits(bitmapData); return result; } private IEnumerable FindMatch(IEnumerable haystackLines, int[] needleLine) { var y = 0; foreach (int[] haystackLine in haystackLines) { for (int x = 0, n = haystackLine.Length - needleLine.Length; x < n; ++x) { if (ContainSameElements(haystackLine, x, needleLine, 0, needleLine.Length)) { yield return new Point(x, y); } } y += 1; } } private bool ContainSameElements(int[] first, int firstStart, int[] second, int secondStart, int length) { for (int i = 0; i < length; ++i) { if (first[i + firstStart] != second[i + secondStart]) { return false; } } return true; } private bool IsNeedlePresentAtLocation(int[][] haystack, int[][] needle, Point point, int alreadyVerified) { //we already know that "alreadyVerified" lines already match, so skip them for (int y = alreadyVerified; y < needle.Length - 1; y++) { if (!ContainSameElements(haystack[y + point.Y], point.X, needle[y], 0, needle[y].Length)) { return false; } } return true; } } }