Windows GDI三元光栅操作
2011-03-06 15:19:58| 分类: windows程序设计 | 标签: |字号大中小 订阅
Windows 绘图是在DC(device context)中进行。所有的的位图操作都会涉及到源位图,目的位图和当前DC的画刷。这三者之间可以进行逻辑与,逻辑或,逻辑非和逻辑异或操作。三者的不同组合一共构成了256种操作的结果,也就是有256种三元光栅操作。使用BitBlt、PatBlt和StretchBlt时都会使用到这三钟光栅操作码,即ROP 码,像SRCCOPY ,PATPAINT ,SRCAND 等。这256种光栅操作在windows种由四个字节定义,他们都是规定好的。其高位字(high-order word)是布尔操作索引,其低位字(low-order word)是操作码。16位的操作索引从0开始。具体的十六进制值如下所示,你会发现这些编码是从0x00 - 0xFF.
0x000042 ,0x010289 ,0x020C89 ,0x0300AA ,0x040C88 ,0x0500A9 ,0x060865 ,0x0702C5 ,
0x080F08 ,0x090245 ,0x0A0329 ,0x0B0B2A ,0x0C0324 ,0x0D0B25 ,0x0E08A5 ,0x0F0001 ,
0x100C85 ,0x1100A6 ,0x120868 ,0x1302C8 ,0x140869 ,0x1502C9 ,0x165CCA ,0x171D54 ,
0x180D59 ,0x191CC8 ,0x1A06C5 ,0x1B0768 ,0x1C06CA ,0x1D0766 ,0x1E01A5 ,0x1F0385 ,
0x200F09 ,0x210248 ,0x220326 ,0x230B24 ,0x240D55 ,0x251CC5 ,0x2606C8 ,0x271868 ,
0x280369 ,0x2916CA ,0x2A0CC9 ,0x2B1D58 ,0x2C0784 ,0x2D060A ,0x2E064A ,0x2F0E2A ,
0x30032A ,0x310B28 ,0x320688 ,0x330008 ,0x3406C4 ,0x351864 ,0x3601A8 ,0x370388 ,
0x38078A ,0x390604 ,0x3A0644 ,0x3B0E24 ,0x3C004A ,0x3D18A4 ,0x3E1B24 ,0x3F00EA ,
0x400F0A ,0x410249 ,0x420D5D ,0x431CC4 ,0x440328 ,0x450B29 ,0x4606C6 ,0x47076A ,
0x480368 ,0x4916C5 ,0x4A0789 ,0x4B0605 ,0x4C0CC8 ,0x4D1954 ,0x4E0645 ,0x4F0E25 ,
0x500325 ,0x510B26 ,0x5206C9 ,0x530764 ,0x5408A9 ,0x550009 ,0x5601A9 ,0x570389 ,
0x580785 ,0x590609 ,0x5A0049 ,0x5B18A9 ,0x5C0649 ,0x5D0E29 ,0x5E1B29 ,0x5F00E9 ,
0x600365 ,0x6116C6 ,0x620786 ,0x630608 ,0x640788 ,0x650606 ,0x660046 ,0x6718A8 ,
0x6858A6 ,0x690145 ,0x6A01E9 ,0x6B178A ,0x6C01E8 ,0x6D1785 ,0x6E1E28 ,0x6F0C65 ,
0x700CC5 ,0x711D5C ,0x720648 ,0x730E28 ,0x740646 ,0x750E26 ,0x761B28 ,0x7700E6 ,
0x7801E5 ,0x791786 ,0x7A1E29 ,0x7B0C68 ,0x7C1E24 ,0x7D0C69 ,0x7E0955 ,0x7F03C9 ,
0x8003E9 ,0x810975 ,0x820C49 ,0x831E04 ,0x840C48 ,0x851E05 ,0x8617A6 ,0x8701C5 ,
0x8800C6 ,0x891B08 ,0x8A0E06 ,0x8B0666 ,0x8C0E08 ,0x8D0668 ,0x8E1D7C ,0x8F0CE5 ,
0x900C45 ,0x911E08 ,0x9217A9 ,0x9301C4 ,0x9417AA ,0x9501C9 ,0x960169 ,0x97588A ,
0x981888 ,0x990066 ,0x9A0709 ,0x9B07A8 ,0x9C0704 ,0x9D07A6 ,0x9E16E6 ,0x9F0345 ,
0xA000C9 ,0xA11B05 ,0xA20E09 ,0xA30669 ,0xA41885 ,0xA50065 ,0xA60706 ,0xA707A5 ,
0xA803A9 ,0xA90189 ,0xAA0029 ,0xAB0889 ,0xAC0744 ,0xAD06E9 ,0xAE0B06 ,0xAF0229 ,
0xB00E05 ,0xB10665 ,0xB21974 ,0xB30CE8 ,0xB4070A ,0xB507A9 ,0xB616E9 ,0xB70348 ,
0xB8074A ,0xB906E6 ,0xBA0B09 ,0xBB0226 ,0xBC1CE4 ,0xBD0D7D ,0xBE0269 ,0xBF08C9 ,
0xC000CA ,0xC11B04 ,0xC21884 ,0xC3006A ,0xC40E04 ,0xC50664 ,0xC60708 ,0xC707AA ,
0xC803A8 ,0xC90184 ,0xCA0749 ,0xCB06E4 ,0xCC0020 ,0xCD0888 ,0xCE0B08 ,0xCF0224 ,
0xD00E0A ,0xD1066A ,0xD20705 ,0xD307A4 ,0xD41D78 ,0xD50CE9 ,0xD616EA ,0xD70349 ,
0xD80745 ,0xD906E8 ,0xDA1CE9 ,0xDB0D75 ,0xDC0B04 ,0xDD0228 ,0xDE0268 ,0xDF08C8 ,
0xE003A5 ,0xE10185 ,0xE20746 ,0xE306EA ,0xE40748 ,0xE506E5 ,0xE61CE8 ,0xE70D79 ,
0xE81D74 ,0xE95CE6 ,0xEA02E9 ,0xEB0849 ,0xEC02E8 ,0xED0848 ,0xEE0086 ,0xEF0A08 ,
0xF00021 ,0xF10885 ,0xF20B05 ,0xF3022A ,0xF40B0A ,0xF50225 ,0xF60265 ,0xF708C5 ,
0xF802E5 ,0xF90845 ,0xFA0089 ,0xFB0A09 ,0xFC008A ,0xFD0A0A ,0xFE02A9 ,0xFF0062
其实这些光栅操作编码只需要一个字节来定义就够了。如果P是画笔,S是源头像, D是目标位。给出如下的定义:
如果操作的结果总是P,那么定义它为Rop_P = 0xF0 //1 1 1 1 0 0 0 0
如果操作的结果总是S,那么定义它为Rop_S = 0xCC//1 1 0 0 1 1 0 0
如果操作的结果总是D,那么定义它为Rop_D =0xAA//1 0 1 0 1 0 1 0
所有的其它光栅操作都可以由这三个操作推导出来。布尔逻辑操作逻辑与用AND(或&)表示,逻辑或用OR(或 || )表示,逻辑非用NOT(~)表示,逻辑异或用XOR(或^)表示。比如有如下的需求:
① 如果源位图是1,目标为0,那么操作的结果是源位图;如果源位图是0,目标为1,那么操作的结果是目标位图。
根据这个描述可以得到这个格式:(Rop_S & ~Rop_D) || (~Rop_S & Rop_D) 代入上面的值,可以得到结果0x66。查表可得这个光栅操作的编码为:0x660046 根据描述,这个操作的结果其实就是源位图和目标位图的逻辑异或,为SRCINVERT。在文件wingid.h种有如下定义:
#define SRCINVERT (DWORD)0x00660046
因此这个推导是正确的。
② 如果源位图是1,那么结果是0;如果源位图为1,那么结果是目标位图。
根据这个描述可以得到这个格式:~Rop_S || (~Rop_S && Rop_D) 代码上面的值,可以得到结果0x22。查表可得这个光栅操作的编码为:0x220326
有了以上两个光栅操作。我们就可以把一个位图椭圆化显示出来。
如下图所示:
上门图中左边是源位图,右边是把这个位图以椭圆化显示出来。具体代码如下:
static HBITMAP hBitmapImag,hBitmapImag1, hBitmapMask ;
static HINSTANCE hInstance ;
static int cxClient, cyClient, cxBitmap, cyBitmap ;
BITMAP bitmap, bitmap1;
static HDC hdc, hdcMemImag, hdcMemMask, hdcMemImag1 ;
int x, y ;
PAINTSTRUCT ps ;
switch (message)
{
case WM_CREATE:
hInstance = ((LPCREATESTRUCT) lParam)->hInstance ;
// Load the original image and get its size
hBitmapImag = LoadBitmap (hInstance, TEXT ("Matthew1")) ;
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) ;
hBitmapImag1 = LoadBitmap (hInstance, TEXT ("Matthew1")) ;
GetObject (hBitmapImag1, sizeof (BITMAP), &bitmap1) ;
hdcMemImag1 = CreateCompatibleDC (NULL) ;
SelectObject (hdcMemImag1, hBitmapImag1) ;
// 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 (hdcMemImag1) ;
DeleteDC (hdcMemImag) ;
DeleteDC (hdcMemMask) ;
return 0 ;
case WM_SIZE:
cxClient = LOWORD (lParam) ;
cyClient = HIWORD (lParam) ;
return 0 ;
case WM_PAINT:
hdc = BeginPaint (hwnd, &ps) ;
// Select bitmaps into memory DCs
hdcMemImag = CreateCompatibleDC (hdc) ;
SelectObject (hdcMemImag, hBitmapImag) ;
hdcMemMask = CreateCompatibleDC (hdc) ;
SelectObject (hdcMemMask, hBitmapMask) ;
// Center image
x = (cxClient - cxBitmap) / 4 ;
y = (cyClient - cyBitmap) / 2 ;
// Do the bitblts
BitBlt (hdc, x, y, cxBitmap, cyBitmap, hdcMemImag1, 0, 0, SRCCOPY) ;
BitBlt (hdc, 3*x, y, cxBitmap, cyBitmap, hdcMemMask, 0, 0, 0x220326) ;//反色
BitBlt (hdc, 3*x, y, cxBitmap, cyBitmap, hdcMemImag, 0, 0, SRCPAINT) ;
DeleteDC (hdcMemImag) ;
DeleteDC (hdcMemMask) ;
EndPaint (hwnd, &ps) ;
return 0 ;
case WM_DESTROY:
DeleteObject (hBitmapImag1) ;
DeleteObject (hBitmapImag) ;
DeleteObject (hBitmapMask) ;
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam)