mikjay Posted November 16, 2009 Share Posted November 16, 2009 (edited) 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 November 16, 2009 by mikjay Link to comment Share on other sites More sharing options...
AndyG Posted November 17, 2009 Share Posted November 17, 2009 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 objectsI´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 More sharing options...
mikjay Posted November 17, 2009 Author Share Posted November 17, 2009 (edited) 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? expandcollapse popup_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 November 17, 2009 by mikjay Link to comment Share on other sites More sharing options...
AndyG Posted November 18, 2009 Share Posted November 18, 2009 In my second look through, it looks like $pBitmap is not releasedarrggghhh....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 More sharing options...
mikjay Posted November 18, 2009 Author Share Posted November 18, 2009 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 More sharing options...
AndyG Posted November 18, 2009 Share Posted November 18, 2009 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.expandcollapse popup#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 More sharing options...
mikjay Posted November 18, 2009 Author Share Posted November 18, 2009 Thanks, that one works much better! Link to comment Share on other sites More sharing options...
Fainth Posted January 3, 2010 Share Posted January 3, 2010 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 More sharing options...
Fainth Posted May 29, 2010 Share Posted May 29, 2010 Sorry for digging this one up but i still get this Error, even with the original script and ProSpeed.dll Link to comment Share on other sites More sharing options...
Fainth Posted May 29, 2010 Share Posted May 29, 2010 Could someone just DL it and verify if i am the only one with this problem ? http://www.autoit.de/index.php?page=Attachment&attachmentID=6428 I could use a second opinion. Link to comment Share on other sites More sharing options...
AndyG Posted May 30, 2010 Share Posted May 30, 2010 Does the following example work for you?expandcollapse popup#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_slowI 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 More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now