zoukankan      html  css  js  c++  java
  • 31、Windows API GDI(3)

    一、绘制图形

        GDI所能绘制形状有很多种,可区分为标准形状和非标准形状。标准形状使用几个简单、确定的属性就可以确定的形状,比如矩形(左上角点位置和长度)、椭圆(使用外切矩形)、圆角矩形(一个矩形加圆角半径)、弓形、扇形。

        也有不标准的形状,所有不标准的形状都可以使用多边形(Polygon)来定义。

    定义多边形也需要使用一个点数组。将点数组中的点依其在数组中的顺序连接起来,就是一个多边形。

    wps_clip_image-2430

    在绘制时,图形内部使用DC的当前画刷对象进行填充,图形的边使用DC的当前画笔对象进行勾勒。

    1、相关API

    GetClientRect

    SetRect

    CopyRect

    可以将一个RECT在屏幕上显示出来,显出的方式是有内部填充、边沿勾勒,也可以对一个RECT进行反转操作。反转操作会将现有RECT现有的填充颜色取反。FillRectFrameRectInvertRect函数分别实现这3个功能。

    坐标原点是左上角。

    ScreenToClient函数和ClientToScreen函数是两个操作点坐标的API函数,其功能是将点从相对于屏幕的位置计算相对于窗口客户区的位置,以及从窗口客户区的位置计算相对于屏幕的位置。

    二、位图操作

    1、相关API函数及数据结构

    CreateDC

    CreateCompatibleDC

    GetDeviceCapS

    SelectObject

    BitBlt

    stretchBlt

    GetDIBits

    DeleteDC

    ReleaseDC

    GetWindowRect

    主要涉及以下结构和数据类型。

    HDC

    HBITMAP

    BITMAPINFO

    BITMAPFILEHEADER

    RECT

    2、截取屏幕的流程

    截取屏幕输出一般需要经过以下步骤。

    ◇使用字符串“DISPLAY”为参教,调用CreateDC,得到类型为“显示”的DC

    ◇调用CreateCompatibleDC创建一个内存DC

    ◇得到需要截取的屏幕区域,比如调用GetDeviceCaps获取屏幕的大小,GetWindowRect获取窗口区域等。

    ◇调用CreateCompatibleBitmap创建BITMAP对象。

    ◇调用SelectObject,将创建的BITMAP选择入内存DC,并将返回值使用另外一个BITMAP对象句柄来保存。SelectObj ect的返回值表示了DC中被替换的图形对象。

    ◇调用BitBlt函数将源DC(显示类型的DC)指定位块(bit-block)的颜色数据转移到目的DC(内存)中,.

    ◇将之前保存的旧的BITMAP对象再调用SelectObject选择回内存DC中,这样从显示DCBitBlt到内存DC中的位块颜色数据就被替换,SelectObject的返回值即是从屏幕DC中得到的位图对象(HBITMAP类型)。

    之后就可以使用这个HBITMAP句柄来进行位图的操作,比如显示在屏幕的特定区域上。

    3、将位图显示在屏幕上

        将位图文件显示在界面上的原理与截屏类似,也是将位图文件选择入DC,区别是显示位图文件时所选择入的DC是用于显示的窗口DC。如果在显示时需要拉伸,则需要使用StretchBlt函数在DC间转换。

        显示位图的流程:

    (1)创建内存DC,将BITMAP对象选择入内存DC;

    (2)获取用于显示位图的窗口client区域的DC;

    (3)从位图对象中获取位图属性,包括大小、长宽等;

    (4)计算在client获取中显示的位置:

    (5)根据需要调用StretchBltBitBlt函数,在内存DC和窗口Client区域DC间转移;

    (6)释放相关资源。

    StretchBlt函数的功能是在两个DC的指定区域中复制位图,将源DC中指定区域的位图复制到目的DC的指定区域上,并根据区域的大小和长宽比例关系拉伸或压缩位图。

    BitBlt函数的功能是将源DC上的颜色信息转移到目的DC的指定区域上,转移时仅限于DC的最大范围,超出范围的部分不转移,不进行拉伸和压缩。

    示例

    截屏
    **************************************/
    /* 头文件 */
    #include
    <windows.h>
    /* 常量定义 */
    #define PALVERSION 0x300
    #define CAP_SHOW_MODE_STRTCH 1
    #define CAP_SHOW_MODE_NOSTRTCH 0

    /* 全局变量 */
    HBITMAP ghBitmap
    = NULL;
    RECT rectShow;
    // 修改这里截取不同的窗口,如果为NULL,则截取屏幕
    LPSTR szCaptureWindowName = "Windows 任务管理器";

    /* 函数申明 */
    LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM);
    HBITMAP ScreenCapture(LPSTR filename ,WORD BitCount,LPRECT lpRect);
    VOID DoPaint(HWND hWnd, DWORD dwMode);

    /*************************************
    * DWORD WINAPI WinMain(HINSTANCE hinstance,
    HINSTANCE hPrevInstance,
    LPSTR lpCmdLine,
    int nCmdShow)
    * 功能 截屏,保存为文件,并显示在窗口上
    *
    *************************************
    */
    INT WINAPI WinMain(HINSTANCE hinstance,
    HINSTANCE hPrevInstance,
    LPSTR lpCmdLine,
    int nCmdShow)
    {
    WNDCLASSEX wcx;
    HWND hwnd;
    MSG msg;
    WORD wport
    = 80;
    BOOL fGotMessage;
    HWND hwndCap
    = NULL;

    // 截取全屏幕还是窗口
    if(szCaptureWindowName != NULL)
    {
    hwndCap
    = FindWindow(NULL,"Windows 任务管理器");
    // 获取窗口的RECT,可自行修改,获取屏幕中的任意区域
    if(!GetWindowRect(hwndCap,&rectShow))
    {
    MessageBox(NULL,
    "Can not find window to capture", "erroe",MB_OK);
    return 0;
    }
    }
    // 注册窗口类,并创建窗口,用于显示截取的位图
    wcx.cbSize = sizeof(wcx);
    wcx.style
    = CS_HREDRAW | CS_VREDRAW;
    wcx.lpfnWndProc
    = MainWndProc;
    wcx.cbClsExtra
    = 0;
    wcx.cbWndExtra
    = 0;
    wcx.hInstance
    = hinstance;
    wcx.hIcon
    = LoadIcon(NULL, MAKEINTRESOURCE(IDI_APPLICATION));
    wcx.hCursor
    = LoadCursor(NULL, IDC_ARROW);
    wcx.hbrBackground
    = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wcx.lpszMenuName
    = NULL;
    wcx.lpszClassName
    = "MainWClass";
    wcx.hIconSm
    = NULL;

    if( !RegisterClassEx(&wcx))
    return 1;
    // 创建窗口
    hwnd = CreateWindow(
    "MainWClass",
    "CAP",
    WS_OVERLAPPEDWINDOW
    | WS_CLIPCHILDREN | WS_CLIPSIBLINGS |
    WS_MAXIMIZE
    | WS_POPUPWINDOW,
    CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
    (HWND) NULL, (HMENU) NULL, hinstance, (LPVOID) NULL);

    if (!hwnd)
    return 1;

    // 截取屏幕,可根据需要设置不同的参数,这里只演示截取特定窗口。
    ghBitmap = ScreenCapture("taskmgr.bmp" ,32, &rectShow);
    // 显示
    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    while ((fGotMessage = GetMessage(&msg, (HWND) NULL, 0, 0)) != 0 && fGotMessage != -1)
    {
    TranslateMessage(
    &msg);
    DispatchMessage(
    &msg);
    }
    return msg.wParam;
    UNREFERENCED_PARAMETER(lpCmdLine);
    }

    LRESULT CALLBACK MainWndProc(
    HWND hwnd,
    UINT uMsg,
    WPARAM wParam,
    LPARAM lParam)
    {
    switch (uMsg)
    {
    case WM_PAINT:
    // 显示截取的屏幕
    DoPaint(hwnd,CAP_SHOW_MODE_STRTCH);
    break;
    case WM_DESTROY:
    // 创建的BITMAP对象需要删除,以释放资源
    DeleteObject(ghBitmap);
    ExitProcess(
    0);
    break;
    default:
    break;
    }
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }

    /*************************************
    * VOID DoPaint(HWND hWnd, DWORD dwMode)
    * 功能 将位图(全局变量ghBitmap)显示在界面上
    *
    * 参数 HWND hWnd,用于显示位图的窗口
    * DWORD dwMode,模式,是否拉申
    *
    * 无返回值
    *************************************
    */
    VOID DoPaint(HWND hWnd, DWORD dwMode)
    {
    PAINTSTRUCT ps;
    RECT rect;
    HDC hdcMem;
    BITMAP bm;
    // BeginPaint
    HDC hDC = BeginPaint(hWnd, &ps);
    // 获取窗口的Client区域,用于显示位图
    GetClientRect(hWnd, &rect);

    // 设置拉申模式
    SetStretchBltMode(hDC, HALFTONE);
    // 将BITMAP对象选择入内存DC
    hdcMem = CreateCompatibleDC(hDC);
    SelectObject(hdcMem, ghBitmap);
    if (ghBitmap)
    {
    // 获取DIB属性
    if (GetObject(ghBitmap, sizeof(BITMAP), &bm))
    {
    // 判断参数示:是否根据显示窗口大小拉申位图
    // 采用不同的方面将内存DC StretchBl t至窗口Client区域DC
    if(dwMode == CAP_SHOW_MODE_STRTCH)
    {
    StretchBlt(hDC,
    0, 0, rect.right, rect.bottom,
    hdcMem,
    0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
    }
    else
    {
    // 不拉伸,计算显示的位置,将其显示在Client的中央
    INT ixStart = (rect.right - rect.left - bm.bmWidth)/2;
    INT iyStart
    = (rect.bottom - rect.top - bm.bmHeight)/2;
    ixStart
    = ixStart < 0 ? 0 : ixStart;
    iyStart
    = iyStart < 0 ? 0 : iyStart;
    BitBlt(hDC,
    0, 0, rect.right, rect.bottom,
    hdcMem,
    -ixStart,-iyStart, SRCCOPY);
    }
    DeleteDC(hdcMem);
    }
    }
    // 如果没有位图,则使用Brush填充
    else
    {
    PatBlt(hDC,
    0, 0, rect.right, rect.bottom, BLACKNESS);
    }
    // EndPaint
    EndPaint(hWnd, &ps);
    }

    /*************************************
    * BITMAP ScreenCapture(LPSTR filename ,WORD BitCount,LPRECT lpRect);
    * 功能 截取指定区域的屏幕,并保存为文件
    *
    * 参数 LPSTR filename 保存位图文件的文件路径,如果为NULL,则不保存
    * WORD BitCount Bit深度,用于表示一个像素点所使用的数据长度
    * LPRECT lpRect 所需截取的屏幕区域,如果为NULL,则获取全屏幕
    *
    * 返回 HBITMAP 所截取的位图对象
    *************************************
    */
    HBITMAP ScreenCapture(LPSTR filename ,WORD BitCount,LPRECT lpRect)
    {
    HBITMAP hBitmap;
    // 显示器屏幕DC
    HDC hScreenDC = CreateDC("DISPLAY", NULL, NULL, NULL);
    HDC hmemDC
    = CreateCompatibleDC(hScreenDC);
    // 显示器屏幕的宽和高
    int ScreenWidth = GetDeviceCaps(hScreenDC, HORZRES);
    int ScreenHeight = GetDeviceCaps(hScreenDC, VERTRES);
    // 旧的BITMAP,用于与所需截取的位置交换
    HBITMAP hOldBM;
    // 保存位图数据
    PVOID lpvpxldata;
    // 截屏获取的长宽及起点
    INT ixStart;
    INT iyStart;
    INT iX;
    INT iY;
    // 位图数据大小
    DWORD dwBitmapArraySize;
    // 几个大小
    DWORD nBitsOffset;
    DWORD lImageSize ;
    DWORD lFileSize ;
    // 位图信息头
    BITMAPINFO bmInfo;
    // 位图文件头
    BITMAPFILEHEADER bmFileHeader;
    // 写文件用
    HANDLE hbmfile;
    DWORD dwWritten;

    // 如果LPRECT 为NULL 截取整个屏幕
    if(lpRect == NULL)
    {
    ixStart
    = iyStart = 0;
    iX
    = ScreenWidth;
    iY
    =ScreenHeight;
    }
    else
    {
    ixStart
    = lpRect->left;
    iyStart
    = lpRect->top;
    iX
    = lpRect->right - lpRect->left;
    iY
    = lpRect->bottom - lpRect->top;
    }
    // 创建BTIMAP
    hBitmap = CreateCompatibleBitmap(hScreenDC, iX, iY);
    // 将BITMAP选择入内存DC。
    hOldBM = (HBITMAP)SelectObject(hmemDC, hBitmap);
    // BitBlt屏幕DC到内存DC,根据所需截取的获取设置参数
    BitBlt(hmemDC, 0, 0, iX, iY, hScreenDC, ixStart, iyStart, SRCCOPY);
    // 将旧的BITMAP对象选择回内存DC,返回值为被替换的对象,既所截取的位图
    hBitmap = (HBITMAP)SelectObject(hmemDC, hOldBM);
    if(filename == NULL)
    {
    DeleteDC( hScreenDC);
    DeleteDC(hmemDC);
    return hBitmap;
    }
    // 为位图数据申请内存空间
    dwBitmapArraySize = ((((iX*32) + 31) & ~31)>> 3)* iY;
    lpvpxldata
    = HeapAlloc(GetProcessHeap(),HEAP_NO_SERIALIZE,dwBitmapArraySize);
    ZeroMemory(lpvpxldata,dwBitmapArraySize);

    // 添充 BITMAPINFO 结构
    ZeroMemory(&bmInfo,sizeof(BITMAPINFO));
    bmInfo.bmiHeader.biSize
    = sizeof(BITMAPINFOHEADER);
    bmInfo.bmiHeader.biWidth
    = iX;
    bmInfo.bmiHeader.biHeight
    = iY;
    bmInfo.bmiHeader.biPlanes
    = 1;
    bmInfo.bmiHeader.biBitCount
    = BitCount;
    bmInfo.bmiHeader.biCompression
    = BI_RGB;

    // 添充 BITMAPFILEHEADER 结构
    ZeroMemory(&bmFileHeader,sizeof(BITMAPFILEHEADER));
    nBitsOffset
    = sizeof(BITMAPFILEHEADER) + bmInfo.bmiHeader.biSize;
    lImageSize
    =
    ((((bmInfo.bmiHeader.biWidth
    * bmInfo.bmiHeader.biBitCount) + 31) & ~31)>> 3)
    * bmInfo.bmiHeader.biHeight;
    lFileSize
    = nBitsOffset + lImageSize;
    bmFileHeader.bfType
    = 'B'+('M'<<8);
    bmFileHeader.bfSize
    = lFileSize;
    bmFileHeader.bfOffBits
    = nBitsOffset;

    // 获取DIB用于写入到文件
    GetDIBits(hmemDC, hBitmap, 0, bmInfo.bmiHeader.biHeight,
    lpvpxldata,
    &bmInfo, DIB_RGB_COLORS);
    // 写文件
    hbmfile = CreateFile(filename,
    GENERIC_WRITE,
    FILE_SHARE_WRITE,
    NULL,
    CREATE_ALWAYS,
    FILE_ATTRIBUTE_NORMAL,
    NULL);

    if(hbmfile == INVALID_HANDLE_VALUE)
    {
    MessageBox(NULL,
    "create file error","error",MB_OK);
    }

    WriteFile(hbmfile,
    &bmFileHeader,sizeof(BITMAPFILEHEADER),&dwWritten,NULL);
    WriteFile(hbmfile,
    &bmInfo,sizeof(BITMAPINFO),&dwWritten,NULL);
    WriteFile(hbmfile,lpvpxldata,lImageSize,
    &dwWritten,NULL);
    CloseHandle(hbmfile);

    // 释放内存,清除不同的DC。
    // 这里没有删除BITMAP对象,需在显示完成后删除
    HeapFree(GetProcessHeap(),HEAP_NO_SERIALIZE,lpvpxldata);
    ReleaseDC(
    0, hScreenDC);
    DeleteDC(hmemDC);
    return hBitmap;
    }

    参考

    [1] 精通Windows API 函数、接口、编程实例

    [2] http://msdn.microsoft.com/en-us/library/dd183553%28VS.85%29.aspx

  • 相关阅读:
    hud 1166 敌兵布阵
    zznu 1914 asd的甩锅计划
    poj 1860 Currency Exchange
    poj 3026 Borg Maze (BFS + Prim)
    poj 2349 Arctic Network
    POJ 1502 MPI Maelstrom
    poj 1308 Is It A Tree?
    hdu 1272 小希的迷宫
    poj 1679 http://poj.org/problem?id=1679
    POJ 2492 A Bug's Life
  • 原文地址:https://www.cnblogs.com/mydomain/p/1959858.html
Copyright © 2011-2022 走看看