找回密码
 加入
搜索
查看: 5983|回复: 6

[图形处理] [已解决]_GDIPlus_BitmapLockBits函数的使用

  [复制链接]
发表于 2011-4-11 20:00:19 | 显示全部楼层 |阅读模式
本帖最后由 gto250 于 2011-4-13 18:59 编辑


Func _myReadBitmapMsg($hBitmap, $iType=1);
        Local $aBmpData[5]
    $aBmpData[1] = _GDIPlus_ImageGetWidth ($hBitmap)
    $aBmpData[2] = _GDIPlus_ImageGetHeight ($hBitmap)
        Local $BitmapData = _GDIPlus_BitmapLockBits($hBitmap, 0, 0, $aBmpData[1], $aBmpData[2], $GDIP_ILMREAD, $GDIP_PXF24RGB)
        $aBmpData[3] = Abs(DllStructGetData($BitmapData, "Stride"))
        $aBmpData[4] = DllStructGetData($BitmapData, "Scan0");
        _GDIPlus_BitmapUnlockBits($hBitmap, $BitmapData)
        Local $tBuff, $iH
        Switch $iType;已测试比StringRegExp快
                Case -1
                        Return $aBmpData
                Case 0
                        For $iH = 1 To $aBmpData[2]
                                $tBuff = DllStructCreate("byte[" & ($aBmpData[1]*3) & "]", $aBmpData[4] + ($iH-1)*$aBmpData[3])
                                $aBmpData[0] &= StringTrimLeft(DllStructGetData($tBuff, 1),2)
                        Next
                        Return $aBmpData
                Case Else
                        Local $aRet[$aBmpData[2]]
                        For $iH = 1 To $aBmpData[2]
                                $tBuff = DllStructCreate("byte[" & ($aBmpData[1]*3) & "]", $aBmpData[4] + ($iH-1)*$aBmpData[3])
                                $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,将颜色数组写入图片中


自己试着写了段代码,在五楼。
感觉没有错,为什么就实现不了呢

发表于 2011-4-11 22:24:14 | 显示全部楼层
好复杂,得研究一段时间
发表于 2011-4-12 00:58:03 | 显示全部楼层
直接用像素呢,别用色块
 楼主| 发表于 2011-4-12 07:33:10 | 显示全部楼层
"不知你有没有发现前面2个得到颜色/设置颜色的GDI+函数巨慢无比?"文中的两个GDI+函数就是GdipBitmapSetPixel和GdipBitmapGetPixel
 楼主| 发表于 2011-4-12 20:49:59 | 显示全部楼层

#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[0]>=$win_xy[0]+8 And $m_xy[1]>$win_xy[1]+192 And $m_xy[0]<$win_xy[0]+$win_xy[2]+8 And $m_xy[1]<$win_xy[1]+$win_xy[3]+192 Then
                GUICtrlSetPos ( $Button3, $m_xy[0]-$win_xy[0]-8, $m_xy[1]-$win_xy[1]-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  




自己试试写了一个。
但是还是没有反应!
无奈
发表于 2011-4-18 17:58:06 | 显示全部楼层
我也遇着同样问题, 怎样解决?
发表于 2011-9-1 18:29:32 | 显示全部楼层
水平有限,持续关注中···
您需要登录后才可以回帖 登录 | 加入

本版积分规则

QQ|手机版|小黑屋|AUTOIT CN ( 鲁ICP备19019924号-1 )谷歌 百度

GMT+8, 2024-5-19 18:38 , Processed in 0.073913 second(s), 20 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表