区域和裁减区域-Window GDI
區域和裁減區域-Window GDI
原文:http://blog.csdn.net/windcsn/article/details/492436
區域的創建和選擇
一個應用程序通過調用指定形狀的函數來創建一個區域。下表顯示了創建標準圖形的函數
| 形狀 | 函數 |
| 矩形區域 | CreateRectRgn, CreateRectRgnIndirect, SetRectRgn |
| 圓角的矩形區域 | CreateRoundRectRgn |
| 橢圓區域 | CreateEllipticRgn, CreateEllipticRgnIndirect |
| 多邊形區域 | CreatePolygonRgn, CreatePolyPolygonRgn |
每個區域創建函數返回一個HANDLE來標示新創建的區域。一個應用程序可以通過調用SelectObject函數并將這個HANDLE作為第二個參數來將一個區域選擇進設備內容中。在一個區域被選擇進設備內容之后,應用程序可以對其執行各種操作。
區域操作
應用程序能夠合并區域、比較區域、著色和返回區域內部、給區域畫邊框、得到區域的大小和測試光標是否位于區域的范圍。
?
?
合并區域
應用程序通過調用CombineRgn函數來合并兩個區域。使用這個函數,應用程序能夠合并兩個區域的交集、兩個區域除交集之外的區域、兩個區域的并集等等。下面5個值定理了區域合并的類型。
| 值 | 意義 |
| RGN_AND | 兩個區域的交集 |
| RGN_COPY | 兩個區域的第一個區域作為新的區域 |
| RGN_DIFF | 第一個區域的部分減去兩個區域的交集 |
| RGN_OR | 兩個區域的并集 |
| RGN_XOR | 兩個區域的并集減去兩個區域的交集 |
下面圖形顯示了5種使用CombineRgn來操作正方形和圓合并的可能結果:
比較區域
應用程序通過調用EqualRgn來比較兩個區域來判斷他們是否一樣。EqualRgn認為如果兩個區域在形狀和大小上相等就認為他們相等。
填充區域
應用程序可以通過調用FillRgn并提供一個刷子來填充某區域的內部。當程序調用FillRgn時,系統使用特定的設備內容的當前填充模式刷子來填充區域。有良種填充模式:交替的和纏繞的。程序能調用SetPolyFillMode函數來設置一個設備內容的填充模式。應用程序調用GetPolyFillMode函數來得到設備內容的當前填充模式。
下圖描述了良種填充模式,一種使用交替模式,另一種使用纏繞模式。
交替模式
在交替模式下,為了判斷那些像素需要高亮,執行下面的測試:
1.在區域內部選擇一個像素
2.延正X軸方向畫一條虛設的光線,從像素開始到無窮遠
3.每次光線和邊界線相交的,增加一個記數值
系統高亮那些記數值是奇數的像素。
?
?
纏繞模式
為了判斷纏繞模式下那些像素需要高亮,需要執行下面測試:
1.在畫每個邊界線的時候判斷方向
2.在區域的內部選擇一個像素
3.畫一條光線,延正X方向,從像素點到無窮遠
4.每次光線與邊界線在正Y部分正交的時候,增加記數值,如果在Y負方向,減記數值。
所有非0的像素被高亮。
| AA |
| A |
| B |
在交替模式下:
A發出的光線經過了三條邊界,那么記數值為3,B經過了兩條邊界,記數值為2,所以A所在的區域為高亮,B所在的區域不是。
?
?
區域著色
應用程序使用當前選進設備內容的刷子來填充區域的內部,刷子通過PaintRgn函數來選擇的,這個函數使用當前的多邊形填充模式(交替和纏繞)。
?
?
反轉區域
程序通過調用InvertRgn函數來使區域的顏色反色。在單色的顯示設備上,InvertRgn是白色像素變黑,黑色像素變白。在彩色屏幕上,這個反轉依賴于產生屏幕顏色的技術類型。
?
?
為區域增加框架
應用程序可以調用FrameRgn函數來為區域周圍畫一個邊界,并指定邊界的寬度和刷子的模式。
?
?
得到區域的矩形范圍
應用程序通過調用GetRgnBox函數來得到區域邊界矩形的大小。如果區域是規則的,GetRgnBox返回區域的大小;如果區域是橢圓形,函數返回包圍在橢圓周圍的最小矩形的大小,長邊的長度和橢圓的主軸相等,短邊和橢圓的次軸相同。如果區域是多邊形,GetRgnBox返回最小的包圍多邊形的矩形。
?
?
移動區域
應用程序調用OffsetRgn函數來移動區域。給定的延X和Y軸防線的偏移決定了左右上下移動的邏輯單位。
?
?
點擊測試區域
應用在區域上執行點擊測試來判斷當前光標位置的坐標。然后傳遞這些坐標和區域的HANDLE給PtInRegion函數。光標的坐標可以由多種鼠標操作得到,例如WM_LBUTTONDOWN、WM_LBUTTONUP、WM_RBUTTONDOWN和WM_RBUTTONUP。PtInRegion函數的返回值指出當前光標位置是否在給定的區域內。
?
?
使用區域來裁減輸出
本節包含一個簡單的例子,介紹你怎么樣使用區域是用戶可以定義這樣輸出客戶區域的一部分。用作這個目的的區域被叫做裁減區域。
本節的例子,用戶可以通過程序來抓獲整個桌面為一位圖,但能保存圖象的一部分作為BMP文件。
通過單擊Define Clip Region菜單,用戶能夠通過單擊鼠標左鍵并拖動鼠標來選擇一個裁減區域。當用戶拖動鼠標的時候,應用程序畫一個相對于新裁減區域的矩形。
通過單擊Clip菜單,用戶能夠重畫指定矩形邊界內的圖像獨立部分。
本節提供下面的主題:
定義裁減區域
當用戶單擊Define Clip Region時,系統產生一個WM_COMMAND消息。該消息的wParam參數包含了程序自定義常量IDM_DEFINE,這指出用戶選擇了菜單,程序通過處理該輸出并設置布爾變量fDefineRegion,如下面的代碼:
case WM_COMMAND:
????switch (wParam)
????{
?
????????case IDM_DEFINE:
????????????fDefineRegion = TRUE;
????????????break;
在Define Clipping Region之后,用戶開始通過鼠標的單擊和拖動來畫矩形。
當用戶按下鼠標左鍵時,系統產生WM_LBUTTONDOWN消息,lParam參數包含了光標的位置,它對應于裁減區域矩形的左上角。程序處理WM_LBUTTONDOWN消息如下:
// These variables are required for clipping. static POINT ptUpperLeft; static POINT ptLowerRight; static POINT aptRect[5]; static POINT ptTmp; static POINTS ptsTmp; static BOOL fDefineRegion; static BOOL fRegionExists; static HRGN hrgn; static RECT rctTmp; int i; switch (message) { ????case WM_LBUTTONDOWN: ????????if (fDefineRegion) ????????{ ????????// Retrieve the new upper left corner. ????????????ptsTmp = MAKEPOINTS(lParam); ????????????ptUpperLeft.x = (LONG) ptsTmp.x; ????????????ptUpperLeft.y = (LONG) ptsTmp.y; ????????} ????????if (fRegionExists) ????????{ ????????????// Erase the previous rectangle. ????????????hdc = GetDC(hwnd); ????????????SetROP2(hdc, R2_NOTXORPEN); ????????????if (!Polyline(hdc, (CONST POINT *) aptRect, 5)) ????????????????errhandler("Polyline Failed", hwnd); ????????????ReleaseDC(hwnd, hdc); ????????????// Clear the rectangle coordinates. ????????????for (i = 0; i < 4; i++) ????????????{ ????????????????aptRect[i].x = 0; ????????????????aptRect[i].y = 0; ????????????} ????????????// Clear the temporary point structure. ????????????ptTmp.x = 0; ????????????ptTmp.y = 0; ????????????// Clear the lower right coordinates. ????????????ptLowerRight.x = 0; ????????????ptLowerRight.y = 0; ????????????// Reset the flag. ????????????fRegionExists = FALSE; ????????????fDefineRegion = TRUE; ????????????// Retrieve the new upper left corner. ????????????ptsTmp = MAKEPOINTS(lParam); ????????????ptUpperLeft.x = (LONG) ptsTmp.x; ????????????ptUpperLeft.y = (LONG) ptsTmp.y; ????????} ????break; }當用戶拖動鼠標的時候,系統產生WM_MOUSEMOVE消息并存儲新的光標位置到lParam參數中。每次應用程序接收到WM_MOUSEMOVE消息時,它都刪除先前的矩形(如果存在的話)并通過PolyLine函數來畫一個新的區域,以矩形的四個角的坐標,程序執行下面的工作。
// These variables are required for clipping. static POINT ptUpperLeft; static POINT ptLowerRight; static POINT aptRect[5]; static POINT ptTmp; static POINTS ptsTmp; static BOOL fDefineRegion; static BOOL fRegionExists; static HRGN hrgn; static RECT rctTmp; int i; switch (message) { ????case WM_MOUSEMOVE: ????if (wParam & MK_LBUTTON && fDefineRegion) ????{ ????????// Get a window DC. ????????hdc = GetDC(hwnd); ????????if (!SetROP2(hdc, R2_NOTXORPEN)) ????????????errhandler("SetROP2 Failed", hwnd); ????????// If previous mouse movement occurred, store the original ????????// lower right corner coordinates in a temporary structure. ???????//如果先前鼠標移動了,原來較小的右下角坐標到ptLowerRight ????????if (ptLowerRight.x) ????????{ ????????????ptTmp.x = ptLowerRight.x; ????????????ptTmp.y = ptLowerRight.y; ????????} ????????// Get the new coordinates of the clipping region's lower ????????// right corner. ????????//取得新的右下角的坐標 ????????ptsTmp = MAKEPOINTS(lParam); ????????ptLowerRight.x = (LONG) ptsTmp.x; ????????ptLowerRight.y = (LONG) ptsTmp.y; ????????// If previous mouse movement occurred, erase the original ????????// rectangle. ????????//如果鼠標已經移動了,刪除原來的矩形 ????????if (ptTmp.x) ????????{ ????????????aptRect[0].x = ptUpperLeft.x; ????????????aptRect[0].y = ptUpperLeft.y; ????????????aptRect[1].x = ptTmp.x; ????????????aptRect[1].y = ptUpperLeft.y; ????????????aptRect[2].x = ptTmp.x; ????????????aptRect[2].y = ptTmp.y; ????????????aptRect[3].x = ptUpperLeft.x; ????????????aptRect[3].y = ptTmp.y; ????????????aptRect[4].x = aptRect[0].x; ????????????aptRect[4].y = aptRect[0].y; ????????????if (!Polyline(hdc, (CONST POINT *) aptRect, 5)) ????????????????errhandler("Polyline Failed", hwnd); ????????} ????????aptRect[0].x = ptUpperLeft.x; ????????aptRect[0].y = ptUpperLeft.y; ????????aptRect[1].x = ptLowerRight.x; ????????aptRect[1].y = ptUpperLeft.y; ????????aptRect[2].x = ptLowerRight.x; ????????aptRect[2].y = ptLowerRight.y; ????????aptRect[3].x = ptUpperLeft.x; ????????aptRect[3].y = ptLowerRight.y; ????????aptRect[4].x = aptRect[0].x; ????????aptRect[4].y = aptRect[0].y; ????????if (!Polyline(hdc, (CONST POINT *) aptRect, 5)) ?????????????errhandler("Polyline Failed", hwnd); ????????ReleaseDC(hwnd, hdc); ????} ????break;?
?
裁減輸出
在用戶選擇Clip菜單之后,應用程序使用用戶創建的裁減區域的矩形坐標,在定義裁減區域后,將它選進程序的設備內容中,程序重畫位圖,程序執行下面的工作:
// These variables are required for clipping. static POINT ptUpperLeft; static POINT ptLowerRight; static POINT aptRect[5]; static POINT ptTmp; static POINTS ptsTmp; static BOOL fDefineRegion; static BOOL fRegionExists; static HRGN hrgn; static RECT rctTmp; int i; case WM_COMMAND: ????switch (wParam) ????{ ????case IDM_CLIP: ????hdc = GetDC(hwnd); ????// Retrieve the application's client rectangle and paint // with the default (white) brush. //得到程序的客戶區矩形,并用白刷子填充 ????GetClientRect(hwnd, &rctTmp); ????FillRect(hdc, &rctTmp, GetStockObject(WHITE_BRUSH)); // Use the rect coordinates to define a clipping region. //使用rect的坐標來定義一個裁減區域 ????hrgn = CreateRectRgn(aptRect[0].x, aptRect[0].y, ????????aptRect[2].x, aptRect[2].y); ????SelectClipRgn(hdc, hrgn); // Transfer (draw) the bitmap into the clipped rectangle. //將位圖畫到裁減矩形中 ????BitBlt(hdc, ???????0, 0, ???????bmp.bmWidth, bmp.bmHeight, ???????hdcCompatible, ???????0, 0, ???????SRCCOPY); ????ReleaseDC(hwnd, hdc); ????break; ????}總結
以上是生活随笔為你收集整理的区域和裁减区域-Window GDI的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 裁剪(Clipping)-Window
- 下一篇: 图片镂空算法集合[图](转)