Bitmap drawing of windows programming

Bitmap drawing of windows programming

double buffering technology

It flickers when the screen is refreshed. The reason is that the drawing is not synchronized with the refresh of the display, and there is a time difference. To solve this problem, double buffering technology is required for drawing. Double buffering technology is relative to single buffering. Single buffering is to draw directly on the device DC; while double buffering is to first draw in a memory buffer compatible with the device DC, and then copy it to the device DC at one time. . There will be no flickering phenomenon when displayed on the screen at one time.

  • In layman's terms it is
  1. Ordinary drawing is to draw directly on the blackboard we can see
  2. Double buffering is to finish drawing on a virtual blackboard first, and copy the pictures on the virtual blackboard to the blackboard we can see when it is used;

related functions

  • LoadImage (load image)
  • CreateCompatibleDC (create memory DC)
  • BitBlt (performs a bit-block transfer)
  • StretchBlt (copy bitmap and stretch or compress bitmap)
  • TransparentBlt (bitmap transparency)
  • DeleteDC (delete memory DC)

LoadImage

Load icons, cursors, animated cursors or bitmaps.

HANDLE LoadImageA(
  [in, optional] HINSTANCE hInst,
  [in]           LPCSTR    name,
  [in]           UINT      type,
  [in]           int       cx,
  [in]           int       cy,
  [in]           UINT      fuLoad
);

Parameter analysis

parameter name meaning
hInst 【1】DLL or executable file (handle to .exe module), which contains the image to be loaded. See GetModuleHandle for details . Note that starting with 32-bit Windows, instance handles ( HINSTANCE ), such as application instance handles exposed by the WinMain system function call, and module handles ( HMODULE ) as well. 【2】If you want to load OEM image, please set this parameter as NULL . 【3】If you want to load an independent resource (icon, cursor or bitmap file) (for example, c:\myimage.bmp), please set this parameter to NULL .
name The image to load. If the hinst parameter is non- NULL and the fuLoad parameter omits LR_LOADFROMFILE , lpszName specifies the image resource in the hinst module . If the image resource is to be loaded by name from the module, the lpszName parameter is a pointer to a null-terminated string containing the name of the image resource. If you want to load image resources by serial number from a module, use the MAKEINTRESOURCE macro to convert the image serial number into a form that can be passed to the LoadImage function.
type The type of image to load. See table below
cx The width of the icon or cursor in pixels. If this parameter is zero and the fuLoad parameter LR_DEFAULTSIZE , the function uses the SM_CXICON or SM_CXCURSOR system indicator value to set the width. If this parameter is zero and LR_DEFAULTSIZE is not used , the function uses the actual resource width.
cy Height of the icon or cursor in pixels. If this parameter is zero and the fuLoad parameter LR_DEFAULTSIZE , the function uses the SM_CYICON or SM_CYCURSOR system indicator value to set the height. If this parameter is zero and LR_DEFAULTSIZE is not used , the function uses the actual resource height.
fuLoad see table below

return value

Type: HANDLE

If the function succeeds, the return value is a handle to the newly loaded image.

If the function fails, the return value is NULL . To get more error information, call GetLastError.

Remark

If IS_INTRESOURCE( lpszName ) is TRUE , then lpszName specifies the integer identifier for the given resource. Otherwise, it is a pointer to a null-terminated string. If the first character of the string is a pound sign (#), the remaining characters represent the decimal number that specifies the resource's integer identifier. For example, the character string "#258" represents the identifier 258.

When you are done using a loaded bitmap, cursor, or icon without specifying the LR_SHARED flag, you can free its associated memory by calling one of the functions in the following table.

resource publish function
Bitmap DeleteObject
cursor DestroyCursor
icon DestroyIcon

**hInst: **

If the hinst parameter is NULL and the fuLoad parameter omits the LR_LOADFROMFILE value, lpszName specifies the OEM image to load. OEM image identifiers are defined in Winuser.h and have the following prefixes.

prefix meaning
OBM_ OEM bitmap
OIC_ OEM icon
Ocr_ OEM cursor

type:

value meaning
IMAGE_BITMAP Load the bitmap.
IMAGE_CURSOR Load the cursor.
IMAGE_ICON Meaning loading icon.

fuLoad:

This parameter can take one or more of the following values.

Value meaning
LR_CREATEDIBSECTION When the uType parameter specifies IMAGE_BITMAP , it causes the function to return a DIB section bitmap instead of a compatible bitmap. This flag can be used to load a bitmap without mapping it to the display device's colors.
LR_DEFAULTCOLOR The default flag; it does nothing. This means "not LR_MONOCHROME ".
LR_DEFAULTSIZE If the cxDesired or cyDesired value is set to zero, the width or height specified by the cursor or icon's system indicator value is used. If this flag is not specified, and cxDesired and cyDesired are set to zero, the function will use the actual resource size. If the resource contains multiple images, the function uses the size of the first image.
LR_LOADFROMFILE Loads an individual image, (icon, cursor or bitmap file) from the file specified by lpszName .
LR_LOADMAP3DCOLORS Search the image in the color table and replace the following shades of gray with the corresponding 3D colors. Dk Gray, RGB (128, 128, 128) and COLOR_3DSHADOW Gray, RGB (192, 192, 192) and COLOR_3DFACE Lt Gray, RGB (223, 223, 223 ), COLOR_3DLIGHT If you want to load a bitmap with a color depth greater than 8bpp, please Do not use this option.
LR_LOADTRANSPARENT 检索图像中第一个像素的颜色值,并将颜色表中的相应条目替换为默认窗口颜色 (COLOR_WINDOW) 。 使用该条目的图像中的所有像素都将成为默认窗口颜色。 此值仅适用于具有相应颜色表的图像。如果要加载颜色深度大于 8bpp 的位图,请不要使用此选项。如果 fuLoad 同时包括 LR_LOADTRANSPARENTLR_LOADMAP3DCOLORS 值, LR_LOADTRANSPARENT 优先。 但是,颜色表项替换为 COLOR_3DFACE 而不是 COLOR_WINDOW
LR_MONOCHROME 加载黑白图像。
LR_SHARED 如果多次加载映像,则共享映像句柄。 如果未设置 LR_SHARED ,则对同一资源的 LoadImage 的第二次调用将再次加载映像并返回不同的句柄。使用此标志时,系统会在不再需要资源时销毁资源。不要对具有非标准大小的图像使用 LR_SHARED ,这些图像在加载后可能会更改,或者从文件加载。加载系统图标或游标时,必须使用 LR_SHARED ,否则函数将无法加载资源。无论请求的大小如何,此函数都会找到缓存中请求的资源名称的第一个映像。
LR_VGACOLOR 使用真正的 VGA 颜色。

CreateCompatibleDC

CreateCompatibleDC 函数 (DC) 创建与指定设备兼容的内存设备上下文。

HDC CreateCompatibleDC(
  [in] HDC hdc
);
参数名 含义
hdc 现有 DC 的句柄。 如果此句柄为 NULL,则该函数将创建与应用程序的当前屏幕兼容的内存 DC。

返回值

如果函数成功,则返回值是内存 DC 的句柄。

如果函数失败,则返回值为 NULL

备注

  1. 内存 DC 仅存在于内存中。 创建内存 DC 时,其显示图面正好是一个单色像素宽和一个单色像素高。 在应用程序可以使用内存 DC 进行绘图操作之前,它必须选择正确宽度和高度到 DC 的位图。 若要选择 DC 中的位图,请使用 CreateCompatibleBitmap 函数,指定所需的高度、宽度和颜色组织。
  2. 创建内存 DC 后,所有属性都设置为普通默认值。 内存 DC 可用作普通 DC。 可以设置属性;获取其属性的当前设置;并选择笔、画笔和区域。
  3. CreateCompatibleDC 函数只能与支持光栅操作的设备一起使用。 应用程序可以通过调用 GetDeviceCaps 函数来确定设备是否支持这些操作。
  4. 不再需要内存 DC 时,请调用 DeleteDC 函数。 建议调用 DeleteDC 以删除 DC。 但是,还可以使用 HDC 调用 DeleteObject 以删除 DC。
  5. 如果 hdcNULL,则调用 CreateCompatibleDC 的线程拥有创建的 HDC。 销毁此线程后,HDC 将不再有效。 因此,如果创建 HDC 并将其传递给另一个线程,则退出第一个线程,第二个线程将无法使用 HDC。
  6. Icm: 如果为图像颜色管理 (ICM) 启用了传递给此函数的 DC,则由该函数创建的 DC 已启用 ICM。 源和目标颜色空间在 DC 中指定。

BitBlt

BitBlt 函数执行与从指定源设备上下文到目标设备上下文中的像素矩形对应的颜色数据的位块传输。

BOOL BitBlt(
  [in] HDC   hdc,
  [in] int   x,
  [in] int   y,
  [in] int   cx,
  [in] int   cy,
  [in] HDC   hdcSrc,
  [in] int   x1,
  [in] int   y1,
  [in] DWORD rop
);

参数解析:

参数名 含义
hdc 目标设备上下文的句柄。
x 目标矩形左上角的 x 坐标(以逻辑单位为单位)。
y 目标矩形左上角的 y 坐标(以逻辑单位为单位)。
cx 源矩形和目标矩形的宽度(以逻辑单位为单位)。
cy 源和目标矩形的高度(以逻辑单位为单位)。
hdcSrc 源设备上下文的句柄。
x1 源矩形左上角的 x 坐标(以逻辑单位为单位)。
y1 源矩形左上角的 y 坐标(以逻辑单位为单位)。
rop 光栅操作代码。 这些代码定义源矩形的颜色数据如何与目标矩形的颜色数据组合,以实现最终颜色。

**光栅操作代码: **

Value 含义
黑暗 使用与物理调色板中的索引 0 关联的颜色填充目标矩形。 (对于默认的物理调色板,该颜色为黑色。)
CAPTUREBLT 包括在生成的图像中窗口顶部分层的任何窗口。 默认情况下,图像仅包含窗口。 请注意,这通常无法用于打印设备上下文。
DSTINVERT 反转目标矩形。
MERGECOPY 使用布尔 AND 运算符将源矩形的颜色与当前在 hdcDest 中选择的画笔合并。
MERGEPAINT 使用布尔 OR 运算符将倒置源矩形的颜色与目标矩形的颜色合并。
NOMIRRORBITMAP 防止位图镜像。
NOTSRCCOPY 将倒置源矩形复制到目标。
NOTSRCERASE 使用布尔 OR 运算符合并源矩形和目标矩形的颜色,然后反转生成的颜色。
PATCOPY 将当前在 hdcDest 中选择的画笔复制到目标位图中。
PATINVERT 使用布尔 XOR 运算符将当前在 hdcDest 中选择的画笔的颜色与目标矩形的颜色组合在一起。
PATPAINT 使用布尔 OR 运算符将当前在 hdcDest 中选择的画笔的颜色与倒置源矩形的颜色组合在一起。 此操作的结果与目标矩形的颜色结合使用,方法是使用布尔 OR 运算符。
SRCAND 使用布尔 AND 运算符合并源矩形和目标矩形的颜色。
SRCCOPY 将源矩形直接复制到目标矩形。
SRCERASE 使用布尔 AND 运算符将目标矩形的反转颜色与源矩形的颜色组合在一起。
SRCINVERT 使用布尔 XOR 运算符合并源矩形和目标矩形的颜色。
SRCPAINT 使用布尔 OR 运算符合并源矩形和目标矩形的颜色。
使用与物理调色板中的索引 1 关联的颜色填充目标矩形。 (对于默认的物理调色板,该颜色为白色。)

返回值

如果该函数成功,则返回值为非零值。

如果函数失败,则返回值为零。 要获得更多的错误信息,请调用 GetLastError。

备注

  1. BitBlt 仅对目标 DC 执行剪辑。
  2. 如果旋转或剪切转换在源设备上下文中有效, BitBlt 将返回错误。 如果源设备上下文中存在其他转换 (并且匹配转换在目标设备上下文中无效) ,则目标设备上下文中的矩形会根据需要拉伸、压缩或旋转。
  3. 如果源和目标设备上下文的颜色格式不匹配, BitBlt 函数将源颜色格式转换为匹配目标格式。
  4. 记录增强型图元文件时,如果源设备上下文标识增强型图元文件设备上下文,则会发生错误。
  5. 并非所有设备都支持 BitBlt 函数。 有关详细信息,请参阅 GetDeviceCaps 函数中的RC_BITBLT光栅功能条目以及以下函数: MaskBltPlgBltStretchBlt
  6. 如果源和目标设备上下文表示不同的设备,则 BitBlt 将返回错误。 若要在不同设备的 DC 之间传输数据,请通过调用 GetDIBit 将内存位图转换为 DIB。 若要向第二台设备显示 DIB,请调用 SetDIBitsStretchDIBits
  7. Icm: 当出现 blit 时,不会执行颜色管理。

代码示例

if (!BitBlt(hdcMemDC,
    0, 0,
    rcClient.right - rcClient.left, rcClient.bottom - rcClient.top,
    hdcWindow,
    0, 0,
    SRCCOPY))
{
    
    
    MessageBox(hWnd, L"BitBlt has failed", L"Failed", MB_OK);
    goto done;
}

StretchBlt

StretchBlt 函数将一个位图从源矩形复制到目标矩形中,并拉伸或压缩位图以适应目标矩形的尺寸(如有必要)。 系统根据当前在目标设备上下文中设置的拉伸模式拉伸或压缩位图。

BOOL StretchBlt(
  [in] HDC   hdcDest,
  [in] int   xDest,
  [in] int   yDest,
  [in] int   wDest,
  [in] int   hDest,
  [in] HDC   hdcSrc,
  [in] int   xSrc,
  [in] int   ySrc,
  [in] int   wSrc,
  [in] int   hSrc,
  [in] DWORD rop
);

参数解析:

参数名 含义
hdcDest 目标设备上下文的句柄。
xDest 目标矩形左上角的 x 坐标(以逻辑单位为单位)。
yDest 目标矩形左上角的 y 坐标(以逻辑单位为单位)。
wDest 目标矩形的宽度(以逻辑单元表示)。
hDest 目标矩形的高度(以逻辑单元表示)。
hdcSrc 源设备上下文的句柄。
xSrc 源矩形左上角的 x 坐标(以逻辑单位为单位)。
ySrc 源矩形左上角的 y 坐标(以逻辑单位为单位)。
wSrc 源矩形的宽度(以逻辑单元表示)。
hSrc 源矩形的高度(以逻辑单元表示)。
rop 要执行的光栅操作。 光栅操作代码定义系统如何在涉及画笔、源位图和目标位图的输出操作中组合颜色。参考上面的表

返回值

如果该函数成功,则返回值为非零值。

如果函数失败,则返回值为零。

备注

  1. StretchBlt 在内存中拉伸或压缩源位图,然后将结果复制到目标矩形。 此位图可以是兼容位图 (DDB) ,也可以是 CreateDIBSection 的输出。 模式或目标像素的颜色数据在拉伸或压缩后合并。
  2. 记录增强的图元文件时, (发生错误,如果源设备上下文标识增强型图元文件设备上下文,函数将返回 FALSE) 。
  3. 如果指定的光栅操作需要画笔,系统将使用当前选择的画笔进入目标设备上下文。
  4. 使用当前为目标设备上下文指定的转换来转换目标坐标;源坐标通过使用当前为源设备上下文指定的转换进行转换。
  5. 如果源转换具有旋转或剪切,则会发生错误。
  6. 如果目标位图、源位图和图案位图的颜色格式不相同, StretchBlt 会将源位图和模式位图转换为与目标位图匹配。
  7. 如果 StretchBlt 必须将单色位图转换为颜色位图,则会将白色位 (1) 设置为背景色,将黑色位 (0) 设置为前景色。 若要将颜色位图转换为单色位图,它将将背景色与白色匹配的像素设置为白色 (1) ,并将所有其他像素设置为黑色 (0) 。 在转换中将使用彩色设备上下文的前景色和背景色。
  8. 如果 nWidthSrcnWidthDest 参数的符号或 nHeightSrc 和 nHeightDest 参数不同,StretchBlt 将创建位图的镜像图像。 如果 nWidthSrcnWidthDest 具有不同的符号,则函数会在 x 轴上创建位图的镜像图像。 如果 nHeightSrcnHeightDest 具有不同的符号,则函数会在 y 轴上创建位图的镜像图像。
  9. 并非所有设备都支持 StretchBlt 函数。 有关详细信息,请参阅 GetDeviceCaps
  10. Icm: 当发生 blit 操作时,不会执行颜色管理。
  11. 在多个监视器系统中使用时, hdcSrchdcDest 都必须引用同一设备,否则该函数将失败。 若要在不同设备的 DC 之间传输数据,请通过调用 GetDIBit 将内存位图转换为 DIB。 若要向第二台设备显示 DIB,请调用 SetDIBitsStretchDIBits

TransparentBlt

TransparentBlt 函数执行与从指定源设备上下文到目标设备上下文中的像素矩形对应的颜色数据的位块传输。

BOOL TransparentBlt(
  [in] HDC  hdcDest,
  [in] int  xoriginDest,
  [in] int  yoriginDest,
  [in] int  wDest,
  [in] int  hDest,
  [in] HDC  hdcSrc,
  [in] int  xoriginSrc,
  [in] int  yoriginSrc,
  [in] int  wSrc,
  [in] int  hSrc,
  [in] UINT crTransparent
);

参数解析:

参数名 含义
hdcDest 目标设备上下文的句柄。
xoriginDest 目标矩形左上角的 x 坐标(以逻辑单位为单位)。
yoriginDest 目标矩形左上角的 y 坐标(以逻辑单位为单位)。
wDest 目标矩形的宽度(以逻辑单元表示)。
hDest 目标矩形的高度(以逻辑单元表示)。
hdcSrc 源设备上下文的句柄。
xoriginSrc 源矩形的 x 坐标(以逻辑单位为单位)。
yoriginSrc 源矩形的 y 坐标(以逻辑单位为单位)。
wSrc 源矩形的宽度(以逻辑单元表示)。
hSrc 源矩形的高度(以逻辑单元表示)。
crTransparent 要视为透明的源位图中的 RGB 颜色。

返回值:

如果函数成功,则返回值为 TRUE

如果函数失败,则返回值为 FALSE

备注:

  1. TransparentBlt 函数适用于兼容位图 (DDB) 。
  2. TransparentBlt 函数支持源位图的所有格式。 但是,对于 32 bpp 位图,它只复制 alpha 值。 使用 AlphaBlend 指定透明度为 32 位/像素位图。
  3. 如果源矩形和目标矩形的大小不相同,则会拉伸源位图以匹配目标矩形。 使用 SetStretchBltMode 函数时,BLACKONWHITE 和 WHITEONBLACK 的 iStretchMode 模式将转换为 TransparentBlt 函数的 COLORONCOLOR。
  4. 目标设备上下文指定目标坐标的转换类型。 源设备上下文指定源坐标的转换类型。
  5. 如果源或目标的宽度或高度为负,则 TransparentBlt 不会镜像位图。
  6. 在多个监视器系统中使用时, hdcSrchdcDest 都必须引用同一设备,否则该函数将失败。 若要在不同设备的 DC 之间传输数据,请通过调用 GetDIBit 将内存位图转换为 DIB。 若要向第二台设备显示 DIB,请调用 SetDIBitsStretchDIBits

DeleteDC

DeleteDC 函数 (DC) 删除指定的设备上下文。

BOOL DeleteDC(
  [in] HDC hdc // 设备上下文的句柄。
);

返回值:

如果该函数成功,则返回值为非零值。

如果函数失败,则返回值为零。

备注:

应用程序不得删除通过调用 GetDC 函数获取其句柄的 DC。 相反,它必须调用 ReleaseDC 函数来释放 DC。


综合应用代码示例

#include <windows.h>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
    
    
  static TCHAR szAppName[] = TEXT("NueXini");
  HWND hWnd;
  MSG msg;
  WNDCLASS wndclass;

  wndclass.style = CS_HREDRAW | CS_VREDRAW;
  wndclass.lpfnWndProc = WndProc;
  wndclass.cbClsExtra = 0;
  wndclass.cbWndExtra = 0;
  wndclass.hInstance = hInstance;
  wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
  wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
  wndclass.lpszMenuName = NULL;
  wndclass.lpszClassName = szAppName;

  if (!RegisterClass(&wndclass))
  {
    
    
    MessageBox(NULL, TEXT("Error"), szAppName, MB_ICONERROR | MB_OK);
    return 0;
  }

  hWnd = CreateWindow(
      szAppName,
      szAppName,
      WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT,
      CW_USEDEFAULT,
      CW_USEDEFAULT,
      CW_USEDEFAULT,
      NULL,
      NULL,
      hInstance,
      NULL);
  ShowWindow(hWnd, iCmdShow);
  UpdateWindow(hWnd);

  while (GetMessage(&msg, NULL, 0, 0))
  {
    
    
    TranslateMessage(&msg);
    DispatchMessage(&msg);
  }

  return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    
    
  HDC hdc, hdcMem;
  PAINTSTRUCT ps;
  HBITMAP hBitMap;
  BITMAP bm;

  switch (message)
  {
    
    
  case WM_CREATE:
    return 0;

  case WM_SIZE:
    return 0;

  case WM_PAINT:
    hdc = BeginPaint(hwnd, &ps);

    hdcMem = CreateCompatibleDC(hdc);
    hBitMap = (HBITMAP)LoadImage(NULL, TEXT("../monster.bmp"), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);

    SelectObject(hdcMem, hBitMap);
    GetObject(hBitMap, sizeof(BITMAP), &bm);

    // 原样输出位图
    BitBlt(hdc, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, SRCCOPY);

    // 复制上面的位图
    StretchBlt(hdc, 0, bm.bmHeight, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);

    // 获取一个颜色像素,输出透明位图
    TransparentBlt(hdc, bm.bmWidth + 10, 0, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, bm.bmWidth, bm.bmHeight, GetPixel(hdcMem, 0, 0));

    // 复制上面的位图, 缩小2倍
    StretchBlt(hdc, bm.bmWidth + 10, bm.bmHeight, bm.bmWidth / 2, bm.bmHeight / 2, hdcMem, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);

    // 获取一个颜色像素,输出缩小2倍的透明位图
    TransparentBlt(hdc, bm.bmWidth * 2, 0, bm.bmWidth / 2, bm.bmHeight / 2, hdcMem, 0, 0, bm.bmWidth, bm.bmHeight, GetPixel(hdcMem, 0, 0));

    // 释放位图
    DeleteObject(hBitMap);
    // 释放内存DC
    DeleteDC(hdcMem);

    EndPaint(hwnd, &ps);
    return 0;

  case WM_DESTROY:
    PostQuitMessage(0);
    return 0;
  }
  return DefWindowProc(hwnd, message, wParam, lParam);
}


enjoy it ~

Guess you like

Origin blog.csdn.net/a924282761/article/details/127848776