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 ? ;位图的颜色深度
bipression 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 CreatepatibleDC;eax
mov @hDc;eax
pop eax
push eax
invoke CreatepatibleBitmap;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函数将位图数据拷贝到这个位图中,最后将位图句柄返回以供后面使用。
来源:电子工业出版社 作者:罗云彬 上一页 回书目 下一页
上一页 回书目 下一页
第7章 图形操作
7。4 块传送操作(1)
除了7。2小节中的绘图函数,块传送函数也是重要的图形操作函数。块传送指把源位置中的数据块按照指定的方式传送到目的位置中。把内存中的位图复制到窗口客户区以及在不同的DC中复制图形数据都要用到块传送操作,块传送完成的工作就相当于图形之间的拷贝工作。块传送函数有PatBlt,BitBlt,MaskBlt,PlgBlt,TransparentBlt和StretchBlt等。
7。4。1 块传送方式
与7。2。4小节中介绍的绘图函数的ROP操作类似,块传送函数也是可以用ROP码来定义的传送方式,但块传送函数的ROP码定义不同于7。2。4小节中的ROP码,因为这里涉及的操作对象更多。
块传送的ROP码是一个32位的整数,对应的操作涉及3种原始数据:源像素、目标像素和画刷,块传送操作的结果是目标像素的数据被3种原始数据的计算结果替换掉。
并不是每一种ROP码都要用到全部3种原始数据,有的甚至连1种也用不到,例如全黑或者全白的ROP码。块传送函数使用的ROP码总共有256种,它们是3种原始数据进行不同位操作(取反、与、或和异或)的组合,但有些ROP码对应的操作结果实在是太难想像了,比如ROP码0e20746对应的操作是((目标像素 xor 画刷) and 源像素) xor 目标像素),凭这个算式的确比较难以想像最后得到的位图是什么样子的!在实际使用中很多算法组合也并不是那么有用,所以Windows只对15种最常用的ROP码定义了预定义的助记代码,
如表7。6所示,对于这些ROP码,在程序中可以直接使用助记码,对于表中没有列出的ROP码,可以直接使用16进制数值。
表7。6 块传送函数中使用的ROP码
ROP码
16进制数值
新像素点算法
BLACKNESS
00000042h
全部为0
DSTINVERT
00550009h
not 目标像素
MERGECOPY
00c000cah
画刷 and 源像素
MERGEPAINT
00bb0226h
(not 源像素)or 目标像素
NOTSRCCOPY
00330008h
not 源像素
NOTSRCERASE
001100a6h
not(源像素 or 目标像素)
PATCOPY
00f00021h
画刷
PATINVERT
005a0049h
画刷 xor 目标像素
PATPAINT
00fb0a09h
画刷 or (not 源像素)or 目标像素
SRCAND
008800c6h
源像素 and 目标像素
SRCCOPY
00cc0020h
源像素
SRCERASE
00440328h
源像素 and(not 目标像素)
SRCINVERT
00660046h
源像素 xor 目标像素
SRCPAINT
00ee0086h
源像素 or 目标像素
WHITENESS
00ff0062h
全部为1
7。4。2 块传送函数
1。 PatBlt函数
PatBlt函数完成的是“图案块传送”的功能,即“Pattern Block Transfer”。使用的方法是:
invoke PatBlt,hDC,xDest,yDest,dwWidth,dwHeight,dwROP
这个函数将当前画刷的图案拷贝到hDC中以(xDest,yDest)为左上角坐标,dwWidth为宽度,dwHeigth为高度的区域中,传送的方式由dwROP中的ROP码指定。PatBlt函数的功能和矩形填充函数FillRect与InvertRect等是很像的,但它包含了它们的全部功能,如ROP码指定DSTINVERT,那么PatBlt的功能就相当于InvertRect函数;ROP码指定为PATCOPY的时候,PatBlt的功能相当于FillRect函数。
在BmpClock。asm的_CreateBackGround子程序中,当建立背景图片的时候,就是用PATCOPY方式的PatBlt函数用资源中的背景图片填充整个时钟背景的。
在所有的ROP码中,可以用在PatBlt函数中的只有一部分,所有算法中包含源像素的ROP码在PatBlt函数中都不
小提示:按 回车 [Enter] 键 返回书目,按 ← 键 返回上一页, 按 → 键 进入下一页。
赞一下
添加书签加入书架