WIN32汇编语言教程:第07章 图形操作 · 7.3 创建和使用位图(5)

创建一个位图需要的参数是高度、宽度以及颜色深度,要创建位图必须得知这些参数。使用CreateCompatibleBitmap创建位图的时候,参数中有一个hDC,这是个参考hDC,也就是说,新位图的颜色深度和hDC对应的“设备环境”的颜色深度相同(注意:有个hDC参数的意思并不是将创建的位图选入这个hDC中)。CreateBitmap函数则直接在参数dwPlanes和dwBitsPerPel中指定了颜色深度。两个函数的dwWidth和dwHeight参数指定创建的位图的宽度和高度。

在例子程序的_CreateBackGround子程序中,为了建立背景图片和时钟图片,需要建立两个未初始化的位图和操作它们的DC,所以程序一开始用GetDC函数获取主窗口的hDC来当做参考DC,然后用CreateCompatibleDC函数建立了两个DC(句柄放在全局变量hDcBack和hDcClock中),并用CreateCompatibleBitmap建立了两个位图(句柄放入hBmpBack和hBmpClock中),接下来用SelectObject将这两个位图选入新建的hDC中。

创建背景图片的过程中还要用到资源中的背景图片、边框图片和边框的遮掩图片,对于这些图片,程序用LoadBitmap函数装入,并使用CreateCompatibleDC为每个图片建立一个DC。

对于不再使用的位图,要用DeleteObject函数将它们删除。所以在子程序的最后,使用DeleteObject函数将临时使用的位图句柄删除,并使用DeleteDC将操作这些位图的hDC删除。

操作未初始化位图需要用到CreateCompatibleDC和CreateCompatibleBitmap函数,初学者常犯的错误是用CreateCompatibleDC返回的hDC当做CreateCompatibleBitmap函数的参考hDC,这样的结果是建立的位图是单色的,正确的做法是两个函数的参考hDC都使用窗口客户区的hDC。

7.3.3 使用设备无关位图

设备无关位图简称为DIB,这在5.3.1小节中已经有所介绍。DIB一般是存放在磁盘上的以bmp为扩展名的位图文件,使用DIB的关键是如何将DIB中的数据转化为一个内存中的位图并返回一个位图句柄。

bmp文件的文件结构是这样定义的:文件的开始是一个BITMAPFILEHEADER结构,这个结构定义如下:

BITMAPFILEHEADER STRUCT
 bfType         WORD     ?   ;文件标识,必须是“BM”
 bfSize         DWORD   ?   ;文件长度
 bfReserved1     WORD    ?   ;0
 bfReserved2     WORD    ?   ;0
 bfOffBits      DWORD    ?   ;位图像素数据在文件中的起始位置
BITMAPFILEHEADER  ENDS

BITMAPFILEHEADER结构的后面要么是BITMAPCOREHEADER结构,要么是BITMAPINFOHEADER结构和索引色表,这两种结构的定义如下:

BITMAPCOREHEADER STRUCT
 bcSize          DWORD   ?   ;本结构长度
 bcWidth        WORD    ?   ;位图宽度
 bcHeight        WORD    ?   ;位图高度
 bcPlanes        WORD     ?   ;位图的色平面数
 bcBitCount      WORD     ?   ;位图的颜色深度
BITMAPCOREHEADER  ENDS
 
BITMAPINFOHEADER STRUCT
 bcSize          DWORD   ?   ;本结构长度
 bcWidth        WORD    ?   ;位图宽度
 bcHeight        WORD     ?   ;位图高度
 bcPlanes       WORD    ?   ;位图的色平面数
 bcBitCount      WORD    ?   ;位图的颜色深度
 biCompression   DWORD   ?   ;位图的压缩方式
 biSizeImage    DWORD   ?   ;图形尺寸
 biXPelsPerMeter DWORD   ?   ;图形x方向分辨率,单位是像素/米
 biYPelsPerMeter DWORD    ?   ;图形y方向分辨率,单位是像素/米
 biClrUsed      DWORD   ?
 biClrImportant  DWORD    ?
BITMAPINFOHEADER  ENDS

这两个数据结构主要包含了位图的一些参数,在这些数据结构的后面,就是位图的像素数据了,整个bmp文件就由这3部分组成。

要使用DIB,可以首先将整个文件读到内存中,然后从这些数据结构中得知位图的各种参数,最后使用SetDIBitsToDevice函数将位图数据复制到一个hDC中,如果这个hDC对应一个未初始化的位图,那么就相当于得到了包含磁盘bmp位图数据的位图句柄,并且可以在任何地方使用它。当然,在这以后可以将读入文件数据的内存释放掉。

SetDIBitsToDevice函数的用法是:

invoke SetDIBitsToDevice,hDC,xDest,yDest,\
           dwWidth,dwHeight,xSrc,ySrc,uStartScan,cScanLines,\
           lpvBits,lpbmi,fuColorUse

hDC是目的DC的句柄,xDest和yDest指定了位图复制到hDC的左上角位置,dwWidth和dwHeight指定了要复制的宽度和高度,xSrc和ySrc指定DIB中要复制的左上角位置,uStartScan和cScanLines指定开始复制的扫描线和要复制的扫描线数,最后,lpvBits指向DIB中的像素数据部分,lpbmi指向DIB中的BITMAPINFO或BITMAPCOREINFO结构,fuColorUse指定了DIB中数据的类型,用DIB_RGB_COLORS表示数据是RGB类型的。

子程序_CreateDIBitmap分析一个DIB文件的参数并返回包含整个DIB位图数据的位图句柄,读者可以在任何地方使用这个位图句柄。子程序的输入参数_hWnd用来获取参考hDC的窗口句柄,_lpFileData是将DIB文件整个读入内存后的内存指针。代码如下:

_CreateDIBitmap     proc  _hWnd,_lpFileData
           local   @lpBitmapInfo,@lpBitmapBits
           local   @dwWidth,@dwHeight
           local   @hDc,@hBitmap
 
           pushad
           mov     @hBitmap,0
           mov     esi,_lpFileData
           mov     eax,BITMAPFILEHEADER.bfOffBits [esi]
           add     eax,esi
           mov     @lpBitmapBits,eax
           add     esi,sizeof BITMAPFILEHEADER
           mov     @lpBitmapInfo,esi
           .if     BITMAPINFO.bmiHeader.biSize [esi] == sizeof BITMAPCOREHEADER
                    movzx eax,BITMAPCOREHEADER.bcWidth [esi]
                    movzx ebx,BITMAPCOREHEADER.bcHeight [esi]
           .else
                    mov    eax,BITMAPINFOHEADER.biWidth [esi]
                    mov    ebx,BITMAPINFOHEADER.biHeight [esi]
           .endif
           mov     @dwWidth,eax
           mov     @dwHeight,ebx
;********************************************************************
; 建立空的 Bitmap Object
;********************************************************************
           invoke  GetDC,_hWnd
           push    eax
           invoke  CreateCompatibleDC,eax
           mov     @hDc,eax
           pop     eax
           push    eax
           invoke  CreateCompatibleBitmap,eax,@dwWidth,@dwHeight
           mov     @hBitmap,eax
           invoke  SelectObject,@hDc,@hBitmap
           pop     eax
           invoke  ReleaseDC,hWinMain,eax
;********************************************************************
; 将文件内容设置到建立的 Bitmap 中
;********************************************************************
           invoke  SetDIBitsToDevice,@hDc,0,0,@dwWidth,@dwHeight,\
                    0,0,0,@dwHeight,\
                    @lpBitmapBits,@lpBitmapInfo,DIB_RGB_COLORS
           .if     eax == 0
                    invoke DeleteObject,@hBitmap
                    mov @hBitmap,0
           .endif
           invoke  DeleteDC,@hDc
           popad
           mov     eax,@hBitmap
           ret
 
_CreateDIBitmap     endp

_CreateDIBitmap子程序首先分析DIB文件的数据,确定BITMAPFILEHEADER后面的数据结构是BITMAPINFO还是BITMAPCOREINFO,并从结构中获取位图的高度和宽度,然后建立一个未初始化的位图,并用SetDIBitsToDevice函数将位图数据拷贝到这个位图中,最后将位图句柄返回以供后面使用。

上页:第07章 图形操作 · 7.3 创建和使用位图(4) 下页:第07章 图形操作 · 7.4 块传送操作(1)

第07章 图形操作

版权所有 © 中山市飞娥软件工作室 证书:粤ICP备09170368号