1 // 仿写_4_找茬辅助.cpp : 定义应用程序的入口点。 2 // 3 4 #include "stdafx.h" 5 #include "仿写_4_找茬辅助.h" 6 #include <windowsx.h> 7 #include <vector> 8 using std::vector; 9 10 #define MAX_LOADSTRING 100 11 12 // 全局变量: 13 HINSTANCE hInst; // 当前实例 14 TCHAR szTitle[MAX_LOADSTRING]; // 标题栏文本 15 TCHAR szWindowClass[MAX_LOADSTRING]; // 主窗口类名 16 17 // 此代码模块中包含的函数的前向声明: 18 ATOM MyRegisterClass(HINSTANCE hInstance); 19 BOOL InitInstance(HINSTANCE, int); 20 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); 21 INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM); 22 23 int APIENTRY _tWinMain(_In_ HINSTANCE hInstance, 24 _In_opt_ HINSTANCE hPrevInstance, 25 _In_ LPTSTR lpCmdLine, 26 _In_ int nCmdShow) 27 { 28 UNREFERENCED_PARAMETER(hPrevInstance); 29 UNREFERENCED_PARAMETER(lpCmdLine); 30 31 // TODO: 在此放置代码。 32 MSG msg; 33 HACCEL hAccelTable; 34 35 // 初始化全局字符串 36 LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); 37 LoadString(hInstance, IDC__4_, szWindowClass, MAX_LOADSTRING); 38 MyRegisterClass(hInstance); 39 40 // 执行应用程序初始化: 41 if (!InitInstance (hInstance, nCmdShow)) 42 { 43 return FALSE; 44 } 45 46 hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC__4_)); 47 48 // 主消息循环: 49 while (GetMessage(&msg, NULL, 0, 0)) 50 { 51 if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) 52 { 53 TranslateMessage(&msg); 54 DispatchMessage(&msg); 55 } 56 } 57 58 return (int) msg.wParam; 59 } 60 61 62 63 // 64 // 函数: MyRegisterClass() 65 // 66 // 目的: 注册窗口类。 67 // 68 ATOM MyRegisterClass(HINSTANCE hInstance) 69 { 70 WNDCLASSEX wcex; 71 72 wcex.cbSize = sizeof(WNDCLASSEX); 73 74 wcex.style = CS_HREDRAW | CS_VREDRAW; 75 wcex.lpfnWndProc = WndProc; 76 wcex.cbClsExtra = 0; 77 wcex.cbWndExtra = 0; 78 wcex.hInstance = hInstance; 79 wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI__4_)); 80 wcex.hCursor = LoadCursor(NULL, IDC_ARROW); 81 wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); 82 wcex.lpszMenuName = MAKEINTRESOURCE(IDC__4_); 83 wcex.lpszClassName = szWindowClass; 84 wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); 85 86 return RegisterClassEx(&wcex); 87 } 88 89 // 90 // 函数: InitInstance(HINSTANCE, int) 91 // 92 // 目的: 保存实例句柄并创建主窗口 93 // 94 // 注释: 95 // 96 // 在此函数中,我们在全局变量中保存实例句柄并 97 // 创建和显示主程序窗口。 98 // 99 BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) 100 { 101 HWND hWnd; 102 103 hInst = hInstance; // 将实例句柄存储在全局变量中 104 105 hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, 106 CW_USEDEFAULT, 0, 1600, 700, NULL, NULL, hInstance, NULL); 107 108 if (!hWnd) 109 { 110 return FALSE; 111 } 112 113 ShowWindow(hWnd, nCmdShow); 114 UpdateWindow(hWnd); 115 116 return TRUE; 117 } 118 119 static HBITMAP hBitmap1; 120 static HBITMAP hBitmap2; 121 static BOOL helpFlag = 0; 122 vector<COORD> vcPoints; 123 void ShowPicture(HWND hWnd){ 124 125 //加载图片 126 hBitmap1 = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_BITMAP1)); 127 hBitmap2 = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_BITMAP2)); 128 129 //获取图片信息 130 BITMAP bitmap; 131 GetObject(hBitmap1, sizeof(BITMAP), &bitmap); 132 133 //获取DC 134 HDC hdc = GetDC(hWnd); 135 HDC hdcMem = CreateCompatibleDC(hdc); 136 137 //选入图片1 138 SelectObject(hdcMem, hBitmap1); 139 140 //复制到DC,完成图片1显示 141 BitBlt(hdc, 0, 0, bitmap.bmWidth, bitmap.bmHeight, hdcMem, 0, 0, SRCCOPY); 142 143 //选入图片2 144 SelectObject(hdcMem, hBitmap2); 145 146 //复制到DC,完成图片2显示 147 BitBlt(hdc, bitmap.bmWidth + 10, 0, bitmap.bmWidth, bitmap.bmHeight, hdcMem, 0, 0, SRCCOPY); 148 149 if (helpFlag) 150 { 151 //找茬 152 //设置图片 153 SelectObject(hdc , hBitmap1); 154 SelectObject(hdcMem, hBitmap2); 155 //设置采样系数 156 DWORD dwAmendValue = 40; //x,y轴 相差不超过40的点只算一个点 157 DWORD dwSampling = 3; //每三个像素点找一次,加快匹配速度 158 //清空容器 159 vcPoints.clear(); 160 161 COORD point = {-1,-1}; 162 //找出不一样的地方 163 for (int row = 0; row <= bitmap.bmHeight; row += dwSampling) 164 { 165 for (int col = 0; col <= bitmap.bmWidth; col += dwSampling) 166 { 167 COLORREF src = GetPixel(hdc , col, row);//图1 168 COLORREF dec = GetPixel(hdcMem, col, row);//图2 169 if (src != dec) 170 { 171 //精确找到不同的像素点,仅作测试用 172 //SetPixel(hdc, col, row, 255); 173 174 //第一个不同点 175 if (point.X == -1) 176 { 177 point.X = col; 178 point.Y = row; 179 continue; 180 } 181 //两点比较近的话,看成是一个不同的点 182 if ((abs(col - point.X) + abs(row - point.Y)) < dwAmendValue) 183 { 184 point.X = (col + point.X) / 2; 185 point.Y = (row + point.Y) / 2; 186 continue; 187 } 188 //找到了一个新的点,把上一个点加入容器,并重新开始 189 if ((abs(col - point.X) + abs(row - point.Y)) > dwAmendValue) 190 { 191 //把上一个点加入容器 192 vcPoints.push_back(point); 193 //然后开始记录新的不同点 194 point.X = col; 195 point.Y = row; 196 continue; 197 } 198 } 199 //结束的时候最后一个不同点也加到向量内 200 if (((abs(col - bitmap.bmWidth) + abs(row - bitmap.bmHeight)))<dwSampling*dwSampling) 201 { 202 vcPoints.push_back(point); 203 } 204 } 205 } 206 } 207 208 ReleaseDC(hWnd,hdc); 209 DeleteDC(hdcMem); 210 DeleteObject(hBitmap1); 211 DeleteObject(hBitmap2); 212 } 213 214 void ShowDifferent(HWND hWnd){ 215 216 if (vcPoints.size()<0) 217 { 218 return; 219 } 220 //获取DC 221 HDC hdc = GetDC(hWnd); 222 223 //显示不一样的地方 224 HPEN hPen = CreatePen(PS_SOLID, 4, RGB(246, 106, 44)); 225 HBRUSH hBrush = GetStockBrush(NULL_BRUSH); 226 SelectObject(hdc, hPen); 227 SelectObject(hdc, hBrush); 228 for (size_t i = 0; i < vcPoints.size(); i++) 229 { 230 Ellipse(hdc, vcPoints[i].X - 30, vcPoints[i].Y - 30, vcPoints[i].X + 30, vcPoints[i].Y + 30); 231 } 232 ReleaseDC(hWnd, hdc); 233 } 234 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 235 { 236 int wmId, wmEvent; 237 PAINTSTRUCT ps; 238 HDC hdc; 239 switch (message) 240 { 241 case WM_COMMAND: 242 wmId = LOWORD(wParam); 243 wmEvent = HIWORD(wParam); 244 // 分析菜单选择: 245 switch (wmId) 246 { 247 case IDM_HELP: 248 //既找茬,又显示图片,还显示结果 249 helpFlag = TRUE; 250 ShowPicture(hWnd); 251 ShowDifferent(hWnd); 252 break; 253 case IDM_START: 254 //不找茬,只显示图片,不显示结果 255 helpFlag = FALSE; 256 ShowPicture(hWnd); 257 break; 258 default: 259 return DefWindowProc(hWnd, message, wParam, lParam); 260 } 261 break; 262 case WM_PAINT: 263 { 264 hdc = BeginPaint(hWnd, &ps); 265 // TODO: 在此添加任意绘图代码... 266 //响应paint消息时,不找茬,只显示图片,以及结果(无结果就不显示结果)。 267 helpFlag = FALSE; 268 ShowPicture(hWnd); 269 ShowDifferent(hWnd); 270 271 EndPaint(hWnd, &ps); 272 } break; 273 case WM_DESTROY: 274 PostQuitMessage(0); 275 break; 276 default: 277 return DefWindowProc(hWnd, message, wParam, lParam); 278 } 279 return 0; 280 }