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 winDC = GetWindowDC(hWnd);
95 var rect = new Rect();
96 GetWindowRect(hWnd, ref rect);
97 var bmp = new Bitmap(rect.Right - rect.Left, rect.Bottom - rect.Top, PixelFormat.Format32bppArgb);
98 var g = Graphics.FromImage(bmp);
100 BitBlt(hDC, 0, 0, bmp.Width, bmp.Height, winDC, 0, 0, SRCCOPY);
103 ReleaseDC(hWnd, winDC);
107 [DllImport("user32.dll")]
108 private static extern IntPtr GetWindowDC(IntPtr hWnd);
110 [DllImport("user32.dll")]
111 private static extern IntPtr ReleaseDC(IntPtr hWnd, IntPtr hDC);
113 // ReSharper disable once InconsistentNaming
114 private const int SRCCOPY = 0xcc0020;
116 [DllImport("gdi32.dll")]
117 private static extern int BitBlt(IntPtr hDestDC, int x, int y, int nWidth, int nHeight,
118 IntPtr hSrcDC, int xSrc, int ySrc, int dwRop);
120 [DllImport("user32.dll")]
121 private static extern int GetWindowRect(IntPtr hWnd, ref Rect lpRec);
123 [StructLayout(LayoutKind.Sequential)]
132 private Rectangle DetectGameScreen(Bitmap bmp)
134 var height = bmp.Height;
135 var width = bmp.Width;
136 var map = new byte[height, width];
137 var data = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly,
138 PixelFormat.Format32bppArgb);
141 var ptr = (byte*)data.Scan0;
142 for (var y = 0; y < data.Height; y++)
144 for (var x = 0; x < data.Width; x++)
146 var p = ptr + y * data.Stride + x * 4;
147 map[y, x] = (byte)(p[0] == 255 && p[1] == 255 && p[2] == 255 ? 1 : 0);
151 bmp.UnlockBits(data);
152 const int corner = 40;
153 for (var y = 0; y < height; y++)
156 for (var x = 0; x < width; x++)
158 if ((map[y, x] & 1) == 1)
161 map[y, x - corner + 1] |= 2;
169 for (var x = 0; x < width; x++)
172 for (var y = 0; y < height; y++)
174 if ((map[y, x] & 1) == 1)
177 map[y - corner + 1, x] |= 4;
185 var rect = new Rectangle();
187 for (var y = 0; y < height - corner; y++)
189 for (var x = 0; x < height - corner; x++)
191 if (!(map[y, x] == 7 && map[y + 1, x + 1] == 0))
195 for (var x1 = rect.X; x1 < width; x1++)
197 if ((map[rect.Y, x1] & 4) == 0)
199 rect.Width = x1 - rect.X;
202 if (rect.Width < WidthMin)
204 for (var y1 = rect.Y; y1 < height; y1++)
206 if ((map[y1, rect.X] & 2) == 0)
208 rect.Height = y1 - rect.Y;
211 if (rect.Height < HeightMin)
219 return found ? rect : Rectangle.Empty;