Windows编程之非矩形位图

windows下画一张非矩形的位图并不容易,主要是因为外部的位图一般是矩形状的,如果要将此矩形状的位图显示成非矩形图(即只显示大图中一部分形状),需要采用“掩码”位图和一些光栅操作。这个在一些小游戏中很常用,使用一张大图,将游戏中常用的小图标都包含进去,然后挨个读取其中的一些图标来单独操作。

1,根据《Windows程序设计》的例子,先看两张图:

                                             

                      原图                                                                            实现后的效果(图1.2)

2,实现代码

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 ;
     
     switch (message) {
     case WM_CREATE:
          hInstance = ((LPCREATESTRUCT) lParam)->hInstance ;
          hBitmapImag = LoadBitmap (hInstance, TEXT ("Matthew")) ;
          GetObject (hBitmapImag, sizeof (BITMAP), &bitmap) ;
          cxBitmap = bitmap.bmWidth ;
          cyBitmap = bitmap.bmHeight ;
          hdcMemImag  = CreateCompatibleDC (NULL) ;
          SelectObject (hdcMemImag, hBitmapImag) ;

          hBitmapMask = CreateBitmap (cxBitmap, cyBitmap, 1, 1, NULL) ;
          hdcMemMask = CreateCompatibleDC (NULL) ;
          SelectObject (hdcMemMask, hBitmapMask) ;
          
          SelectObject (hdcMemMask, GetStockObject (BLACK_BRUSH)) ;
          Rectangle (hdcMemMask, 0, 0, cxBitmap, cyBitmap) ;
          SelectObject (hdcMemMask, GetStockObject (WHITE_BRUSH)) ;
          Ellipse (hdcMemMask, 0, 0, cxBitmap, cyBitmap) ;

          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) ;

          hdcMemImag = CreateCompatibleDC (hdc) ;
          SelectObject (hdcMemImag, hBitmapImag) ;

          hdcMemMask = CreateCompatibleDC (hdc) ;
          SelectObject (hdcMemMask, hBitmapMask) ;

          x = (cxClient - cxBitmap) / 2 ;
          y = (cyClient - cyBitmap) / 2 ;

          BitBlt (hdc, x, y, cxBitmap, cyBitmap, hdcMemMask, 0, 0, 0x220326) ;
          BitBlt (hdc, x, y, cxBitmap, cyBitmap, hdcMemImag, 0, 0, SRCPAINT) ;

          DeleteDC (hdcMemImag) ;
          DeleteDC (hdcMemMask) ;
          EndPaint (hwnd, &ps) ;
          return 0 ;
     case WM_DESTROY:
          DeleteObject (hBitmapImag) ;
          DeleteObject (hBitmapMask) ;
          PostQuitMessage (0) ;
          return 0 ;
     }
     return DefWindowProc (hwnd, message, wParam, lParam) ;
}

3,上面的代码虽然不多,但对于初学者却很不好理解,下面对重点部分进行解释。

3.1 ,WM_CREATE部分。BITMASK用LoadBitmap函数在变量hBitmapImag中取得原始图像的句柄,通过GetObject函数将此位图的宽和高赋给bitmap变量,然后将原始位图的句柄选入内存设备环境中。注意内存设备环境和普通dhc主要区别是它只存在于内存中(在其上面画图时,先要在内存设备环境上铺上一张位图(hbitmap)),并不在显示器上显示出来。

3.2 ,程序创建一个和原始图像一样大小的单色位图,并将此选入内存设备环境中。接着就是选画一个这个图一样大的黑色矩形,然后在黑色矩形上画一个白色的椭圆(这是一个单色图,按位图颜色可知,黑色区域是0,白色是1):

3.3 ,通过BitBlt将掩码应用 在原始图像上:

                 图3.3

注意,为什么把这部分代码放在WM_CREATE中,是因为CreateCompatibleDC函数创建的内存设备环境只涉及到内存中操作,并不显示在界面上,值都是固定的,不用更新。

4,WM_PAINT部分。

这部分代码的主要作用就是将上面图像部分的黑色背景去掉。主要代码就是两个BitBlt函数:

BitBlt (hdc, x, y, cxBitmap, cyBitmap, hdcMemMask, 0, 0, 0x220326) ;
BitBlt (hdc, x, y, cxBitmap, cyBitmap, hdcMemImag, 0, 0, SRCPAINT) ;

这两行代码主要的意义在于最后这个参数ROP(一共有255种操作,具体见下面的“windows光栅操作”项)。0x220326代表逻辑操作D&~S(目标和取反的源进行按位操作),操作后的图像如下:

                 图4.1

即画上一个黑色的椭圆。

然后将图4.1和图3.3进行SRCPAINT逻辑操作,源图是图3.3,目标图是4.1,图3.3的外部是黑色的,于是图4.1对应部分被保留。而图4.1的内部是黑色的,所以图3.3对应部分被保留。最终实现效果就是图1.1的效果。

Windows 光栅操作

光栅操作涉及到三个对象的结合,三者的不同组合一共构成了256种操作的结果,也就是有256种三元光栅操作。使用BitBlt、PatBlt和StretchBlt时都会使用到这三钟光栅操作码,即ROP 码,像SRCCOPY ,PATPAINT ,SRCAND 等(只有15种操作有具体的名字)。这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;如果源位图为1,那么结果是目标位图。

根据这个描述可以得到这个格式:~Rop_S || (~Rop_S && Rop_D) 代码上面的值,可以得到结果0x22。查表可得这个光栅操作的编码为:0x220326。

转载于:https://my.oschina.net/moluyingxing/blog/854115

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值