windows 程序设计 位图

位图
1 位图入门
  位图的缺点:第一个问题是容易受设备依赖性的影响,第二个缺点是需要很大的储存空间。

2 位图来源
   自己制作,扫描仪,数码相机,等等。

3 位图尺寸
 通常都是 32*32,64*64, 一般第一个数字表示宽度。计算机内存是线性的,那么存储位图是一行一行存储的。

4  颜色和位图

除空间尺寸以外,位图还有颜色尺寸。这里指的是每个图素所需要的位数,有时也称为位图的 颜色深度(color depth)、位数(bit-count)或 位/图素(bpp:bits per pixel)数。位图中的每个图素都有相同数量的颜色位。

每图素1位的位图称为二阶(bilevel)、 二色(bicolor)或者单色(monochrome)位图。每图素可以是0或1,0表示黑色,1可以表示白色,但并不总是这样。对于其它颜色,一个图素就需要有多个位。可能的颜色值等于2位数值。用2位可以得到4种颜色,用4位可以得16种颜色,8位可得到256种颜色,16位可得到65,536种颜色,而24位可得到16,777,216种颜色。

如何将颜色位的组合与人们所熟悉的颜色相对应是目前处理位图时经常碰到(而且常常是灾难)的问题。



5 实际设备

调色盘管理器允许应用程序在256色显示器上显示实际位图。Windows所储存的20种颜色如表所示。

IRGB

RGB颜色

颜色名称

00000000

00-00-00

00000001

80-00-00

暗红

00000010

00-80-00

暗绿

00000011

80-80-00

暗黄

00000100

00-00-80

暗蓝

00000101

80-00-80

暗洋红

00000110

00-80-80

暗青

00000111

C0-C0-C0

亮灰

00001000

C0-DC-C0

美元绿

00001001

A6-CA-F0

天蓝

11110110

FF-FB-F0

乳白

11110111

A0-A0-A4

中性灰

11111000

80-80-80

暗灰

11111001

FF-00-00

11111010

00-FF-00

绿

11111011

FF-FF-00

11111100

00-00-FF

11111101

FF-00-FF

洋红

11111110

00-FF-FF

11111111

FF-FF-FF



在调用GetDeviceCaps时,您能利用BITSPIXEL和PLANES常数来获得显示卡的颜色单位,这些值显示如表14-3所示

表14-3

BITSPIXEL

PLANES

颜色数

1

1

2

1

4

16

8

1

256

15或16

1

32,768或65 536

24或32

1

16 777 216



6 块传输

我前面提到过,您可以把整个视讯显示器看作是一幅大位图。您在屏幕上见到的图素由储存在视讯显示卡上内存中的位来描述。任何视讯显示的矩形区域也都是一个位图,其大小是它所包含的行列数。

让我们从将图像从视讯显示的一个区域复制到另一个区域,开始我们在位图世界的旅行吧!这个是强大的BitBlt函数的工作。


BOOL BitBlt(HDC hdcDest,
  int nXDest,
  int nYDest,
  int nWidth,
  int nHeight,
  HDC hdcSrc,
  int nXSrc,
  int nYSrc,
  DWORD dwRop);

hdcDest:指向目标设备环境的句柄。
nXDest:指定目标矩形区域左上角的X轴逻辑坐标。
nYDest:指定目标矩形区域左上角的Y轴逻辑坐标。
nWidth:指定源和目标矩形区域的逻辑宽度。
nHeight:指定源和目标矩形区域的逻辑高度。
hdcSrc:指向源设备环境的句柄。
nXSrc:指定源矩形区域左上角的X轴逻辑坐标。
nYSrc:指定源矩形区域左上角的Y轴逻辑坐标。
 
dwRop:指定光栅操作代码。这些代码将定义源矩形区域的颜色数据,如何与目标矩形区域的颜色数据组合以完成最后的颜色。
下面列出了一些常见的光栅操作代码:
BLACKNESS:表示使用与物理 调色板的索引0相关的色彩来填充目标矩形区域,(对缺省的物理调色板而言,该颜色为黑色)。
DSTINVERT:表示使目标矩形区域颜色取反。
MERGECOPY:表示使用 布尔型的AND(与)操作符将源矩形区域的颜色与特定模式组合一起。
MERGEPAINT:通过使用 布尔型的OR(或)操作符将反向的源矩形区域的颜色与目标矩形区域的颜色合并。
NOTSRCCOPY:将源矩形区域颜色取反,于拷贝到目标矩形区域。
NOTSRCERASE:使用 布尔类型的OR(或)操作符组合源和目标矩形区域的颜色值,然后将合成的颜色取反。
PATCOPY:将特定的模式拷贝到目标位图上。
PATPAINT:通过使用 布尔OR(或)操作符将源矩形区域取反后的颜色值与特定模式的颜色合并。然后使用OR(或)操作符将该操作的结果与目标矩形区域内的颜色合并。
PATINVERT:通过使用XOR(异或)操作符将源和目标矩形区域内的颜色合并。
SRCAND:通过使用AND(与)操作符来将源和目标矩形区域内的颜色合并。
SRCCOPY:将源矩形区域直接拷贝到目标矩形区域。
SRCERASE:通过使用AND(与)操作符将目标矩形区域颜色取反后与源矩形区域的颜色值合并。
SRCINVERT:通过使用 布尔型的XOR(异或)操作符将源和目标矩形区域的颜色合并。
SRCPAINT:通过使用 布尔型的OR(或)操作符将源和目标矩形区域的颜色合并。
WHITENESS:使用与物理 调色板中索引1有关的 颜色填充目标矩形区域。(对于缺省物理 调色板来说,这个颜色就是白色)。

图案(P):1 1 1 1 0 0 0 0

来源(s):1 1 0 0 1 1 0 0

目的(D):1 0 1 0 1 0 1 0

布尔操作

ROP代码

名称

结果:

0 0 0 0 0 0 0 0

0

0x000042

BLACKNESS

 

0 0 0 1 0 0 0 1

~(S|D)

0x1100A6

NOTSRCERASE

 

0 0 1 1 0 0 1 1

~S

0x330008

NOTSRCCOPY

 

0 1 0 0 0 1 0 0

S & ~D

0x440328

SRCERASE

 

0 1 0 1 0 1 0 1

~D

0x550009

DSTINVERT

 

0 1 0 1 1 0 1 0

P ^ D

0x5A0049

PATINVERT

 

0 1 1 0 0 1 1 0

S ^ D

0x660046

SRCINVERT

 

1 0 0 0 1 0 0 0

S & D

0x8800C6

SRCAND

 

1 0 1 1 1 0 1 1

~S| D

0xBB0226

MERGEPAINT

 

1 1 0 0 0 0 0 0

P & S

0xC000CA

MERGECOPY

 

1 1 0 0 1 1 0 0

S

0xCC0020

SRCCOPY

 

1 1 1 0 1 1 1 0

S| D

0xEE0086

SRCPAINT

 

1 1 1 1 0 0 0 0

P

0xF00021

PATCOPY

 

1 1 1 1 1 0 1 1

P| ~S| D

0xFB0A09

PATPAINT

 

1 1 1 1 1 1 1 1

1

0xFF0062

WHITENESS


在BitBlt函数中,目的图像与来源图像的尺寸是相同的,因为函数只有两个参数来说明宽度和高度。
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
     static int  cxClient, cyClient, cxSource, cySource ;
     HDC         hdcClient, hdcWindow ;
     int         x, y ;
     PAINTSTRUCT ps ;
     
     switch (message)
     {
     case WM_CREATE:
          cxSource = GetSystemMetrics (SM_CXSIZEFRAME) +
                     GetSystemMetrics (SM_CXSMICON) ;

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

          for (y = 0 ; y < cyClient ; y += cySource)
          for (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) ;
}

     

可以使用StretchBlt 来拉伸位图。得到桌面的句柄,把桌面图标贴到窗口上。
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
     static int  cxClient, cyClient, cxSource, cySource ;
     HDC         hdcClient, hdcWindow ;
     PAINTSTRUCT ps ;
     static RECT rect,rect1;

     switch (message)
     {
     case WM_CREATE:

		 GetClientRect(GetDesktopWindow(),&rect);
		 GetWindowRect(GetDesktopWindow(), &rect1);

          return 0 ;

     case WM_SIZE:
          cxClient = LOWORD (lParam) ;
          cyClient = HIWORD (lParam) ;
          return 0 ;

     case WM_PAINT:
          hdcClient = BeginPaint (hwnd, &ps) ;
          hdcWindow = GetDC(NULL);
		
		  SetStretchBltMode(hdcClient,COLORONCOLOR);

          StretchBlt (hdcClient, 0, 0, cxClient, cyClient,
                      hdcWindow, 0, 0, rect.right, rect.bottom, MERGECOPY) ;

          ReleaseDC (hwnd, hdcWindow) ;
          EndPaint (hwnd, &ps) ;
          return 0 ;

     case WM_DESTROY:
          PostQuitMessage (0) ;
          return 0 ;
     }
     return DefWindowProc (hwnd, message, wParam, lParam) ;
}

BitBlt和StretchBlt函数中所有的坐标与大小都是依据逻辑单位的。但是当您在BitBlt函数中定义了两个不同的设备内容,而这两个设备内容虽然参考同一个实际设备,却各自有着不同的映像模式,这时将发生什么结果呢?如果出现这种情况,呼叫BitBlt产生的结果就显得不明确了:cx和cy参数都是逻辑单位,而它们同样应用于来源设备内容和目的设备内容中的矩形区。所有的坐标和尺寸必须在实际的位传输之前转换为设备坐标。因为cx和cy值同时用于来源和目的设备内容,所以此值必须转换为设备内容自己的单位。

当来源和目的设备内容相同,或者两个设备内容都使用MM_TEXT图像模式时,设备单位下的矩形尺寸在两个设备内容中会是相同的,然后才由Windows进行图素对图素的转换。不过,如果设备单位下的矩形尺寸在两个设备内容中不同时,则Windows就把此工作转交给更通用的StretchBlt函数。

StretchBlt也允许水平或垂直翻转图像。如果cxSrc和cxDst标记(转换成设备单位以后)不同,那么StretchBlt就建立一个镜像:左右翻转。在STRETCH程序中,通过将xDst参数改为cxClient并将cxDst参数改成-cxClient,您就可以做到这一点。如果cySrc和cyDst不同,则StretchBlt会上下翻转图像。要在STRETCH程序中测试这一点,可将yDst参数改为cyClient并将cyDst参数改成-cyClient。


StretchBlt模式

使用StretchBlt会碰到一些与位图大小缩放相关的一些根本问题。在扩展一个位图时,StretchBlt必须复制图素行或列。如果放大倍数不是原图的整数倍,那么此操作会造成产生的图像有些失真。

如果目的矩形比来源矩形小,那么StretchBlt在缩小图像时就必须把两行(或列)或者多行(或列)的图素合并到一行(或列)。完成此操作有四种方法,它根据设备内容伸展模式属性来选择其中一种方法。您可使用SetStretchBltMode函数来修改这个属性。

iMode可取下列值:

  • BLACKONWHITE或者STRETCH_ANDSCANS(内定)如果两个或多个图素得合并成一个图素,那么StretchBlt会对图素执行一个逻辑AND运算。这样的结果是只有全部的原始图素是白色时该图素才为白色,其实际意义是黑色图素控制了白色图素。这适用于白背景中主要是黑色的单色位图。
     
  • WHITEONBLACK或STRETCH_ORSCANS 如果两个或多个图素得合并成一个图素,那么StretchBlt执行逻辑OR运算。这样的结果是只有全部的原始图素都是黑色时才是黑色,也就是说由白色图素决定颜色。这适用于黑色背景中主要是白色的单色位图。
     
  • COLORONCOLOR或STRETCH_DELETESCANS StretchBlt简单地消除图素行或列,而没有任何逻辑组合。这是通常是处理彩色位图的最佳方法。
     
  • HALFTONE或STRETCH_HALFTONE Windows根据组合起来的来源颜色来计算目的的平均颜色。这将与半调调色盘联合使用, 第十六章将展示这一程序。

使用这个模式,可以更好的显示图片。

SetStretchBltMode(hdcClient,COLORONCOLOR);

BITBLT和STRETCH程序简单地将来源位图复制给了目的位图,在过程中也可能进行了缩放。这是把SRCCOPY作为BitBlt和StretchBlt函数最后一个参数的结果。SRCCOPY只是您能在这些函数中使用的256个位映像操作中的一个。让我们先在STRETCH程序中做一个别的实验,然后再系统地研究位映像操作。

尽量用NOTSRCCOPY来代替SRCCOPY。与它们名称一样,位映像操作在复制位图时转换其颜色。在显示区域窗口,所有的颜色转换:黑色变成白色、白色变成黑色,蓝色变成黄色。现在试一下SRCINVERT,您将得到同样效果。如果试一下BLACKNESS,正如其名称一样,整个显示区域都将变成黑色,而WHITENESS则使其变成白色。

现在试一试用下列代码代替StretchBlt函数:

SelectObject (hdcClient, CreateHatchBrush (HS_DIAGCROSS, RGB (0, 0, 0)));
        SetStretchBltMode(hdcClient,COLORONCOLOR);
StretchBlt (hdcClient, 0, 0, cxClient, cyClient,hdcWindow, 0, 0, cxSource, cySource, MERGECOPY) ;
        
DeleteObject (hdcClient, GetStockObject (WHITE_BRUSH)) ;
        

这次,您将在图像上看到一个菱形的画刷,这是什么?

我在前面说过,BitBlt和StretchBlt函数不是简单的位块传输。此函数实际在下面三种图像间执行位操作。

  • Source 来源位图,拉伸或压缩(如果有必要)到目的矩形的尺寸。
     
  • Destination 在BitBlt或StretchBlt呼叫之前的目的矩形。
     
  • Pattern 在目的设备内容中选择的目前画刷,水平或垂直地复制到目的矩形范围内。
     

结果是复制到了目的矩形中。



PatBlt

除了BitBlt和StretchBlt以外,Windows还包括一个称为PatBlt (「pattern block transfer:图案块传输」)的函数。这是三个「blt」函数中最简单的。与BitBlt和StretchBlt不同,它只使用一个目的设备内容。PatBlt语法是:

PatBlt (hdc, x, y, cx, cy, dwROP) ;
        

x、y、cx和cy参数字于逻辑单位。逻辑点(x,y)指定了矩形的左上角。矩形宽为cx单位,高为cy单位。这是PatBlt修改的矩形区域。PatBlt在画刷与目的设备内容上执行的逻辑操作由dwROP参数决定,此参数是ROP代码的子集-也就是说,您可以只使用那些不包括来源目的设备内容的ROP代码。下表列出了PatBlt支持的16个位映像操作:

图案(P):1 1 0 0

目的(D):1 0 1 0

布尔操作

ROP代码

名称

结果:

0 0 0 0

0

0x000042

BLACKNESS

 

0 0 0 1

~(P | D)

0x0500A9

 
 

0 0 1 0

~P & D

0x0A0329

 
 

0 0 1 1

~P

0x0F0001

 
 

0 1 0 0

P & ~D

0x500325

 
 

0 1 0 1

~D

0x550009

DSTINVERT

 

0 1 1 0

P ^ D

0x5A0049

PATINVERT

 

0 1 1 1

~(P & D)

0x5F00E9

 
 

1 0 0 0

P & D

0xA000C9

 
 

1 0 0 1

~(P ^ D)

0xA50065

 
 

1 0 1 0

D

0xAA0029

 
 

1 0 1 1

~P | D

0xAF0229

 
 

1 1 0 0

P

0xF00021

PATCOPY

 

1 1 0 1

P | ~D

0xF50225

 
 

1 1 1 0

P | D

0xFA0089

 
 

1 1 1 1

1

0xFF0062

WHITENESS


下面列出了PatBlt一些更常见用途。如果想画一个黑色矩形,您可呼叫

PatBlt (hdc, x, y, cx, cy, BLACKNESS) ;
        

要画一个白色矩形,请用

PatBlt (hdc, x, y, cx, cy, WHITENESS) ;
        

实际上,此程序代码是Windows用于执行FillRect函数的动作。如果您呼叫

InvertRect (hdc, &rect) ;
        

Windows将其转换成函数:

PatBlt (hdc,       rect.left, rect.top,
        
                                         rect.right - rect.left,
        
                                         rect.bottom - rect.top, DSTINVERT) ;
        

CreateCompatibleBitmap 创建一个兼容的位图   不在需要时,使用DeleteObject 删除它


CreateCompatibleDC      创建一个兼容的DC 
不在需要时 使用 DeleteDC 删除它

CreateBitmapIndirect 创建一个单色位图,不能创建一个彩色位图。

因此,基本的规则是这样的:不要用CreateBitmap、CreateBitmapIndirect或SetBitmapBits来设定彩色DDB的位,您只能安全地使用这些函数来设定单色DDB的位

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
     static HBITMAP hBitmap ;
     static int     cxClient, cyClient, cxSource, cySource ;
     BITMAP         bitmap ;
     HDC            hdc, hdcMem ;
     HINSTANCE      hInstance ;
     int            x, y ;
     PAINTSTRUCT    ps ;
     
     switch (message)
     {
     case WM_CREATE:
          hInstance = ((LPCREATESTRUCT) lParam)->hInstance ;

          hBitmap = LoadBitmap (hInstance, TEXT ("Bricks")) ;

          GetObject (hBitmap, sizeof (BITMAP), &bitmap) ;

          cxSource = bitmap.bmWidth ;
          cySource = bitmap.bmHeight ;

          return 0 ;

     case WM_SIZE:
          cxClient = LOWORD (lParam) ;
          cyClient = HIWORD (lParam) ;
          return 0 ;

     case WM_PAINT:
          hdc = BeginPaint (hwnd, &ps) ;

          hdcMem = CreateCompatibleDC (hdc) ;
          SelectObject (hdcMem, hBitmap) ;

          for (y = 0 ; y < cyClient ; y += cySource)
          for (x = 0 ; x < cxClient ; x += cxSource)
          {
               BitBlt (hdc, x, y, cxSource, cySource, hdcMem, 0, 0, SRCCOPY) ;
          }

          DeleteDC (hdcMem) ;
          EndPaint (hwnd, &ps) ;
          return 0 ;

     case WM_DESTROY:
          DeleteObject (hBitmap) ;
          PostQuitMessage (0) ;
          return 0 ;
     }
     return DefWindowProc (hwnd, message, wParam, lParam) ;
}

请记住,画刷和位图都是GDI对象,而且您应该在程序终止前删除您在程序中建立画刷和位图。如果您依据位图建立画刷,那么在用画刷画图时,Windows将复制位图位到画刷所绘制的区域内。呼叫CreatePatternBrush(或者CreateBrushIndirect)之后,您可以立即删除位图而不会影响到画笔。类似地,您也可以删除画刷而不会影响到您选进的原始位图。注意,BRICKS3在建立画刷后删除了位图,并在程序终止前删除了画刷。


下面代码是兼容DC和兼容位图的使用:
case   WM_CREATE:
        
                          hdc = GetDC (hwnd) ;
        
                          hdcMem  = CreateCompatibleDC (hdc) ;
        

                          GetTextExtentPoint32 (hdc, szText, lstrlen (szText), &size) ;
        
                          cxBitmap = size.cx ;
        
                          cyBitmap = size.cy ;
        
                          hBitmap = CreateCompatibleBitmap (hdc, cxBitmap, cyBitmap) ;
        

                          ReleaseDC (hwnd, hdc) ;
        

                          SelectObject (hdcMem, hBitmap) ;
        
                          TextOut (hdcMem, 0, 0, szText, lstrlen (szText)) ;
        
                          return 0 ;

       
       
       
       
       

你可能感兴趣的:(windows,位图)