Jump to content

What if I need to find a picture on screen twice?


mikjay
 Share

Recommended Posts

Hi all,

I've successfully implemented PtB_ClickBMP in my script to find the coordinates of 4 pictures on screen, that I have saved as bitmaps on disk. These coordinates are stored to variables, and used later. The script ends up dragging the objects to blank space in a new location. The place they end up is variable, so I need to find the pictures again. When I call the function again, it returns the old locations of the 4 objects. This happens regardless if the objects exist in the old location or not. When I run the second call by itself, it finds the new location just fine. It seems to me that the variables have already been populated, so the function returns the old variables. I'm not absolutely sure, as it is totally beyond my understanding. Does anybody have any idea what is going on? Thanks!

Edited by mikjay
Link to comment
Share on other sites

Hi,

i wrote _PtB_ClickBmp() to find a picture on a screen or in a window. It seems that it works^^. I´ll try to understand your problem, so lets go:

The script ends up dragging the objects to blank space in a new location.  The place they end up is variable, so I need to find the pictures again.  

How does your script "drag the objects...in a new location"?

When I call the function again, it returns the old locations of the 4 objects

I´ll try to understand: You have found the correct position of the searched pictures at the screen. Then your script is moving this "picture" to a new location. Now you want to find the changed position and call the function a second time. But the function returns not the new location, but the old location!?

This is strange, because _PtB_ClickBmp() makes a screenshot and searches the picture within the data of the screenshot-bitmap....If the image is found at the old location, it can only mean that the position of the image has not changed. At least not in the area, which is stored in a screenshot. Sorry for my bad grammar^^

I think, now its the time to show me the relevant part of your script so that i  comprehend what´s going on there....  :)

Andy

Link to comment
Share on other sites

Hi Andy, thanks for your reply, and the great function!

When you told me the function takes a screenshot of the search area and searches that bitmap for the picture(s) in question, it made me wonder if the screenshot variables stayed the same for all the function calls. It would make sense, as the first 4 pics are found with the desktop being exactly the same. It's strange though, the script looks like it resets the variables at the end, yet in my case it seems to be reusing the same screenshot.

In my second look through, it looks like $pBitmap is not released. However, when I restored the ;_GDIPlus_ImageDispose($pBitmap) ;zerstört die pixeldatastruct, daher erst später!!!

line, it causes autoit to crash. I can still post my relevant code, but this seems to be an issue. What do you think?

_GDIPlus_Startup()
$postooltde = _PtB_ClickBMP(@DesktopDir & "\Test Dir\tooltde.bmp")
If @error Then
    MsgBox(48, "Not Found", "TOOLTDE,500 was not found.  Please add it to your Home Collection and try again.")
    Exit
EndIf
$postoolcma = _PtB_ClickBMP(@DesktopDir & "\Test Dir\toolcma.bmp")
If @error Then
    MsgBox(48, "Not Found", "TOOL_CMA_EVERETT was not found.  Please add it to your Home Collection and try again.")
    Exit
EndIf
$postoolde = _PtB_ClickBMP(@DesktopDir & "\Test Dir\toolde.bmp")
If @error Then
    MsgBox(48, "Not Found", "TOOL_DE_EVERETT was not found.  Please add it to your Home Collection and try again.")
    Exit
EndIf
$postoolgrp = _PtB_ClickBMP(@DesktopDir & "\Test Dir\toolgrp.bmp")
If @error Then
    MsgBox(48, "Not Found", "TOOL_GROUP_EVERETT was not found.  Please add it to your Home Collection and try again.")
    Exit
EndIf

;Body of code

;To demonstrate copying the objects
        ControlSend("", "", "", "{CTRLDOWN}")
    MouseClick("primary", $postoolcma[0],$postoolcma[1])
    MouseClick("primary", $postoolde[0],$postoolde[1])
    MouseClick("primary", $postoolgrp[0],$postoolgrp[1])
    ControlSend("", "", "", "{CTRLUP}")
    Sleep(500)
    MouseClickDrag("primary", $postoolcma[0],$postoolcma[1], 542, 372)
WinSetState("Home Collection", "", @SW_MINIMIZE) ;Attempted to hide the original window so it wouldn't interfere
;Now to find the new locations
        _PtB_ClickBMP(@DesktopDir & "\Test Dir\toolcma.bmp", "Object Browser", "primary", 1)
    ControlSend("", "", "", "{CTRLDOWN}")
    _PtB_ClickBMP(@DesktopDir & "\Test Dir\toolde.bmp", "Object Browser", "primary", 1)
    _PtB_ClickBMP(@DesktopDir & "\Test Dir\toolgrp.bmp", "Object Browser", "primary", 1)
    ControlSend("", "", "", "{CTRLUP}")
Edited by mikjay
Link to comment
Share on other sites

 

In my second look through, it looks like $pBitmap is not released

arrggghhh....you are right! This is because i copied the function out of the PushTheButton-Script after the changes in there...

I will fix this, big THX for the reply!

And btw., do you use the prospeed.dll?

Andy

Link to comment
Share on other sites

Thanks, Andy!

This is where I come across as very newbish - I'm not sure how to use DLLs unless I have it in the script directory. In my case, I'd like the script to be as low impact as possible, meaning the less it has to install files on disk the better. I have been using clickbmp on slow mode as a result.

Link to comment
Share on other sites

  hmmmm, the problem was fixed in one of the earlier versions. Try the following script pls or download the newest _PtB_ClickBMP() (which is part of the PushTheButton-Script)  here

The script copies a part of the Windows-"Start"-Icon into a window. After that, this "image" will be searched at the screen. The position of the found image will be shown in a tooltip. Move the window and you will see that the _PtB_ClickBMP()-function will find every position correctly.

#include <WinAPI.au3>
#include <Array.au3>
#include <GDIPlus.au3>
#include <GDIPlusConstants.au3>
#include <ScreenCapture.au3>
#include <StructureConstants.au3>
#include <WinAPI.au3>
;#include <prospeed30.au3>
#include <WindowsConstants.au3>
#include <misc.au3>
#include-once

;**********example***************
If FileExists("prospeed.dll") Then $prospeed_dll = DllOpen("prospeed.dll")

$bmpfile = "test.bmp"
MsgBox(262144, "Example", "Press OK to start the test, ESC to end test") ;### Debug MSGBOX
_GDIPlus_Startup()
_ScreenCapture_Capture($bmpfile, 15, @DesktopHeight - 20, 20, @DesktopHeight - 13, False) ;Windows-Logo at START-Button

GUICreate("Move the Window!")
GUICtrlCreatePic($bmpfile, 10, 10, 5, 7)
GUISetState(@SW_SHOW)


Do
    $timerinit = TimerInit()
    $coord = _PtB_ClickBMP($bmpfile, "FULLSCREEN", "right", 0) ;klicks left onto the button
    If @error Then
        ToolTip("Bitmap not found!")
    Else
        $zeit = TimerDiff($timerinit)
        ToolTip("Button found " & StringFormat("in : %.3f%", $zeit / 1000) & " Seconds!" & @CRLF & "at x/y   " & $coord[0] & " / " & $coord[1]) ;### Debug MSGBOX
        sleep(1000)
    EndIf

Until _IsPressed("1B") or guigetmsg()=-3
If FileExists("prospeed.dll") Then DllClose("prospeed.dll")
;***********example end**************






; #FUNCTION# ====================================================================================================================
; Name...........:     _PtB_clickBMP  (needs prospeed.dll from http://frabbing.bplaced.net/ for fast search in memory)
; Description ...:     searches a Bitmap in the full Screen or in a Window and clicks at the found position of the Bitmap
;                    It is recommended to use the PushTheButton-Program (www.AutoIt.de) for the creation of the Bitmap
; Syntax.........:     _PtB_clickBMP($bitmapfile[, $hWin = "FULLSCREEN"[,$sMouseButton="left"[, $iClicks=1 ]]]]])
; Parameters ....:     $bitmapfile     - Name of the Bitmap-File to search for
;                      $hWin           - Title/Handle of the window to search in, or "FULLSCREEN", or "" for active window
;                    $MouseButton    - The button to click: "left", "right", "middle", "main", "menu", "primary", "secondary".
;                    $iClick            - The number of times to click the mouse. Default is 1. 0 is possible^^
; Return values .:     Success          - Array with coordinates of the Mouseclick x=array[0] y=array[1]
;                                   - if "FULLSCREEN" then coordinates are absolute screen coordinates
;                                    - otherwise relative coords to the active window
;                      Failure          - @error is set to 1
; Author ........:     Andy @ www.autoit.de
; Modified.......:
; Remarks .......:
; Related .......:
; Link ..........;
; Example .......; Yes
; ===============================================================================================================================
;
;TODO: wenn vertikale scrollbalken im fenster/fullscreen sind, scrollen erlauben und nur scrollbalken auf bewegung checken

;untersucht, ob Bitmap2 in Bitmap1 enthalten ist
;Originalfunc by JunkEW , modified by Andy@ www.autoit.de, finds the exact match
Func _PtB_ClickBMP($bitmapfile, $hWin = "FULLSCREEN", $sMousebutton = "left", $iClicks = 0) ;rückgabe x- und y-position des gefundenen hotspots in einem array [0]und[1]

    Dim $aresult[2] ;return array x- and y-coords
    Local $gefunden = 0, $maxanzahlpixel = 50, $exitflag = 0, $check, $pixel, $px, $py, $dx, $dy
    Local $window_height, $window_width, $xy, $pix, $prozent

    If $hWin = "" Then $hWin = "[ACTIVE]" ;
    If $hWin = Default Then $hWin = "FULLSCREEN" ;suche im gesamten Bildschirminhalt
    If $sMousebutton = Default Then $sMousebutton = "left"
    If $iClicks = Default Then $iClicks = 1
    Local $opt_1 = Opt("mouseclickdelay") ;sichern der Optionen, werden am ende der Funktion wieder hergestellt
    Local $opt_2 = Opt("mouseclickdowndelay")
    Local $opt_3 = Opt("MouseCoordMode")
    Local $opt_4 = Opt("PixelCoordMode")
    Local $PtBfile = StringTrimRight($bitmapfile, StringLen($bitmapfile) - StringInStr($bitmapfile, ".") + 1) & ".ptb"
    Opt("mouseclickdelay", 1)
    Opt("mouseclickdowndelay", 1)
    ;im ptbfile sind Parameter für das Suchen der Bitmaps abgelegt
    Local $file = FileOpen($PtBfile, 0) ;daten lesen
    If $file = -1 Then ;fehler beim datenlesen, oder ptb-Datei nicht vorhanden
        If FileExists($bitmapfile) Then ;wenn es aber eine Bitmap gibt, dann kann man auch nur mit der
            $Anzahl_bestpixel = 500 ;bitmapsuche suchen
        Else ;wenn es weder Bitmap noch *.ptb-file gibt, fällt die Suche aus^^
            MsgBox(262144 + 1, "Fehler in Funktion _PtB_ClickBMP()", "Keine Bitmap und keine *.ptb-Datei mit Informationen zur Suche gefunden!" & @CRLF & "Bitte benutzen Sie das Programm PushTheButton, um eine Bitmap zu erzeugen!")
            SetError(1, 0, 1)
            Return -1
        EndIf
    Else ;ansonsten daten aus der *.ptb-Datei einlesen
        $check = FileReadLine($file, 1) ;pixelchecksum
        $pixel = FileReadLine($file, 2) ;pixelfarbe in hex RGB
        $Anzahl_bestpixel = Number(FileReadLine($file, 3)) ;niedrigste Anzahl der gesuchten Pixel
        $px = FileReadLine($file, 4) ;x-Versatz des Hotspots innerhalb des pics
        $py = FileReadLine($file, 5) ;y-Versatz des Hotspots innerhalb des pics
        $dx = FileReadLine($file, 6) ;breite in pixel
        $dy = FileReadLine($file, 7) ;hoehe in pixel
        FileClose($PtBfile)
    EndIf
    If $hWin = "FULLSCREEN" Then
        Opt("PixelCoordmode", 1) ; für Fullscreen setzen
        Opt("MouseCoordMode", 1) ;gesamter screen
        ;thx an Funkey
        Local $VirtualDesktopWidth = DllCall("user32.dll", "int", "GetSystemMetrics", "int", 78) ;sm_virtualwidth
        $window_width = $VirtualDesktopWidth[0]
        Local $VirtualDesktopHeight = DllCall("user32.dll", "int", "GetSystemMetrics", "int", 79) ;sm_virtualheight
        $window_height = $VirtualDesktopHeight[0]
    Else
        Opt("PixelCoordmode", 0) ;für lokales Fenster setzen
        Opt("MouseCoordMode", 0) ;aktives Fenster
        $xy = WinGetPos($hWin) ;breite und höhe des Fensters
        $window_width = $xy[2]
        $window_height = $xy[3]
    EndIf

    If $Anzahl_bestpixel > $maxanzahlpixel Then ;wenn wenige passende farbige pixel auf dem Bildschirm sind...
        ConsoleWrite("Verfahren mit Bitmapsuche gewählt" & @CRLF) ;dann strings suchen (Bitmap2 in Bitmap1 suchen)
        If FileExists(@ScriptDir & "\ProSpeed.dll") Then
            $aresult = _FindBMP($hWin, $bitmapfile) ;suchen per stringfunktion in der Bitmap
        Else
            $aresult = _FindBMP_slow($hWin, $bitmapfile) ;suchen per stringfunktion in der Bitmap
        EndIf
        If IsArray($aresult) Then $gefunden = 1

    Else ;wenn es nur wenige Pixel in der angegebenen Farbe gibt, ist diese Variante mit pixelsearxch schneller
        ConsoleWrite("Verfahren mit Pixelsuche gewählt" & @CRLF)
        Local $x = 0, $y = 0
        While 1
            $pix = PixelSearch($x, $y, $window_width, $window_height, Dec($pixel)) ;pixelfarbe suchen
            If @error Or $exitflag Then ExitLoop ;nicht gefunden oder esc gedrückt, dann pagedown
            ;msgbox(0,"pix gefunden an",$pix[0]&"  "&$pix[1])
            While 1
                $x = $pix[0] ;x- und y-koordinaten des gefundenen pixels (hotspot)
                $y = $pix[1]
                ;$prozent = ($y * $window_width + $x) * 100 / $window_width / $window_height
                ;ToolTip(StringFormat("Suche läuft : %.0f%%", $prozent), $window_width / 2, $window_height / 2)
                Local $p1x = $x - $px, $p1y = $y - $py ;umrechnen der hotspotkoordinaten für checksum
                Local $p2x = $p1x + $dx - 1, $p2y = $p1y + $dy - 1
                ;    msgbox(0,"pixel mit farbe "&$pixel,$p1x&"  "&$p1y&@crlf&$p2x&"  "&$p2y&@crlf&PixelChecksum($p1x,$p1y,$p2x,$p2y))
                If PixelChecksum($p1x, $p1y, $p2x, $p2y) = $check Then ;wenn pixelchecksum gleich der gespeicherten pixelchecksum ist, dann gefunden
                    $gefunden = 1
                    $aresult[0] = $x
                    $aresult[1] = $y
                    ExitLoop
                EndIf
                $x += 1 ;ein pixel weiter in der zeile
                $pix = PixelSearch($x, $y, $window_width, $y, Dec($pixel)) ;pixel suchen
                If @error Or $exitflag Then ExitLoop ;wenn in der zeile kein pixel mehr, dann raus
            WEnd
            If $gefunden = 1 Then ExitLoop
            $x = 0 ;neue spalte
            $y += 1 ;neue zeile
        WEnd
    EndIf
    $exitflag = 0
    ;ToolTip("")
    If $gefunden = 0 Then ;gesuchte Pixel nicht gefunden
        SetError(1, 0, 1)
        Return -1
    Else ;gefunden
        If $sMousebutton <> "" Then
            MouseMove($aresult[0], $aresult[1], 0) ;maus schnellstmöglich zur Position
            For $i = 1 To $iClicks ;anzahl der klicks
                MouseDown($sMousebutton) ;es wird die maustaste betätigt
                MouseUp($sMousebutton)
            Next
        EndIf
        SetError(0, 0, 0)
        Opt("mouseclickdelay", $opt_1)
        Opt("mouseclickdowndelay", $opt_2)
        Opt("MouseCoordMode", $opt_3)
        Opt("PixelCoordMode", $opt_4)
        Return $aresult ;array mit den hotspot-koordinaten zurückgeben
    EndIf
EndFunc   ;==>_PtB_ClickBMP


;untersucht, ob Bitmap2 in Bitmap1 enthalten ist
;Originalfunc by JunkEW , modified by Andy@ www.autoit.de, finds the exact match
Func _FindBMP($BMP1, $BMP2)
    Dim $BMP1Data = "", $BMP1Width = 0, $BMP1Height = 0, $BMP1LineWidth = 0, $pbitmap1 = 0, $bitmapinfo1
    Dim $BMP2Data = "", $BMP2Width = 0, $BMP2Height = 0, $BMP2LineWidth = 0, $pbitmap2 = 0, $bitmapinfo2
    Dim $koord[2]
    Local $searchFor, $line, $iPos = 1, $imgBytes = 3, $exit
    Local $ptr1, $ptr2, $struct_bmp1, $struct_bmp2, $struct_1, $struct_2
    Local $string_1, $string_2, $prozent, $flag, $a, $b, $xy
    Local $VirtualDesktopWidth = DllCall("user32.dll", "int", "GetSystemMetrics", "int", 78) ;sm_virtualwidth
    Local $DesktopWidth = $VirtualDesktopWidth[0]
    Local $VirtualDesktopHeight = DllCall("user32.dll", "int", "GetSystemMetrics", "int", 79) ;sm_virtualheight
    Local $DesktopHeight = $VirtualDesktopHeight[0]


    $ptr1 = _GetImage($BMP1, $BMP1Data, $BMP1Width, $BMP1Height, $BMP1LineWidth, $pbitmap1, $bitmapinfo1) ;holt alle Infos aus der Bitmap (Fullscreen, Fenster oder File)
    $ptr2 = _GetImage($BMP2, $BMP2Data, $BMP2Width, $BMP2Height, $BMP2LineWidth, $pbitmap2, $bitmapinfo2)

    If $BMP2Height = 0 Then
        SetError(1, 0, 0)
        Return False
    EndIf

    $exit = DllStructGetSize($ptr1) + 1 ;letzte mögliche bildschirm(fenster) position)
    $struct_2 = DllStructCreate("ubyte[" & ($BMP2Width * 3) & "]");erste zeile der 2. bitmap, nach dieser Position wird gin der ersten Bitmap gesucht
    DllStructSetData($struct_2, 1, $BMP2Data)

    ;erste Zeile der Bitmap2 in Bitmap1 suchen
    $iPos = FindBytes(DllStructGetPtr($ptr1), 0, DllStructGetSize($ptr1) - DllStructGetSize($struct_2) - (($BMP2Height - 1) * $BMP1LineWidth), DllStructGetPtr($struct_2), DllStructGetSize($struct_2)) + 1
    ;zeilenweises vergleichen der beiden bitmaps, ist bitmap2 in bitmap1 enthalten?
    While 1
        If $iPos <> 0 And $iPos <> $exit Then ;nur, wenn es eine übereinstimmung gibt weitermachen
            ;    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $iPos = ' & $iPos & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
            Local $e = Mod(($iPos - 1), $BMP1LineWidth) ;position innerhalb des Strings
            If $e / $imgBytes = Int($e / $imgBytes) Then ;prüfen ob ipos am anfang eines farbbits steht, wenn nicht, nächste zeile suchen
;~                 $prozent = $iPos / 3 * 100 / $BMP1Width / $BMP1Height
;~                 ToolTip(StringFormat("Suche läuft : %.0f%%", $prozent) & @CRLF & "Zeile " & Int($iPos / $imgBytes / $BMP1Width), $BMP1Width / 2, $BMP1Height / 2)
                $flag = 0
                For $i = 0 To $BMP2Height - 1 ;zeilenweise die Bitmaps vergleichen
                    $a = DllStructGetPtr($ptr1) + $iPos - 1 + $i * $BMP1LineWidth ;pointer auf die position in der struct, an der die erste übereinstimmung ist
                    $b = DllStructGetPtr($ptr2) + $i * $BMP2LineWidth ;pointer auf die zeile
                    If CompareBytes($a, $b, 3 * $BMP2Width, 0) <> 0 Then ;wenn keine Übereinstimmung, dann nächste suchen
                        $flag = 1
                        ExitLoop
                    EndIf
                Next
                If $flag = 0 Then ;alle zeilen haben übereingestimmt, BMP2 ist in BMP1 enthalten!                    $koord[0] = Mod(($iPos - 1), $BMP1LineWidth) / $imgBytes ;koordinaten auf dem screen
                    $koord[0] = Mod(($iPos - 1), $BMP1LineWidth) / $imgBytes ;koordinaten auf dem screen
                    $koord[1] = Int(($iPos - 1) / $BMP1LineWidth)
                    $BMP1Data = 0 ;strukturen löschen, Speicher freigeben
                    $BMP2Data = 0
                    $struct_2 = 0
                    $ptr1 = 0
                    $ptr2 = 0
                    _GDIPlus_BitmapUnlockBits($pbitmap1, $bitmapinfo1)
                    _GDIPlus_BitmapUnlockBits($pbitmap2, $bitmapinfo2)
                    _GDIPlus_ImageDispose($pbitmap1) ;Bitmaps löschen
                    _GDIPlus_ImageDispose($pbitmap2)
                    Return $koord
                EndIf

                $iPos = FindBytes(DllStructGetPtr($ptr1), $iPos + $imgBytes, DllStructGetSize($ptr1) - DllStructGetSize($struct_bmp2) - (($BMP2Height - 1) * $BMP1LineWidth) - $iPos, DllStructGetPtr($struct_2), DllStructGetSize($struct_2)) + 1
                If $iPos = 0 Or $iPos = $exit Then ExitLoop ;nicht gefunden
            Else ;ipos ist innerhalb eines farbbits und nicht am anfang
                $iPos = FindBytes(DllStructGetPtr($ptr1), $iPos + 1, DllStructGetSize($ptr1) - DllStructGetSize($struct_bmp2) - (($BMP2Height - 1) * $BMP1LineWidth) - $iPos, DllStructGetPtr($struct_2), DllStructGetSize($struct_2)) + 1
                If $iPos = 0 Or $iPos = $exit Then ExitLoop
            EndIf
        Else
            ExitLoop
        EndIf
    WEnd
    $BMP1Data = 0 ;strukturen löschen, Speicher freigeben
    $BMP2Data = 0
    $struct_2 = 0
    $ptr1 = 0
    $ptr2 = 0
    _GDIPlus_BitmapUnlockBits($pbitmap1, $bitmapinfo1)
    _GDIPlus_BitmapUnlockBits($pbitmap2, $bitmapinfo2)
    _GDIPlus_ImageDispose($pbitmap1) ;Bitmaps löschen
    _GDIPlus_ImageDispose($pbitmap2)
    SetError(1, 0, 1)
    Return 0 ;
EndFunc   ;==>_FindBMP


;aus einer Datei oder einem Screenshot die Pixeldaten im BGR-Format in einen String schreiben
;Originalfunc by JunkEW , modified by Andy@ www.autoit.de, gets the Bitmapdata as BGR-String
Func _GetImage($bmpfile, ByRef $BMPDataStart, ByRef $Width, ByRef $Height, ByRef $Stride, ByRef $pBitmap, ByRef $BitmapData)

    Local $Scan0, $hbScreen, $handle, $imgBytes = 3, $pixeldata, $pixeldata2, $xy
    Local $VirtualDesktopWidth = DllCall("user32.dll", "int", "GetSystemMetrics", "int", 78) ;sm_virtualwidth
    Local $VirtualDesktopHeight = DllCall("user32.dll", "int", "GetSystemMetrics", "int", 79) ;sm_virtualheight

    ; Load the bitmap to search in
    If StringUpper($bmpfile) = "FULLSCREEN" Then
        $hbScreen = _ScreenCapture_Capture("", 0, 0, $VirtualDesktopWidth[0], $VirtualDesktopHeight[0], False)
        If @error Then MsgBox(0, "", "Fehler Screencapture FULLSCREEN")
        $pBitmap = _GDIPlus_BitmapCreateFromHBITMAP($hbScreen); returns memory bitmap
        If @error Then MsgBox(0, "", "Fehler Bitmapcreate_FromHBITMAP Screen")
    Else
        ;try to get a handle
        $handle = WinGetHandle($bmpfile)
        If @error Then
            ;Assume its an unknown handle so correct filename should be given
            $hbScreen = _GDIPlus_BitmapCreateFromFile($bmpfile)
            $pBitmap = $hbScreen
            If @error Then MsgBox(0, "", "Fehler BitmapCreateFromFile")
        Else ;aktuelles fenster
            $xy = WinGetPos($bmpfile)
            $hbScreen = _ScreenCapture_CaptureWnd("", $handle, 0, 0, $xy[2], $xy[3], False)
            If @error Then MsgBox(0, "", "Fehler Screencapturewnd")
            $pBitmap = _GDIPlus_BitmapCreateFromHBITMAP($hbScreen); returns memory bitmap
            If @error Then MsgBox(0, "", "Fehler BitmapCreateFromHBITMAP File")
        EndIf
    EndIf

    ;_GDIPlus_BitmapLockBits gibt $tagGDIPBITMAPDATA-Struktur zurück
    $BitmapData = _GDIPlus_BitmapLockBits($pBitmap, 0, 0, _GDIPlus_ImageGetWidth($pBitmap), _GDIPlus_ImageGetHeight($pBitmap), $GDIP_ILMREAD, $GDIP_PXF24RGB)
    If @error Then MsgBox(0, "", "Error locking region " & @error)
    $Stride = DllStructGetData($BitmapData, "Stride");Stride - Offset, in bytes, between consecutive scan lines of the bitmap. If the stride is positive, the bitmap is top-down. If the stride is negative, the bitmap is bottom-up.
    $Width = DllStructGetData($BitmapData, "Width");Image width - Number of pixels in one scan line of the bitmap.
    $Height = DllStructGetData($BitmapData, "Height");Image height - Number of scan lines in the bitmap.
    ;$pixelFormat = DllStructGetData($BitmapData, "PixelFormat");Pixel format - Integer that specifies the pixel format of the bitmap
    $Scan0 = DllStructGetData($BitmapData, "Scan0");Scan0 - Pointer to the first (index 0) scan line of the bitmap.
    $pixeldata = DllStructCreate("byte[" & (Abs($Stride) * ($Height)) & "]", $Scan0)
    $BMPDataStart = DllStructGetData($pixeldata, 1) ;string im Struct-format, d.h. Byte+nulByte, in dem die pixeldaten im BGR-Format stehen
    ;    _GDIPlus_BitmapUnlockBits($pbitmap, $BitmapData)
    ;_GDIPlus_ImageDispose($pBitmap) zerstört die pixeldatastruct, daher erst später!!!
    _WinAPI_DeleteObject($hbScreen)
    Return $pixeldata
EndFunc   ;==>_GetImage

Func _findbytes($string_1, $string_2, $startpos) ;string2 im string1 finden, erst ab sehr grossen strings schneller als stringinstr()
    Local $struct_1 = DllStructCreate("ubyte[" & (StringLen($string_1) + StringLen($string_2)) & "]")
    Local $struct_2 = DllStructCreate("ubyte[" & StringLen($string_2) & "]")
    DllStructSetData($struct_1, 1, $string_1 & $string_2)
    DllStructSetData($struct_2, 1, $string_2)
    Local $t = TimerInit()
    Local $pos = FindBytes(DllStructGetPtr($struct_1), $startpos, DllStructGetSize($struct_1), DllStructGetPtr($struct_2), DllStructGetSize($struct_2)) + 1
    Local $findbytes = TimerDiff($t)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $findbytes = ' & $findbytes & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
    ;    MsgBox(262144, 'Debug line ~' & @ScriptLineNumber, 'Selection:' & @LF & '$pos' & @LF & @LF & 'Return:' & @LF & $pos) ;### Debug MSGBOX
    $struct_1 = 0
    $struct_2 = 0

    If $pos = -1 Or $pos = StringLen($string_1) + 1 Then Return 0
    Return $pos
EndFunc   ;==>_findbytes


Func CompareBytes($S_MemoryPointer1, $S_MemoryPointer2, $S_ByteSize, $S_Tolerance)
    Local $C_Compare = DllCall($prospeed_dll, "long", "CompareBytes", _
            "long", $S_MemoryPointer1, _
            "long", $S_MemoryPointer2, _
            "long", $S_ByteSize, _
            "long", $S_Tolerance)
    Return $C_Compare[0]
EndFunc   ;==>CompareBytes

Func FindBytes($b, $O, $a, $S, $L)
    Local $S_FindBytes = DllCall($prospeed_dll, "long", "FindBytes", _
            "long", $b, _
            "long", $O, _
            "long", $a, _
            "long", $S, _
            "long", $L)
    Return $S_FindBytes[0]
EndFunc   ;==>FindBytes


Func _FindBMP_slow($BMP1, $BMP2)
    Dim $BMP1Data = "", $BMP1Width = 0, $BMP1Height = 0, $BMP1LineWidth = 0, $pbitmap1 = 0, $bitmapinfo1
    Dim $BMP2Data = "", $BMP2Width = 0, $BMP2Height = 0, $BMP2LineWidth = 0, $pbitmap2 = 0, $bitmapinfo2
    Dim $koord[2]
    Local $searchFor, $line, $iPos = 1, $imgBytes = 3, $prozent, $ptr1, $ptr2
    Local $VirtualDesktopWidth = DllCall("user32.dll", "int", "GetSystemMetrics", "int", 78) ;sm_virtualwidth
    Local $DesktopWidth = $VirtualDesktopWidth[0]
    Local $VirtualDesktopHeight = DllCall("user32.dll", "int", "GetSystemMetrics", "int", 79) ;sm_virtualheight
    Local $DesktopHeight = $VirtualDesktopHeight[0]


    ; Load the bitmap to search in
    $ptr1 = _GetImage($BMP1, $BMP1Data, $BMP1Width, $BMP1Height, $BMP1LineWidth, $pbitmap1, $bitmapinfo1)
    $BMP1Data = BinaryToString($BMP1Data)
    $ptr2 = _GetImage($BMP2, $BMP2Data, $BMP2Width, $BMP2Height, $BMP2LineWidth, $pbitmap2, $bitmapinfo2)
    $BMP2Data = BinaryToString($BMP2Data)
    If $BMP2Height = 0 Then
        SetError(1, 0, 0)
        Return False
    EndIf
    Local $searchFor1 = StringMid($BMP2Data, 1, ($BMP2Width * $imgBytes)) ;1. pixel-zeile in der bitmap2 (string)
    $iPos = StringInStr($BMP1Data, $searchFor1, 2, 1) ;1. fundstelle des strings in Bitmap2
    ;zeilenweises vergleichen der beiden bitmaps, ist bitmap2 in bitmap1 enthalten?
    While 1
        Local $flag = 0
        If $iPos <> 0 Then
            If ($iPos - 1) / $imgBytes = Int(($iPos - 1) / $imgBytes) Then ;;prüfen ob ipos am anfang eines farbbits steht
                $prozent = $iPos / 3 * 100 / $DesktopWidth / $DesktopHeight
                ToolTip(StringFormat("Suche läuft : %.0f%%", $prozent) & @CRLF & "Zeile " & Int($iPos / $imgBytes / $DesktopWidth), $DesktopWidth / 2, $DesktopHeight / 2)
                For $S = 2 To $BMP2Height ;zeilenweise das suchbild mit dem screen vergleichen
                    $searchFor = StringMid($BMP2Data, 1 + (($S - 1) * $BMP2LineWidth), $BMP2Width * $imgBytes) ; s-te zeile aus dem ausschnitt
                    $line = StringMid($BMP1Data, $iPos + (($S - 1) * $BMP1LineWidth), $BMP2Width * $imgBytes) ;zeile "unter" der gefundenen zeile im screen
                    If $searchFor <> $line Then ;zeilen nicht gleich,
                        $flag = 1
                        ExitLoop ;exit for/next
                    EndIf
                Next
                If $flag = 0 Then ;alle zeilen haben übereingestimmt, BMP2 ist in BMP1 enthalten!                    $koord[0] = Mod(($iPos - 1), $BMP1LineWidth) / $imgBytes ;koordinaten auf dem screen
                    $koord[0] = Mod(($iPos - 1), $BMP1LineWidth) / $imgBytes ;koordinaten auf dem screen
                    $koord[1] = Int(($iPos - 1) / $BMP1LineWidth)
                    $BMP1Data = 0 ;strukturen löschen, Speicher freigeben
                    $BMP2Data = 0
                    $ptr1 = 0
                    $ptr2 = 0
                    _GDIPlus_BitmapUnlockBits($pbitmap1, $bitmapinfo1)
                    _GDIPlus_BitmapUnlockBits($pbitmap2, $bitmapinfo2)
                    _GDIPlus_ImageDispose($pbitmap1) ;Bitmaps löschen
                    _GDIPlus_ImageDispose($pbitmap2)
                    ToolTip("")
                    Return $koord
                EndIf
                $iPos = StringInStr($BMP1Data, $searchFor1, 2, 1, $iPos + $imgBytes)
                If $iPos = 0 Then ExitLoop ;nicht gefunden
            Else ;ipos ist innerhalb eines farbbits und nicht am anfang
                $iPos = StringInStr($BMP1Data, $searchFor1, 2, 1, $iPos + 1)
                If $iPos = 0 Then ExitLoop
            EndIf
        Else
            ExitLoop
        EndIf
    WEnd
    $BMP1Data = 0 ;strukturen löschen, Speicher freigeben
    $BMP2Data = 0
    $ptr1 = 0
    $ptr2 = 0
    _GDIPlus_BitmapUnlockBits($pbitmap1, $bitmapinfo1)
    _GDIPlus_BitmapUnlockBits($pbitmap2, $bitmapinfo2)
    _GDIPlus_ImageDispose($pbitmap1) ;Bitmaps löschen
    _GDIPlus_ImageDispose($pbitmap2)
    ToolTip("")
    SetError(1, 0, 0)
    Return 0 ;
EndFunc   ;==>_FindBMP_slow
 

I'm not sure how to use DLLs unless I have it in the script directory
  :) If you have the prospeed.dll in your script-directory, _PtB_ClickBMP() will use the dll automatically, if the script finds no dll, it will be used the "not_so_fast"-native AutoIt-Code.
Link to comment
Share on other sites

  • 1 month later...

Thanks, that one works much better!

As far as the slow compare works yes, but as soon as i copy the prospeed.dll in my script dir , it gives me

<path>\bmpcompare.au3 (353) : ==> Subscript used with non-Array variable.:

Return $S_FindBytes[0]

Return $S_FindBytes^ ERROR

->22:48:51 AutoIT3.exe ended.rc:1

Func FindBytes($b, $O, $a, $S, $L)
    Local $S_FindBytes = DllCall($prospeed_dll, "long", "FindBytes", _
            "long", $b, _
            "long", $O, _
            "long", $a, _
            "long", $S, _
            "long", $L)
    Return $S_FindBytes[0]
EndFunc   ;==>FindBytes

Any ideas ? i am not deep into this DLL to seek it out myself.

Link to comment
Share on other sites

  • 4 months later...

Does the following example work for you?

#include <GDIPlus.au3>
#include <Misc.au3>
#include <WinAPI.au3>
#include <GDIPlusConstants.au3>
#include <ScreenCapture.au3>
;#include <prospeed30.au3>
#include-once

;**********example***************
If FileExists("prospeed.dll") Then $prospeed_dll = DllOpen("prospeed.dll")

$bmpfile = "test.bmp"
MsgBox(262144, "Example", "Press OK to start the test, ESC to end test") ;### Debug MSGBOX
_GDIPlus_Startup()
_ScreenCapture_Capture($bmpfile, 15, @DesktopHeight - 20, 20, @DesktopHeight - 13, False) ;Windows-Logo at START-Button

GUICreate("Move the Window!")
GUICtrlCreatePic($bmpfile, 10, 10, 5, 7)
GUISetState(@SW_SHOW)


Do
    $timerinit = TimerInit()
    $coord = _PtB_ClickBMP($bmpfile, "FULLSCREEN", "right", 0) ;klicks left onto the button
    If @error Then
        ToolTip("Bitmap not found!")
    Else
        $zeit = TimerDiff($timerinit)
        ToolTip("Button found " & StringFormat("in : %.3f%", $zeit / 1000) & " Seconds!" & @CRLF & "at x/y   " & $coord[0] & " / " & $coord[1]) ;### Debug MSGBOX
        sleep(1000)
    EndIf

Until _IsPressed("1B") or guigetmsg()=-3
If FileExists("prospeed.dll") Then DllClose("prospeed.dll")
;***********example end**************



; #FUNCTION# ====================================================================================================================
; Name...........:     _PtB_clickBMP  (needs prospeed.dll from http://frabbing.bplaced.net/ for fast search in memory)
; Description ...:     searches a Bitmap in the full Screen or in a Window and clicks at the found position of the Bitmap
;                    It is recommended to use the PushTheButton-Program (www.AutoIt.de) for the creation of the Bitmap
; Syntax.........:     _PtB_clickBMP($bitmapfile[, $hWin = "FULLSCREEN"[,$sMouseButton="left"[, $iClicks=1 ]]]]])
; Parameters ....:     $bitmapfile     - Name of the Bitmap-File to search for
;                      $hWin           - Title/Handle of the window to search in, or "FULLSCREEN", or "" for active window
;                    $MouseButton    - The button to click: "left", "right", "middle", "main", "menu", "primary", "secondary".
;                    $iClick            - The number of times to click the mouse. Default is 1. 0 is possible^^
; Return values .:     Success          - Array with coordinates of the Mouseclick x=array[0] y=array[1]
;                                   - if "FULLSCREEN" then coordinates are absolute screen coordinates
;                                    - otherwise relative coords to the active window
;                      Failure          - @error is set to 1
; Author ........:     Andy @ www.autoit.de
; Modified.......:
; Remarks .......:
; Related .......:
; Link ..........;
; Example .......; Yes
; ===============================================================================================================================
;
;TODO: wenn vertikale scrollbalken im fenster/fullscreen sind, scrollen erlauben und nur scrollbalken auf bewegung checken

;untersucht, ob Bitmap2 in Bitmap1 enthalten ist
;Originalfunc by JunkEW , modified by Andy@ www.autoit.de, finds the exact match
Func _PtB_ClickBMP($bitmapfile, $hWin = "FULLSCREEN", $sMousebutton = "left", $iClicks = 0) ;rückgabe x- und y-position des gefundenen hotspots in einem array [0]und[1]

    Dim $aresult[2] ;return array x- and y-coords
    Local $gefunden = 0, $maxanzahlpixel = 50, $exitflag = 0, $check, $pixel, $px, $py, $dx, $dy
    Local $window_height, $window_width, $xy, $pix, $prozent

    If $hWin = "" Then $hWin = "[ACTIVE]" ;
    If $hWin = Default Then $hWin = "FULLSCREEN" ;suche im gesamten Bildschirminhalt
    If $sMousebutton = Default Then $sMousebutton = "left"
    If $iClicks = Default Then $iClicks = 1
    Local $opt_1 = Opt("mouseclickdelay") ;sichern der Optionen, werden am ende der Funktion wieder hergestellt
    Local $opt_2 = Opt("mouseclickdowndelay")
    Local $opt_3 = Opt("MouseCoordMode")
    Local $opt_4 = Opt("PixelCoordMode")
    Local $PtBfile = StringTrimRight($bitmapfile, StringLen($bitmapfile) - StringInStr($bitmapfile, ".") + 1) & ".ptb"
    Opt("mouseclickdelay", 1)
    Opt("mouseclickdowndelay", 1)
    ;im ptbfile sind Parameter für das Suchen der Bitmaps abgelegt
    Local $file = FileOpen($PtBfile, 0) ;daten lesen
    If $file = -1 Then ;fehler beim datenlesen, oder ptb-Datei nicht vorhanden
        If FileExists($bitmapfile) Then ;wenn es aber eine Bitmap gibt, dann kann man auch nur mit der
            $Anzahl_bestpixel = 500 ;bitmapsuche suchen
        Else ;wenn es weder Bitmap noch *.ptb-file gibt, fällt die Suche aus^^
            MsgBox(262144 + 1, "Fehler in Funktion _PtB_ClickBMP()", "Keine Bitmap und keine *.ptb-Datei mit Informationen zur Suche gefunden!" & @CRLF & "Bitte benutzen Sie das Programm PushTheButton, um eine Bitmap zu erzeugen!")
            SetError(1, 0, 1)
            Return -1
        EndIf
    Else ;ansonsten daten aus der *.ptb-Datei einlesen
        $check = FileReadLine($file, 1) ;pixelchecksum
        $pixel = FileReadLine($file, 2) ;pixelfarbe in hex RGB
        $Anzahl_bestpixel = Number(FileReadLine($file, 3)) ;niedrigste Anzahl der gesuchten Pixel
        $px = FileReadLine($file, 4) ;x-Versatz des Hotspots innerhalb des pics
        $py = FileReadLine($file, 5) ;y-Versatz des Hotspots innerhalb des pics
        $dx = FileReadLine($file, 6) ;breite in pixel
        $dy = FileReadLine($file, 7) ;hoehe in pixel
        FileClose($PtBfile)
    EndIf
    If $hWin = "FULLSCREEN" Then
        Opt("PixelCoordmode", 1) ; für Fullscreen setzen
        Opt("MouseCoordMode", 1) ;gesamter screen
        ;thx an Funkey
        Local $VirtualDesktopWidth = DllCall("user32.dll", "int", "GetSystemMetrics", "int", 78) ;sm_virtualwidth
        $window_width = $VirtualDesktopWidth[0]
        Local $VirtualDesktopHeight = DllCall("user32.dll", "int", "GetSystemMetrics", "int", 79) ;sm_virtualheight
        $window_height = $VirtualDesktopHeight[0]
    Else
        Opt("PixelCoordmode", 0) ;für lokales Fenster setzen
        Opt("MouseCoordMode", 0) ;aktives Fenster
        $xy = WinGetPos($hWin) ;breite und höhe des Fensters
        $window_width = $xy[2]
        $window_height = $xy[3]
    EndIf

    If $Anzahl_bestpixel > $maxanzahlpixel Then ;wenn wenige passende farbige pixel auf dem Bildschirm sind...
        ConsoleWrite("Verfahren mit Bitmapsuche gewählt" & @CRLF) ;dann strings suchen (Bitmap2 in Bitmap1 suchen)
        If FileExists(@ScriptDir & "\ProSpeed.dll") Then
            $aresult = _FindBMP($hWin, $bitmapfile) ;suchen per stringfunktion in der Bitmap
        Else
            $aresult = _FindBMP_slow($hWin, $bitmapfile) ;suchen per stringfunktion in der Bitmap
        EndIf
        If IsArray($aresult) Then $gefunden = 1

    Else ;wenn es nur wenige Pixel in der angegebenen Farbe gibt, ist diese Variante mit pixelsearxch schneller
        ConsoleWrite("Verfahren mit Pixelsuche gewählt" & @CRLF)
        Local $x = 0, $y = 0
        While 1
            $pix = PixelSearch($x, $y, $window_width, $window_height, Dec($pixel)) ;pixelfarbe suchen
            If @error Or $exitflag Then ExitLoop ;nicht gefunden oder esc gedrückt, dann pagedown
            ;msgbox(0,"pix gefunden an",$pix[0]&"  "&$pix[1])
            While 1
                $x = $pix[0] ;x- und y-koordinaten des gefundenen pixels (hotspot)
                $y = $pix[1]
                ;$prozent = ($y * $window_width + $x) * 100 / $window_width / $window_height
                ;ToolTip(StringFormat("Suche läuft : %.0f%%", $prozent), $window_width / 2, $window_height / 2)
                Local $p1x = $x - $px, $p1y = $y - $py ;umrechnen der hotspotkoordinaten für checksum
                Local $p2x = $p1x + $dx - 1, $p2y = $p1y + $dy - 1
                ;    msgbox(0,"pixel mit farbe "&$pixel,$p1x&"  "&$p1y&@crlf&$p2x&"  "&$p2y&@crlf&PixelChecksum($p1x,$p1y,$p2x,$p2y))
                If PixelChecksum($p1x, $p1y, $p2x, $p2y) = $check Then ;wenn pixelchecksum gleich der gespeicherten pixelchecksum ist, dann gefunden
                    $gefunden = 1
                    $aresult[0] = $x
                    $aresult[1] = $y
                    ExitLoop
                EndIf
                $x += 1 ;ein pixel weiter in der zeile
                $pix = PixelSearch($x, $y, $window_width, $y, Dec($pixel)) ;pixel suchen
                If @error Or $exitflag Then ExitLoop ;wenn in der zeile kein pixel mehr, dann raus
            WEnd
            If $gefunden = 1 Then ExitLoop
            $x = 0 ;neue spalte
            $y += 1 ;neue zeile
        WEnd
    EndIf
    $exitflag = 0
    ;ToolTip("")
    If $gefunden = 0 Then ;gesuchte Pixel nicht gefunden
        SetError(1, 0, 1)
        Return -1
    Else ;gefunden
        If $sMousebutton <> "" Then
            MouseMove($aresult[0], $aresult[1], 0) ;maus schnellstmöglich zur Position
            For $i = 1 To $iClicks ;anzahl der klicks
                MouseDown($sMousebutton) ;es wird die maustaste betätigt
                MouseUp($sMousebutton)
            Next
        EndIf
        SetError(0, 0, 0)
        Opt("mouseclickdelay", $opt_1)
        Opt("mouseclickdowndelay", $opt_2)
        Opt("MouseCoordMode", $opt_3)
        Opt("PixelCoordMode", $opt_4)
        Return $aresult ;array mit den hotspot-koordinaten zurückgeben
    EndIf
EndFunc   ;==>_PtB_ClickBMP


;untersucht, ob Bitmap2 in Bitmap1 enthalten ist
;Originalfunc by JunkEW , modified by Andy@ www.autoit.de, finds the exact match
Func _FindBMP($BMP1, $BMP2)
    Dim $BMP1Data = "", $BMP1Width = 0, $BMP1Height = 0, $BMP1LineWidth = 0, $pbitmap1 = 0, $bitmapinfo1
    Dim $BMP2Data = "", $BMP2Width = 0, $BMP2Height = 0, $BMP2LineWidth = 0, $pbitmap2 = 0, $bitmapinfo2
    Dim $koord[2]
    Local $searchFor, $line, $iPos = 1, $imgBytes = 3, $exit
    Local $ptr1, $ptr2, $struct_bmp1, $struct_bmp2, $struct_1, $struct_2
    Local $string_1, $string_2, $prozent, $flag, $a, $b, $xy
    Local $VirtualDesktopWidth = DllCall("user32.dll", "int", "GetSystemMetrics", "int", 78) ;sm_virtualwidth
    Local $DesktopWidth = $VirtualDesktopWidth[0]
    Local $VirtualDesktopHeight = DllCall("user32.dll", "int", "GetSystemMetrics", "int", 79) ;sm_virtualheight
    Local $DesktopHeight = $VirtualDesktopHeight[0]


    $ptr1 = _GetImage($BMP1, $BMP1Data, $BMP1Width, $BMP1Height, $BMP1LineWidth, $pbitmap1, $bitmapinfo1) ;holt alle Infos aus der Bitmap (Fullscreen, Fenster oder File)
    $ptr2 = _GetImage($BMP2, $BMP2Data, $BMP2Width, $BMP2Height, $BMP2LineWidth, $pbitmap2, $bitmapinfo2)

    If $BMP2Height = 0 Then
        SetError(1, 0, 0)
        Return False
    EndIf

    $exit = DllStructGetSize($ptr1) + 1 ;letzte mögliche bildschirm(fenster) position)
    $struct_2 = DllStructCreate("ubyte[" & ($BMP2Width * 3) & "]");erste zeile der 2. bitmap, nach dieser Position wird gin der ersten Bitmap gesucht
    DllStructSetData($struct_2, 1, $BMP2Data)

    ;erste Zeile der Bitmap2 in Bitmap1 suchen
    $iPos = FindBytes(DllStructGetPtr($ptr1), 0, DllStructGetSize($ptr1) - DllStructGetSize($struct_2) - (($BMP2Height - 1) * $BMP1LineWidth), DllStructGetPtr($struct_2), DllStructGetSize($struct_2)) + 1
    ;zeilenweises vergleichen der beiden bitmaps, ist bitmap2 in bitmap1 enthalten?
    While 1
        If $iPos <> 0 And $iPos <> $exit Then ;nur, wenn es eine übereinstimmung gibt weitermachen
            ;    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $iPos = ' & $iPos & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
            Local $e = Mod(($iPos - 1), $BMP1LineWidth) ;position innerhalb des Strings
            If $e / $imgBytes = Int($e / $imgBytes) Then ;prüfen ob ipos am anfang eines farbbits steht, wenn nicht, nächste zeile suchen
;~                 $prozent = $iPos / 3 * 100 / $BMP1Width / $BMP1Height
;~                 ToolTip(StringFormat("Suche läuft : %.0f%%", $prozent) & @CRLF & "Zeile " & Int($iPos / $imgBytes / $BMP1Width), $BMP1Width / 2, $BMP1Height / 2)
                $flag = 0
                For $i = 0 To $BMP2Height - 1 ;zeilenweise die Bitmaps vergleichen
                    $a = DllStructGetPtr($ptr1) + $iPos - 1 + $i * $BMP1LineWidth ;pointer auf die position in der struct, an der die erste übereinstimmung ist
                    $b = DllStructGetPtr($ptr2) + $i * $BMP2LineWidth ;pointer auf die zeile
                    If CompareBytes($a, $b, 3 * $BMP2Width, 0) <> 0 Then ;wenn keine Übereinstimmung, dann nächste suchen
                        $flag = 1
                        ExitLoop
                    EndIf
                Next
                If $flag = 0 Then ;alle zeilen haben übereingestimmt, BMP2 ist in BMP1 enthalten!                    $koord[0] = Mod(($iPos - 1), $BMP1LineWidth) / $imgBytes ;koordinaten auf dem screen
                    $koord[0] = Mod(($iPos - 1), $BMP1LineWidth) / $imgBytes ;koordinaten auf dem screen
                    $koord[1] = Int(($iPos - 1) / $BMP1LineWidth)
                    $BMP1Data = 0 ;strukturen löschen, Speicher freigeben
                    $BMP2Data = 0
                    $struct_2 = 0
                    $ptr1 = 0
                    $ptr2 = 0
                    _GDIPlus_BitmapUnlockBits($pbitmap1, $bitmapinfo1)
                    _GDIPlus_BitmapUnlockBits($pbitmap2, $bitmapinfo2)
                    _GDIPlus_ImageDispose($pbitmap1) ;Bitmaps löschen
                    _GDIPlus_ImageDispose($pbitmap2)
                    Return $koord
                EndIf

                $iPos = FindBytes(DllStructGetPtr($ptr1), $iPos + $imgBytes, DllStructGetSize($ptr1) - DllStructGetSize($struct_bmp2) - (($BMP2Height - 1) * $BMP1LineWidth) - $iPos, DllStructGetPtr($struct_2), DllStructGetSize($struct_2)) + 1
                If $iPos = 0 Or $iPos = $exit Then ExitLoop ;nicht gefunden
            Else ;ipos ist innerhalb eines farbbits und nicht am anfang
                $iPos = FindBytes(DllStructGetPtr($ptr1), $iPos + 1, DllStructGetSize($ptr1) - DllStructGetSize($struct_bmp2) - (($BMP2Height - 1) * $BMP1LineWidth) - $iPos, DllStructGetPtr($struct_2), DllStructGetSize($struct_2)) + 1
                If $iPos = 0 Or $iPos = $exit Then ExitLoop
            EndIf
        Else
            ExitLoop
        EndIf
    WEnd
    $BMP1Data = 0 ;strukturen löschen, Speicher freigeben
    $BMP2Data = 0
    $struct_2 = 0
    $ptr1 = 0
    $ptr2 = 0
    _GDIPlus_BitmapUnlockBits($pbitmap1, $bitmapinfo1)
    _GDIPlus_BitmapUnlockBits($pbitmap2, $bitmapinfo2)
    _GDIPlus_ImageDispose($pbitmap1) ;Bitmaps löschen
    _GDIPlus_ImageDispose($pbitmap2)
    SetError(1, 0, 1)
    Return 0 ;
EndFunc   ;==>_FindBMP


;aus einer Datei oder einem Screenshot die Pixeldaten im BGR-Format in einen String schreiben
;Originalfunc by JunkEW , modified by Andy@ www.autoit.de, gets the Bitmapdata as BGR-String
Func _GetImage($bmpfile, ByRef $BMPDataStart, ByRef $Width, ByRef $Height, ByRef $Stride, ByRef $pBitmap, ByRef $BitmapData)

    Local $Scan0, $hbScreen, $handle, $imgBytes = 3, $pixeldata, $pixeldata2, $xy
    Local $VirtualDesktopWidth = DllCall("user32.dll", "int", "GetSystemMetrics", "int", 78) ;sm_virtualwidth
    Local $VirtualDesktopHeight = DllCall("user32.dll", "int", "GetSystemMetrics", "int", 79) ;sm_virtualheight

    ; Load the bitmap to search in
    If StringUpper($bmpfile) = "FULLSCREEN" Then
        $hbScreen = _ScreenCapture_Capture("", 0, 0, $VirtualDesktopWidth[0], $VirtualDesktopHeight[0], False)
        If @error Then MsgBox(0, "", "Fehler Screencapture FULLSCREEN")
        $pBitmap = _GDIPlus_BitmapCreateFromHBITMAP($hbScreen); returns memory bitmap
        If @error Then MsgBox(0, "", "Fehler Bitmapcreate_FromHBITMAP Screen")
    Else
        ;try to get a handle
        $handle = WinGetHandle($bmpfile)
        If @error Then
            ;Assume its an unknown handle so correct filename should be given
            $hbScreen = _GDIPlus_BitmapCreateFromFile($bmpfile)
            $pBitmap = $hbScreen
            If @error Then MsgBox(0, "", "Fehler BitmapCreateFromFile")
        Else ;aktuelles fenster
            $xy = WinGetPos($bmpfile)
            $hbScreen = _ScreenCapture_CaptureWnd("", $handle, 0, 0, $xy[2], $xy[3], False)
            If @error Then MsgBox(0, "", "Fehler Screencapturewnd")
            $pBitmap = _GDIPlus_BitmapCreateFromHBITMAP($hbScreen); returns memory bitmap
            If @error Then MsgBox(0, "", "Fehler BitmapCreateFromHBITMAP File")
        EndIf
    EndIf

    ;_GDIPlus_BitmapLockBits gibt $tagGDIPBITMAPDATA-Struktur zurück
    $BitmapData = _GDIPlus_BitmapLockBits($pBitmap, 0, 0, _GDIPlus_ImageGetWidth($pBitmap), _GDIPlus_ImageGetHeight($pBitmap), $GDIP_ILMREAD, $GDIP_PXF24RGB)
    If @error Then MsgBox(0, "", "Error locking region " & @error)
    $Stride = DllStructGetData($BitmapData, "Stride");Stride - Offset, in bytes, between consecutive scan lines of the bitmap. If the stride is positive, the bitmap is top-down. If the stride is negative, the bitmap is bottom-up.
    $Width = DllStructGetData($BitmapData, "Width");Image width - Number of pixels in one scan line of the bitmap.
    $Height = DllStructGetData($BitmapData, "Height");Image height - Number of scan lines in the bitmap.
    ;$pixelFormat = DllStructGetData($BitmapData, "PixelFormat");Pixel format - Integer that specifies the pixel format of the bitmap
    $Scan0 = DllStructGetData($BitmapData, "Scan0");Scan0 - Pointer to the first (index 0) scan line of the bitmap.
    $pixeldata = DllStructCreate("byte[" & (Abs($Stride) * ($Height)) & "]", $Scan0)
    $BMPDataStart = DllStructGetData($pixeldata, 1) ;string im Struct-format, d.h. Byte+nulByte, in dem die pixeldaten im BGR-Format stehen
    ;    _GDIPlus_BitmapUnlockBits($pbitmap, $BitmapData)
    ;_GDIPlus_ImageDispose($pBitmap) zerstört die pixeldatastruct, daher erst später!!!
    _WinAPI_DeleteObject($hbScreen)
    Return $pixeldata
EndFunc   ;==>_GetImage

Func _findbytes($string_1, $string_2, $startpos) ;string2 im string1 finden, erst ab sehr grossen strings schneller als stringinstr()
    Local $struct_1 = DllStructCreate("ubyte[" & (StringLen($string_1) + StringLen($string_2)) & "]")
    Local $struct_2 = DllStructCreate("ubyte[" & StringLen($string_2) & "]")
    DllStructSetData($struct_1, 1, $string_1 & $string_2)
    DllStructSetData($struct_2, 1, $string_2)
    Local $t = TimerInit()
    Local $pos = FindBytes(DllStructGetPtr($struct_1), $startpos, DllStructGetSize($struct_1), DllStructGetPtr($struct_2), DllStructGetSize($struct_2)) + 1
    Local $findbytes = TimerDiff($t)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $findbytes = ' & $findbytes & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
    ;    MsgBox(262144, 'Debug line ~' & @ScriptLineNumber, 'Selection:' & @LF & '$pos' & @LF & @LF & 'Return:' & @LF & $pos) ;### Debug MSGBOX
    $struct_1 = 0
    $struct_2 = 0

    If $pos = -1 Or $pos = StringLen($string_1) + 1 Then Return 0
    Return $pos
EndFunc   ;==>_findbytes


Func CompareBytes($S_MemoryPointer1, $S_MemoryPointer2, $S_ByteSize, $S_Tolerance)
    Local $C_Compare = DllCall($prospeed_dll, "long", "CompareBytes", _
            "long", $S_MemoryPointer1, _
            "long", $S_MemoryPointer2, _
            "long", $S_ByteSize, _
            "long", $S_Tolerance)
    Return $C_Compare[0]
EndFunc   ;==>CompareBytes

Func FindBytes($b, $O, $a, $S, $L)
    Local $S_FindBytes = DllCall($prospeed_dll, "long", "FindBytes", _
            "long", $b, _
            "long", $O, _
            "long", $a, _
            "long", $S, _
            "long", $L)
    Return $S_FindBytes[0]
EndFunc   ;==>FindBytes


Func _FindBMP_slow($BMP1, $BMP2)
    Dim $BMP1Data = "", $BMP1Width = 0, $BMP1Height = 0, $BMP1LineWidth = 0, $pbitmap1 = 0, $bitmapinfo1
    Dim $BMP2Data = "", $BMP2Width = 0, $BMP2Height = 0, $BMP2LineWidth = 0, $pbitmap2 = 0, $bitmapinfo2
    Dim $koord[2]
    Local $searchFor, $line, $iPos = 1, $imgBytes = 3, $prozent, $ptr1, $ptr2
    Local $VirtualDesktopWidth = DllCall("user32.dll", "int", "GetSystemMetrics", "int", 78) ;sm_virtualwidth
    Local $DesktopWidth = $VirtualDesktopWidth[0]
    Local $VirtualDesktopHeight = DllCall("user32.dll", "int", "GetSystemMetrics", "int", 79) ;sm_virtualheight
    Local $DesktopHeight = $VirtualDesktopHeight[0]


    ; Load the bitmap to search in
    $ptr1 = _GetImage($BMP1, $BMP1Data, $BMP1Width, $BMP1Height, $BMP1LineWidth, $pbitmap1, $bitmapinfo1)
    $BMP1Data = BinaryToString($BMP1Data)
    $ptr2 = _GetImage($BMP2, $BMP2Data, $BMP2Width, $BMP2Height, $BMP2LineWidth, $pbitmap2, $bitmapinfo2)
    $BMP2Data = BinaryToString($BMP2Data)
    If $BMP2Height = 0 Then
        SetError(1, 0, 0)
        Return False
    EndIf
    $fillbytes=mod($BMP1LineWidth,$BMP1Width)
    Local $searchFor1 = StringMid($BMP2Data, 1, ($BMP2Width * $imgBytes)) ;1. pixel-zeile in der bitmap2 (string)
    $iPos = StringInStr($BMP1Data, $searchFor1, 1, 1) ;1. fundstelle des strings in Bitmap2
    ;zeilenweises vergleichen der beiden bitmaps, ist bitmap2 in bitmap1 enthalten?
    While 1
        Local $flag = 0
        If $iPos <> 0 Then
            If ($iPos - 1) / $imgBytes = Int(($iPos - 1) / $imgBytes) Then ;;prüfen ob ipos am anfang eines farbbits steht
;~                 $prozent = $iPos / 3 * 100 / $DesktopWidth / $DesktopHeight
;~                 ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $prozent = ' & $prozent & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console
                ToolTip(StringFormat("Suche läuft : %.0f%%", $prozent) & @CRLF & "Zeile " & Int($iPos / $imgBytes / $DesktopWidth), $DesktopWidth / 2, $DesktopHeight / 2)
                For $S = 2 To $BMP2Height ;zeilenweise das suchbild mit dem screen vergleichen
                    $searchFor = StringMid($BMP2Data, 1 + (($S - 1) * $BMP2LineWidth), $BMP2Width * $imgBytes) ; s-te zeile aus dem ausschnitt
                    $line = StringMid($BMP1Data, $iPos + (($S - 1) * $BMP1LineWidth), $BMP2Width * $imgBytes) ;zeile "unter" der gefundenen zeile im screen
                    If $searchFor <> $line Then ;zeilen nicht gleich,
                        $flag = 1
                        ExitLoop ;exit for/next
                    EndIf
                Next
                If $flag = 0 Then ;alle zeilen haben übereingestimmt, BMP2 ist in BMP1 enthalten!                    $koord[0] = Mod(($iPos - 1), $BMP1LineWidth) / $imgBytes ;koordinaten auf dem screen
                    $koord[0] = Mod(($iPos - 1), $BMP1LineWidth) / $imgBytes ;koordinaten auf dem screen
                    $koord[1] = Int(($iPos - 1) / $BMP1LineWidth)
                    $BMP1Data = 0 ;strukturen löschen, Speicher freigeben
                    $BMP2Data = 0
                    $ptr1 = 0
                    $ptr2 = 0
                    _GDIPlus_BitmapUnlockBits($pbitmap1, $bitmapinfo1)
                    _GDIPlus_BitmapUnlockBits($pbitmap2, $bitmapinfo2)
                    _GDIPlus_ImageDispose($pbitmap1) ;Bitmaps löschen
                    _GDIPlus_ImageDispose($pbitmap2)
                    ToolTip("")
                    Return $koord
                EndIf
                $iPos = StringInStr($BMP1Data, $searchFor1, 1, 1, $iPos + $imgBytes)
                If $iPos = 0 Then ExitLoop ;nicht gefunden
            Else ;ipos ist innerhalb eines farbbits und nicht am anfang
                $iPos = StringInStr($BMP1Data, $searchFor1, 1, 1, $iPos + 1)
                If $iPos = 0 Then ExitLoop
            EndIf
        Else
            ExitLoop
        EndIf
    WEnd
    $BMP1Data = 0 ;strukturen löschen, Speicher freigeben
    $BMP2Data = 0
    $ptr1 = 0
    $ptr2 = 0
    _GDIPlus_BitmapUnlockBits($pbitmap1, $bitmapinfo1)
    _GDIPlus_BitmapUnlockBits($pbitmap2, $bitmapinfo2)
    _GDIPlus_ImageDispose($pbitmap1) ;Bitmaps löschen
    _GDIPlus_ImageDispose($pbitmap2)
    ToolTip("")
    SetError(1, 0, 0)
    Return 0 ;
EndFunc   ;==>_FindBMP_slow
I changed the script a little bit to speed up the "slow" bitmapsearch by a factor of 3 (stringfunktions are REALLY fast in AutoIt)! Now the "slow" search-function with  pure AutoIt-code needs only the double of time than the "fast" prospeed-function( written in assembler). This is really nice, so there is no need for the prospeed.dll in the most cases, i think!

If you want to use the prospeed.dll, be sure to have the latest version. Download the dll and a VERY cool AutoIt-Graphic-Demo here

Link to comment
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
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...