[已解决]_GDIPlus_BitmapLockBits函数的使用
本帖最后由 gto250 于 2011-4-13 18:59 编辑Func _myReadBitmapMsg($hBitmap, $iType=1);
Local $aBmpData
$aBmpData = _GDIPlus_ImageGetWidth ($hBitmap)
$aBmpData = _GDIPlus_ImageGetHeight ($hBitmap)
Local $BitmapData = _GDIPlus_BitmapLockBits($hBitmap, 0, 0, $aBmpData, $aBmpData, $GDIP_ILMREAD, $GDIP_PXF24RGB)
$aBmpData = Abs(DllStructGetData($BitmapData, "Stride"))
$aBmpData = DllStructGetData($BitmapData, "Scan0");
_GDIPlus_BitmapUnlockBits($hBitmap, $BitmapData)
Local $tBuff, $iH
Switch $iType;已测试比StringRegExp快
Case -1
Return $aBmpData
Case 0
For $iH = 1 To $aBmpData
$tBuff = DllStructCreate("byte[" & ($aBmpData*3) & "]", $aBmpData + ($iH-1)*$aBmpData)
$aBmpData &= StringTrimLeft(DllStructGetData($tBuff, 1),2)
Next
Return $aBmpData
Case Else
Local $aRet[$aBmpData]
For $iH = 1 To $aBmpData
$tBuff = DllStructCreate("byte[" & ($aBmpData*3) & "]", $aBmpData + ($iH-1)*$aBmpData)
$aRet[$iH-1] = StringTrimLeft(DllStructGetData($tBuff, 1), 2)
Next
Return $aRet
EndSwitch
EndFunc
这段是从阿福的验证码识别中的例子中找到的,查看了一下帮助文件,发现_GDIPlus_BitmapLockBits中的$iFlags有以下三个参数可选
$iFlags
指定位图的锁定部分是否可用于读取或写入及调用方是否已分配有缓冲的设置标记. 可为下列组合:
$GDIP_ILMREAD - 用于读取的图像部分锁定
$GDIP_ILMWRITE - 用于写入的图像部分锁定
$GDIP_ILMUSERINPUTBUF - 缓冲已分配给用户
网上VB学DGI+中有这么一段资料:
3.GdipBitmapLockBits & GdipBitmapUnlockBits
看看名字,LockBits,锁定……锁定是什么呢……这个先不要管他。不知你有没有发现前面2个得到颜色/设置颜色的GDI+函数巨慢无比?(不过貌似比VB中的Point快)。为什么呢?其实我也不知道(怎么可能呢?)
在我这台破烂电脑上,一幅800*800左右的图片,Get所有的Pixel花费了约1s……,那么1024*768怎么办?更大的怎么办?有没有更快的?答案是,有。用什么?就是这个——GdipBitmapLockBits。
GdipBitmapLockBits,GdipBitmapUnlockBits是一对函数,他们可以将Bitmap上数据映射到内存和将内存中位图数据写回Bitmap,这个函数是一整块的,非常适合处理一大片的点——例如整个图像。
演示代码:
1. Option Explicit
2.
3. Dim bitmap As Long, rc As RECTL
4. Dim data() As Long
5.
6. Dim graphics As Long
7.
8. Private Sub Form_Load()
9. InitGDIPlus
10.
11. GdipCreateBitmapFromFile StrPtr("c:\TestImg.png"), bitmap
12. GdipGetImageWidth bitmap, rc.Right
13. GdipGetImageHeight bitmap, rc.Bottom
14.
15. ReDim data(rc.Right - 1, rc.Bottom - 1)
16.
17. Dim BmpData As BitmapData
18. With BmpData
19. .Width = rc.Right
20. .Height = rc.Bottom
21.
22. .PixelFormat = GpPixelFormat.PixelFormat32bppARGB
23. .scan0 = VarPtr(data(0, 0))
24. .stride = 4 * CLng(rc.Right)
25. End With
26.
27. GdipBitmapLockBits bitmap, rc, ImageLockModeUserInputBuf Or ImageLockModeWrite Or ImageLockModeRead, GpPixelFormat.PixelFormat32bppARGB, BmpData
28.
29. Dim i As Long, j As Long, s As String
30. For i = 0 To rc.Bottom - 1
31. For j = 0 To rc.Right - 1
32. data(j, i) = data(j, i) + data(j, i)
33. Next
34. Next
35.
36. GdipBitmapUnlockBits bitmap, BmpData
37.
38. GdipCreateFromHDC Me.hDC, graphics
39. GdipDrawImageRectI graphics, bitmap, 0, 0, rc.Right, rc.Bottom
40. GdipDeleteGraphics graphics
41.
42. GdipDisposeImage bitmap
43. End Sub
44.
45. Private Sub Form_Unload(Cancel As Integer)
46. TerminateGDIPlus
47. End Sub
我们先注意BmpData结构体,它实际上就是数据的设置。
scan0内存地址我们写的是VarPtr(data(0,0))。
stride = 4 * CLng(rc.Right):扫描宽度,这一个实际上就是二维数组每隔多少字节增加第一维,其中4是Long的存储长度,4个字节。
我们可以把数组的存储想象为一个矩形,gdi+放数据就是从左到右放,放到了边界则从下一行的第一个再从左向右放……
GdipBitmapLockBits:
我们首先用它来得到位图数据,方式是ImageLockModeWrite Or ImageLockModeRead(ImageLockModeUserInputBuf必须写)。即我们传给他的data(),它将把位图数据写入;而在GdipBitmapUnlockBits时候将data()数据写入位图。注意:如果只是Write模式,那么你将得不到原始数据。
data(j, i) = data(j, i) + data(j, i) 这句是一句简单的颜色处理变换,让我们能看到处理效果
GdipBitmapUnlockBits:完成最后的写入&释放工作。后面几句是绘制这个新图片用。
注意了,这里LockBits得到的数据data()是data(y,x),即列,行。注意注意!切记!Lockbits时候也要按照传入长度和宽度,不然VB会给你一个可爱的错误“Visual Basic 遇到问题需要关闭……”。
想问一下,在au3中,怎么样才能将一段颜色数组写入到图片中
也就是我创建了下面的一张空白的500*500像素的图片
$hImage = _GDIPlus_BitmapCreateFromScan0(500, 500,0,$GDIP_PXF32ARGB)
如何使用_GDIPlus_BitmapLockBits,将颜色数组写入图片中
自己试着写了段代码,在五楼。
感觉没有错,为什么就实现不了呢
好复杂,得研究一段时间 直接用像素呢,别用色块 "不知你有没有发现前面2个得到颜色/设置颜色的GDI+函数巨慢无比?"文中的两个GDI+函数就是GdipBitmapSetPixel和GdipBitmapGetPixel
#include <ButtonConstants.au3>
#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>
#include <WinApi.au3>
#Include <GDIPlusEx.au3>
#Include <ScreenCapture.au3>
#Region ### START Koda GUI section ### Form=
HotKeySet("{F1}","pic")
$Form1 = GUICreate("Form1", 500, 470, 500, 500)
$Pic1 = GUICtrlCreatePic("", 0, 0, 498, 448)
$Button1 = GUICtrlCreateButton("Button1", 205, 450, 75, 20)
$Button2 = GUICtrlCreateButton("Button2", 290, 450, 75, 20)
$Button2 = GUICtrlCreateButton("Button2", 290, 450, 75, 20)
$Button3 = GUICtrlCreateButton("", 200, 450, 15, 15)
_GDIPlus_Startup ()
GUISetState(@SW_SHOW)
#EndRegion ### END Koda GUI section ###
While 1
$hd=_WinAPI_GetDesktopWindow()
If IsHWnd($hd) Then
$win_xy=WinGetPos($hd)
$m_xy=MouseGetPos()
If $m_xy>=$win_xy+8 And $m_xy>$win_xy+192 And $m_xy<$win_xy+$win_xy+8 And $m_xy<$win_xy+$win_xy+192 Then
GUICtrlSetPos ( $Button3, $m_xy-$win_xy-8, $m_xy-$win_xy-192 )
EndIf
EndIf
$nMsg = GUIGetMsg()
Switch $nMsg
Case $GUI_EVENT_CLOSE
_GDIPlus_Shutdown ()
Exit
EndSwitch
WEnd
Func pic()
$hd=_WinAPI_GetDesktopWindow()
If IsHWnd($hd) Then
_Capture2($hd, 8, 192, 517,192,498,448)
EndIf
EndFunc
Func _Capture2($hWnd, $iLeft_1,$iTop_1,$iLeft_2, $iTop_2,$iWidth, $iheight)
$h1=_Capture3($hWnd, $iLeft_1,$iTop_1,$iWidth, $iheight)
$h2=_Capture3($hWnd, $iLeft_2,$iTop_2,$iWidth, $iheight)
DllCall("user32.dll", "lparam", "SendMessage", "hwnd", GUICtrlGetHandle($Pic1), "int", 0x0172, "wparam", 0, "lparam",ImageColorToTransparent($h1,$h2))
EndFunc
Func _Capture3($hWnd, $iLeft_1,$iTop_1,$iWidth, $iheight)
Local $_SRCCOPY = 0x00CC0020
Local $_SRCINVERT = 0x00660046
Local $hDDC = _WinAPI_GetDC($hWnd)
Local $hCDC = _WinAPI_CreateCompatibleDC($hDDC)
Local $hBMP = _WinAPI_CreateCompatibleBitmap($hDDC, $iWidth, $iheight)
_WinAPI_SelectObject($hCDC, $hBMP)
_WinAPI_BitBlt($hCDC, 0, 0, $iWidth, $iheight, $hDDC, $iLeft_1, $iTop_1, $_SRCCOPY)
_WinAPI_ReleaseDC($hWnd, $hDDC)
_WinAPI_DeleteDC($hCDC)
Return $hBMP
EndFunc
Func ImageColorToTransparent($hImage1,$hImage2, $iStartPosX = 0, $iStartPosY = 0, $GuiSizeX = Default, $GuiSizeY = Default)
Local $hBitmap1, $Reslt, $width, $height, $stride, $format, $Scan0, $v_Buffer, $v_Value, $iIW, $iIH
$b1=_GDIPlus_BitmapCreateFromHBITMAP($hImage1)
$b2=_GDIPlus_BitmapCreateFromHBITMAP($hImage2)
$iIW = _GDIPlus_ImageGetWidth($b1)
$iIH = _GDIPlus_ImageGetHeight($b2)
MsgBox(0,$iIW,$iIH)
If $GuiSizeX = Default Or $GuiSizeX > $iIW - $iStartPosX Then $GuiSizeX = $iIW - $iStartPosX
If $GuiSizeY = Default Or $GuiSizeY > $iIH - $iStartPosY Then $GuiSizeY = $iIH - $iStartPosY
$Reslt1 = _GDIPlus_BitmapLockBits($b1, 0, 0, $GuiSizeX, $GuiSizeY, BitOR($GDIP_ILMREAD, $GDIP_ILMWRITE), $GDIP_PXF32ARGB)
$Reslt2 = _GDIPlus_BitmapLockBits($b2, 0, 0, $GuiSizeX, $GuiSizeY, BitOR($GDIP_ILMREAD, $GDIP_ILMWRITE), $GDIP_PXF32ARGB)
$width1 = DllStructGetData($Reslt1, "width")
$height1 = DllStructGetData($Reslt1, "height")
$stride1 = DllStructGetData($Reslt1, "stride")
$format1 = DllStructGetData($Reslt1, "format")
$Scan01 = DllStructGetData($Reslt1, "Scan0")
$width2 = DllStructGetData($Reslt2, "width")
$height2 = DllStructGetData($Reslt2, "height")
$stride2 = DllStructGetData($Reslt2, "stride")
$format2 = DllStructGetData($Reslt2, "format")
$Scan02 = DllStructGetData($Reslt2, "Scan0")
For $i = 0 To $GuiSizeX - 1
For $j = 0 To $GuiSizeY - 1
$v_Buffer1 = DllStructCreate("dword", $Scan01 + ($j * $stride1) + ($i * 4))
$v_Value1 = DllStructGetData($v_Buffer1, 1)
$v_Buffer2 = DllStructCreate("dword", $Scan02 + ($j * $stride2) + ($i * 4))
$v_Value2 = DllStructGetData($v_Buffer2, 1)
If Hex($v_Value2, 6) = Hex($v_Value1, 6) Then
DllStructSetData($v_Buffer1, 1, 0xff0000); Sets Transparency here. Alpha Channel = 00, not written to.
EndIf
Next
Next
_GDIPlus_BitmapUnlockBits($b1, $Reslt1)
_GDIPlus_BitmapUnlockBits($b2, $Reslt2)
Return $b1
EndFunc
自己试试写了一个。
但是还是没有反应!
无奈 我也遇着同样问题, 怎样解决? 水平有限,持续关注中···
页:
[1]