Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 04/30/2021 in all areas

  1. Code below searches a certain bitmap (all supported formats of GDI+) picture in another picture or on screen (after saved as bitmap) not depending on 3rd party dll's Pentium 4 of 3 GHz takes * about 4.5 seconds on a 1280*1024 desktop to find a 260*260 bitmap. Partial match 0.5 seconds * about 1 seconds on a 1280*1024 desktop to find a 20*17 bitmap. Partial match 0.5 seconds Some references I used to come up with this solution * code to get a smaller bitmap: http://www.autoitscript.com/forum/index.ph...=pixelchecksum) * Pixelchecksum seems not to do the full job but in combination with below it can become very fast: http://www.autoitscript.com/forum/index.ph...l=pixelchecksum * A pixel by pixel searcher http://www.autoitscript.com/forum/index.ph...&hl=compare * UDF Get or Read Pixel from Memory * GetDIBits Not fully finished but all comments/enhancements are appreciated * Save to file or directly on special window description SCREEN, [ACTIVE] or name of picture file * Searching is done on a line by line basis instead of pixel by pixel * Bitmap to search in example program should be fully visible to work for first 3 examples as it are screenshots taken. Same applies for 3 in AUTOIT homepage * Speed depends on the size of the bitmap you are searching for but is about linear and < 5 seconds * Some doubts on left and top returned (sometimes seems to be off by 1 or several pixels) * Transparency (when search letters on a different background) http://www.winprog.org/tutorial/transparency.html * Match quicker by doing a bitblt with srcinvert when first line is found (instead of checking line by line) * $BMP1 and $BMP2 to be HBITMAP handle as input instead of filenames (will make searching within partial screen Sample to work * Install pics.zip into %temp% / Save BMP attachments for example to @tempdir (%temp%) for example to work Sample code #Region includes Opt('MustDeclareVars', 1) ;#include <GUIConstants.au3> #include <GDIPlus.au3> #Include <ScreenCapture.au3> #include <string.au3> #include <WinAPI.au3> #include <WindowsConstants.au3> #EndRegion ;~ If debugging output is wanted to understand and analyse the algorithm put this on true/false ;~ Const $bDebug=True Const $bDebug=False #region example ;~ Const $cMatchLinePercentage=0.97 ;Minimum matching, put on 1 if exact matching is needed on all lines Const $cMatchLinePercentage=0.99 ;Minimum matching, put on 1 if exact matching is needed on all lines ;~ Constants for type of picture matching const $c24RGBFullMatch=1 ;Load as 24 bits and full match const $c24RGBPartialMatch=2 ;Load as 24 bits and partial match const $c16RGBFullMatch=3 ;Load as 16 bits and full match const $c16RGBPartialMatch=4 ;Load as 16 bits and partial match ; ** Example start ** ; Screen samples Global Const $Bitmap1Filename = @scriptDir & "\FULLSCREEN.BMP" Global Const $Bitmap2Filename = @scriptDir & "\CALCULATOR.BMP" Global Const $Bitmap3Filename = @scriptDir & "\BACKSPACE.BMP" ;BMP samples Global Const $Bitmap4Filename = @scriptDir & "\7WDS_BW.BMP" Global Const $Bitmap5Filename = @scriptDir & "\SEVEN_BW.BMP" Global Const $Bitmap6Filename = @scriptDir & "\CAT_BW.BMP" Global Const $Bitmap7Filename = @scriptDir & "\AUTOIT3.bmp";Make sure the homepage of autoit with 3 is visible local $calcHWND, $begin, $pos, $aWinPos, $aWinCSize, $start local $pBitmap, $BitmapData, $pixelFormat Opt("WinTitleMatchMode", 4);Matching windows by advanced options ; Initialize GDI+ library _GDIPlus_Startup () ;Calculator, make sure its started $calcHWND = WinGetHandle("[REGEXPCLASS:.*Calc.*]") If $calcHWND = "" Then Run("calc.exe") Sleep(2000) $calcHWND = WinGetHandle("[REGEXPCLASS:.*Calc.*]") EndIf If $calcHWND = "" Then consolewrite("Using active window which is 99% sure equal to the calculator window" & @LF ) $calcHWND = WinGetHandle("[ACTIVE]") EndIf consolewrite($calcHWND) ;Capture the calculator screen $begin = TimerInit() winactivate($calcHWND) Sleep(1000) _ScreenCapture_CaptureWnd($Bitmap2Filename, $calcHWND,0,0,-1,-1,False) ConsoleWrite("Saving calculator window " & TimerDiff($begin) & " milliseconds " & @LF) winmove("[ACTIVE]","",223,341) ;~ Get the base information of the calc window $aWinPos = WinGetPos($calchWnd) $aWinCSize = WinGetClientSize($calchWnd) Sleep(500) ;Capture an area within the calculator area backspace $begin = TimerInit() $pos=controlgetpos("","","[CLASS:Button; TEXT:BACKSPACE]") ;~ $pos=controlgetpos("","","[CLASS:Button; INSTANCE:2]") if @error=1 Then consolewrite("Not recognizing so we are on a windows 10 environment most likely, fix by providing manual controls" & @CRLF) consolewrite("Read frequently asked questions in Wiki number 31 and use simplespy" & @CRLF) local $pos[4] ;~ Backspace button <394;693;75;74> ;~ Button 2 <315;927;75;74> $pos[0]=394 $pos[1]=693 $pos[2]=75 $pos[3]=74 ;~ Func _UIA_DrawRect($tLeft, $tRight, $tTop, $tBottom, $color = 0xFF, $PenWidth = 4) _UIA_DrawRect($pos[0],$pos[0]+$pos[2],$pos[1],$pos[1]+$pos[2]) ;~ Fix quick and dirty as simplespy gives screencoordinates not relative to window $pos[0]=394 - $aWinpos[0] $pos[1]=693 - $aWinpos[1] EndIf ;Q&D calculation of offsets to capture _ScreenCapture_Capture($Bitmap3Filename, ($aWinPos[0]+$pos[0]) + ($aWinPos[2] - $aWinCSize[0])-3, ($awinpos[1]+$pos[1])+ ($aWinPos[3]-$aWinCSize[1])-3, $aWinPos[0]+$pos[0]+$pos[2]+3, ($awinpos[1]+$pos[1])+ ($aWinPos[3]-$aWinCSize[1])+$pos[3]-3,false) ConsoleWrite("Saving backspacebutton " & TimerDiff($begin) & " milliseconds " & @LF) ; Capture full screen $begin = TimerInit() _ScreenCapture_Capture($Bitmap1Filename,0,0,-1,-1,False) ConsoleWrite("Saving full screen took " & TimerDiff($begin) & " milliseconds " & @LF) Sleep(500) func filegetname($f) local $i $i=stringinstr($f,"\",false,-1) if $i > 0 Then return stringmid($f,$i+1) Else return $f EndIf EndFunc ;Do the actual find Func FindTester($BMP1, $BMP2, $Bool) local $tResult $start = TimerInit() $tResult=findBMP($BMP1,$BMP2, $Bool) ConsoleWrite($tResult & " " & FileGetName($BMP2) & " in " & FileGetName($BMP1) & " ** matchtype " & $Bool & " time elapsed: " & TimerDiff($start) & " milliseconds" & @LF) EndFunc if not $bDebug=True Then ; Not very usefull to find full screen and tricky as screen is most likely changed (clock, output from application etc.) ; findTester("SCREEN",$Bitmap1Filename,TRUE);Find the full screen itself ; findTester($Bitmap1Filename,$Bitmap1Filename,$c24RGBFullMatch);Find the full screen itself 31 seconds findTester($Bitmap1Filename,$Bitmap1Filename,$c24RGBPartialMatch);Find the full screen itself 2.8529088255245 seconds ; findTester($Bitmap1Filename,$Bitmap1Filename,$c16RGBFullMatch);Find the full screen itself 21 seconds findTester($Bitmap1Filename,$Bitmap1Filename,$c16RGBPartialMatch);Find the full screen itself 1 seconds ; Be aware that overlapping windows, moving things on screen can make it difficult to find on full screen findTester("SCREEN",$Bitmap2Filename,$c24RGBFullMatch);Find the full calculatorscreen findTester("SCREEN",$Bitmap2Filename,$c24RGBPArtialMatch);Find the full calculatorscreen with partial match findTester("SCREEN",$Bitmap2Filename,$c16RGBFullMatch);Find the full calculatorscreen findTester("SCREEN",$Bitmap2Filename,$c16RGBPArtialMatch);Find the full calculatorscreen with partial match findTester($Bitmap1Filename,$Bitmap2Filename,$c16RGBFullMatch);Find the full calculatorscreen findTester($Bitmap1Filename,$Bitmap2Filename,$c16RGBPartialMatch);Find the full calculatorscreen with partial match findTester($Bitmap2Filename,$Bitmap3Filename,$c24RGBFullMatch);Find the backspace button findTester($Bitmap2Filename,$Bitmap3Filename,$c24RGBPartialMatch);Find the backspace button with partial match findTester($Bitmap2Filename,$Bitmap3Filename,$c16RGBFullMatch);Find the backspace button findTester($Bitmap2Filename,$Bitmap3Filename,$c16RGBPartialMatch);Find the backspace button with partial match winactivate($calcHWND);Make sure calculator is active on the screen findTester("[ACTIVE]",$Bitmap3Filename,$c24RGBFullMatch);Find the backspace button findTester("[ACTIVE]",$Bitmap3Filename,$c24RGBPartialMatch);Find the backspace button with partial match findTester("[ACTIVE]",$Bitmap3Filename,$c16RGBFullMatch);Find the backspace button on active screen findTester("[ACTIVE]",$Bitmap3Filename,$c16RGBPartialMatch);Find the backspace button with partial match findTester("SCREEN",$Bitmap3Filename,$c24RGBFullMatch);Find the backspace button findTester("SCREEN",$Bitmap3Filename,$c24RGBPartialMatch);Find the backspace button with partial match findTester("SCREEN",$Bitmap3Filename,$c16RGBFullMatch);Find the backspace button findTester("SCREEN",$Bitmap3Filename,$c16RGBPartialMatch);Find the backspace button with partial match findTester($Bitmap4Filename,$Bitmap5Filename,$c16RGBFullMatch);Find the seven findTester($Bitmap4Filename,$Bitmap5Filename,$c16RGBPartialMatch);Find the seven with partial match findTester($Bitmap4Filename,$Bitmap6Filename,$c16RGBFullMatch);Find the cat findTester($Bitmap4Filename,$Bitmap6Filename,$c16RGBPartialMatch);Find the cat with partial match findTester($Bitmap1Filename,$Bitmap7Filename,$c24RGBFullMatch);Find the 3 of Autoit Homepage findTester($Bitmap1Filename,$Bitmap7Filename,$c24RGBPartialMatch);Find the 3 of Autoit Homepage findTester($Bitmap1Filename,$Bitmap7Filename,$c16RGBFullMatch);Find the 3 of Autoit Homepage findTester($Bitmap1Filename,$Bitmap7Filename,$c16RGBPartialMatch);Find the 3 of Autoit Homepage Else ;~ findTester($Bitmap4Filename,$Bitmap6Filename,$c24RGBFullMatch);Find the cat ;~ findTester($Bitmap1Filename,$Bitmap2Filename,$c24RGBFullMatch);Find the full calculatorscreen findTester("SCREEN",$Bitmap2Filename,$c24RGBFullMatch);Find the full calculatorscreen EndIf _GDIPlus_Shutdown() ;** Example end ** #EndRegion #Region actual functions ;=============================================================================== ; Function Name: findBMP ; Description: Finds a bitmap (.BMP) in another BMP file (other formats PNG and TIFF work also other formats less usefull GIF, JPEG, Exif, WMF, and EMF should work) ; Syntax: findBMP($BMP1, $BMP2, $MatchType=TRUE) ; ; Parameter(s): $BMP1 = Filename of bitmap to search in ; $BMP2 = Filename of bitmap to search for ; $MatchType = c24RGBFullMatch, c24RGBPartialMatch, c16RGBFullMatch, c16RGBPartialMatch ; ; Return Value(s): On Success: = Returns Array List ; On Failure: = @error 1 (Control was found but there was an error with the DLLCall) ; ; Author(s): JunkEW ; ; Note(s): ; * Its never an exact match even with TRUE as last few bits are disposed in algorithm and lines below ; are not checked under assumption that those are 99.99% of the time correct ; * locking bits overview http://www.bobpowell.net/lockingbits.htm ; ToDo: ; * Transparency (when search letters on a different background) http://www.winprog.org/tutorial/transparency.html ; * Match quicker by doing a bitblt with srcinvert when first line is found (instead of checking line by line) ; * $BMP1 and $BMP2 to be HBITMAP handle as input instead of filenames (will make searching within partial screen easier) ; Example(s): ; ;=============================================================================== Func findBMP($BMP1, $BMP2, $MatchType=$c24RGBFullMatch) Dim $fLine[1];Line number of found line(s), redimmed when second picture size is known Dim $BMP1Data="", $BMP1Width=0, $BMP1Height=0, $BMP1LineWidth=0; Dim $BMP2Data="", $BMP2Width=0, $BMP2Height=0, $BMP2LineWidth=0 Dim $foundAt = "", $matchPossible=FALSE, $matchedLines=0, $foundAtLeft=-1, $foundAtTop=-1 Dim $bestMatchLine=-1, $HighestMatchingLines=-1; For knowing when no match is found where best area is Dim $iPos=1; dim $imgBytes, $avData; local $iFuzzyDist, $searchFor, $iAbove, $bMatchPossible, $aboveLine local $j, $imgBits local $tDebug if ($MatchType=$c24RGBFullMatch) or ($matchtype=$c24RGBPartialMatch) then $imgBytes=3 Else $imgBytes=2 endif ; Load the bitmap to search in getImage($BMP1, $BMP1Data, $BMP1Width, $BMP1Height, $BMP1LineWidth, $imgBytes) $BMP1Data = BinaryToString($BMP1Data) ; Load the bitmap to find getImage($BMP2, $BMP2Data, $BMP2Width, $BMP2Height, $BMP2LineWidth, $imgBytes) ;Make it strings to be able to use string functions for searching $BMP2Data = BinaryToString($BMP2Data) if $bDebug=True Then ;~ START debugging ;Get some debugging information FileDelete(@ScriptDir & "\BMP1DATA.TXT") FileDelete(@ScriptDir & "\BMP2DATA.TXT") FileDelete(@ScriptDir & "\COMPAREDLINES.TXT") consolewrite($BMP1Width & @crlf) consolewrite($BMP1Height & @crlf) consolewrite($BMP1LineWidth & @crlf) consolewrite(stringlen($BMP1Data) & @crlf) consolewrite(".{" & $BMP1LineWidth & "}"& @CRLF) consolewrite(".{" & $BMP2LineWidth & "}"& @CRLF) $tDebug=StringRegExpReplace(_stringtohex($BMP1Data),"(.{" & $BMP1LineWidth*2 & "})","$1" & @CRLF) consolewrite(@error & @extended & @CRLF) FileWrite (@ScriptDir & "\BMP1DATA.TXT" , $tdebug) $tDebug=StringRegExpReplace(_stringtohex($BMP2Data),"(.{" & $BMP2LineWidth*2 & "})","$1" & @CRLF) consolewrite(@error & @extended & @CRLF) FileWrite (@ScriptDir & "\BMP2DATA.TXT" , $tdebug) ;~ END debugging EndIf ;For reference of line where in BMP2FindIn a line of BMP2Find was found If $BMP2Height = 0 Then SetError(1,0,0) Return False EndIf ReDim $fline[$BMP2Height] ;If exact match check every 1 line else do it more fuzzy (as most likely other lines are unique) if ($MatchType=$c24RGBFullMatch) or ($matchtype=$c16RGBFullMatch) Then $iFuzzyDist = 1 Else ;Check fuzzy every 10% of lines $iFuzzyDist = ceiling(($bmp2height * 0.1)) endIf $begin = TimerInit() ;Look for each line of the bitmap if it exists in the bitmap to find in ;~ Split bitmap to search in lines ;~ $avData=stringregexp($BMP2Data, ".{1," & $BMP2lineWidth & "}+", 3) dim $searchForRegEx $searchForRegEx = StringMid($BMP2Data, 1 + (0 * $BMP2lineWidth), ($BMP2lineWidth - $imgBytes)) $searchForRegEx = $searchForRegEx & ".*" & StringMid($BMP2Data, 1 + ($BMP2Height * $BMP2lineWidth), ($BMP2lineWidth - $imgBytes)) Local $aArray=stringregexp($BMP1Data,$searchForRegEx,3) if @error=0 Then consolewrite("Regex found " & TimerDiff($begin) & " ms " & @crlf) ;~ For $i = 0 To UBound($aArray) - 1 ;~ consolewrite("RegExp Test with Option 3 - " & $i & $aArray[$i]) ;~ Next endif For $i = 0 To $BMP2Height - 1 ;Minus imgbytes as last bits are padded with unpredictable bytes (24 bits image assumption) or 2 when 16 bits $searchFor = StringMid($BMP2Data, 1 + ($i * $BMP2lineWidth), ($BMP2lineWidth - $imgBytes)) ;~ $searchfor=stringleft($avData[$i],$BMP2lineWidth - $imgBytes) $iPos = StringInStr($BMP1Data, $searchFor, 2, 1, $iPos) ; $iPos = StringInStr($BMP1Data, $searchFor) ;Look for all lines above if there is also a match ;Not doing it for the lines below as speed is more important and risk of mismatch on lines below is small $iAbove=1 if $iPos > 0 then $bMatchPossible=True $matchedLines=1;As first found line is matched we start counting ;Location of the match $foundAtTop = Int($iPos / $BMP1lineWidth) -$i $foundAtLeft = int(mod($iPos,$bmp1linewidth) / $imgBytes) Else ;~ No 1st line found so far nothing to start matching $bMatchPossible=false exitloop endif while (($i+$iAbove) <= ($BMP2Height -1)) and ($bMatchPossible=True) $searchFor = StringMid($BMP2Data, 1 + (($i + $iAbove) * $BMP2lineWidth), ($BMP2lineWidth - $imgBytes)) ;~ $searchfor = stringleft($avData[$i+$iAbove],$BMP2lineWidth - $imgBytes) $aboveLine = stringmid($BMP1Data,$iPos + ($iAbove * $BMP1LineWidth), ($BMP2LineWidth - $imgBytes)) if $bDebug=True Then ;~ START debugging $tDebug=StringRegExpReplace(_stringtohex($searchfor),"(.{8})","$1_") FileWrite (@ScriptDir & "\COMPAREDLINES.TXT" , $tDebug & @crlf) $tDebug=StringRegExpReplace(_stringtohex($aboveline),"(.{8})","$1_") FileWrite (@ScriptDir & "\COMPAREDLINES.TXT" , $tDebug & @crlf) If $aboveLine <> $searchFor Then FileWrite (@ScriptDir & "\COMPAREDLINES.TXT" , "** MISMATCH ** of line " & (1+$iAbove) & " in 2nd bitmap at line " & ($foundAtTop + $i) & @crlf) endIf ;~ END debugging EndIf if comparePicLine($aboveline,$searchfor) = false then $bMatchPossible=False ;To remember the area with the best match if $matchedLines >= $HighestMatchingLines Then $HighestMatchingLines = $matchedLines ;Best guess of location ;~ $foundAtTop = $fline[$i] + $i - $BMP2Height $foundAtTop = Int($iPos / $BMP1lineWidth);+ $i - $BMP2Height $bestMatchLine = Int($iPos / $BMP1lineWidth) EndIf ExitLoop EndIf $matchedLines=$matchedLines + 1 $iAbove=$iAbove+$iFuzzyDist WEnd ;If bMatchPossible is still true most likely we have found the bitmap if $bmatchPossible = True then ;~ ConsoleWrite("Could match top: " & $foundAtTop & " left: " & $foundAtLeft & " in " & TimerDiff($begin) / 1000 & " seconds" & @LF) ; MouseMove($foundatleft,$foundatTop) exitloop else ;~ consolewrite("i not matched " & $ipos & " " & $matchedlines & @crlf ) EndIf Next ;For some debugging of time ; if $bMatchPossible = True Then ; ConsoleWrite("Searching took " & TimerDiff($begin) / 1000 & " seconds " & @LF) ; Else ; ConsoleWrite("NOT FOUND Searching took " & TimerDiff($begin) / 1000 & " seconds" & @LF) ; endif ;Return an error if not found else return an array with all information if $bMatchPossible = False Then SetError(1, 0, 0) endif ; return stringsplit($bMatchPossible & ";" & $matchedLines & ";" & $foundAtLeft & ";" & $foundAtTop & ";" & $bmp2width & ";" & $BMP2Height & ";" & $HighestMatchingLines & ";" & $bestMatchLine,";") return $bMatchPossible & ";" & $matchedLines & ";" & $foundAtLeft & ";" & $foundAtTop & ";" & $bmp2width & ";" & $BMP2Height & ";" & $HighestMatchingLines & ";" & $bestMatchLine EndFunc;==>findBMP func comparePicLine($s1,$s2) local $sLen, $iMatched if $s1=$s2 Then return True Else $iMatched=0 $sLen=stringlen($s1) for $tJ=1 to $slen if stringmid($s1,$tJ,1)=stringmid($s2,$tJ,1) Then $iMatched=$imatched+1 Else if $bDebug=True Then ;~ START debugging FileWrite (@ScriptDir & "\COMPAREDLINES.TXT" , "Debug mismatch pixel " & $tj & "=" & int($tj/4) & @crlf) endif endif Next if ($iMatched / $sLen ) > $cMatchLinePercentage then return true Else return false endif EndIf endfunc Func GetImage($BMPFile, byref $BMPDataStart, byref $Width, byRef $Height, byref $Stride, $imgBytes=3) local $Scan0, $pixelData, $hbScreen, $pBitmap, $pBitmapCap, $handle ; Load the bitmap to search in If $BMPFile="SCREEN" Then $hbScreen=_ScreenCapture_Capture("",0,0,-1,-1,False) $pBitmap = _GDIPlus_BitmapCreateFromHBITMAP($hbScreen); returns memory bitmap Else ;try to get a handle $handle = WinGetHandle($BMPFile) If @error Then ;Assume its an unknown handle so correct filename should be given $pBitmap = _GDIPlus_BitmapCreateFromFile($BMPFile) Else $hbScreen=_ScreenCapture_CaptureWnd("",$handle,0,0,-1,-1,False) $pBitmap = _GDIPlus_BitmapCreateFromHBITMAP($hbScreen); returns memory bitmap EndIf EndIf ;Get $tagGDIPBITMAPDATA structure ;~ ConsoleWrite("Bitmap Width: " & _GDIPlus_ImageGetWidth($pBitmap) & @CRLF ) ;~ ConsoleWrite("Bitmap Height: " & _GDIPlus_ImageGetHeight($pBitmap) & @CRLF) ;~ 24 bits (3 bytes) or 16 bits (2 bytes) comparison if ($imgBytes=2) then $BitmapData= _GDIPlus_BitmapLockBits($pBitmap, 0, 0, _GDIPlus_ImageGetWidth($pBitmap), _GDIPlus_ImageGetHeight($pBitmap), $GDIP_ILMREAD, $GDIP_PXF16RGB555) ;~ $BitmapData= _GDIPlus_BitmapLockBits($pBitmap, 0, 0, _GDIPlus_ImageGetWidth($pBitmap), _GDIPlus_ImageGetHeight($pBitmap), $GDIP_ILMREAD, $GDIP_PXF32ARGB) Else $BitmapData= _GDIPlus_BitmapLockBits($pBitmap, 0, 0, _GDIPlus_ImageGetWidth($pBitmap), _GDIPlus_ImageGetHeight($pBitmap), $GDIP_ILMREAD, $GDIP_PXF24RGB) ;~ $BitmapData= _GDIPlus_BitmapLockBits($pBitmap, 0, 0, _GDIPlus_ImageGetWidth($pBitmap), _GDIPlus_ImageGetHeight($pBitmap), $GDIP_ILMREAD, $GDIP_PXF32ARGB) endIf 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("ubyte lData[" & (abs($Stride) * $Height-1) & "]", $Scan0) $BMPDataStart = $BMPDataStart & DllStructGetData($pixeldata,"lData") _GDIPlus_BitmapUnlockBits($pBitmap, $BitmapData) _GDIPlus_ImageDispose ($pBitmap) _WinAPI_DeleteObject ($pBitmap) EndFunc;==>GetImage ; Draw rectangle on screen. Func _UIA_DrawRect($tLeft, $tRight, $tTop, $tBottom, $color = 0xFF, $PenWidth = 4) Local $hDC, $hPen, $obj_orig, $x1, $x2, $y1, $y2 $x1 = $tLeft $x2 = $tRight $y1 = $tTop $y2 = $tBottom $hDC = _WinAPI_GetWindowDC(0) ; DC of entire screen (desktop) $hPen = _WinAPI_CreatePen($PS_SOLID, $PenWidth, $color) $obj_orig = _WinAPI_SelectObject($hDC, $hPen) _WinAPI_DrawLine($hDC, $x1, $y1, $x2, $y1) ; horizontal to right _WinAPI_DrawLine($hDC, $x2, $y1, $x2, $y2) ; vertical down on right _WinAPI_DrawLine($hDC, $x2, $y2, $x1, $y2) ; horizontal to left right _WinAPI_DrawLine($hDC, $x1, $y2, $x1, $y1) ; vertical up on left ; clear resources _WinAPI_SelectObject($hDC, $obj_orig) _WinAPI_DeleteObject($hPen) _WinAPI_ReleaseDC(0, $hDC) EndFunc ;==>_UIA_DrawRect #EndRegion Edit: Speed and partial match enhancements. Search is within a split second especially when partial match is turned on Edit2: Cleaned up code in a nicer way, returns best match results even if find is false Edit 24 march 2008: Becomes dependent on beta v3.2.11.5 (beta) ;$iPos = StringInStr($BMP1Data, $searchFor) $iPos = StringInStr($BMP1Data, $searchFor, 2, 1, $iPos+1) Edit 13th june 2008 updated for new autoit version Edit 31st august 2008 added some reference links Edit 04 sept 2008 completely rewritten using GDI plus functions and speedenhancements by using different 24 bits and 16 bits pictures Edit 23 nov 2008 small additional check on bmp2height beeing 0 Edit 1st dec 2008 fixed top/left, added [active] find on active screen, work with window special description Edit 20st feb 2009 fixed Stringinstr to use additional parameters, now matchin b/w pictures better $iPos = StringInStr($BMP1Data, $searchFor, 2, 1, $iPos) Edit jan 5th 2013 full updated all working under Windows 7 / 64 bits (not tested under windows XP but no reason to be broken) edit jan 20st 2018 checked with windows 10, quickfix as calculator is not recognized by AU3Inf, basic algorithm still works fine see also works with BMP, PNG and TIFF added threshold for small bits off on a single line (unclear why GDI writes those pixels/shade variation) speed I assume is no issue for nowadays CPU power pics.zip
    1 point
  2. zuladabef, This works when both the UpDown and direct user input is used to change the minutes: #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> #include <Date.au3> Example() Func Example() GUICreate("My GUI get time", 200, 200, 800, 200) ; Get current time $sTime = _NowTime(4) $iHour = Int(StringLeft($sTime, 2)) $iMins = Int(StringRight($sTime, 2)) ; Set to nearest quarter Switch $iMins Case 53 To 59, 01 To 07 $iMins = 0 Case 08 To 22 $iMins = 15 Case 23 To 37 $iMins = 30 Case 38 To 52 $iMins = 45 EndSwitch Local $idDate = GUICtrlCreateDate("", 20, 20, 100, 20, BitOR($DTS_UPDOWN, $DTS_TIMEFORMAT)) GUICtrlSendMsg($idDate, $DTM_SETFORMATW, 0, "HH:mm") GUICtrlSetData($idDate, _NowCalcDate() & StringFormat(" %02i:%02i:00", $iHour, $iMins)) GUISetState(@SW_SHOW) Local $iHour, $iQuart, $sDate While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE ExitLoop Case $idDate ; In case we need to alter the hour too $iHourChange = 0 ; Read minutes $iMins = Int(StringRight(GUICtrlRead($idDate), 2)) ; Set minutes to next quarter - depending on direction of movement Switch $iMins Case 1 To 13 $iMins = 15 Case 16 To 28 $iMins = 30 Case 31 To 43 $iMins = 45 Case 46 To 58 $iMins = 00 $iHourChange = +1 Case 02 To 14 $iMins = 00 $iHourChange = -1 Case 17 To 29 $iMins = 15 Case 32 To 44 $iMins = 30 Case 47 To 59 $iMins = 45 EndSwitch ; Read hour $iHour = Int(StringLeft(GUICtrlRead($idDate), 2)) ; Set new time $sDate = _NowCalcDate() & StringFormat(" %02i:%02i:00", $iHour + $iHourChange, $iMins) GUICtrlSetData($idDate, $sDate) EndSwitch WEnd EndFunc ;==>Example I am now looking into how to deal with direct user input. Looks like it was easier then I thought it might be! M23
    1 point
  3. No there is only one line in yourprog.au3 and it is not #pragma...
    1 point
  4. 1 point
  5. @meety. You cannot run directly from startup folder a program that #RequireAdmin. But you can ShellExecute a second script that includes #RequireAdmin. Script 1 (must be compiled and copied into startup folder) ShellExecute("c:\apps\autoit\TempExtra.au3") Script 2 (uncompiled, called here as TempExtra.au3) #RequireAdmin MsgBox(0,"","test") Working fine for me on Win7. ps. you may also need to exclude startup folder from your AV scan (or use a shortcut instead of having the exe physically there)
    1 point
  6. @Schmand Are you using the full version of Scite? If so, you should be able to press Ctrl+F5 to perform a syntax check on the script. That will generally identify an issues such as missing #include files. When you run the script from Scite, you should get some helpful diagnostic information posted in the Output panel. Please post that here for review.
    1 point
  7. Look at posibility of compilation to A3X (compiled format without runtime module). So maybe you could compile your functions/includes to A3X format and then in main script use #include <functions.a3x> I'm not 100% sure if it would work this way but it was disccused here already, so try to search here for A3X compile & include ... EDIT: According https://www.autoitscript.com/trac/autoit/ticket/383 it should work since the version: 3.3.9.5
    1 point
  8. @Danp2 Is it possible to using WD+GoogleChrome open few URL's in separate TAB's and manage them concurently ? If yes .. could you be so nice and give me any hint on: How to switch between already opened URL's/TAB's ?
    1 point
  9. here is the last update ... I fix also the Copy to clipboard ArrayDisplayInternals2.7z
    1 point
  10. Got one ! thanks for this unexpected proxy upvote
    1 point
  11. Could we have the correct question ? 😅 For us, or at least for me, that mean your issue was solved.
    1 point
  12. Exactly, only changes for Au3Check compliance and moving the examples to a subdirectory, because it then makes managing UDF files much easier. What I mean by this is taking into account the broader perspective and multi-project management, .. .IMHO it is kind of "Good Coding Practices" to Move examples to SubDirectory. For example I have one directory for UDF which comes form FORUM members, and one which I manage and release on the forum, and one for my private UDF. In each of this folder I have about 20 different UDF, and if I also had to have all examples in the same directories, then it would have totally mess with too many UDF mixed with examples at one directory. So I thought that I try to separate UDF main files from Examples and from my testing script. This is entire the back stage story related to moving examples file to subfolder. As to Au3Check compliance. I know that not everyone likes it because it would require rewriting a significant part of their existing scripts. In general, the proposed changes do not affect the correctness of AutoIt's execution of these scripts, but again in a broader perspective, they show users a number of good practices that are followed / required / enforced by the already mentioned Au3Check. As I am in order to develop good habits, in the SciTE4Au3 environment I turned on the compliance requirement for each script I run. This allows me to explore the analyzed code more thoroughly (because I have to refactor it), learn a lot. The amount of my extra work is sometimes small, sometimes large, but I always try to share it with the community. I know not everyone will support my approach, that's why I kindly ask about taking the change consideration into yours UDF.
    1 point
  13. Local $sentences=".!? " & StringRegExpReplace(FileRead("2.txt"), "([\!\.\?][' '])", "$1.!?") $sentences=StringRegExpReplace($sentences, "([\n][\n])", ".!?") FileDelete("results.txt") For $word In StringSplit(FileRead("1.txt"), @CRLF, 3) FileWriteLine("results.txt",@CRLF & "WORD: "& $word) $iEPos=1 For $n = 1 to 3 $iWPos=StringInStr($sentences, $word, 0, 1, $iEpos) If $iWPos=0 Then ExitLoop $iSPos=StringInStr($sentences, ".!?", 0, -1, $iwPos) $iEPos=StringInStr($sentences, ".!?", 0, 1, $iwPos) $sentence=StringStripWS(StringMid($sentences, $iSPos + 3, $iEPos - $iSpos - 3),3) FileWriteLine("results.txt", $sentence) Next Next dice.
    1 point
  14. Local $sentences=".!? " & StringRegExpReplace(FileRead("2.txt"), "([\!\.\?])", "$1.!?") FileDelete("results.txt") For $word In StringSplit(FileRead("1.txt"), @CRLF, 3) FileWriteLine("results.txt",@CRLF & "WORD: "& $word) $iEPos=1 For $n = 1 to 3 $iWPos=StringInStr($sentences, $word, 0, 1, $iEpos) If $iWPos=0 Then ExitLoop $iSPos=StringInStr($sentences, ".!?", 0, -1, $iwPos) $iEPos=StringInStr($sentences, ".!?", 0, 1, $iwPos) $sentence=StringStripWS(StringMid($sentences, $iSPos + 3, $iEPos - $iSpos - 3),3) FileWriteLine("results.txt", $sentence) Next Next IMHO, you deserve an A+.
    1 point
  15. Hi, you could use the GUISetAccelerators instead of hotkey. (maybe)
    1 point
  16. Close Enough #include <Array.au3> $txt = 'The light that fills the room feels cold and blue, tinted by the shades across the window. This wind' _ & 'ow faces south. so the light trickles in slowly and at first I can ignore it. but eventually I must ' _ & 'open my eyes to this underwater light, and take a deep the breath in. I used to get up so early. Some da' _ & 'ys I would go outside and watch the sunrise. warming my hands with a mug of herbal tea. The world wa' _ & 's quie....' $sWords = "the|cold|light" $word_MatchRepeat = 3 $array = _a($txt, $sWords, $word_MatchRepeat) _ArrayDisplay($array, "Results") Func _a($s, $wPatt, $WR) Local $aWords = StringSplit($wPatt, "|"), $patt = '[^.]+(\b\Q' & StringReplace($wPatt, "|", "\E|\b\Q") & _ '\E)+([.$]|[^.]+\.)(*SKIP)(*F)|\b[^.]+\.|[^ ]{2,}|[.$]{2,}' Local $a = StringRegExp(StringRegExpReplace($s, $patt, ""), '\b[^.]+\.', 3) For $i = 0 To $aWords[0] _ArrayColInsert($a, 1) Next For $i = 1 To $aWords[0] For $j = 0 To UBound($a) - 1 If StringRegExp($a[$j][0], $aWords[$i]) Then $a[$j][$i] = $aWords[$i] $a[$j][UBound($a, 2) - 1] += 1 EndIf Next Next _ArraySort($a, 0, Default, Default, UBound($a, 2) - 1) _ArrayColInsert($aWords, 1) Local $aNew[0][2] For $i = 1 To $aWords[0][0] Local $x = 0, $iCount = 0, $1 Do $x += 1 If $aWords[$i][1] >= $WR Then ExitLoop $index = _ArraySearch($a, "\w", Default, Default, Default, 3, Default, $i) If $index < 0 Then ExitLoop _ArrayAdd($aNew, $a[$index][0] & "|" & $aWords[$i][0], Default, "|") For $j = 1 To $aWords[0][0] If $j <> $i Then If $a[$index][$j] Then $aWords[$j][1] += 1 If $aWords[$j][1] > $WR Then $1 = _ArraySearch($aNew, $aWords[$j][0], Default, Default, 1, Default, Default, 1) If $1 >= 0 Then _ArrayDelete($aNew, $1) EndIf EndIf $aNew[UBound($aNew) - 1][1] &= ", " & $a[$index][$j] EndIf Else $aWords[$i][1] += 1 EndIf $a[$index][$j] = "" Next $iCount += 1 Until $iCount > $WR Next Return $aNew EndFunc
    1 point
  17. 3-liner: For $sentence In StringSplit(StringRegExpReplace(FileRead("2.txt", FileDelete("results.txt")-2),"([\!\.\?])","$1.!?"), ".!?",3) If StringRegExp($sentence,"\W" & StringStripWS(FileRead("1.txt"),2) & "\W") Then FileWriteLine("results.txt",$sentence) Next @mikell, fork and knife fed 1.txt 2.txt results.txt
    1 point
  18. An hybrid solution maybe ? #include <Constants.au3> $p = "word 1|word 2|word 3" $txt = "Sentence 1 without the searched term. Sentence 2 is word 1 sentence. " & @crlf & "Sentence 3 without the searched term. Sentence 4 without the searched term. Sentence 5, is word 2 sentence. " & @crlf & "Sentence 6 is word 3 sentence. Sentence 7 is otherword 3 sentence. Sentence 8 without the searched term." $aSentence = StringSplit($txt, ".", $STR_NOCOUNT) For $i = 0 to UBound($aSentence) - 2 If StringRegExp($aSentence[$i], "\b(" & $p & ")\b") Then FileWriteLine("Result.txt", StringStripWS($aSentence[$i], $STR_STRIPLEADING+$STR_STRIPTRAILING)) Next
    1 point
  19. ... but some are passionate guys who create something similar themselves so this allows a first try #Include <Array.au3> $p = "word 1|word 2|word 3" $txt = " Sentence 1 without the searched term. Sentence 2 is word 1 sentence. " & @crlf & "Sentence 3 without the searched term. Sentence 4 without the searched term. Sentence 5, is word 2 sentence. " & @crlf & "Sentence 6 is word 3 sentence. Sentence 7 is otherword 3 sentence. Sentence 8 without the searched term. " $res = StringRegExp($txt, '(?s)\s*([^.]+\b(?|' & $p & ')\b[^.]+\.)', 3) _ArrayDisplay($res) Edit Waiting now for new requirements to come
    1 point
  20. My earlier code had a typo (execScript vs ExecuteScript). Once you fix that, the code will run like I posted as long as the page already uses jQuery. If not, then run _jQuerify first. Here's an example using the first HTML file you posted, which doesn't load jQuery by default -- #include <ie.au3> Local $oIE = _IECreate(@ScriptDir & "\test.htm") _jQuerify($oIE) $ss = '$(function(){$("li").each(function(index,element){$(element).css("opacity",(index+1)/10);$(element).css("border","5px solid red");})});' $oIE.document.parentwindow.execScript($ss) ; #FUNCTION# ==================================================================================================================== ; Name ..........: _jQuerify ; Description ...: ; Syntax ........: _jQuerify(Byref $oIE) ; Parameters ....: $oIE - Object variable of an InternetExplorer.Application. ; Return values .: an object variable pointing to the jQuery library ; Author ........: Chimp ; Modified ......: ; Remarks .......: ; Related .......: ; Link ..........: ; Example .......: ; =============================================================================================================================== Func _jQuerify(ByRef $oIE) Local $jsEval, $jQuery, $otherlib = False ; create a reference to the javascript eval() function $oIE.document.parentWindow.setTimeout('document.head.eval = eval', 0) Do Sleep(250) $jsEval = Execute('$oIE.Document.head.eval') Until IsObj($jsEval) ; if jQuery is not already loaded then load it If $jsEval("typeof jQuery=='undefined'") Then ; check if the '$' (dollar) name is already in use by other library If $jsEval("typeof $=='function'") Then $otherlib = True Local $oScript = $oIE.document.createElement('script'); $oScript.type = 'text/javascript' ; If you want to load jQuery from a disk file use the following statement ; where i.e. jquery-1.9.1.js is the file containing the jQuery source ; (or also use a string variable containing the whole jQuery listing) ;~ $oScript.TextContent = FileRead(@ScriptDir & "\jquery-1.9.1.js") ; <--- from a file ; If you want to download jQuery from the web use this statement $oScript.src = 'https://code.jquery.com/jquery-latest.min.js' ; <--- from an url $oIE.document.getElementsByTagName('head').item(0).appendChild($oScript) Do Sleep(250) Until $jsEval("typeof jQuery == 'function'") EndIf Do Sleep(250) $jQuery = $jsEval("jQuery") Until IsObj($jQuery) If $otherlib Then $jsEval('jQuery.noConflict();') Return $jQuery EndFunc ;==>_jQuerify
    1 point
  21. seadoggie01

    Exit Register

    OnAutoItExitRegister is nice, but it doesn't quite hit the spot for me. What if I want to save and close an Excel document when the script ends? Then I have to make the document global (possibly the Excel object as well) and write a separate function. I'm lazy and don't like separate functions. Enter Sandman ExitRegister Register functions with parameters to be run on script exit. If you want to, you can even insert them at the beginning. For our Excel example: Now I can sleep easy knowing that Excel will be closed even if the workbook fails to be created and the script exits early. Documentation to come soon... I hope... 🤥 Updated with documentation. I forgot to mention, I only added 10 parameters for the exit functions, but his can be expanded very quickly, so let me know if you need more! I don't think I've ever used more than 10 parameters on a function (before now)
    1 point
  22. NULLs have a history, so that is that. As far as ConsoleWrite a NUL, I guess no one care to use it the way he will. I too use PHP with AutoIt but I use TCP due to the overhead of loading an EXE as CGI. But even if the Ticket don't get adopted, the function he wrote is good to have. The $str is not modified so it will not be added twice in AutoIt's memory, so the "Const ByRef $str" can be dropped, adding flexibility to the function.
    1 point
  23. That _NTP_FT function seems not to work behind a proxy. I use this function to get the date which should be accurate. #include <Array.au3> Global $iError = 0, $oErrorChk = ObjEvent("AutoIt.Error", "ObjErrChk") $aResult = GetDateFromINet() If @error Then ConsoleWrite("Error connecting to internet!" & @CRLF) Else _ArrayDisplay($aResult) EndIf Func GetDateFromINet($bProxy = False, $sProxy = "", $sURL = "http://www.google.com/") Local $oHTTP = ObjCreate("winhttp.winhttprequest.5.1") If $iError Then Return SetError(1, 0, 0) If $bProxy Then $oHttp.SetProxy(2, $sProxy) $oHTTP.Open("GET", $sURL, False) $oHTTP.Send() If $iError Then Return SetError(2, 0, 0) Local $sDate = $oHTTP.GetResponseHeader("Date") Local $sYear = StringRegExpReplace($sDate, ".+,\s*\d+\s*\w+\s*(20\d+)\s*.*", "$1") Local $iMonth, $aMonth[13] = [12, "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dez"] $iMonth = _ArraySearch($aMonth, StringRegExpReplace($sDate, ".+,\s*\d+\s*(\w+)\s*20\d+\s*.*", "$1")) Local $iDay, $aDay[8] = [7, "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"] $iDay = StringRegExpReplace($sDate, ".+,\s*(\d+)\s*\w+\s*20\d+\s*.*", "$1") $oHTTP = Null Local $aDate[3] = [$sYear, StringFormat("%02i", $iMonth), StringFormat("%02i", $iDay)] Return $aDate EndFunc Func ObjErrChk() $iError += 1 ConsoleWrite($oErrorChk.scriptline & @CRLF) ConsoleWrite($oErrorChk.windescription & @CRLF) ConsoleWrite($oErrorChk.number & " / " & Hex($oErrorChk.number) & @CRLF) EndFunc
    1 point
  24. Maybe that's what you are looking for? Local $sFileOpenDialog = FileOpenDialog("", @WorkingDir & "\", "Exe (*.exe)", 1) If @error Then Exit Local $hFileOpen = FileOpen($sFileOpenDialog, 16) If $hFileOpen = -1 Then MsgBox($MB_SYSTEMMODAL, "", "An error occurred when reading the file.") Exit EndIf Local $sFileRead = FileRead($hFileOpen) FileClose($hFileOpen) Local $File_struct = DllStructCreate("BYTE File[" & BinaryLen($sFileRead) & "]") DllStructSetData($File_struct, "File", $sFileRead) for $io = 0 to BinaryLen($sFileRead) msgbox(0,"","0x" & hex(DllStructGetData($File_struct, "File",$io),2)) next
    1 point
  25. llewxam

    Tab background color

    Just wanted to mention that I was very glad to find this Melba23, I have a nice blue background in my GUI and have never used CreateTab until today, I was SOOOOO upset with how my app looked because the background color was wrong. Thanks for this solution, very simple idea, I appreciate your expertise as always!! Ian
    1 point
  26. Melba23

    Tab background color

    MadMaxx, Here is my take on how you might do it: #include <GUIConstantsEx.au3> #include <GuiTab.au3> $hGUI = GUICreate("Test", 500, 500) $hTab_1 = GUICtrlCreateTab(10, 10, 230, 90) $hTab_10 = GUICtrlCreateTabitem("Red") _GUICtrlTab_SetBkColor($hGUI, $hTab_1, 0xFFCCCC) $hTab_11 = GUICtrlCreateTabitem("Green") _GUICtrlTab_SetBkColor($hGUI, $hTab_1, 0xCCFFCC) $hTab_12 = GUICtrlCreateTabitem("Blue") _GUICtrlTab_SetBkColor($hGUI, $hTab_1, 0xCCCCFF) GUICtrlCreateTabitem ("") ; end tabitem definition GUISetState() GUISetState() While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE Exit EndSwitch WEnd Func _GUICtrlTab_SetBkColor($hWnd, $hSysTab32, $sBkColor) Local $aTabPos = ControlGetPos($hWnd, "", $hSysTab32) Local $aTab_Rect = _GUICtrlTab_GetItemRect($hSysTab32, -1) GUICtrlCreateLabel("", $aTabPos[0]+2, $aTabPos[1]+$aTab_Rect[3]+4, $aTabPos[2]-6, $aTabPos[3]-$aTab_Rect[3]-7) GUICtrlSetBkColor(-1, $sBkColor) GUICtrlSetState(-1, $GUI_DISABLE) EndFunc M23
    1 point
  27. DaRam

    wait for any key press?

    Or this, for any Key Down or Mouse Click: While 1 If Check4KbdOrMousePress() Then ExitLoop WEnd Func Check4KbdOrMousePress() Local $i Local $Keycodes = StringSplit("01|02|04|05|06" & _ "|08|09|0C|0D|10|11|12|13|14|1B|20|21|22" & _ "|23|24|25|26|27|28|29|2A|2B|2C|2D|2E|30" & _ "|31|32|33|34|35|36|37|38|39|41|42|43|44" & _ "|45|46|47|48|49|4A|4B|4C|4D|4E|4F|50|51" & _ "|52|53|54|55|56|57|58|59|5A|5B|5C|60|61" & _ "|62|63|64|65|66|67|68|69|6A|6B|6C|6D|6E" & _ "|6F|70|71|72|73|74|75|76|77|78|79|7A|7B" & _ "|90|91|A0|A1|A2|A3|A4|A5", "|") For $i in $Keycodes If _IsPressed(String($i)) Then Return 1 Next Return 0 EndFunc
    1 point
  28. Can I get the correct answer?
    0 points
×
×
  • Create New...