14.1 位图基础
(1)位图和图元文件的区别:位图是点阵图形;图元文件是矢量图形
(2)位图的缺点:
①受设备相关的影响(如色彩、分辨率、纵横比例)
②需要很大的存储空间:如640×480像素,16种颜色(4位),需要640*480*4/8/1024(即150KB);1024×768像素,24位图形需要1024*768*24/8/1024/1024(即2.25MB)。位图的存储空间是由图像大小和它所包含颜色的数目决定。而图元文件的存储空间是由图像的复杂度和它所包含的GDI命令的个数来决定的。
(3)位图的优点:速度快,将位图复制到视频显示器,通常比绘制一个图元文件要快得多。
14.2 位图尺寸
14.2.1 颜色和位图
(1)颜色深度(Color Depth):每个像素需要的位的数目。也称位数(bit-count)或每像素位数(bits per pixel,bpp)。
(2)单色位图:每个像素只有1位,也称为“二级(bitlevel)”或“二色”位图。
(3)位数(n)和所能表示的颜色数目(m): m =2^n
14.2.2 现实世界的设备
(1)CGA和HGC显卡:单色(1位)
(2)EGA:16种颜色(4位)。EGA提供64种颜色的调色板,但应用程序只能选16种)。
①16色位图的色彩编码IRGB(强度—红—绿—蓝)
②EGA把内存分为4个“颜色平面”,分别是强度、红、绿、蓝。而每个像素颜色的定义是分别从这4个平面中取1位出来组合得一个IRGB值,然后将此值做为索引从下列表格中取出相应的RGB颜色。
③IRGB值与RGB颜色值的对应关系
IRGB |
RGB颜色 |
颜色名称 |
IRGB |
RGB颜色 |
颜色名称 |
|
0000 |
00-00-00 |
黑 |
1000 |
80-80-80 |
深灰 |
|
0001 |
00-00-80 |
深蓝 |
1001 |
00-00-FF |
蓝 |
|
0010 |
00-80-00 |
深绿 |
1010 |
00-FF-00 |
绿 |
|
0011 |
00-80-80 |
深青 |
1011 |
00-FF-FF |
青 |
|
0100 |
80-00-00 |
深红 |
1100 |
FF-00-00 |
红 |
|
0101 |
80-00-80 |
深洋红 |
1101 |
FF-00-FF |
洋红 |
|
0110 |
80-80-00 |
深黄 |
1110 |
FF-FF-00 |
黄 |
|
0111 |
C0-C0-C0 |
浅灰 |
1111 |
FF-FF-FF |
白 |
(3)VGA或SVGA显卡:256种颜色(每个像素用8位,不一定对应具体的颜色),显卡采用的是“调色板查找表”的方式。其中20种是保留颜色,其作236种可以自定义。
(4)全真彩显卡:16位或24位。现在一般用24位。即每个像素用3个字节表示。
14.3 位块传输
14.3.1 几个位块传输函数
(1)BitBlt函数:BitBlt(hdcDst,xDst,yDst,cx,cy,hdcSrc,xSrc,ySrc,dwROP);
①从“源”设备环境传输到“目标”设备环境(注意是从DC到DC的传输,源是来自DC而不是资源文件)。
②源和目标设备可以相同
③最重要限制是两个设备一定要“兼容”,如无法从屏幕的东西blt到打印机DC中。
④坐标单位和尺寸是基于逻辑单位的。而图像的尺寸cx和cy是源和目标设备共用的参数。如果当源和设备的逻辑单位不同(即映射模式不同)时,图像会被缩放,相当于StretchBlt函数,但其灵活性不如StretchBlt。
【BitBlt程序】注意由于Win7的Aero特性,标题栏等非客户区会出现毛玻璃效果,从而使该程序不能正常运行!
效果图
/*------------------------------------------------------------ BITBLT.C -- BitBlt 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("BitBlt"); 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(NULL, IDI_INFORMATION); wndclass.hIconSm = LoadIcon(NULL, IDI_INFORMATION); 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("BitBlt 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) { static int cxClient, cyClient, cxSource, cySource; HDC hdcClient, hdcWindow; PAINTSTRUCT ps; switch (message) { case WM_CREATE: //cxSource=边框+标题栏中图标按钮的宽度 cxSource = GetSystemMetrics(SM_CXSIZEFRAME) + GetSystemMetrics(SM_CXSIZE); //cySource=边框+标题栏高度 cySource = GetSystemMetrics(SM_CYSIZEFRAME) + GetSystemMetrics(SM_CYCAPTION); return 0; case WM_SIZE: cxClient = LOWORD(lParam); cyClient = HIWORD(lParam); return 0; case WM_PAINT: hdcClient = BeginPaint(hwnd, &ps); hdcWindow = GetWindowDC(hwnd); //整个窗口含非客户区的dc for (int y = 0; y < cyClient; y += cySource) for (int x = 0; x < cxClient; x += cxSource) { BitBlt(hdcClient, x, y, cxSource, cySource, hdcWindow, 0, 0, SRCCOPY); } ReleaseDC(hwnd, hdcWindow); EndPaint(hwnd, &ps); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam); }
(2)StretchBlt函数:——拉伸位图
StretchBlt(hdcDst,xDst,yDst,cxDst,cyDst,hdcSrc,xSrc,ySrc,cxSrc,cySrc, dwPOP);
①除拉伸外,还可以镜像图像或翻转图像。如将cxSrc或cxDst符号
②拉伸模式:SetStreatchBltMode(hdc,iMode)——拉伸或缩小时,像素的复制或合并
模式 |
说明 |
BLACKONWHITE STRETCH_ANDSCANS(默认) |
如果两个或多个像素必须结合与一个像素,则进行逻辑与操作。像素都是白是,结果才是白。也就是合并的结果一般给出黑色,只有都是白色是才为白。这对白底黑色图案的单色位图来说比较好。 |
WHITEONBLACK STRETCH_ORSCANS |
逻辑或运算。当像素都是黑时,才是黑色。也就是合并的结果一般给出白色,只有像素都是黑色是才是黑的。这对黑底白色图像的单色位置比较好。 |
COLORONCOLOR STRETCH_DELETESCANS |
简单地去掉像素行或列。这对彩色位图常是最佳的方法。 |
HALFTONE STRETCH_HALFTONE |
结合源的颜色,计算平均目标颜色。一般和半色调色板一起使用(见第16章) |
【StretchBlt程序】——注意在Win7下会出现与BitBlt程序一样的问题
效果图
/*------------------------------------------------------------ STRETCH.C -- StretchBlt 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("StretchBlt"); 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(NULL, IDI_INFORMATION); wndclass.hIconSm = LoadIcon(NULL, IDI_INFORMATION); 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("StretchBlt 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) { static int cxClient, cyClient, cxSource, cySource; HDC hdcClient, hdcWindow; PAINTSTRUCT ps; switch (message) { case WM_CREATE: //cxSource=边框+标题栏中图标按钮的宽度 cxSource = GetSystemMetrics(SM_CXSIZEFRAME) + GetSystemMetrics(SM_CXSIZE); //cySource=边框+标题栏高度 cySource = GetSystemMetrics(SM_CYSIZEFRAME) + GetSystemMetrics(SM_CYCAPTION); return 0; case WM_SIZE: cxClient = LOWORD(lParam); cyClient = HIWORD(lParam); return 0; case WM_PAINT: hdcClient = BeginPaint(hwnd, &ps); hdcWindow = GetWindowDC(hwnd); //整个窗口含非客户区的dc StretchBlt(hdcClient, 0, 0, cxClient, cyClient, hdcWindow, 0, 0, cxSource, cySource, SRCCOPY); ReleaseDC(hwnd, hdcWindow); EndPaint(hwnd, &ps); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam); }
(3)PatBlt——图案块传输:PatBlt(hdc,x,y,cx,cy,dwROP);
①单位都是基于逻辑单位的
②该函数没有源句柄,因为源为hdc中的画刷句柄。
③PatBlt和FillRect函数比较
应用举例 |
函数调用的差别 |
绘制黑色矩形 |
PatBlt(hdc,x,y,cx,cy,BLCKNESS); |
FillRect(hdc,&rect,hBrush); //hBrush为黑色画刷,内部也是通过PatBlt的。 |
|
反转矩形颜色 |
PatBlt(hdc,x,y,cx,cy,DSTINVERT); |
InvertRect(hdc,&rect);//内部调用PatBlt |
14.3.2 光栅操作ROP
(1)位块传输时要涉及三个图像像素位的操作
①源:将源位图拉伸或压缩成目标矩形同样的大小
②目标:函数调用前的目标矩形
③图案:即目标设备上的画刷,要在横向和纵向上不断重复,直到与目标区域一样大。
(2)支持BitBlt、StretchBlt与PatBlt的光栅操作不同(见MSDN相应的函数说明)
14.3.3 单顶点和逻辑矩形问题——以PatBlt(hdc,x,y,cx,cy,dwROP)为例
(1)GDI绘图函数中,只有BitBlt、PatBlt、StretchBlt是以单个顶点加边长来规定逻辑矩形坐标的。其他的函数都要求左上角和右下角坐标。
(2)不同映射模式下顶点坐标和逻辑矩形的设置