1 // Copyright (C) 2015 Kazuhiro Fujieda <fujieda@users.osdn.me>
3 // This program is part of BurageSnap.
5 // BurageSnap is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, see <http://www.gnu.org/licenses/>.
20 using System.Drawing.Imaging;
21 using System.Runtime.InteropServices;
28 private const int WidthMin = 600, HeightMin = 400;
30 private Rectangle _rectangle;
32 public Bitmap CaptureGameScreen()
34 if (_hWnd == IntPtr.Zero || _rectangle.IsEmpty)
36 using (var bmp = CaptureWindow(_hWnd))
37 return bmp.Clone(_rectangle, bmp.PixelFormat);
40 public Bitmap CaptureGameScreen(string title)
42 _hWnd = FindWindow(title);
43 if (_hWnd == IntPtr.Zero)
45 using (var bmp = CaptureWindow(_hWnd))
47 _rectangle = DetectGameScreen(bmp);
48 if (_rectangle.IsEmpty)
50 return bmp.Clone(_rectangle, bmp.PixelFormat);
54 private IntPtr FindWindow(string title)
56 var found = IntPtr.Zero;
57 EnumWindows((hWnd, lParam) =>
59 var rect = new Rect();
60 if (GetWindowRect(hWnd, ref rect) == 0 || rect.Right - rect.Left < WidthMin ||
61 rect.Bottom - rect.Top < HeightMin)
63 if (!GetWindowText(hWnd).Contains(title))
71 public static string GetWindowText(IntPtr hWnd)
73 var size = GetWindowTextLength(hWnd);
76 var sb = new StringBuilder(size + 1);
77 GetWindowText(hWnd, sb, sb.Capacity);
81 [DllImport("user32.dll", CharSet = CharSet.Unicode)]
82 private static extern int GetWindowText(IntPtr hWnd, StringBuilder strText, int maxCount);
84 [DllImport("user32.dll", CharSet = CharSet.Unicode)]
85 private static extern int GetWindowTextLength(IntPtr hWnd);
87 public delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
89 [DllImport("user32.dll", CharSet = CharSet.Unicode)]
90 private static extern bool EnumWindows(EnumWindowsProc enumProc, IntPtr lParam);
92 public static Bitmap CaptureWindow(IntPtr hWnd)
94 var rect = new Rect();
95 GetWindowRect(hWnd, ref rect);
96 var width = rect.Right - rect.Left;
97 var height = rect.Bottom - rect.Top;
98 var bmp = new Bitmap(width, height, PixelFormat.Format24bppRgb);
99 using (var g = Graphics.FromImage(bmp))
100 g.CopyFromScreen(rect.Left, rect.Top, 0, 0, new Size(width, height), CopyPixelOperation.SourceCopy);
104 [DllImport("user32.dll")]
105 private static extern int GetWindowRect(IntPtr hWnd, ref Rect lpRec);
107 [StructLayout(LayoutKind.Sequential)]
116 private Rectangle DetectGameScreen(Bitmap bmp)
118 var height = bmp.Height;
119 var width = bmp.Width;
120 var map = new byte[height, width];
121 var data = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly,
122 PixelFormat.Format24bppRgb);
125 var ptr = (byte*)data.Scan0;
126 for (var y = 0; y < data.Height; y++)
128 for (var x = 0; x < data.Width; x++)
130 var p = ptr + y * data.Stride + x * 3;
131 map[y, x] = (byte)(p[0] == 255 && p[1] == 255 && p[2] == 255 ? 1 : 0);
135 bmp.UnlockBits(data);
136 for (var y = 0; y < height - 1; y++)
138 var rect = Rectangle.Empty;
139 if (!CheckEdge(map, 0, width, y, y, Edge.HorizontalTop))
142 for (var x = 0; x < width - 1; x++)
144 if (!CheckEdge(map, x, x, rect.Y, height, Edge.VerticalLeft))
147 rect = FindBottomAndRight(map, rect);
148 if (rect == Rectangle.Empty)
150 if (!CheckEdge(map, rect.X, rect.Right, y, y, Edge.HorizontalTop))
152 if (CheckEdge(map, x, x, rect.Y, rect.Bottom, Edge.VerticalLeft))
156 return Rectangle.Empty;
159 private Rectangle FindBottomAndRight(byte[,] map, Rectangle rect)
161 var height = map.GetLength(0);
162 var width = map.GetLength(1);
163 for (var y = rect.Y; y < height - 1; y++)
165 if (!CheckEdge(map, rect.X, width, y, y, Edge.HorizontalBottom))
167 rect.Height = y - rect.Y + 1;
169 for (var x = rect.X; x < width - 1; x++)
171 if (!CheckEdge(map, x, x, rect.Y, rect.Bottom, Edge.VerticalRight))
173 rect.Width = x - rect.X + 1;
177 return Rectangle.Empty;
178 if (!CheckEdge(map, rect.X, rect.Right, y, y, Edge.HorizontalBottom))
180 return rect.Width >= WidthMin && rect.Height >= HeightMin ? rect : Rectangle.Empty;
182 return Rectangle.Empty;
185 private bool CheckEdge(byte[,] map, int left, int right, int top, int bottom, Edge edge)
190 case Edge.HorizontalTop:
191 for (; left < right; left++)
193 if (!(map[top, left] == 1 && map[top + 1, left] == 0))
195 if (++n < WidthMin / 3)
200 case Edge.VerticalLeft:
201 for (; top < bottom; top++)
203 if (!(map[top, left] == 1 && map[top, left + 1] == 0))
205 if (++n < HeightMin / 3)
210 case Edge.HorizontalBottom:
211 for (; left < right; left++)
213 if (!(map[bottom, left] == 0 && map[bottom + 1, left] == 1))
215 if (++n < WidthMin / 3)
220 case Edge.VerticalRight:
221 for (; top < bottom; top++)
223 if (!(map[top, right] == 0 && map[top, right + 1] == 1))
225 if (++n < HeightMin / 3)