BeBoP

Pixel Search bitmap stored within Memory?

9 posts in this topic

#1 ·  Posted (edited)

Hello, I wrote a simple function to read a pixel color from a bitmap saved in memory. The method I use takes the screenshot of a window ignoring any windows that might be on top. This is important because I want to code to work while the window is in the background(not minimized). This is why will not work for me. Would it be possible for me to some how use parts of that UDF and maintain the method of obtaining the snapshot or is there some other way I can search for a pixel in memory.

Here is the code I have so far.

#include <WinAPI.au3>
$winHandle = WinGetHandle("[CLASS:Notepad]")
ConsoleWrite(memoryReadPixel(10,10,$winHandle) & @CRLF)
Func memoryReadPixel($x,$y,$handle)
$hDC = _WinAPI_GetWindowDC($handle)
$iColor = DllCall("gdi32.dll","int","GetPixel","int",$hDC,"int",$x,"int",$y)
$sColor = Hex($iColor[0],6)
_WinAPI_ReleaseDC($handle, $hDC)
Return Hex("0x" & StringRight($sColor,2) & StringMid($sColor,3,2) & StringLeft($sColor,2))
EndFunc

I have tried using for loops with x,y,width,height checking each pixel in-between but those were much too slow.

Thanks for any help.

Edited by BeBoP

Share this post


Link to post
Share on other sites



BeBoP,

Take a look at this from Manadar - it might help you. :)

M23


Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind._______My UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Share this post


Link to post
Share on other sites

Thanks for the help Melba23 but Manadar's script can only check single pixels. I need the script to be able to preform a search. Checking every pixel is just not very efficient.

Share this post


Link to post
Share on other sites

If do not take into account the time for creating a screenshot, the _PixelSearchEx() is approximately 4 times faster than native PixelSearch(). To run this example you will need to download a library.

#Include <ScreenCapture.au3>
#Include <WinAPIEx.au3>

$Timer = TimerInit()
$Pos = PixelSearch(0, 0, @DesktopWidth, @DesktopHeight, 0x00FFFF)
ConsoleWrite('PixelSearch()   => X = ' & $Pos[0] & ', Y = ' & $Pos[1] & ', Time = ' & TimerDiff($Timer) & @CR & @CR)

$hBitmap = _ScreenCapture_Capture()

$Timer = TimerInit()
$Pos = _PixelSearchEx($hBitmap, 0x00FFFF)
ConsoleWrite('PixelSearchEx() => X = ' & $Pos[0] & ', Y = ' & $Pos[1] & ', Time = ' & TimerDiff($Timer) & @CR)

Func _PixelSearchEx($hBitmap, $iColor)

    Static $pProc = 0

    If Not $pProc Then
        If @AutoItX64 Then

            ; Not implemented!

            Return SetError(1, 0, 0)
        Else
            $pProc = __Init(Binary( _
                      '0x5553575631C0505050837C24280074118B6C2428837D14007407B801000000EB' & _
                        '0231C021C0747F8B6C24288B5D084B891C2431C03B04247F6DC7442404000000' & _
                        '008B6C24288B5D044B3B5C24047C528B6C24288B5D148B7C24048B34248B6C24' & _
                        '280FAF750401F7C1E70201FB895C24088B6C24088B5D0081E3FFFFFF003B5C24' & _
                        '2475188B5C24048B6C24288B7D082B3C244FC1E71009FB89D8EB14FF44240471' & _
                        'A0FF0C24718CB8FFFFFFFFEB0231C083C40C5E5F5B5DC21000'))
        EndIf
    EndIf

    Local $tDIB, $tInt, $tPos, $aPos, $Ret, $Error = True

    $hBitmap = _WinAPI_CopyBitmap($hBitmap)
    If @error Then
        Return SetError(1, 0, 0)
    EndIf
    Do
        $tDIB = DllStructCreate($tagDIBSECTION)
        If (Not _WinAPI_GetObject($hBitmap, DllStructGetSize($tDIB), DllStructGetPtr($tDIB))) Or (DllStructGetData($tDIB, 'bmBitsPixel') <> 32) Or (DllStructGetData($tDIB, 'biCompression')) Then
            ExitLoop
        EndIf
        $Ret = _WinAPI_CallWindowProc($pProc, 0, $iColor, DllStructGetPtr($tDIB), 0)
        If (@error) Or ($Ret = -1) Then
            ExitLoop
        EndIf
        $Error = False
    Until 1
    _WinAPI_DeleteObject($hBitmap)
    If $Error Then
        Return SetError(1, 0, 0)
    EndIf
    $tInt = DllStructCreate('int')
    $tPos = DllStructCreate('ushort;ushort', DllStructGetPtr($tInt))
    DllStructSetData($tInt, 1, $Ret)
    Dim $aPos[2]
    For $i = 0 To 1
        $aPos[$i] = DllStructGetData($tPos, $i + 1)
    Next
    Return $aPos
EndFunc   ;==>_PixelSearchEx

Share this post


Link to post
Share on other sites

#5 ·  Posted (edited)

Edit: Scratch that, the script works. The color was simply not being found. Thanks Yashied and Melba.

#include <WinAPI.au3>
#Include <WinAPIEx.au3>
#include <Array.au3>

$window = "[CLASS:Notepad]"
$handle = WinGetHandle($window)
$aWinPos = WinGetPos($handle)

$hDC = _WinAPI_GetWindowDC($handle)
$hMemDC = _WinAPI_CreateCompatibleDC($hDC)

$hBitmap = _WinAPI_CreateCompatibleBitmap($hDC, $aWinPos[2], $aWinPos[3])
_WinAPI_SelectObject($hMemDC, $hBitmap)

_PrintWindow($handle, $hMemDC)

$lookup = _PixelSearchEx($hBitmap, 0x00FFFF)

_ArrayDisplay($lookup)

_WinAPI_DeleteDC($hMemDC)
_WinAPI_ReleaseDC($handle, $hDC)
_WinAPI_DeleteObject($hBitmap)

Func _PixelSearchEx($hBitmap, $iColor)

    Static $pProc = 0

    If Not $pProc Then
        If @AutoItX64 Then
            ; Not implemented!

            Return SetError(1, 0, 0)
        Else
            $pProc = __Init(Binary( _
                      '0x5553575631C0505050837C24280074118B6C2428837D14007407B801000000EB' & _
                        '0231C021C0747F8B6C24288B5D084B891C2431C03B04247F6DC7442404000000' & _
                        '008B6C24288B5D044B3B5C24047C528B6C24288B5D148B7C24048B34248B6C24' & _
                        '280FAF750401F7C1E70201FB895C24088B6C24088B5D0081E3FFFFFF003B5C24' & _
                        '2475188B5C24048B6C24288B7D082B3C244FC1E71009FB89D8EB14FF44240471' & _
                        'A0FF0C24718CB8FFFFFFFFEB0231C083C40C5E5F5B5DC21000'))
        EndIf
    EndIf

    Local $tDIB, $tInt, $tPos, $aPos, $Ret, $Error = True

    $hBitmap = _WinAPI_CopyBitmap($hBitmap)
    If @error Then
        Return SetError(1, 0, 0)
    EndIf
    Do
        $tDIB = DllStructCreate($tagDIBSECTION)
        If (Not _WinAPI_GetObject($hBitmap, DllStructGetSize($tDIB), DllStructGetPtr($tDIB))) Or (DllStructGetData($tDIB, 'bmBitsPixel') <> 32) Or (DllStructGetData($tDIB, 'biCompression')) Then
            ExitLoop
        EndIf
        $Ret = _WinAPI_CallWindowProc($pProc, 0, $iColor, DllStructGetPtr($tDIB), 0)
        If (@error) Or ($Ret = -1) Then
            ExitLoop
        EndIf
        $Error = False
    Until 1
    _WinAPI_DeleteObject($hBitmap)
    If $Error Then
        Return SetError(1, 0, 0)
    EndIf
    $tInt = DllStructCreate('int')
    $tPos = DllStructCreate('ushort;ushort', DllStructGetPtr($tInt))
    DllStructSetData($tInt, 1, $Ret)
    Dim $aPos[2]
    For $i = 0 To 1
        $aPos[$i] = DllStructGetData($tPos, $i + 1)
    Next
    Return $aPos
EndFunc   ;==>_PixelSearchEx

Func _PrintWindow($hWnd, $hMemDC, $iFlag = 0)
    $aRet = DllCall("User32.dll", "int", "PrintWindow", _
                                         "hwnd", $hWnd, _
                                         "hwnd", $hMemDC, _
                                         "int", $iFlag)
    Return $aRet[0]
EndFunc   ;==>_PrintWindow
Edited by BeBoP
1 person likes this

Share this post


Link to post
Share on other sites

#7 ·  Posted (edited)

Hello, I wrote a simple function to read a pixel color from a bitmap saved in memory. The method I use takes the screenshot of a window ignoring any windows that might be on top. This is important because I want to code to work while the window is in the background(not minimized). This is why will not work for me. Would it be possible for me to some how use parts of that UDF and maintain the method of obtaining the snapshot or is there some other way I can search for a pixel in memory.

Actually, when I started writing FastFind UDF, I initialy wanted to use PrintWindow (to be able to track window content, even when window is hidden, out of screen or minimized) and I've done some experimentations with it. Unfortunately, it appears to be very application dependant, and OS dependant. For instance, Flash applications do not render properly with Printwindow. Also hidden applications appeared to be properly captured in some cases but not in others. That's the reason I prefered not to use Printwindow.

So I confirm that FastFind can't capture hidden content in a reliable way.

Edited by FastFrench

Share this post


Link to post
Share on other sites

#8 ·  Posted (edited)

On 1/10/2012 at 2:55 AM, BeBoP said:

Edit: Scratch that, the script works. The color was simply not being found. Thanks Yashied and Melba.

#include <WinAPI.au3>
#Include <WinAPIEx.au3>
#include <Array.au3>

$window = "[CLASS:Notepad]"
$handle = WinGetHandle($window)
$aWinPos = WinGetPos($handle)

$hDC = _WinAPI_GetWindowDC($handle)
$hMemDC = _WinAPI_CreateCompatibleDC($hDC)

$hBitmap = _WinAPI_CreateCompatibleBitmap($hDC, $aWinPos[2], $aWinPos[3])
_WinAPI_SelectObject($hMemDC, $hBitmap)

_PrintWindow($handle, $hMemDC)

$lookup = _PixelSearchEx($hBitmap, 0x00FFFF)

_ArrayDisplay($lookup)

_WinAPI_DeleteDC($hMemDC)
_WinAPI_ReleaseDC($handle, $hDC)
_WinAPI_DeleteObject($hBitmap)

Func _PixelSearchEx($hBitmap, $iColor)

    Static $pProc = 0

    If Not $pProc Then
        If @AutoItX64 Then
            ; Not implemented!

            Return SetError(1, 0, 0)
        Else
            $pProc = __Init(Binary( _
                      '0x5553575631C0505050837C24280074118B6C2428837D14007407B801000000EB' & _
                        '0231C021C0747F8B6C24288B5D084B891C2431C03B04247F6DC7442404000000' & _
                        '008B6C24288B5D044B3B5C24047C528B6C24288B5D148B7C24048B34248B6C24' & _
                        '280FAF750401F7C1E70201FB895C24088B6C24088B5D0081E3FFFFFF003B5C24' & _
                        '2475188B5C24048B6C24288B7D082B3C244FC1E71009FB89D8EB14FF44240471' & _
                        'A0FF0C24718CB8FFFFFFFFEB0231C083C40C5E5F5B5DC21000'))
        EndIf
    EndIf

    Local $tDIB, $tInt, $tPos, $aPos, $Ret, $Error = True

    $hBitmap = _WinAPI_CopyBitmap($hBitmap)
    If @error Then
        Return SetError(1, 0, 0)
    EndIf
    Do
        $tDIB = DllStructCreate($tagDIBSECTION)
        If (Not _WinAPI_GetObject($hBitmap, DllStructGetSize($tDIB), DllStructGetPtr($tDIB))) Or (DllStructGetData($tDIB, 'bmBitsPixel') <> 32) Or (DllStructGetData($tDIB, 'biCompression')) Then
            ExitLoop
        EndIf
        $Ret = _WinAPI_CallWindowProc($pProc, 0, $iColor, DllStructGetPtr($tDIB), 0)
        If (@error) Or ($Ret = -1) Then
            ExitLoop
        EndIf
        $Error = False
    Until 1
    _WinAPI_DeleteObject($hBitmap)
    If $Error Then
        Return SetError(1, 0, 0)
    EndIf
    $tInt = DllStructCreate('int')
    $tPos = DllStructCreate('ushort;ushort', DllStructGetPtr($tInt))
    DllStructSetData($tInt, 1, $Ret)
    Dim $aPos[2]
    For $i = 0 To 1
        $aPos[$i] = DllStructGetData($tPos, $i + 1)
    Next
    Return $aPos
EndFunc   ;==>_PixelSearchEx

Func _PrintWindow($hWnd, $hMemDC, $iFlag = 0)
    $aRet = DllCall("User32.dll", "int", "PrintWindow", _
                                         "hwnd", $hWnd, _
                                         "hwnd", $hMemDC, _
                                         "int", $iFlag)
    Return $aRet[0]
EndFunc   ;==>_PrintWindow

The code is good working.

But I want to search in rectangle area of Notepad Program. How to do this? 

Edited by Wanarmal

Share this post


Link to post
Share on other sites

Yeh!! I got it.

I use _WinAPI_BitBlt fuction.

Thank you for code from this topic.

It the best code of pixel search. :)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now