首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > VB >

getbitmapbits函数 图象处理有关问题

2012-02-17 
getbitmapbits函数 图象处理问题本人初学图象逐象素处理,于是写了下边的小程序,就是把一个图贴到另一个图

getbitmapbits函数 图象处理问题
本人初学图象逐象素处理,于是写了下边的小程序,就是把一个图贴到另一个图的上边,但是逐点处理的,可贴的效果有点问题,请高手指教.
图a
图b
结果
代码

VB code
Option ExplicitPrivate Declare Function GetBitmapBits Lib "gdi32" (ByVal hBitmap As Long, ByVal dwCount As Long, lpBits As Any) As LongPrivate Declare Function SetBitmapBits Lib "gdi32" (ByVal hBitmap As Long, ByVal dwCount As Long, lpBits As Any) As LongPrivate Declare Function GetObject Lib "gdi32" Alias "GetObjectA" (ByVal hObject As Long, ByVal nCount As Long, lpObject As Any) As LongPrivate Type BITMAP    bmType As Long    bmWidth As Long    bmHeight As Long    bmWidthBytes As Long    bmPlanes As Integer    bmBitsPixel As Integer    bmBits As LongEnd TypePrivate Sub Form_Load()    Dim lpA As BITMAP, lpB As BITMAP    Dim PicA As StdPicture, PicB As StdPicture    Dim a() As Byte, b() As Byte    Dim i As Long, j As Long        Set PicA = LoadPicture("C:\Documents and Settings\user\桌面\8.jpg")    Set PicB = LoadPicture("C:\Documents and Settings\user\桌面\w03.jpg")        GetObject PicA.Handle, Len(lpA), lpA    GetObject PicB.Handle, Len(lpB), lpB'    Debug.Print lpB.bmBitsPixel, lpB.bmWidthBytes, lpB.bmWidth, lpB.bmHeight    ReDim a(1 To lpA.bmWidthBytes, 1 To lpA.bmHeight)    ReDim b(1 To lpB.bmWidthBytes, 1 To lpB.bmHeight)        GetBitmapBits PicA.Handle, lpA.bmWidthBytes * lpA.bmHeight, a(1, 1)    GetBitmapBits PicB.Handle, lpB.bmWidthBytes * lpB.bmHeight, b(1, 1)        For i = 1 To lpB.bmHeight        For j = 1 To lpB.bmWidth * 3            a(j, i) = b(j, i)        Next    Next        SetBitmapBits PicA.Handle, lpA.bmWidthBytes * lpA.bmHeight, a(1, 1)    Form1.Picture = PicAEnd Sub


[解决办法]
找到问题所在了:

扫描行: 
  一行的图像数据叫做一个扫描行。一个扫描行的长度必须是4的倍数(字节),如果不是,则需要补齐。计算公式:LineBytes=((biWidth*biBitCount+31)And &HFFFFFFE0)\8 

首先,这个公式对于DDB是不适用的,正真的DDB的扫描行的计算公式是:
iWidthBytes = 2 * ((cx * cBitsPixel + 15) / 16); //cx为位图宽,cBitsPixel为每个像素的位数
也就是说他只要是2的倍数就可以了,

 我们这个利用GetObject 这个API得到的bmWidthBytes也就不是完全正确了。
这样就可以解释我们图B的宽度是4的倍数时效果正确,而为偶数时效果完全错误。


Option Explicit
Private Declare Function GetBitmapBits Lib "gdi32" (ByVal hBitmap As Long, ByVal dwCount As Long, lpBits As Any) As Long
Private Declare Function SetBitmapBits Lib "gdi32" (ByVal hBitmap As Long, ByVal dwCount As Long, lpBits As Any) As Long
Private Declare Function GetObject Lib "gdi32" Alias "GetObjectA" (ByVal hObject As Long, ByVal nCount As Long, lpObject As Any) As Long

Private Type BITMAP
bmType As Long
bmWidth As Long
bmHeight As Long
bmWidthBytes As Long
bmPlanes As Integer
bmBitsPixel As Integer
bmBits As Long
End Type


Private Sub Form_Load()

Dim lpA As BITMAP, lpB As BITMAP
Dim PicA As StdPicture, PicB As StdPicture
Dim a() As Byte, b() As Byte
Dim i As Long, j As Long
Dim StrideA As Long, StrideB As Long
Set PicA = LoadPicture("C:\1.jpg")
Set PicB = LoadPicture("C:\2.jpg")

GetObject PicA.Handle, Len(lpA), lpA
GetObject PicB.Handle, Len(lpB), lpB
StrideA = 2 * ((lpA.bmWidth * lpA.bmBitsPixel + 15) \ 16)
StrideB = 2 * ((lpB.bmWidth * lpB.bmBitsPixel + 15) \ 16)

' Debug.Print lpB.bmBitsPixel, lpB.bmWidthBytes, lpB.bmWidth, lpB.bmHeight

ReDim a(1 To StrideA, 1 To lpA.bmHeight)
ReDim b(1 To StrideB, 1 To lpB.bmHeight)

GetBitmapBits PicA.Handle, StrideA * lpA.bmHeight, a(1, 1)
GetBitmapBits PicB.Handle, StrideB * lpB.bmHeight, b(1, 1)

For i = 1 To lpB.bmHeight
For j = 1 To lpB.bmWidth * 3


a(j, i) = b(j, i)
Next
Next

SetBitmapBits PicA.Handle, lpA.bmWidthBytes * lpA.bmHeight, a(1, 1)
Form1.Picture = PicA
End Sub


这样运行就完整正确了。

还有一点说下,GetBitmapBits 和GetDibits函数得到的图像数据的顺序是相反的。


顺便贴些DDB的资料:

DDB的创建:
DDB由一个句柄来标识,可以通过调用某个创建函数来获得句柄,这些函数可以是:CreateBitmap( )、CreateCompatibleBitmap( )和CreateBitmapIndirect( )。
在Windowswewi DDB分配内存时,每行像素具有偶数个字节,即
iWidthBytes = 2 * ((cx * cBitsPixel + 15) / 16); //cx为位图宽,cBitsPixel为每个像素的位数
因此,为DDB分配的内存就是
iBitmapBytes = cy * cPlanes * iWidthBytes; //cPlanes为颜色板的数目
创建DDB的基本规则是:不要用CreateBitmap( )、CreateBitmapIndirect( )或SetBitmapBits( )来设置彩色DDB的位,您只能安全地设置单色DDB的位。
 
DDB的使用:
内存设备描述表是您选进位图的唯一一种设备描述表类型(如果需要,您也可以将其他GDI对象选进内存设备描述表),它只存在于内存中,并不是真正的图形输出设备,但可以说与某个实际设备“兼容”,可以通过CreateCompatibleDC( )来创建内存设备描述表,可以用SelectObject( )将GDI对象选进内存设备描述表。这时,DDB就成为了内存设备描述表的显示表面。
如果用GDI画图函数在内存设备描述表中画图,那么图像将画在位图上。这是非常有用的。还可以将内存设备描述表作为源,把视频设备描述表作为目标来调用BitBlt( ),这就是在显示器上绘制位图的方法。如果把视频设备作为源,把内存设备作为目标,那么调用BitBlt( )可以将屏幕上的一些内容复制给位图。

热点排行