Leaderboard
Popular Content
Showing content with the highest reputation on 11/24/2019 in all areas
-
A little (late...) pseudo-explanation Sometimes it's easier to define first what you don't want to match, then skip/fail it and apply what is needed to the rest3 points
-
TeraCopy Timer updated to v3.3. See first post. (v3.3) The STOP button now has a red area around it when Shutdown is enabled, and its screen position is now recorded & restored. More Splash are shown for Calculating and Recalculating. (v3.2) All relevant controls are now disabled until Job processing has finished. The STOP button now has additional information in regard to 'Stop Monitoring'. P.S. By the way, 'Stop Monitoring', also means stop controlling.2 points
-
Find BMP in another BMP (imagesearch)
HansHenrik reacted to junkew for a topic
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.zip1 point -
Try the following modification to get better error information:1 point
-
I wrote that quite quickly and I suppose there are holes left around. For instance, the definition of number isn't fully correct as that would match inside strings! That's because recursion inside the nested names don't need to be matched: if you request only numbers, for instance, nothing forces this part to be an element, itself part of an array or table. Also, multi-dimensional tables (arrays) need to have the same number of entries for dimensions > 1, which is hard to check that way. Nonetheless the use of named subroutines, as in (?(DEFINE) (?<object> ...) ... (... (?&object) ... ) can be very handy at times.1 point
-
OTOH if you want to match JSON definitions of its internal structure you can do so explicitely: Local $sIn = "{[[Elton John, Bonnie & Clyde, Sally, 123],[one 1, 2, 3, 4 four 4]], abc, [7,{a,b,[c,d,3]}]}" _String2Json($sIn) MsgBox(0, "Result", $sIn) Func _String2Json(ByRef $s) $s = StringRegExpReplace($s, _ '(?x)' & _ '(?(DEFINE) (?<table> \{ \h* (?: (?&element) (?: \h* , \h* (?&element) )* \h* \} ) ) )' & _ '(?(DEFINE) (?<array> \[ \h* (?: (?&element) (?: \h* , \h* (?&element) )* \h* \] ) ) )' & _ '(?(DEFINE) (?<element> (?&table) | (?&array) | (?&number) | (?&string) ) )' & _ '(?(DEFINE) (?<number> [-+]? \d+ (?: \.\d+ )? (?: [Ee] [-+]? \d+ )? ) )' & _ '(?(DEFINE) (?<string> \b \w* [^\[\],]*[[:alpha:]_]+ [\w\h]* ) )' & _ '( (?&string) )', _ '"$6"') EndFunc ;==>_Array2Json Of course, once that invalid input string is reformatted to correctly enclose strings inside double quotes, things are easier to handle.1 point
-
Strictly following the requirements from your example above, this should work ... $s = "[[Elton John,Peter,Sally,123],[1 one 1,2,3,4 four 4]]" $res = StringRegExpReplace($s, '\b\d+(?!\h*\w)\b(*SKIP)(*F)|([\w\h]+)', '"$1"') Msgbox(0,"", $res)1 point
-
Something like this should do it. It is a updated version of _ArrayToString() - see the comments in the UDF: #include <Array.au3> Local $aArray = [["Elton John", "Peter", "Sally", 123], ["one 1", 2, 3, "4 four 4"]] MsgBox(0, "Result", _Array2Json($aArray)) Func _Array2Json($aArray) If (Not IsArray($aArray)) Or (UBound($aArray, 0) > 2) Then Return SetError(1, 0, '') Local $sOpening, $sClosing If UBound($aArray, 0) = 1 Then $sOpening = '[' $sClosing = ']' Else $sOpening = '[[' $sClosing = ']]' EndIf $sOutpt = $sOpening & _ArrayToString_ex($aArray, ",", -1, -1, "],[") & $sClosing ; $sOutpt = ???? how to quote strings ???? Return $sOutpt EndFunc ;==>_Array2Json Func _ArrayToString_ex(Const ByRef $aArray, $sDelim_Col = "|", $iStart_Row = -1, $iEnd_Row = -1, $sDelim_Row = @CRLF, $iStart_Col = -1, $iEnd_Col = -1) If $sDelim_Col = Default Then $sDelim_Col = "|" If $sDelim_Row = Default Then $sDelim_Row = @CRLF If $iStart_Row = Default Then $iStart_Row = -1 If $iEnd_Row = Default Then $iEnd_Row = -1 If $iStart_Col = Default Then $iStart_Col = -1 If $iEnd_Col = Default Then $iEnd_Col = -1 If Not IsArray($aArray) Then Return SetError(1, 0, -1) Local $iDim_1 = UBound($aArray, $UBOUND_ROWS) - 1 If $iStart_Row = -1 Then $iStart_Row = 0 If $iEnd_Row = -1 Then $iEnd_Row = $iDim_1 If $iStart_Row < -1 Or $iEnd_Row < -1 Then Return SetError(3, 0, -1) If $iStart_Row > $iDim_1 Or $iEnd_Row > $iDim_1 Then Return SetError(3, 0, "") If $iStart_Row > $iEnd_Row Then Return SetError(4, 0, -1) Local $sRet = "" Switch UBound($aArray, $UBOUND_DIMENSIONS) Case 1 For $i = $iStart_Row To $iEnd_Row ; Added this logic If IsString($aArray[$i]) Then $sRet &= '"' & $aArray[$i] & '"' & $sDelim_Col Else $sRet &= $aArray[$i] & $sDelim_Col EndIf Next Return StringTrimRight($sRet, StringLen($sDelim_Col)) Case 2 Local $iDim_2 = UBound($aArray, $UBOUND_COLUMNS) - 1 If $iStart_Col = -1 Then $iStart_Col = 0 If $iEnd_Col = -1 Then $iEnd_Col = $iDim_2 If $iStart_Col < -1 Or $iEnd_Col < -1 Then Return SetError(5, 0, -1) If $iStart_Col > $iDim_2 Or $iEnd_Col > $iDim_2 Then Return SetError(5, 0, -1) If $iStart_Col > $iEnd_Col Then Return SetError(6, 0, -1) For $i = $iStart_Row To $iEnd_Row For $j = $iStart_Col To $iEnd_Col ; Added this logic If IsString($aArray[$i][$j]) Then $sRet &= '"' & $aArray[$i][$j] & '"' & $sDelim_Col Else $sRet &= $aArray[$i][$j] & $sDelim_Col EndIf Next $sRet = StringTrimRight($sRet, StringLen($sDelim_Col)) & $sDelim_Row Next Return StringTrimRight($sRet, StringLen($sDelim_Row)) Case Else Return SetError(2, 0, -1) EndSwitch Return 1 EndFunc ;==>_ArrayToString_ex Jos1 point
-
You should check out my Process UDF which is exactly what it is supposed to do that and it even has an example of a GUI which shows you the output of a command:1 point
-
FModMem UDF build 2019-11-24
ScrapeYourself reacted to UEZ for a topic
Code updated to support also x64 execution.1 point -
ahh, I see. Try this (untested) : $InpConsole = GUICtrlCreateInput("", 8, 176, 545, 200) ; .... GUICtrlSetData ($InpConsole, _Seven_Zip ()) Func _Seven_Zip() If GuiCtrlRead($Inp) = "" or GuiCtrlRead($Out) = "" then Return MsgBox (64,"Controlla le caselle", "una o più caselle sono vuote") $cmd = Run($7zDir & ' a -mx "' & GUICtrlRead($Out) & '" "' & GUICtrlRead($Inp) & '\*"',"",@SW_HIDE,$STDERR_MERGED) ProcessWaitClose ($cmd) Return StdoutRead($cmd) EndFunc1 point
-
little typo : 180 (as in Output), not 108 .1 point
-
Not able to click a login button
FrancescoDiMuro reacted to Danp2 for a topic
That's an out of date version. Please update and then report back. P.s. Suggest that you change your password as you posted it in the output above.😂1 point -
I don't quite understand your question/issue. Are you trying to figure out how to calculate the checksum or are you trying to figure out why you are not seeing "0x" when you display hex/binary values? This little snippet is one way to calculate the checksum according to your specifications. The 2 pairs of ConsoleWrites produce the same output. They just do it using different functions. For more complex outputs, I prefer to use the StringFormat function. So one uses the StringFormat function and the other uses the Hex function, like in your script. Note that the Hex function uses the 2nd parameter, that tells it how many characters to output, which in this case is 2. As for calculating the checksum, I think you may have been over-thinking it a bit. You had the right idea in summing the ASC values. You should have just sum the integers values first and then convert the resulting integer to its hex representation (83 + 65 + 32 = 180). 180 in base10 (decimal) is B4 in base16 (hex). Instead, you were trying to add the hex string representation of the integers ("53" + "41" + "20" = 114). #include <Constants.au3> example() Func example() Local $sString = "SA " Local $iChecksum = 0 $aChars = StringSplit($sString, "") For $i = 1 To $aChars[0] $iChecksum += Asc($aChars[$i]) ;~ ConsoleWrite(StringFormat('"%s" = %i (0x%X)', $aChars[$i], Asc($aChars[$i]), Asc($aChars[$i])) & @CRLF) ConsoleWrite('"' & $aChars[$i] & '" = ' & Asc($aChars[$i]) & " (0x" & Hex(Asc($aChars[$i]), 2) & ")" & @CRLF) Next ConsoleWrite(StringFormat("$iChecksum = %i (0x%X)", $iChecksum, $iChecksum) & @CRLF) ;~ ConsoleWrite("$iChecksum = " & $iChecksum & " (0x" & Hex($iChecksum, 2) & ")" & @CRLF) EndFunc Output: "S" = 83 (0x53) "A" = 65 (0x41) " " = 32 (0x20) $iChecksum = 180 (0xB4)1 point
-
Read data from specific Row
CiaronJohn reacted to water for a topic
Simply use _Excel_RangeRead to read this 4 columns. Merged cells will be returned in the leftmost cell of the array. Means: You read columns K:N the string "expected values" would be returned in row 23, column 0 of the returned array.1 point -
Listview scroll event?
pixelsearch reacted to LarsJ for a topic
GUIRegisterMsg is able to catch messages which are send to the GUI. The scrollbars are child windows of the listview. WM_VSCROLL messages are always send to the parent window. In this case the listview. The GUI will never receive the messages and GUIRegisterMsg cannot catch them. You can catch the messages by subclassing the listview: #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> #include <GuiListView.au3> #include <WinAPIShellEx.au3> Global $iFire = 0 $Form1 = GUICreate("Form1", 374, 217, 219, 155) $ListView = GUICtrlCreateListView("A", 8, 8, 354, 206) $hListView = GUICtrlGetHandle($ListView) GUICtrlSendMsg(-1, $LVM_SETCOLUMNWIDTH, 0, 50) For $i = 0 To 100 GUICtrlCreateListViewItem("a", $ListView) Next GUISetState(@SW_SHOW) GUIRegisterMsg($WM_VSCROLL, "WM_VSCROLL") GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY") $pListViewCallback = DllCallbackGetPtr( DllCallbackRegister( "ListViewCallback", "lresult", "hwnd;uint;wparam;lparam;uint_ptr;dword_ptr" ) ) _WinAPI_SetWindowSubclass( $hListView, $pListViewCallback, 9999, 0 ) While 1 $nMsg = GUIGetMsg() Switch $nMsg Case $GUI_EVENT_CLOSE Exit EndSwitch WEnd _WinAPI_RemoveWindowSubclass( $hListView, $pListViewCallback, 9999 ) Func ListViewCallback( $hWnd, $iMsg, $wParam, $lParam, $iSubclassId, $pData ) Switch $iMsg Case $WM_VSCROLL ConsoleWrite("ListViewCallback WM_VSCROLL" & @CRLF) EndSwitch ; Call next function in subclass chain Return DllCall( "comctl32.dll", "lresult", "DefSubclassProc", "hwnd", $hWnd, "uint", $iMsg, "wparam", $wParam, "lparam", $lParam )[0] #forceref $iSubclassId, $pData EndFunc Func WM_VSCROLL($hWnd, $iMsg, $wParam, $lParam) #forceref $hWnd, $iMsg, $wParam, $lParam ConsoleWrite("WM_VSCROLL" & @CRLF) Return $GUI_RUNDEFMSG EndFunc ;==>WM_EXITSIZEMOVE Func WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam) #forceref $hWnd, $iMsg, $wParam, $lParam $tNMHDR = DllStructCreate($tagNMHDR, $lParam) $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom")) $iIDFrom = DllStructGetData($tNMHDR, "IDFrom") $iCode = DllStructGetData($tNMHDR, "Code") Switch $hWndFrom Case $hListView Switch $iCode Case $LVN_BEGINSCROLL $iFire += 1 ConsoleWrite("LVN_BEGINSCROLL " & $iFire & @CRLF) Case $LVN_ENDSCROLL $iFire += 1 ConsoleWrite("LVN_ENDSCROLL " & $iFire & @CRLF) EndSwitch EndSwitch Return $GUI_RUNDEFMSG EndFunc ;==>WM_NOTIFY1 point -
GUICtrlMenuEx UDF (Standard Menu With Icon)
DinFuv reacted to argumentum for a topic
GUICtrlMenuEx.zip1 point -
Quick search, a small modification, and this is the end result: MsgBox(0, '', _String_GetFormattedSizeEx(7098459644)) ; #FUNCTION# ==================================================================================================================== ; Name ..........: _String_GetFormattedSizeEx ; Description ...: Return ByteSize in human-readable format ("complex format" GB + MB + KB ) ; Syntax ........: _String_GetFormattedSizeEx($iByteSize) ; Parameters ....: $iByteSize - an integer value. ; Return values .: ByteSize in format like this: 7 GB 770 MB 089 KB ; Author ........: mLipok ; Modified ......: ; Remarks .......: ; Related .......: ; Link ..........: ; Example .......: No ; =============================================================================================================================== Func _String_GetFormattedSizeEx($iByteSize) Local $sKB = _String_GetFormattedSize(7098459644, 0, 'KB') Local $sMB = _String_GetFormattedSize(7098459644, 0, 'MB') Local $sGB = _String_GetFormattedSize(7098459644, 0, 'GB') Return $sGB & ' ' & StringRight($sMB, 6) & ' ' & StringRight($sKB, 6) EndFunc ;==>_String_GetFormattedSizeEx ; #FUNCTION# ==================================================================================================================== ; Name ..........: _String_GetFormattedSize ; Description ...: Return ByteSize in human-readable format (one of avalaible size format) ; Syntax ........: _String_GetFormattedSize($iByteSize[, $iRound = 2[, $sRetFormat = -1]]) ; Parameters ....: $iByteSize - an integer value. ; $iRound - [optional] an integer value. Default is 2. ; $sRetFormat - [optional] a string value. Default is -1. ; Return values .: ByteSize in choosen format ; Author ........: MrCreatoR ; Modified ......: ; Remarks .......: ; Related .......: ; Link ..........: https://www.autoitscript.com/forum/topic/110713-convertfilesize-udf/#comment-777347 ; Example .......: No ; =============================================================================================================================== Func _String_GetFormattedSize($iByteSize, $iRound = 2, $sRetFormat = -1) Local $asBytes[9] = [8, 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'] ;Last two unreachable ;) Local $iBytes_Val = 2 ^ 10 If $iByteSize < $iBytes_Val Then Return $iByteSize & ' Bytes' Local $iRetFormat_IsString = IsString($sRetFormat) Local $iFor = 1, $iTo = 8, $iStep = 1 If $iRetFormat_IsString Then If Not StringRegExp($sRetFormat, "\A(?i)(KB|MB|GB|TB|PB|EB|ZB|YB)\z") Then Return SetError(1, 0, $iByteSize) Else Local $iFor = 8, $iTo = 1, $iStep = -1 EndIf For $i = $iFor To $iTo Step $iStep If ($iRetFormat_IsString And $sRetFormat = $asBytes[$i]) Or _ (Not $iRetFormat_IsString And $iByteSize >= $iBytes_Val ^ $i) Then Return Round($iByteSize / $iBytes_Val ^ $i, $iRound) & ' ' & $asBytes[$i] EndIf Next EndFunc ;==>_String_GetFormattedSize Now ready to use in my script.Thanks for sharing. mLipok1 point
-
And this too >> Func _ByteSuffix($iBytes, $iRound = 2) ; By Spiff59 Local $A, $aArray[9] = [" B", " KB", " MB", " GB", " TB", " PB", "EB", "ZB", "YB"] While $iBytes > 1023 $A += 1 $iBytes /= 1024 WEnd Return Round($iBytes, $iRound) & $aArray[$A] EndFunc ;==>_ByteSuffix And in WinAPIEx.au3 there is _WinAPI_StrFormatByteSize(). Cheers for adding to the Examples Forum though1 point
-
Image Search Library
KeiosStarqua reacted to Jos for a topic
Not seen the OP for 8 years so assume topic is dead other than the "link dead" posts. *click*0 points