(1)创建 HBITMAP= CreateBitmap(cx,cy,cPlanes,cBitsPixel,lpBits);
参数 |
说明 |
cx,cy |
指定位图宽度和高度,单位为像素。 |
cPlanes |
颜色平面数目。标准的VGA显卡具有4个连续的颜色平面,每个平面取一个对应位,把它们组合起来就是一个像素。但这样被创建出来的位图被限制为标准的16位。 |
cxBits |
每个像素点颜色的位数 |
lpBits |
指向颜色数据数组指针。每行的字节数必须是偶数个字节(不足时以0填充)。如果该参数为NULL,将不对新生成的位图进行初始化。 |
注意:给DDB分配内存:
①每个像素行都必须分配偶数个字节(注意,不是位哦),即:
A、iWidthBytes=2*((cx*cBitsPixel+15)/16); 公式1
公式理解:cx*cBitsPixel为每行像素实际的总位数,(cx*cBitsPixel)/8表示该行像素实际需要的字节数。为了得到个偶
数,将分子分母都乘2,即2*((cx*cBitsPixel)/16),但因隐式转换问题,(cx*cBitsPixel)<16时,会直接去
除小数部分,所以2*((cx*cBitsPixel)/16)的结果为0,为了向上取整,在加个15。即得该公式。
B、与上式的等价公式iWidthBytes =((cx*cBitsPixel+15) & ~15)>>3; 公式2
公式理解:因逻辑运算中移位的特点,除以2相当于将被除数右移1位,除以16
相当于将被除数右移4位。15取反得1111 1111 1111 1111 1111 1111 1111 0000。公式1中(cx*cBitsPixel+15) /16,即相当于被除数右移4位。但因为最后是2*((cx*cBitsPixel+15)/16),所以实际上只需右移3位。我们只需保右移3位的结果仍是偶数即可。为了做到这点,取(cx*cBitsPixel+15)结果(共32 位,设从左向右分别是第32位到第1位)中的第32位到第4位,而右移出低位的3位,再将最后一位设为0,即能 保证为偶数。但这过程也可以先将(cx*cBitsPixel+15)的第1-4位设为0,再右移3位,即 (cx*cBitsPixel+15) & ~15,最后得公式2。
【图解公式】
C、从公式中可以看出,每行的字节数为0、2、4、6、8…等,即0、16位、32位、48位、64位等,也就是位数应为16的倍数!
②像素需要的总内存:iBitmapBytes = cy*cPlanes*iWidthBytes;
③CreateBitmap参数的设置:
A、cPlanes与cBitsPixel都等于1 →单色位图
B、cPlanes和cBitsPixel等于某个设备环境中的值,可以通过GetDeviceCaps得到。因为cPlanes和cBitPixel要从设备环境中得到,可以直接调用CreateCompatibleBitmap(hdc,cx,cy)从而省去调用GetDeviceCap函数。
(2)hBitmapCreateBitmapIndirect(&bitmap);
BITMAP结构体
字段 |
说明 |
bmType |
必须是0 |
bmWidth |
图像的宽度(以像素为单位) |
bmHeight |
图像的高度(以像素为单位) |
bmWidthBytes |
每行的像素的总字节数,必须是偶数个。 调用CreateBitmapIndirect时,不需要设置该字段,Windows会跟据bmWidth和bmBitsPixel值自动计算。 |
bmPlanes |
颜色平面数 |
bmBitsPixel |
每个像素的位数 |
bmBits |
指向存储像素的缓冲区,可以为NULL |
(3)获得BITMAP结构:GetObject(hBitmap,sizeof(BITMAP),&bitmap);
(4)删除位图:DeleteObject(hBitmap);
14.4.2 位图的位
(1)设置像素位:SetBitmapBits(hBitmap,cBytes,&bits); //注意每行为偶数个字节
(2)获取像素位:GetBitmapBits(hBitmap,cBytes,&bits);
(3)关于像素位的注意点:
①对于单色位图,每个像素就是1位,所以bmBits的每位就表示该像素的颜色。
②对于非单色位图,如每个像素对应8位(1字节,如0x37),但0x37不是具体的颜色,因为DDB没有颜色表,该值只是个索引,被显示时对应显卡颜色表索引为0x37的RGB颜色,这就是设备相关的意思!
③对于单位DDB,可以通过SetBitmapBits像素位。但对于彩色图,每个像素位表示的是个索引值,不应直接通过SetBitmapBits、CreateBitmap或CreateBitmapIndirect来也设置像素位。
14.4.3 内存设备环境
(1)创建内存设备环境 hdcMem = CreateCompatibleDC(hdc);
①只存在于内存,并不是一个真实的图形输出设备,与真实设备“兼容”
②hdcMem跟真实的设备环境一样,也有一个显示表面。但刚开始创建是单色且只有1*1像素大小(像素位只有1),为了能在该表面上绘图,可以通过将GDI对象选入hdcMem来增大显示表面(如SetlectObject(hdcMem,hBitmap)),即可完成hBitmap复制到内存hdcMem中,又将该位图作为内存设备环境的显示表面,可以在其上面通过GDI函数进行绘图,图像会画在位图上。
③在各类的设备环境,只有内存设备环境才能选入位图。
④只有单色位图或该位图和内存设备环境兼容的设备有同样的颜色组织的才能被选入内存设备环境。
14.4.4 加载位图资源
(1)加载:hBitmap= LoadBitmap(hInstance,szBitmapName);
①加载系统位图时,第1个参数为NULL,第2个参数的标识符以OBM开头
②若加载成功,则返回的GDI对象和程序正在其上运行的视频显示有相同的颜色组织。并且可以被选入与视频显示兼容的内存设备环境,也就是LoadBitmap会在背后进行颜色的转换,让其与视频显示兼容。
(2)删除位图资源:DeleteObject(hBitmap);
【Bricks1程序】
/*------------------------------------------------------------ BRICKS1.C -- LoadBitmap Demonstration (c) Charles Petzold, 1998 ------------------------------------------------------------*/ #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("Bricks1"); HWND hwnd; MSG msg; WNDCLASSEX wndclass; wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.cbSize = sizeof(WNDCLASSEX); wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInstance; wndclass.hIcon = LoadIcon(hInstance, szAppName); wndclass.hIconSm = LoadIcon(hInstance, szAppName); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = szAppName; if (!RegisterClassEx(&wndclass)) { MessageBox(NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR); return 0; } hwnd = CreateWindow(szAppName, // window class name TEXT("LoadBitmap Demo"), // window caption WS_OVERLAPPEDWINDOW, // window style CW_USEDEFAULT, // initial x position CW_USEDEFAULT, // initial y position CW_USEDEFAULT, // initial x size CW_USEDEFAULT, // initial y size NULL, // parent window handle NULL, // window menu handle hInstance, // program instance handle NULL); // creation parameters 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; HINSTANCE hInstance; static HBITMAP hBitbmp; BITMAP bitmap; static int cxClient, cyClient, cxSource, cySource; switch (message) { case WM_CREATE: hInstance = ((LPCREATESTRUCT)lParam)->hInstance; hBitbmp = LoadBitmap(hInstance, TEXT("Bricks")); GetObject(hBitbmp, sizeof(BITMAP), &bitmap); cxSource = bitmap.bmWidth; cySource = bitmap.bmHeight; return 0; case WM_SIZE: cxClient = LOWORD(lParam); cyClient = HIWORD(lParam); return 0; case WM_PAINT: hdc = BeginPaint(hwnd, &ps); hdcMem = CreateCompatibleDC(hdc); SelectObject(hdcMem, hBitbmp); for (int y = 0; y < cyClient; y += cySource) for (int x = 0; x < cxClient; x += cxSource) { BitBlt(hdc, x, y, cxSource, cySource, hdcMem, 0, 0, SRCCOPY); } DeleteDC(hdcMem); EndPaint(hwnd, &ps); return 0; case WM_DESTROY: DeleteObject(hBitbmp); PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam); }
//resource.h
//{{NO_DEPENDENCIES}} // Microsoft Visual C++ 生成的包含文件。 // 供 Bricks1.rc 使用 // // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 108 #define _APS_NEXT_COMMAND_VALUE 40001 #define _APS_NEXT_CONTROL_VALUE 1001 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif
//Bricks1.rc
// Microsoft Visual C++ generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #include "winres.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // 中文(简体,中国) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE BEGIN "resource.h\0" END 2 TEXTINCLUDE BEGIN "#include ""winres.h""\r\n" "\0" END 3 TEXTINCLUDE BEGIN "\r\n" "\0" END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Bitmap // Bricks BITMAP "Bricks.bmp" #endif // 中文(简体,中国) resources ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED
14.4.5 单色位图
(1)BITMAP中的位图像素缓冲区设置原理,以Bricks程序和HelloDemo程序为例(0代表黑色,1代表白色)
(2)创建位图——以Hello程序为例
①创建BITMAP结构: static BITMAP bitmap={0,20,5,4,1,1};
②设置位图的像素数 static BYTE bits[]={0x51,0x77,0x10,0,
0x57,0x77,0x50,0,
0x13,0x77,0x50,0,
0x57,0x77,0x50,0,
0x51,0x11,0x10,0}
③创建位图:
bitmap.bmBits =(PSTR)bits;
hBitmap =CreateBitmapIndirect(&bitmap);
或 hBitmap = Create(20,5,1,1,bits);
SetBitmap(hBitmap,sizeof(bits),bits)
【Bricks2】
/*------------------------------------------------------------ BRICKS2.C -- Createbitmap Demonstration (c) Charles Petzold, 1998 ------------------------------------------------------------*/ #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("Bricks2"); HWND hwnd; MSG msg; WNDCLASSEX wndclass; wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.cbSize = sizeof(WNDCLASSEX); wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInstance; wndclass.hIcon = LoadIcon(hInstance, szAppName); wndclass.hIconSm = LoadIcon(hInstance, szAppName); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = szAppName; if (!RegisterClassEx(&wndclass)) { MessageBox(NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR); return 0; } hwnd = CreateWindow(szAppName, // window class name TEXT("CreateBitmap Demo"), // window caption WS_OVERLAPPEDWINDOW, // window style CW_USEDEFAULT, // initial x position CW_USEDEFAULT, // initial y position CW_USEDEFAULT, // initial x size CW_USEDEFAULT, // initial y size NULL, // parent window handle NULL, // window menu handle hInstance, // program instance handle NULL); // creation parameters 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; static HBITMAP hBitmap; BITMAP bitmap = { 0, 8, 8, 2, 1, 1 }; static int cxSource, cySource, cxClient, cyClient; //每行2个字节,共8行 static BYTE bits[8][2] = { 0xFF, 0, 0x0C, 0, 0x0C, 0, 0x0C, 0, 0xFF, 0, 0xC0, 0, 0xC0, 0, 0xC0, 0 }; switch (message) { case WM_CREATE: bitmap.bmBits = bits; hBitmap = CreateBitmapIndirect(&bitmap); cxSource = bitmap.bmWidth; cySource = bitmap.bmHeight; return 0; case WM_SIZE: cxClient = LOWORD(lParam); cyClient = HIWORD(lParam); return 0; case WM_PAINT: hdc = BeginPaint(hwnd, &ps); hdcMem = CreateCompatibleDC(hdc); SelectObject(hdcMem, hBitmap); for (int y = 0; y < cyClient; y += cySource) for (int x = 0; x < cxClient; x += cxSource) { BitBlt(hdc, x, y, cxSource, cySource, hdcMem, 0, 0, SRCCOPY); } DeleteDC(hdcMem); EndPaint(hwnd, &ps); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam); }
【HelloDemo】
![](https://images0.cnblogs.com/blog2015/772759/201508/030845002052829.png)
/*------------------------------------------------------------ HELLODEMO.C -- CreateBitmap Demo(Hello Version) (c) Charles Petzold, 1998 ------------------------------------------------------------*/ #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("Hello"); HWND hwnd; MSG msg; WNDCLASSEX wndclass; wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.cbSize = sizeof(WNDCLASSEX); wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInstance; wndclass.hIcon = LoadIcon(hInstance, szAppName); wndclass.hIconSm = LoadIcon(hInstance, szAppName); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = szAppName; if (!RegisterClassEx(&wndclass)) { MessageBox(NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR); return 0; } hwnd = CreateWindow(szAppName, // window class name TEXT("CreateBitmap Demo(Hello Version)"), // window caption WS_OVERLAPPEDWINDOW, // window style CW_USEDEFAULT, // initial x position CW_USEDEFAULT, // initial y position CW_USEDEFAULT, // initial x size CW_USEDEFAULT, // initial y size NULL, // parent window handle NULL, // window menu handle hInstance, // program instance handle NULL); // creation parameters 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; static HBITMAP hBitmap; BITMAP bitmap; static BYTE bits[5][4] = { 0x51, 0x77, 0x10, 0, 0x57, 0x77, 0x50, 0, 0x13, 0x77, 0x50, 0, 0x57, 0x77, 0x50, 0, 0x51, 0x11, 0x10, 0 }; static int cxSource, cySource, cxClient, cyClient; POINT pt; switch (message) { case WM_CREATE: hBitmap = CreateBitmap(20, 5, 1, 1, bits); GetObject(hBitmap, sizeof(BITMAP), &bitmap); cxSource = bitmap.bmWidth; cySource = bitmap.bmHeight; return 0; case WM_SIZE: cxClient = LOWORD(lParam); cyClient = HIWORD(lParam); return 0; case WM_PAINT: hdc = BeginPaint(hwnd, &ps); hdcMem = CreateCompatibleDC(hdc); SelectObject(hdcMem, hBitmap); SaveDC(hdc); //将20*5像素的位图放大显示,类似于StretchBit函数 SetMapMode(hdc, MM_ANISOTROPIC); SetWindowExtEx(hdc, cxSource, cySource, NULL); //窗口的大小就是图像的大小 SetViewportExtEx(hdc, cxClient / 2, cyClient / 2, NULL);//视口大小为整个客户区 pt.x = cxClient / 4; pt.y = cyClient / 4; DPtoLP(hdc, &pt, 1); SetWindowOrgEx(hdc, -pt.x, -pt.y, NULL); //SetViewportOrgEx(hdc, cxClient / 4, cyClient / 4, NULL); //实现与SetWindowOrgEx一样的功能 BitBlt(hdc, 0, 0, cxSource, cySource, hdcMem, 0, 0, SRCCOPY); RestoreDC(hdc, -1); DeleteDC(hdcMem); EndPaint(hwnd, &ps); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam); }
14.4.6 位图画刷
(1)位图画刷至少8*8像素。
(2)调用CreatePatternBrush(hBitmap);
CreateBrushIndirect(LOGBRUSH *lplb);//结构体中的lbStyle设为BS_PATTERN
(3)删除画刷:DeleteObject(hBrush);
/*------------------------------------------------------------ BRICKS3.C -- CreatePatternBrush Demonstration (c) Charles Petzold, 1998 ------------------------------------------------------------*/ #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("Bricks3"); HWND hwnd; MSG msg; WNDCLASSEX wndclass; HBITMAP hBitmap; HBRUSH hBrush; hBitmap = LoadBitmap(hInstance, TEXT("Bricks")); hBrush = CreatePatternBrush(hBitmap); //创建位图画刷 DeleteObject(hBitmap); wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.cbSize = sizeof(WNDCLASSEX); wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInstance; wndclass.hIcon = LoadIcon(hInstance, szAppName); wndclass.hIconSm = LoadIcon(hInstance, szAppName); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = hBrush; wndclass.lpszMenuName = NULL; wndclass.lpszClassName = szAppName; if (!RegisterClassEx(&wndclass)) { MessageBox(NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR); return 0; } hwnd = CreateWindow(szAppName, // window class name TEXT("CreatePatternBrush Demo"), // window caption WS_OVERLAPPEDWINDOW, // window style CW_USEDEFAULT, // initial x position CW_USEDEFAULT, // initial y position CW_USEDEFAULT, // initial x size CW_USEDEFAULT, // initial y size NULL, // parent window handle NULL, // window menu handle hInstance, // program instance handle NULL); // creation parameters ShowWindow(hwnd, iCmdShow); UpdateWindow(hwnd); while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } DeleteObject(hBrush); return msg.wParam; } LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam); }
//resource.h
//{{NO_DEPENDENCIES}} // Microsoft Visual C++ 生成的包含文件。 // 供 Bricks3.rc 使用 // // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 102 #define _APS_NEXT_COMMAND_VALUE 40001 #define _APS_NEXT_CONTROL_VALUE 1001 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif
//Bricks3.rc
// Microsoft Visual C++ generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #include "winres.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // 中文(简体,中国) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE BEGIN "resource.h\0" END 2 TEXTINCLUDE BEGIN "#include ""winres.h""\r\n" "\0" END 3 TEXTINCLUDE BEGIN "\r\n" "\0" END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Bitmap // Bricks BITMAP "Bricks.bmp" #endif // 中文(简体,中国) resources ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED