zoukankan      html  css  js  c++  java
  • 【2012年终总结】之三 opencv + ds采集摄像头视频 简易截图工具

    关于截图工具,QQ的截图可以自动选择窗口,之前以为是颜色相近的选取,后来意识到不对,应该是窗口,用spy++找到的窗口和QQ截取到的窗口也是一样的,

    但是有个问题,那就是怎么选择这些窗口?   我的想法是枚举所有窗口,记录这些窗口的位置和大小,然后当鼠标经过的时候用DC来画框,但是这样有个问题就是枚举到的窗口有几百个,太多了,当鼠标经过的从几百个大小的数组或vector里查找当前鼠标的位置在哪个窗口范围内实在是太拙计了,这种方法实在不太靠谱。

    关于QQ的截图: 拷贝当前屏幕图像然后全屏打开一个(透明?)窗口,把拷贝到的图像贴在那个全屏窗口上,然后鼠标经过窗口时画框。。。

    由于没能实现后面那几步,所以只是做了一个简易的截图工具,其原理差不多,那就是:当截图时拷贝当前屏幕图像然后打开一个对话框,把这个对话框放大到屏幕大小,也就是全屏,然后把屏幕图像贴到对话框上,然后鼠标可以拖动选择区域,在拖动的时候有一个【确定】button在鼠标附近,点击这个button就可以保存选择的区域至bmp文件。 当然需要考虑背景重绘的情况!

    把截图工具封装成了一个类,该类继承自CWnd类,对应的对话框为IDD_DLG_CAPTURE ,在Jietu.h第15行, 对话框上有一个button,在这里button的名字没改,就是button1,如果改了这个名字,对应的代码里也需要修改。

    Jietu.h

     1 #pragma once
     2 
     3 
     4 // CJietu 对话框
     5 
     6 class CJietu : public CDialog
     7 {
     8     DECLARE_DYNAMIC(CJietu)
     9 
    10 public:
    11     CJietu(CWnd* pParent = NULL);   // 标准构造函数
    12     virtual ~CJietu();
    13 
    14 // 对话框数据
    15     enum { IDD = IDD_DLG_CAPTURE };
    16 
    17 protected:
    18     virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持
    19 
    20     DECLARE_MESSAGE_MAP()
    21 public:
    22     afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
    23     afx_msg void OnPaint();
    24     afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
    25     afx_msg void OnMouseMove(UINT nFlags, CPoint point);
    26     afx_msg BOOL OnEraseBkgnd(CDC* pDC);
    27     afx_msg void OnShowWindow(BOOL bShow, UINT nStatus);
    28     virtual BOOL OnInitDialog();
    29 
    30     void WriteBMPFile(HBITMAP hBitMap, LPTSTR filename, HDC hDC, int cx, int cy);
    31 
    32 protected:
    33     int m_nCx;
    34     int m_nCy;
    35 
    36     CPoint m_pointStart;  //记录起点;
    37     CPoint m_pointEnd;    //记录终点;
    38     bool m_bIsBegin;
    39 
    40     CDC m_dcGlobal;
    41     HDC m_hDCGlobal;
    42     HBITMAP m_hBitmapGlobal;
    43     CBitmap m_bitmapGlobal;
    44     CWnd *m_pWndButtonOK;  //确定 按钮; 
    45 
    46 public:
    47     afx_msg void OnBnClickedButton1();
    48 };

    Jietu.cpp

      1 // Jietu.cpp : 实现文件
      2 //
      3 
      4 #include "stdafx.h"
      5 #include "CameraMonitor.h"
      6 #include "Jietu.h"
      7 
      8 
      9 // CJietu 对话框
     10 
     11 IMPLEMENT_DYNAMIC(CJietu, CDialog)
     12 
     13 CJietu::CJietu(CWnd* pParent /*=NULL*/)
     14     : CDialog(CJietu::IDD, pParent)
     15 { 
     16     m_nCx = GetSystemMetrics(SM_CXSCREEN);
     17     m_nCy = GetSystemMetrics(SM_CYSCREEN);
     18     m_bIsBegin = false; 
     19 }
     20 
     21 CJietu::~CJietu()
     22 {
     23     if (m_hDCGlobal)
     24     {
     25         DeleteDC(m_hDCGlobal);
     26     }
     27     if (m_hBitmapGlobal)
     28     {
     29         DeleteObject(m_hBitmapGlobal);
     30     }
     31 
     32     if (m_dcGlobal)
     33     {
     34         m_dcGlobal.DeleteDC();
     35     }
     36 }
     37 
     38 void CJietu::DoDataExchange(CDataExchange* pDX)
     39 {
     40     CDialog::DoDataExchange(pDX);
     41 }
     42 
     43 
     44 BEGIN_MESSAGE_MAP(CJietu, CDialog)
     45     ON_WM_LBUTTONDOWN()
     46     ON_WM_PAINT()
     47     ON_WM_LBUTTONUP()
     48     ON_WM_MOUSEMOVE()
     49     ON_WM_ERASEBKGND()
     50     ON_WM_SHOWWINDOW()
     51     ON_BN_CLICKED(IDC_BUTTON1, &CJietu::OnBnClickedButton1)
     52 END_MESSAGE_MAP()
     53 
     54 
     55 // CJietu 消息处理程序
     56 
     57 void CJietu::OnLButtonDown(UINT nFlags, CPoint point)
     58 {
     59     // TODO: 在此添加消息处理程序代码和/或调用默认值;
     60 
     61     ClientToScreen(&point);
     62     m_pointStart = point;  //记录起点;
     63     m_bIsBegin = true; 
     64 
     65     SetCursor(AfxGetApp()->LoadStandardCursor(IDC_CROSS));
     66 
     67     CDialog::OnLButtonDown(nFlags, point);
     68 }
     69 
     70 void CJietu::OnLButtonUp(UINT nFlags, CPoint point)
     71 {
     72     // TODO: 在此添加消息处理程序代码和/或调用默认值;
     73     m_bIsBegin = false;
     74     ClientToScreen(&point);
     75 
     76     //鼠标左键抬起,鼠标指针恢复正常;
     77     SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW));
     78 
     79 
     80 
     81     CDialog::OnLButtonUp(nFlags, point);
     82 }
     83 
     84 void CJietu::OnMouseMove(UINT nFlags, CPoint point)
     85 {
     86     // TODO: 在此添加消息处理程序代码和/或调用默认值; 
     87 
     88 
     89     if (true == m_bIsBegin)
     90     {
     91         int b = false;
     92         if (false == b && m_pWndButtonOK != NULL)
     93         { 
     94             m_pWndButtonOK->ShowWindow(SW_SHOW);     //确定 按钮显示;
     95             b = true;
     96         }
     97 
     98         Invalidate(TRUE);  //先把之前线条的清空;  
     99         UpdateWindow(); 
    100 
    101         ClientToScreen(&point);   
    102         m_pointEnd = point;          //记录终点;
    103 
    104         CPen pen(PS_SOLID, 6, RGB(255, 0, 0));
    105         CPen *oldPen;
    106         CDC *pDC;
    107         CWnd *pWnd;
    108         CRect rect;
    109 
    110         int cx = m_nCx;
    111         int cy = m_nCy;  
    112 
    113         pWnd = FromHandle(m_hWnd);
    114         pDC = pWnd->GetDC();
    115 
    116         int x1 = m_pointStart.x;
    117         int y1 = m_pointStart.y;
    118         int x2 = point.x;
    119         int y2 = y1;
    120         int x3 = point.x;
    121         int y3 = point.y;
    122         int x4 = x1;
    123         int y4 = y3;
    124 
    125         oldPen = pDC->SelectObject(&pen);
    126 
    127         pDC->MoveTo(x1, y1);
    128         pDC->LineTo(x2, y2);
    129 
    130         pDC->MoveTo(x2, y2);
    131         pDC->LineTo(x3, y3);
    132 
    133         pDC->MoveTo(x3, y3);
    134         pDC->LineTo(x4, y4);
    135 
    136         pDC->MoveTo(x4, y4);
    137         pDC->LineTo(x1, y1);
    138 
    139         int width = abs(x1 - x3);
    140         int height = abs(y1 - y3);
    141         char wArr[5] = {0};
    142         char hArr[5] = {0};
    143         _itoa_s(width, wArr, 10);
    144         _itoa_s(height, hArr, 10);
    145 
    146         CString str("尺寸:");
    147         str += wArr;
    148         str += "x";
    149         str += hArr;
    150         pDC->SetBkMode(TRANSPARENT);
    151 
    152         CFont font;
    153         CFont *oldFont;
    154         font.CreatePointFont(150, _T("宋体"));
    155         oldFont = pDC->SelectObject(&font);
    156         pDC->SetTextColor(RGB(0, 0, 255));
    157 
    158         int xPos = 0;
    159         int yPos = 0;
    160         int xStep = 100;
    161         int yStep = 50;
    162 
    163         //选区到了边界的情况;
    164         if (cx - x3 <= xStep || cy - y3 <= yStep || (cx - x3) >= (cx - xStep)  || (cy - y3) >= (cy - yStep))
    165         {
    166             if (x3 >= x1 && y3 <= y1)
    167             {
    168                 pDC->TextOut(x3 - xStep - 50, y3 + yStep - 10, str);
    169                 m_pWndButtonOK->SetWindowPos(NULL, x3 - xStep - 50, y3 + yStep + 20, 0, 0, SWP_NOSIZE);
    170             }
    171             else if (x3 >= x1 && y3 >= y1)
    172             {
    173                 pDC->TextOut(x3 - xStep - 50, y3 - yStep, str);
    174                 m_pWndButtonOK->SetWindowPos(NULL, x3 - xStep - 50, y3 - yStep - 60, 0, 0, SWP_NOSIZE);
    175             }
    176             else if (x3 <= x1 && y3 >= y1)
    177             {
    178                 pDC->TextOut(x3 + xStep - 20, y3 - yStep, str);
    179                 m_pWndButtonOK->SetWindowPos(NULL, x3 + xStep - 20, y3 - yStep - 60, 0, 0, SWP_NOSIZE);
    180             }
    181             else
    182             {
    183                 pDC->TextOut(x3 + xStep - 50, y3 + yStep - 10, str);
    184                 m_pWndButtonOK->SetWindowPos(NULL, x3 + xStep - 50, y3 + yStep + 20, 0, 0, SWP_NOSIZE);
    185             } 
    186 
    187         }
    188         else
    189         {
    190             pDC->TextOut(x3, y3, str);
    191             m_pWndButtonOK->SetWindowPos(NULL, x3, y3 + 30, 0, 0, SWP_NOSIZE);
    192         }
    193 
    194 
    195         pDC->SelectObject(oldFont);
    196         pDC->SelectObject(oldPen);
    197         pWnd->ReleaseDC(pDC);
    198         pen.DeleteObject();
    199         font.DeleteObject();
    200 
    201     }
    202 
    203     CDialog::OnMouseMove(nFlags, point);
    204 }
    205 
    206 void CJietu::OnPaint()
    207 {
    208     CPaintDC dc(this); // device context for painting
    209     // TODO: 在此处添加消息处理程序代码
    210     // 不为绘图消息调用 CDialog::OnPaint()  
    211     
    212     HWND hWnd = m_hWnd;
    213     CWnd *pWnd = FromHandle(hWnd); 
    214     CDC *pDC = pWnd->GetDC();
    215     HDC hDC = pDC->GetSafeHdc();
    216 
    217     StretchBlt(hDC, 0, 0, m_nCx, m_nCy, m_hDCGlobal, 0, 0, m_nCx, m_nCy, SRCCOPY); 
    218 
    219     pWnd->ReleaseDC(pDC); 
    220      
    221 }
    222 
    223 
    224 
    225 
    226 
    227 BOOL CJietu::OnEraseBkgnd(CDC* pDC)
    228 {
    229     // TODO: 在此添加消息处理程序代码和/或调用默认值;
    230  
    231     HWND hWnd = m_hWnd;
    232     CWnd *pWnd = FromHandle(hWnd); 
    233     HDC hDC = pDC->GetSafeHdc();
    234  
    235     StretchBlt(hDC, 0, 0, m_nCx, m_nCy, m_hDCGlobal, 0, 0, m_nCx, m_nCy, SRCCOPY);  
    236 
    237     return TRUE;
    238 //    return CDialog::OnEraseBkgnd(pDC);
    239 }
    240 
    241 void CJietu::OnShowWindow(BOOL bShow, UINT nStatus)
    242 {  
    243     m_pWndButtonOK = (CWnd*)GetDlgItem(IDC_BUTTON1);   //确定 按钮指针;
    244 
    245 
    246     //////////////////////////////////////////////////////////////////////////
    247     CDialog::OnShowWindow(bShow, nStatus);
    248     SetWindowPos(&wndTop, 0, 0, m_nCx, m_nCy, 0);
    249     ////////////////////////////////////////////////////////////////////////// 
    250  
    251     CDC *pDC = GetDC();
    252     HDC hDC = pDC->GetSafeHdc();
    253 
    254     StretchBlt(hDC, 0, 0, m_nCx, m_nCy, m_hDCGlobal, 0, 0, m_nCx, m_nCy, SRCCOPY);
    255 
    256     ReleaseDC(pDC);
    257  
    258 
    259 }
    260 
    261 BOOL CJietu::OnInitDialog()
    262 {
    263     CDialog::OnInitDialog();
    264 
    265     // TODO:  在此添加额外的初始化;  
    266 
    267     //改变指针形状为十字星;
    268     SetCursor(AfxGetApp()->LoadStandardCursor(IDC_CROSS)); 
    269 
    270 
    271     CWnd *pDesktop = GetDesktopWindow();
    272     HWND hWndDesktop = pDesktop->m_hWnd; 
    273     CDC *pDCDesktop = pDesktop->GetDC();
    274     HDC hDCDesktop = pDCDesktop->GetSafeHdc(); 
    275 
    276     HWND hWnd = m_hWnd;
    277     CWnd *pWnd = FromHandle(hWnd);
    278     CDC *pDC = pWnd->GetDC();
    279     HDC hDC = pDC->GetSafeHdc();
    280 
    281     HDC hDCMem = CreateCompatibleDC(hDCDesktop);                                      //兼容DC;
    282     HBITMAP hBitmap = CreateCompatibleBitmap(hDCDesktop, m_nCx,m_nCy);                //桌面DC的图片;
    283  //   SelectObject(hDCMem, hBitmap);
    284     StretchBlt(hDCMem, 0, 0, m_nCx, m_nCy, hDCDesktop, 0, 0, m_nCx, m_nCy, SRCCOPY);  //拷贝进内存DC;
    285 
    286 
    287     m_dcGlobal.CreateCompatibleDC(pDCDesktop);                         //该DC用来写图片文件时使用;
    288     m_hDCGlobal = m_dcGlobal.GetSafeHdc();                             //该HDC用来写图片文件时使用;
    289 
    290     CBitmap bitmap;
    291     bitmap.CreateCompatibleBitmap(pDCDesktop, m_nCx, m_nCy);           //该图片用来贴图;
    292     m_bitmapGlobal.CreateCompatibleBitmap(pDCDesktop, m_nCx, m_nCy);   //该图片用来风写图片文件时使用;
    293 
    294     m_dcGlobal.SelectObject(&bitmap);                                  // 该DC用来写图片文件时使用;   
    295     m_dcGlobal.BitBlt(0, 0, m_nCx, m_nCy, pDCDesktop, 0, 0, SRCCOPY);  // 该DC用来写图片文件时使用;   
    296 
    297 
    298     pDesktop->ReleaseDC(pDCDesktop);
    299     pWnd->ReleaseDC(pDC);
    300     DeleteDC(hDCMem);
    301     DeleteObject(hBitmap); 
    302 
    303 
    304 
    305     return TRUE;  // return TRUE unless you set the focus to a control
    306     // 异常: OCX 属性页应返回 FALSE
    307 }
    308 
    309 

    //HDC存为BMP 310 void CJietu::WriteBMPFile(HBITMAP hBitMap, LPTSTR filename, HDC hDC, int cx, int cy) 311 { 312 BITMAP bmp; 313 PBITMAPINFO pbmi; 314 WORD cClrBits; 315 HANDLE hf; // file handle 316 BITMAPFILEHEADER hdr; // bitmap file-header 317 PBITMAPINFOHEADER pbih; // bitmap info-header 318 LPBYTE lpBits; // memory pointer 319 DWORD dwTotal; // total count of bytes 320 DWORD cb; // incremental count of bytes 321 BYTE *hp; // byte pointer 322 DWORD dwTmp; 323 // create the bitmapinfo header information 324 if (!GetObject( hBitMap, sizeof(BITMAP), (LPTSTR)&bmp)) 325 { 326 return; 327 } 328 // Convert the color format to a count of bits. 329 cClrBits = (WORD)(bmp.bmPlanes * bmp.bmBitsPixel); 330 if (cClrBits == 1) 331 cClrBits = 1; 332 else if (cClrBits <= 4) 333 cClrBits = 4; 334 else if (cClrBits <= 8) 335 cClrBits = 8; 336 else if (cClrBits <= 16) 337 cClrBits = 16; 338 else if (cClrBits <= 24) 339 cClrBits = 24; 340 else cClrBits = 32; 341 // Allocate memory for the BITMAPINFO structure. 342 if (cClrBits != 24) 343 pbmi = (PBITMAPINFO) LocalAlloc(LPTR, sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1 << cClrBits)); 344 else 345 pbmi = (PBITMAPINFO) LocalAlloc(LPTR, sizeof(BITMAPINFOHEADER)); 346 // Initialize the fields in the BITMAPINFO structure. 347 pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 348 pbmi->bmiHeader.biWidth = cx; //bmp.bmWidth; 349 pbmi->bmiHeader.biHeight = cy; //bmp.bmHeight; 350 pbmi->bmiHeader.biPlanes = bmp.bmPlanes; 351 pbmi->bmiHeader.biBitCount = bmp.bmBitsPixel; 352 if (cClrBits < 24) 353 pbmi->bmiHeader.biClrUsed = 1; // If the bitmap is not compressed, set the BI_RGB flag. 354 pbmi->bmiHeader.biCompression = BI_RGB; 355 // Compute the number of bytes in the array of color 356 // indices and store the result in biSizeImage. 357 pbmi->bmiHeader.biSizeImage = (pbmi->bmiHeader.biWidth + 7) /8 * pbmi->bmiHeader.biHeight * cClrBits; 358 // Set biClrImportant to 0, indicating that all of the 359 // device colors are important. 360 pbmi->bmiHeader.biClrImportant = 0; 361 // now open file and save the data 362 pbih = (PBITMAPINFOHEADER) pbmi; 363 lpBits = (LPBYTE) GlobalAlloc(GMEM_FIXED, pbih->biSizeImage); 364 if (!lpBits) 365 { 366 return; 367 } 368 // Retrieve the color table (RGBQUAD array) and the bits 369 if (!GetDIBits(hDC, HBITMAP(hBitMap), 0, (WORD) pbih->biHeight, lpBits, pbmi, DIB_RGB_COLORS)) 370 { 371 return; 372 } 373 // Create the .BMP file. 374 hf = CreateFile(filename, GENERIC_READ | GENERIC_WRITE, (DWORD) 0, 375 NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 376 (HANDLE) NULL); 377 if (hf == INVALID_HANDLE_VALUE) 378 { 379 return; 380 } 381 hdr.bfType = 0x4d42; // 0x42 = "B" 0x4d = "M" 382 // Compute the size of the entire file. 383 hdr.bfSize = (DWORD) (sizeof(BITMAPFILEHEADER) + pbih->biSize + pbih->biClrUsed 384 * sizeof(RGBQUAD) + pbih->biSizeImage); 385 hdr.bfReserved1 = 0; 386 hdr.bfReserved2 = 0; 387 // Compute the offset to the array of color indices. 388 hdr.bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER) + 389 pbih->biSize + pbih->biClrUsed * sizeof (RGBQUAD); 390 // Copy the BITMAPFILEHEADER into the .BMP file. 391 if (!WriteFile(hf, (LPVOID) &hdr, sizeof(BITMAPFILEHEADER), (LPDWORD) &dwTmp, NULL)) 392 { 393 return; 394 } 395 // Copy the BITMAPINFOHEADER and RGBQUAD array into the file. 396 if (!WriteFile(hf, (LPVOID) pbih, sizeof(BITMAPINFOHEADER) + pbih->biClrUsed * sizeof (RGBQUAD), (LPDWORD) &dwTmp, ( NULL))) 397 { 398 return; 399 } 400 // Copy the array of color indices into the .BMP file. 401 dwTotal = cb = pbih->biSizeImage; 402 hp = lpBits; 403 if (!WriteFile(hf, (LPSTR) hp, (int) cb, (LPDWORD) &dwTmp,NULL)) 404 { 405 return; 406 } 407 // Close the .BMP file. 408 if (!CloseHandle(hf)) 409 { 410 return; 411 } 412 // Free memory. 413 GlobalFree((HGLOBAL)lpBits); 414 }


    //保存按钮
    415 void CJietu::OnBnClickedButton1() 416 { 417 // TODO: 在此添加控件通知处理程序代码; 418 419 CDC dcSave; 420 dcSave.CreateCompatibleDC(&m_dcGlobal); 421 dcSave.SelectObject(&m_bitmapGlobal); 422 423 int x1 = m_pointStart.x; 424 int y1 = m_pointStart.y; 425 426 int x2 = m_pointEnd.x; 427 int y2 = m_pointEnd.y; 428 429 int width = abs(m_pointEnd.x - m_pointStart.x); 430 int height = abs(m_pointEnd.y - m_pointStart.y); 431 432 int xBegin = 0; 433 int yBegin = 0; 434 435 //考虑四种画框的不同情况,寻找矩形不同的左上角坐标; 436 if (x2 >= x1 && y2 <= y1) 437 { 438 xBegin = x1; 439 yBegin = y2; 440 } 441 else if (x2 >= x1 && y2 >= y1) 442 { 443 xBegin = x1; 444 yBegin = y1; 445 } 446 else if (x2 <= x1 && y2 >= y1) 447 { 448 xBegin = x2; 449 yBegin = y1; 450 } 451 else 452 { 453 xBegin = x2; 454 yBegin = y2; 455 } 456 457 //拷贝进dcSave必须从(0,0)开始存储,因为WriteBMPFile指定长宽写的时候就是从(0, 0)开始截取的长宽; 458 //由于m_hDCGlobal保存的是整个桌面的图片,所以要从指定的坐标开始拷贝; 459 StretchBlt(dcSave, 0, 0, width, height, m_hDCGlobal, xBegin, yBegin, width, height, SRCCOPY); 460 CTime time = CTime::GetCurrentTime(); 461 CString strTime; 462 strTime = time.Format("%Y-%m-%d %H%M%S"); 463 int len = strTime.GetLength(); 464 TCHAR *pFileName = new TCHAR[len + 1 + 4]; 465 lstrcpy(pFileName, strTime.GetBuffer(len)); 466 lstrcat(pFileName, _T(".bmp")); 467 468 WriteBMPFile((HBITMAP)m_bitmapGlobal.m_hObject, pFileName, dcSave, width, height); 469 delete [] pFileName; 470 strTime.ReleaseBuffer(len); 471 dcSave.DeleteDC(); 472 473 OnCancel(); 474 }

      

  • 相关阅读:
    【简报】一款使用静态图片生成动画的jQuery插件:JZoopraxiscope
    使用jQuery timelinr和animate.css创建超酷的CSS动画时间轴特效
    超酷信息图分享:你属于哪类geek?
    数据库操作优化
    android R.java aapt
    xml sax 解析 & 符号
    sql server2000 完全卸载
    cmd 命令总结
    手动打包 解释
    bat 执行 java jar包
  • 原文地址:https://www.cnblogs.com/cuish/p/2901432.html
Copyright © 2011-2022 走看看