设备上下文(DC)与内存设备上下文中的位图与画刷属性的一些零碎

设备内容

众所周知,设备上下文是一种包含有关某个设备,如显示器、打印机等的绘制属性信息的WINDOWS数据结构。所有绘制调用都是通过设备上下文对象进行,其中这些对象中包含了画笔,位图,画刷等。设备内容与特定的显示设备相关,对于视讯显示器,设备内容总是与显示器上的特定的窗口相关。

设备内容中的有些值是图形属性,这些属性定义了GDI绘图函数的工作细节,for example,TextOut,设备内容的属性中确定了文字的颜色,文字的背景色,x坐标,Y坐标映射到所要显示区域的方式,还有显示这些文字时系统使用的字体。

当一个程序需要绘图时,首先要取得设备内容句柄,得到此句柄后,Windows用内定的属性填充内部设备内容结构中。绘制完毕之后,必须释放设备内容句柄。

内存设备内容

通过使用一个特别为位图操作的设备环境,可以使得应用程序将输出操作在内存中而不是将其发送到实际的设备中。内存设备环境使得系统将一部分内存当作虚拟设备。它就是一个在内存中的位数组,使得应用程序可以使用它为在一个标准的绘图表面创建位图临时存储颜色数据。由于位图是和设备兼容的,因此内存设备环境在某些时候也就当作兼容设备环境。

内存设备环境作为一个特殊的环境存储位图图像。应用程序可以调用 CreateCompatibleDC 创建一个内存设备环境。

内存设备环境中初始的位图只是一个简单的占位符。它的尺寸为1*1像素。在应用程序进行绘制之前,必须通过调用 SelectObject 选择一个恰当宽度和高度的位图到该内存环境中。要创建一个恰当尺寸的位图,可以使用 CreateBitmap , CreateBitmapIndirect , or CreateCompatibleBitmap 三个函数。当位图被选进内存设备环境后,系统用一个足够大的数组取代单位数组来存储指定的矩形像素的颜色信息。

当应用程序传递一个由 CreateCompatibleDC 返回的句柄到绘制函数时,被要求的输出并不会在设备的绘制表面显示。相反,系统会存储线段,曲线,文字或者区域的颜色信息到位数组中。应用程序可以复制存储在内存中的图像到绘制表面通过调用 BitBlt 函数,并将内存设备环境作为源设备环境,窗口或者屏幕设备环境作为目标设备环境。

例子1:

/*------------------------------------------- BITMASK.C -- Bitmap Masking 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 ("BitMask") ; 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 (LTGRAY_BRUSH) ; wndclass.lpszMenuName = NULL ; wndclass.lpszClassName = szAppName ; if (!RegisterClass (&wndclass)) { MessageBox (NULL, TEXT ("This program requires Windows NT!"), szAppName, MB_ICONERROR) ; return 0 ; } hwnd = CreateWindow (szAppName, TEXT ("Bitmap Masking Demo"), 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) { static HBITMAP hBitmapImag, hBitmapMask ; static HINSTANCE hInstance ; static int cxClient, cyClient, cxBitmap, cyBitmap ; BITMAP bitmap ; HDC hdc, hdcMemImag, hdcMemMask ; int x, y ; PAINTSTRUCT ps ; HBRUSH hBrush; HBITMAP hBitmap; RECT rect; switch (message) { case WM_CREATE: hInstance = ((LPCREATESTRUCT) lParam)->hInstance ; // Load the original image and get its size hBitmapImag = LoadBitmap (hInstance, TEXT ("Matthew")) ; hBrush=CreatePatternBrush(hBitmapImag); GetObject (hBitmapImag, sizeof (BITMAP), &bitmap) ; cxBitmap = bitmap.bmWidth ; cyBitmap = bitmap.bmHeight ; // Select the original image into a memory DC hdcMemImag = CreateCompatibleDC (NULL) ; SelectObject (hdcMemImag, hBitmapImag) ; // Create the monochrome mask bitmap and memory DC hBitmapMask = CreateBitmap (cxBitmap, cyBitmap, 1, 1, NULL) ; hdcMemMask = CreateCompatibleDC (NULL) ; SelectObject (hdcMemMask, hBitmapMask) ; // Color the mask bitmap black with a white ellipse SelectObject (hdcMemMask, GetStockObject (BLACK_BRUSH)) ; Rectangle (hdcMemMask, 0, 0, cxBitmap, cyBitmap) ; SelectObject (hdcMemMask, GetStockObject (WHITE_BRUSH)) ; Ellipse (hdcMemMask, 0, 0, cxBitmap, cyBitmap) ; // Mask the original image BitBlt (hdcMemImag, 0, 0, cxBitmap, cyBitmap, hdcMemMask, 0, 0, SRCAND) ; DeleteDC (hdcMemImag) ; DeleteDC (hdcMemMask) ; return 0 ; case WM_SIZE: cxClient = LOWORD (lParam) ; cyClient = HIWORD (lParam) ; return 0 ; case WM_PAINT: hBitmap = LoadBitmap (hInstance, TEXT ("Matthew")) ; hBrush=CreatePatternBrush(hBitmap); hdc = BeginPaint (hwnd, &ps) ; rect.left=0; rect.top=0; rect.right=200; rect.bottom=320; Rectangle(hdc,rect.left,rect.top,rect.right,rect.bottom); FillRect(hdc,&rect,hBrush); // Select bitmaps into memory DCs hdcMemImag = CreateCompatibleDC (hdc) ; SelectObject (hdcMemImag, hBitmapImag) ; hdcMemMask = CreateCompatibleDC (hdc) ; SelectObject (hdcMemMask, hBitmapMask) ; // Center image x = (cxClient - cxBitmap) / 2 ; y = (cyClient - cyBitmap) / 2 ; // Do the bitblts //BitBlt (hdc, x, y, cxBitmap, cyBitmap, hdcMemMask, 0, 0, 0x220326) ; //BitBlt (hdc, x, y, cxBitmap, cyBitmap, hdcMemImag, 0, 0, SRCPAINT) ; BitBlt (hdc, x, y, cxBitmap, cyBitmap, hdcMemImag, 0, 0, SRCCOPY) ; DeleteDC (hdcMemImag) ; DeleteDC (hdcMemMask) ; DeleteObject(hBrush); EndPaint (hwnd, &ps) ; return 0 ; case WM_DESTROY: DeleteObject (hBitmapImag) ; DeleteObject (hBitmapMask) ; PostQuitMessage (0) ; return 0 ; } return DefWindowProc (hwnd, message, wParam, lParam) ; }

WINDOWS程序设计中位图那章的例子稍微修改了一下,运行结果发现,位图已经变化了,即不再是刚开始从外部导入的那个图片了(图片的主人是作者查尔斯的侄子),从代码中可以看到

首先hBitmapImag = LoadBitmap (hInstance, TEXT ("Matthew")) ;加载了一副位图

hdcMemImag  = CreateCompatibleDC (NULL) ;

SelectObject (hdcMemImag, hBitmapImag) ;并且接着选进了内存设备内容中

其次BitBlt (hdcMemImag, 0, 0, cxBitmap, cyBitmap, hdcMemMask, 0, 0, SRCAND) ;对位图进行了修改,此时的修改毫无疑问修改的是内存设备内容中的位图,修改的方法很简单也很巧妙但却是很有用途的(创建单色位图,其实可以借助这个思路来实现创建透明位图的,这里不多啰嗦)

最后我们在客户区中央输出位图发现输出的是修改过的位图,另外不要被代码中创建的位图画刷所干扰,只是为了结合例子2,达到比较的效果。

可以得出简单的结论:位图被选进内存设备内容中的时候,其实就是选进了位图自身,而不是位图的副本,因此在内存设备内容中修改位图也必然会及时反馈到位图本身的。所以输出的位图是变化后的位图。

例子2;

BRICKS3.C /*------------------------------------------------------------------------- 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") ; HBITMAP hBitmap ; HBRUSH hBrush ; HWND hwnd ; MSG msg ; WNDCLASS wndclass ; hBitmap = LoadBitmap (hInstance, TEXT ("Bricks")) ; hBrush = CreatePatternBrush (hBitmap) ; DeleteObject (hBitmap) ; 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 ; wndclass.lpszMenuName = NULL ; wndclass.lpszClassName = szAppName ; if (!RegisterClass (&wndclass)) { MessageBox ( NULL, TEXT ("This program requires Windows NT!"), szAppName, MB_ICONERROR) ; return 0 ; } hwnd = CreateWindow (szAppName, TEXT ("CreatePatternBrush Demo"), 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) ; } 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) ; }

同样来自这本书上的一个砖块例子,用的是位图画刷来实现的。

我们只对三行代码感兴趣:

           hBitmap = LoadBitmap (hInstance, TEXT ("Bricks")) ;
       
           hBrush = CreatePatternBrush (hBitmap) ;
       
           DeleteObject (hBitmap) ;
加载位图,创建位图画刷,然后立刻删除到此位图。

结果却是正确的,并没有因为删除掉作为画刷的位图而影响画刷本身。

这个例子也可以得出结论:位图被用来创建画刷,此时画刷中的位图是外部位图的一个副本,删除不删除互相不影响,因为彼此已经独立了。

大致可以这样来体会DC吧:

每个DC都关联了很多对象,比如位图,画刷等,DC得到这些对象的指针,以后对DC的操作都是对关联的对象的操作。

创建画刷则是根据位图的内容,创建一个画刷,这个画刷的内容是从位图上复制过来的,副本,创建完毕后,这个位图跟此画刷已经没有任何联系了,彼此独立,删除位图也不会影响到画刷。

例子3用来证明上述观点:

/*------------------------------------------- BITMASK.C -- Bitmap Masking 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 ("BitMask") ; 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 (LTGRAY_BRUSH) ; wndclass.lpszMenuName = NULL ; wndclass.lpszClassName = szAppName ; if (!RegisterClass (&wndclass)) { MessageBox (NULL, TEXT ("This program requires Windows NT!"), szAppName, MB_ICONERROR) ; return 0 ; } hwnd = CreateWindow (szAppName, TEXT ("Bitmap Masking Demo"), 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) { static HBITMAP hBitmapImag, hBitmapMask ; static HINSTANCE hInstance ; static int cxClient, cyClient, cxBitmap, cyBitmap ; BITMAP bitmap ; HDC hdc, hdcMemImag, hdcMemMask ; int x, y ; PAINTSTRUCT ps ; static HBRUSH hBrush;//定义一个画刷,方便测试定义为静态变量 RECT rect; switch (message) { case WM_CREATE: hInstance = ((LPCREATESTRUCT) lParam)->hInstance ; // Load the original image and get its size hBitmapImag = LoadBitmap (hInstance, TEXT ("Matthew")) ; hBrush=CreatePatternBrush(hBitmapImag);//利用原始位图创建位图画刷 GetObject (hBitmapImag, sizeof (BITMAP), &bitmap) ; cxBitmap = bitmap.bmWidth ; cyBitmap = bitmap.bmHeight ; // Select the original image into a memory DC hdcMemImag = CreateCompatibleDC (NULL) ; SelectObject (hdcMemImag, hBitmapImag) ; // Create the monochrome mask bitmap and memory DC hBitmapMask = CreateBitmap (cxBitmap, cyBitmap, 1, 1, NULL) ; hdcMemMask = CreateCompatibleDC (NULL) ; SelectObject (hdcMemMask, hBitmapMask) ; // Color the mask bitmap black with a white ellipse SelectObject (hdcMemMask, GetStockObject (BLACK_BRUSH)) ; Rectangle (hdcMemMask, 0, 0, cxBitmap, cyBitmap) ; SelectObject (hdcMemMask, GetStockObject (WHITE_BRUSH)) ; Ellipse (hdcMemMask, 0, 0, cxBitmap, cyBitmap) ; // Mask the original image BitBlt (hdcMemImag, 0, 0, cxBitmap, cyBitmap, hdcMemMask, 0, 0, SRCAND) ;//位图改变,位图画刷改变不改变此时不晓得 DeleteDC (hdcMemImag) ; DeleteDC (hdcMemMask) ; return 0 ; case WM_SIZE: cxClient = LOWORD (lParam) ; cyClient = HIWORD (lParam) ; return 0 ; case WM_PAINT: hdc = BeginPaint (hwnd, &ps) ; rect.left=0; rect.top=0; rect.right=200; rect.bottom=320; Rectangle(hdc,rect.left,rect.top,rect.right,rect.bottom); FillRect(hdc,&rect,hBrush);//用位图画刷填充此区域,测试位图改变是否影响到了位图画刷 // Select bitmaps into memory DCs hdcMemImag = CreateCompatibleDC (hdc) ; SelectObject (hdcMemImag, hBitmapImag) ; hdcMemMask = CreateCompatibleDC (hdc) ; SelectObject (hdcMemMask, hBitmapMask) ; // Center image x = (cxClient - cxBitmap) / 2 ; y = (cyClient - cyBitmap) / 2 ; // Do the bitblts //BitBlt (hdc, x, y, cxBitmap, cyBitmap, hdcMemMask, 0, 0, 0x220326) ; //BitBlt (hdc, x, y, cxBitmap, cyBitmap, hdcMemImag, 0, 0, SRCPAINT) ; BitBlt (hdc, x, y, cxBitmap, cyBitmap, hdcMemImag, 0, 0, SRCCOPY) ;//证明位图是否改变 DeleteDC (hdcMemImag) ; DeleteDC (hdcMemMask) ; EndPaint (hwnd, &ps) ; return 0 ; case WM_DESTROY: DeleteObject (hBitmapImag) ; DeleteObject (hBitmapMask) ; DeleteObject(hBrush);//必须放到WM_DESTROY中,放在WM_PAINT中就会被删除,下次将消失掉 PostQuitMessage (0) ; return 0 ; } return DefWindowProc (hwnd, message, wParam, lParam) ; }

代码中关键改变位置进行了注释,需要资源文件可以借助WINDOWS程序设计这本书中的源文件,或者干脆选自己一张长的比较清秀的图片来测试吧。

 

你可能感兴趣的:(windows,image,null,application,callback,winapi)