Hashim Posted January 22 Posted January 22 (edited) Happy New Year everyone, this is a successor thread of sorts to one from a few months ago, I've now tested @Werty's latest solution from that thread: ;Be sure $posx and $posy is pointing at the correct spot! Global $posx = 1718, $posy = 699, $result = "", $code[3] ;Lookup table to avoid searching Global $digit[115] = [1,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0, _ 0,0,0,0,0,0,0,0,0,0,6,0,0,0,3,2,0,0,0,0, _ 0,0,0,0,0,0,0,0,9,0,0,0,0,0,8,0,0,0,0,0, _ 0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, _ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, _ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,5] ;Instead of screencapture_capture() $hDDC = _WinAPI_GetDC(0) $hCDC = _WinAPI_CreateCompatibleDC($hDDC) $hBmp = _WinAPI_CreateCompatibleBitmap($hDDC, 34, 20) _WinAPI_SelectObject($hCDC, $hBmp) _WinAPI_BitBlt($hCDC, 0, 0, 34, 20, $hDDC, $posx, $posy, 0x00CC0020) _WinAPI_DeleteDC($hCDC) $result = Getnumber($result) Func Getnumber($result) Local $code[3] = [0,0,0], $value = 64, $pixels = DllStructCreate('dword[680]') DllCall('gdi32.dll', 'dword', 'GetBitmapBits', 'ptr', $hBmp, 'dword', DllStructGetSize($pixels), 'ptr', DllStructGetPtr($pixels)) For $loop = 1 To 680 Step 102 $code[0] += DllStructGetData($pixels, 1, $loop ) = 4278255360 ? $value:0 $code[1] += DllStructGetData($pixels, 1, $loop+16) = 4278255360 ? $value:0 $code[2] += DllStructGetData($pixels, 1, $loop+32) = 4278255360 ? $value:0 $value /= 2 Next Return String($digit[$code[0]]) & String($digit[$code[1]]) & String($digit[$code[2]]) EndFunc I can confirm it works as well for that tool as his original lockbits solution, and is beautifully concise compared to it. I don't have the time to test on the whole dataset so can't confirm how much faster it is but on the few thousand results I did check it definitely doesn't seem slower or less accurate, so I'll take his word for it that this is now the best solution. The problem now is that I need to do the same thing for a similar but newer internal tool, which seems to have been built by the same dev but uses a completely different bitmap font for its results, and the results are also 4 digits instead of 3. It also seems to be in "italics" so I'm not sure whether this makes the solution impossible or if the bitmaps are still uniform enough for the maths to work. The only really good news is that the font is larger than in the original tool. Would it possible to adapt the maths of this solution to these new bitmaps? If I understood how it worked I'd do it myself, but it's way over my head and so was @AndyG's explanation of it, but I have provided all of the possible digits below and can provide more examples if needed. Edited January 22 by Hashim
Hashim Posted January 22 Author Posted January 22 (edited) Anyone at all? Here's the full script I'm using along with my best-guess attempts to adapt the results and constants for a 4-digit result - like changing $value from 64 to 128 and adding loop+64. The program seems to run fine without errors, but the digits are all being recognised as either 1s or 0s (the first two digits always as 1s). I'm happy to buy a drink or five for anyone that can figure this out since management have realised I'm the only person in the department that can extract the data from these old tools. expandcollapse popup#include <WinAPI.au3> Run("tool.exe") Local $tool = WinWaitActive("tool", "", 3) $db = FileOpen(@ScriptDir & "\serials.csv", 1) ;Be sure $posx and $posy is pointing at the correct spot! Global $posx = 829, $posy = 456, $result = "", $code[4] ;Lookup table to avoid searching Global $digit[115] = [1,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0, _ 0,0,0,0,0,0,0,0,0,0,6,0,0,0,3,2,0,0,0,0, _ 0,0,0,0,0,0,0,0,9,0,0,0,0,0,8,0,0,0,0,0, _ 0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, _ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, _ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,5] For $loop = 0 To 999999 Do $serial = StringFormat('%06i', $loop) ControlClick($tool, "", "TTabSheet1", "primary", 1, 100, 100) $hDDC = _WinAPI_GetDC(0) $hCDC = _WinAPI_CreateCompatibleDC($hDDC) $hBmp = _WinAPI_CreateCompatibleBitmap($hDDC, 34, 20) _WinAPI_SelectObject($hCDC, $hBmp) _WinAPI_BitBlt($hCDC, 0, 0, 34, 20, $hDDC, $posx, $posy, 0x00CC0020) _WinAPI_DeleteDC($hCDC) $result = GetNumber($result) Until ((StringLen($result) = 4) and StringIsDigit($result)) FileWrite($db, $serial & "," & $result & @LF) Next FileClose($db) Exit Func GetNumber($result) Local $code[4] = [0,0,0,0], $value = 128, $pixels = DllStructCreate('dword[680]') DllCall('gdi32.dll', 'dword', 'GetBitmapBits', 'ptr', $hBmp, 'dword', DllStructGetSize($pixels), 'ptr', DllStructGetPtr($pixels)) For $loop = 1 To 680 Step 102 $code[0] += DllStructGetData($pixels, 1, $loop ) = 4278255360 ? $value:0 $code[1] += DllStructGetData($pixels, 1, $loop+16) = 4278255360 ? $value:0 $code[2] += DllStructGetData($pixels, 1, $loop+32) = 4278255360 ? $value:0 $code[3] += DllStructGetData($pixels, 1, $loop+64) = 4278255360 ? $value:0 $value /= 2 Next Return String($digit[$code[0]]) & String($digit[$code[1]]) & String($digit[$code[2]]) & String($digit[$code[3]]) EndFunc Edited January 22 by Hashim
junkew Posted January 22 Posted January 22 (edited) Maybe this helps a little in understanding. Its just manipulation of pixels in a certan layout (PNG). Look at the output and zoom in/out, you can see almost the numbers yourself expandcollapse popup#Region includes Opt('MustDeclareVars', 1) ;#include <GUIConstants.au3> #include <GDIPlus.au3> #Include <ScreenCapture.au3> #include <string.au3> #include <WinAPI.au3> #include <WindowsConstants.au3> #EndRegion _GDIPlus_Startup() Dim $BitmapFilename Dim $BMPData="", $BMPWidth=0, $BMPHeight=0, $BMPLineWidth=0, $imgBytes=1 dim $binaryLine for $i=1 to 4 $BitmapFilename = @TempDir & "\" & "pic" & string($i) & ".png" $BMPData="" $BMPWidth=0 $BMPHeight=0 $BMPLineWidth=0 $imgBytes=1 consolewrite($bitmapFileName) ; Load the bitmap to find getImage($BitmapFilename, $BMPData, $BMPWidth, $BMPHeight, $BMPLineWidth, $imgBytes) ;~ See the height and width and dump the data on screen consolewrite($BMPHeight & " ; ") consolewrite($BMPWidth &@CRLF ) consolewrite("0 1 2 3 4 5 6 7 8 9 x x x x " & @CRLF) consolewrite("01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" & @CRLF) For $iLine = 11 To $BMPHeight-12 ;~ From the screenshots we can ignore the first 16 bytes (remember in text its 2 characters ;~ $binaryLine=BinaryMid($bmp1Data,($i*$BMP1LineWidth)+16,$BMP1LineWidth) ;~ and we only need 4 digits which takes about 28 characters and 1 character separator = $binaryLine=BinaryMid($bmpData,($iLine *$BMPLineWidth)+16,60) ;~ Lets make it readable $binaryLine=StringReplace($binaryLine,"0",".") consolewrite($iLine & " : " & $binaryLine & @CRLF) next ;~ lets recognise for $iNumber=1 to 4 consolewrite(@crlf) consolewrite("0 1 2 3 4 5 6 7 8 9 x x x x " & @CRLF) consolewrite("01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" & @CRLF) For $iLine = 11 To $BMPHeight-12 $binaryLine=BinaryMid($bmpData,($iLine *$BMPLineWidth)+16+(($iNumber-1)*15),14) $binaryLine=StringReplace($binaryLine,"0",".") consolewrite($iLine & " : " & $binaryLine & @CRLF) next Next Next _GDIPlus_Shutdown() Func GetImage($BMPFile, byref $BMPDataStart, byref $Width, byRef $Height, byref $Stride, $imgBytes=3) local $Scan0, $pixelData, $hbScreen, $pBitmap, $pBitmapCap, $handle, $bitMapdata, $pixelFormat ; 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) ;~ $hBitmap = _GDIPlus_ImageLoadFromFile($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=1) then $BitmapData= _GDIPlus_BitmapLockBits($pBitmap, 0, 0, _GDIPlus_ImageGetWidth($pBitmap), _GDIPlus_ImageGetHeight($pBitmap), $GDIP_ILMREAD, $GDIP_PXF04INDEXED) Endif 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) EndIf if ($imgBytes=3) then $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 I assume you refer to Edited January 22 by junkew updated script to have 8 bits per pixel for easier seeing ioa747 and Hashim 2 FAQ 31 How to click some elements, FAQ 40 Test automation with AutoIt, Multithreading CLR .NET Powershell CMDLets
junkew Posted January 22 Posted January 22 You should get some output like below, copy pasted to a texteditor (replaced 0 with a dot) you can find out the width of the numbers somewhere around 28 (depending on your colordepth) .x................................................................................................................................................................................ .x....................................................BBB.....................BBB..BBB................BBB..BBB..BBB.....................BBB....................................... .x...................................................B222B...................B222BB222B..............B222BB222BB222B...................B222B...................................... .x...................................................B222B...................B222BB222B..............B222BB222BB222B...................B222B...................................... .x....................................................BBB.....................BBB..BBB................BBB..BBB..BBB.....................BBB....................................... .x................................................................................................................................................................................ .x..............................................BBB..BBB................BBB.....................BBB.................BBB...........BBB..BBB........................................ .x.............................................B222BB222B..............B222B...................B222B...............B222B.........B222BB222B....................................... .x.............................................B222BB222B..............B222B...................B222B...............B222B.........B222BB222B....................................... .x..............................................BBB..BBB................BBB.....................BBB.................BBB...........BBB..BBB........................................ .x................................................................................................................................................................................ .x.........................................BBB.......BBB...........BBB..........................BBB.................BBB................BBB........................................ .x........................................B222B.....B222B.........B222B........................B222B...............B222B..............B222B....................................... .x........................................B222B.....B222B.........B222B........................B222B...............B222B..............B222B....................................... .x.........................................BBB.......BBB...........BBB..........................BBB.................BBB................BBB........................................ .x................................................................................................................................................................................ .x...................................BBB............BBB...........BBB..BBB..BBB..BBB................BBB..BBB..BBB..BBB................BBB......................................... .x..................................B222B..........B222B.........B222BB222BB222BB222B..............B222BB222BB222BB222B..............B222B........................................ .x..................................B222B..........B222B.........B222BB222BB222BB222B..............B222BB222BB222BB222B..............B222B........................................ .x...................................BBB............BBB...........BBB..BBB..BBB..BBB................BBB..BBB..BBB..BBB................BBB......................................... .x................................................................................................................................................................................ .x..................................BBB..BBB..BBB..BBB..BBB......BBB.................BBB..........................BBB................BBB.......................................... .x.................................B222BB222BB222BB222BB222B....B222B...............B222B........................B222B..............B222B......................................... .x.................................B222BB222BB222BB222BB222B....B222B...............B222B........................B222B..............B222B......................................... .x..................................BBB..BBB..BBB..BBB..BBB......BBB.................BBB..........................BBB................BBB.......................................... .x................................................................................................................................................................................ .x................................................BBB...........BBB.................BBB.....................BBB.....................BBB........................................... .x...............................................B222B.........B222B...............B222B...................B222B...................B222B.......................................... .x...............................................B222B.........B222B...............B222B...................B222B...................B222B.......................................... .x................................................BBB...........BBB.................BBB.....................BBB.....................BBB........................................... .x................................................................................................................................................................................ .x................................................BBB................BBB..BBB..BBB................BBB..BBB.....................BBB..BBB..BBB...................................... .x...............................................B222B..............B222BB222BB222B..............B222BB222B...................B222BB222BB222B..................................... .x...............................................B222B..............B222BB222BB222B..............B222BB222B...................B222BB222BB222B..................................... .x................................................BBB................BBB..BBB..BBB................BBB..BBB.....................BBB..BBB..BBB...................................... Hashim 1 FAQ 31 How to click some elements, FAQ 40 Test automation with AutoIt, Multithreading CLR .NET Powershell CMDLets
junkew Posted January 22 Posted January 22 I enhanced the script of my first answer. Based on that you can see the patterns and identify the differences between the numbers 0-9 It depends if your are "reading" bitblt from the screen you should basically iterate per character. If you save them all as png files its like the given script needs to be enhanced and add the pattern later onwards. Hashim 1 FAQ 31 How to click some elements, FAQ 40 Test automation with AutoIt, Multithreading CLR .NET Powershell CMDLets
junkew Posted January 22 Posted January 22 (edited) So here some partial recognition based on the png files. As its italic it will be more complicated to properly first cut the characters nicely. I hope the script gives you some insights on how to do the analysis. When thats done you could directly bitblit line11 and 27 and 41 from the screen as that seems to be a proper discriminator to identify the number. From the screen you can probably directly bitblt with black/white pixels directly which should speed up even more. Due to italic it seems a little harder to calculate the exact position for each digit calculated (maybe even easier to just hardcode them as it seems to be off by 1 or 2 bytes for each digit. expandcollapse popup#Region includes Opt('MustDeclareVars', 1) ;#include <GUIConstants.au3> #include <GDIPlus.au3> #Include <ScreenCapture.au3> #include <string.au3> #include <WinAPI.au3> #include <WindowsConstants.au3> #EndRegion _GDIPlus_Startup() Dim $BitmapFilename Dim $BMPData="", $BMPWidth=0, $BMPHeight=0, $BMPLineWidth=0, $imgBytes=2 dim $binaryLine, $startColumn ;~ for each picture file for $i=1 to 4 $BitmapFilename = @TempDir & "\" & "pic" & string($i) & ".png" $BMPData="" $BMPWidth=0 $BMPHeight=0 $BMPLineWidth=0 $imgBytes=1 consolewrite($bitmapFileName) ; Load the bitmap to find getImage($BitmapFilename, $BMPData, $BMPWidth, $BMPHeight, $BMPLineWidth, $imgBytes) ;~ See the height and width and dump the data on screen consolewrite($BMPHeight & " ; ") consolewrite($BMPWidth &@CRLF ) consolewrite(" 0 1 2 3 4 5 6 7 8 9 x x x x " & @CRLF) consolewrite(" 01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" & @CRLF) For $iLine = 11 To $BMPHeight-12 ;~ From the screenshots we can ignore the first 16 bytes (remember in text its 2 characters ;~ $binaryLine=BinaryMid($bmp1Data,($i*$BMP1LineWidth)+16,$BMP1LineWidth) ;~ and we only need 4 digits which takes about 28 characters and 1 character separator = $binaryLine=BinaryMid($bmpData,($iLine *$BMPLineWidth)+16,60) ;~ $binaryLine=$bmpData ;~ Lets make it readable $binaryLine=StringReplace($binaryLine,"0",".") consolewrite($iLine & " : " & $binaryLine & @CRLF) next ;~ lets recognise for $iNumber=1 to 4 consolewrite(@crlf) consolewrite("0 1 2 3 4 5 6 7 8 9 x x x x " & @CRLF) consolewrite("01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" & @CRLF) ;~ Its hard to determine the column for each digit in a formula if $iNumber=1 then $startColumn=16 if $iNumber=2 then $startColumn=30 if $iNumber=3 then $startColumn=45 if $iNumber=4 then $startColumn=59 ;~ Only a few lines in the png are of interest For $iLine = 11 To $BMPHeight-12 ;~ $binaryLine=BinaryMid($bmpData,($iLine *$BMPLineWidth)+16+(($iNumber-1)*14),15) $binaryLine=BinaryMid($bmpData,($iLine *$BMPLineWidth)+$startColumn,15) $binaryLine=StringReplace($binaryLine,"0"," ") consolewrite($iLine & " : " & $binaryLine & @CRLF) next ;~ if on line 11 at position 28 I have a B it can be a 4 ;~ It seems to be easier to revert back to a string when we have the data local $lineData11=stringstripws(StringRegExpReplace(binaryMid($bmpData,(11*$BMPLineWidth)+$startColumn,15),"[x0]"," "),3) local $lineData27=stringstripws(StringRegExpReplace(binaryMid($bmpData,(27*$BMPLineWidth)+$startColumn,15),"[x0]"," "),3) local $lineData41=stringstripws(StringRegExpReplace(binaryMid($bmpData,(41*$BMPLineWidth)+$startColumn,15),"[x0]"," "),3) consolewrite(string($lineData11) & " - ") consolewrite(string($lineData27) & " - ") consolewrite(string($lineData41) & @crlf) ;~ And here determine the magic lines if (($lineData11="BBB") and ($lineData27="B222B B222B")) then consolewrite("Ita a 4" & @CRLF) if (($lineData11="BBB BBB") and ($lineData27="B222BB222BB222BB222B")) then consolewrite("Ita a 6" & @CRLF) if (($lineData11="BBB BBB BBB") and ($lineData27="B222BB222BB222BB222B")) then consolewrite("Ita a 9" & @CRLF) if (($lineData11="BBB") and ($lineData27="B222B")) then consolewrite("Ita a 1" & @CRLF) if (($lineData11="BBB BBB BBB") and ($lineData27="B222BB222BB222B")) then consolewrite("Ita a 8" & @CRLF) if (($lineData11="BBB BBB BBB") and ($lineData27="B222B B222B B222B")) then consolewrite("Ita a 0" & @CRLF) if (($lineData11="BBB BBB BBB") and ($lineData27="B222BB222B") and ($lineData41="BBB BBB BBB")) then consolewrite("Ita a 3" & @CRLF) if (($lineData11="BBB BBB BBB") and ($lineData27="B222BB222B") and ($lineData41="BBB BBB BBB BBB BBB")) then consolewrite("Ita a 2" & @CRLF) if (($lineData11="BBB BBB BBB BBB BBB") and ($lineData27="B222B") and ($lineData41="BBB")) then consolewrite("Ita a 7" & @CRLF) if (($lineData11="BBB BBB BBB BBB BBB") and ($lineData27="B222B") and ($lineData41="BBB BBB BBB")) then consolewrite("Ita a 5" & @CRLF) Next Next _GDIPlus_Shutdown() Func GetImage($BMPFile, byref $BMPDataStart, byref $Width, byRef $Height, byref $Stride, $imgBytes=3) local $Scan0, $pixelData, $hbScreen, $pBitmap, $pBitmapCap, $handle, $bitMapdata, $pixelFormat ; 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) ;~ $hBitmap = _GDIPlus_ImageLoadFromFile($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=1) then $BitmapData= _GDIPlus_BitmapLockBits($pBitmap, 0, 0, _GDIPlus_ImageGetWidth($pBitmap), _GDIPlus_ImageGetHeight($pBitmap), $GDIP_ILMREAD, $GDIP_PXF04INDEXED) Endif 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) EndIf if ($imgBytes=3) then $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 Edited January 23 by junkew ioa747, argumentum and KaFu 3 FAQ 31 How to click some elements, FAQ 40 Test automation with AutoIt, Multithreading CLR .NET Powershell CMDLets
Werty Posted January 23 Posted January 23 On 1/22/2025 at 3:14 AM, Hashim said: and can provide more examples if needed Some examples where the first digit is 1, preferable 10 images where all 0 through 9 is the first digit, now that they are cursive. The loop probably wont be as simple as in the old thread, but need the images to be sure. Hashim 1 Some guy's script + some other guy's script = my script!
Nine Posted January 23 Posted January 23 (edited) Here another way based on relative pixel location from the first (left/top most) pixel using my ScreenScraping UDF. Coordinates are screen absolute location. expandcollapse popup#include "C:\Apps\AutoIt\GetScreen\GetScreen.au3" #include <Color.au3> Local $hWnd = WinActivate("Microsoft Office Picture Manager") WinWaitActive($hWnd) Global Const $LINE = 423, $COLUMN = 550, $ENDX = 690, $ENDY = 465, $NDIGIT = 4 Global $aDigit = DefineNum() _GetScreen_Initialize($ENDX, $ENDY) Local $hTimer = TimerInit() _GetScreen_GetScreen() Local $iPos = $COLUMN, $vValue For $i = 1 To $NDIGIT $vValue &= GetDigit($iPos) $iPos = @extended Next ConsoleWrite($vValue & @CRLF) ConsoleWrite(TimerDiff($hTimer) & @CRLF) Func GetDigit($iStart) Local $aTmp For $i = $iStart To $ENDX If IsColor(_GetScreen_GetPixel($i, $LINE)) Then For $j = 0 To UBound($aDigit) - 1 $aTmp = $aDigit[$j][2] For $k = 0 To UBound($aTmp) - 1 If Not IsColor(_GetScreen_GetPixel($i + $aTmp[$k][0], $LINE + $aTmp[$k][1])) Then ContinueLoop 2 Next Return SetExtended($i + $aDigit[$j][1], $aDigit[$j][0]) Next ConsoleWrite("error" & @CRLF) Return SetError(1) EndIf Next EndFunc ;==>GetDigit Func DefineNum() Local $aNum[10][3] = [[0, 14, 0], [1, 4, 0], [2, 14, 0], [8, 14, 0], [3, 14, 0], [5, 24, 0], [7, 24, 0], [4, 4, 0], [9, 24, 0], [6, 10, 0]] Local $aTmp = [[13, 15], [-3, 20], [9, 10]] ; 0 $aNum[0][2] = $aTmp Local $aTmp = [[-1, 10], [-2, 15], [-9, 30]] ; 1 $aNum[1][2] = $aTmp Local $aTmp = [[-3, 20], [-9, 30], [11, 30]] ; 2 $aNum[2][2] = $aTmp Local $aTmp = [[-4, 10], [-8, 20], [-2, 15]] ; 8 $aNum[3][2] = $aTmp Local $aTmp = [[8, 15], [3, 15], [-6, 5], [11, 25]] ; 3 $aNum[4][2] = $aTmp Local $aTmp = [[20, 0], [4, 10], [9, 10]] ; 5 $aNum[5][2] = $aTmp Local $aTmp = [[20, 0], [19, 5], [2, 20]] ; 7 $aNum[6][2] = $aTmp Local $aTmp = [[2, 20], [-18, 20], [-4, 25]] ; 4 $aNum[7][2] = $aTmp Local $aTmp = [[-6, 10], [-2, 15], [6, 25]] ; 9 $aNum[8][2] = $aTmp Local $aTmp = [[-12, 15], [-14, 25], [6, 25]] ; 6 $aNum[9][2] = $aTmp Return $aNum EndFunc ;==>DefineNum Func IsColor($nColor) Return Not _ColorGetRed($nColor) And Not _ColorGetBlue($nColor) And _ColorGetGreen($nColor) > Dec("FA") EndFunc $LINE must be the first line (top most) where the bright green color appears $COLUMN can be located somewhere before $ENDX can be anywhere right after the 4 digits $ENDY can be anywhere below under the 4 digits Tested on your 4 pics and it is working fine (and quite fast under 40ms) Edited January 23 by Nine Hashim 1 “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Screen Scraping Multi-Threading Made Easy
junkew Posted January 23 Posted January 23 ChatGPT nows how to crunch this😀 Upload the pictures Question: In each picture there are 4 numbers can you recognize them? Answer: Here are the numbers I recognize from the images: Image 1 (pic1.png): The number is 2409. Image 2 (pic2.png): The number is 0257. Image 3 (pic3.png): The number is 8035. Image 4 (pic4.png): The number is 4691. FAQ 31 How to click some elements, FAQ 40 Test automation with AutoIt, Multithreading CLR .NET Powershell CMDLets
Hashim Posted Friday at 12:03 AM Author Posted Friday at 12:03 AM (edited) On 1/22/2025 at 8:18 PM, junkew said: Maybe this helps a little in understanding. Its just manipulation of pixels in a certan layout (PNG). Look at the output and zoom in/out, you can see almost the numbers yourself expandcollapse popup#Region includes Opt('MustDeclareVars', 1) ;#include <GUIConstants.au3> #include <GDIPlus.au3> #Include <ScreenCapture.au3> #include <string.au3> #include <WinAPI.au3> #include <WindowsConstants.au3> #EndRegion _GDIPlus_Startup() Dim $BitmapFilename Dim $BMPData="", $BMPWidth=0, $BMPHeight=0, $BMPLineWidth=0, $imgBytes=1 dim $binaryLine for $i=1 to 4 $BitmapFilename = @TempDir & "\" & "pic" & string($i) & ".png" $BMPData="" $BMPWidth=0 $BMPHeight=0 $BMPLineWidth=0 $imgBytes=1 consolewrite($bitmapFileName) ; Load the bitmap to find getImage($BitmapFilename, $BMPData, $BMPWidth, $BMPHeight, $BMPLineWidth, $imgBytes) ;~ See the height and width and dump the data on screen consolewrite($BMPHeight & " ; ") consolewrite($BMPWidth &@CRLF ) consolewrite("0 1 2 3 4 5 6 7 8 9 x x x x " & @CRLF) consolewrite("01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" & @CRLF) For $iLine = 11 To $BMPHeight-12 ;~ From the screenshots we can ignore the first 16 bytes (remember in text its 2 characters ;~ $binaryLine=BinaryMid($bmp1Data,($i*$BMP1LineWidth)+16,$BMP1LineWidth) ;~ and we only need 4 digits which takes about 28 characters and 1 character separator = $binaryLine=BinaryMid($bmpData,($iLine *$BMPLineWidth)+16,60) ;~ Lets make it readable $binaryLine=StringReplace($binaryLine,"0",".") consolewrite($iLine & " : " & $binaryLine & @CRLF) next ;~ lets recognise for $iNumber=1 to 4 consolewrite(@crlf) consolewrite("0 1 2 3 4 5 6 7 8 9 x x x x " & @CRLF) consolewrite("01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" & @CRLF) For $iLine = 11 To $BMPHeight-12 $binaryLine=BinaryMid($bmpData,($iLine *$BMPLineWidth)+16+(($iNumber-1)*15),14) $binaryLine=StringReplace($binaryLine,"0",".") consolewrite($iLine & " : " & $binaryLine & @CRLF) next Next Next _GDIPlus_Shutdown() Func GetImage($BMPFile, byref $BMPDataStart, byref $Width, byRef $Height, byref $Stride, $imgBytes=3) local $Scan0, $pixelData, $hbScreen, $pBitmap, $pBitmapCap, $handle, $bitMapdata, $pixelFormat ; 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) ;~ $hBitmap = _GDIPlus_ImageLoadFromFile($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=1) then $BitmapData= _GDIPlus_BitmapLockBits($pBitmap, 0, 0, _GDIPlus_ImageGetWidth($pBitmap), _GDIPlus_ImageGetHeight($pBitmap), $GDIP_ILMREAD, $GDIP_PXF04INDEXED) Endif 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) EndIf if ($imgBytes=3) then $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 I assume you refer to Yes, that's the original thread Thank you for your in-depth explanations, I sort of understand how this particular method of creating each bitmap and comparing them works, which how Werty's earlier script worked, but the part that's way over my head is the latest iteration of his script in my OP, which seems to use a different method entirely and do everything using `DllStructGetData()` and constants like 680 and 16 and 32. On 1/23/2025 at 10:16 PM, junkew said: ChatGPT nows how to crunch this😀 Upload the pictures Question: In each picture there are 4 numbers can you recognize them? Answer: Here are the numbers I recognize from the images: Image 1 (pic1.png): The number is 2409. Image 2 (pic2.png): The number is 0257. Image 3 (pic3.png): The number is 8035. Image 4 (pic4.png): The number is 4691. I think you might be misunderstanding, the images are just examples, I'm trying to do this using a tool that generates its result in a bitmap font. On 1/23/2025 at 3:35 AM, Werty said: Some examples where the first digit is 1, preferable 10 images where all 0 through 9 is the first digit, now that they are cursive. The loop probably wont be as simple as in the old thread, but need the images to be sure. Apologies for the late reply, but now done and uploaded, thank you! On 1/23/2025 at 5:55 PM, Nine said: Here another way based on relative pixel location from the first (left/top most) pixel using my ScreenScraping UDF. Coordinates are screen absolute location. expandcollapse popup#include "C:\Apps\AutoIt\GetScreen\GetScreen.au3" #include <Color.au3> Local $hWnd = WinActivate("Microsoft Office Picture Manager") WinWaitActive($hWnd) Global Const $LINE = 423, $COLUMN = 550, $ENDX = 690, $ENDY = 465, $NDIGIT = 4 Global $aDigit = DefineNum() _GetScreen_Initialize($ENDX, $ENDY) Local $hTimer = TimerInit() _GetScreen_GetScreen() Local $iPos = $COLUMN, $vValue For $i = 1 To $NDIGIT $vValue &= GetDigit($iPos) $iPos = @extended Next ConsoleWrite($vValue & @CRLF) ConsoleWrite(TimerDiff($hTimer) & @CRLF) Func GetDigit($iStart) Local $aTmp For $i = $iStart To $ENDX If IsColor(_GetScreen_GetPixel($i, $LINE)) Then For $j = 0 To UBound($aDigit) - 1 $aTmp = $aDigit[$j][2] For $k = 0 To UBound($aTmp) - 1 If Not IsColor(_GetScreen_GetPixel($i + $aTmp[$k][0], $LINE + $aTmp[$k][1])) Then ContinueLoop 2 Next Return SetExtended($i + $aDigit[$j][1], $aDigit[$j][0]) Next ConsoleWrite("error" & @CRLF) Return SetError(1) EndIf Next EndFunc ;==>GetDigit Func DefineNum() Local $aNum[10][3] = [[0, 14, 0], [1, 4, 0], [2, 14, 0], [8, 14, 0], [3, 14, 0], [5, 24, 0], [7, 24, 0], [4, 4, 0], [9, 24, 0], [6, 10, 0]] Local $aTmp = [[13, 15], [-3, 20], [9, 10]] ; 0 $aNum[0][2] = $aTmp Local $aTmp = [[-1, 10], [-2, 15], [-9, 30]] ; 1 $aNum[1][2] = $aTmp Local $aTmp = [[-3, 20], [-9, 30], [11, 30]] ; 2 $aNum[2][2] = $aTmp Local $aTmp = [[-4, 10], [-8, 20], [-2, 15]] ; 8 $aNum[3][2] = $aTmp Local $aTmp = [[8, 15], [3, 15], [-6, 5], [11, 25]] ; 3 $aNum[4][2] = $aTmp Local $aTmp = [[20, 0], [4, 10], [9, 10]] ; 5 $aNum[5][2] = $aTmp Local $aTmp = [[20, 0], [19, 5], [2, 20]] ; 7 $aNum[6][2] = $aTmp Local $aTmp = [[2, 20], [-18, 20], [-4, 25]] ; 4 $aNum[7][2] = $aTmp Local $aTmp = [[-6, 10], [-2, 15], [6, 25]] ; 9 $aNum[8][2] = $aTmp Local $aTmp = [[-12, 15], [-14, 25], [6, 25]] ; 6 $aNum[9][2] = $aTmp Return $aNum EndFunc ;==>DefineNum Func IsColor($nColor) Return Not _ColorGetRed($nColor) And Not _ColorGetBlue($nColor) And _ColorGetGreen($nColor) > Dec("FA") EndFunc $LINE must be the first line (top most) where the bright green color appears $COLUMN can be located somewhere before $ENDX can be anywhere right after the 4 digits $ENDY can be anywhere below under the 4 digits Tested on your 4 pics and it is working fine (and quite fast under 40ms) Thanks for the new solution, I had a go at implementing it but can't seem to get it recognising anything, possibly because I don't really understand `$line` and `$column` and how to get them. I'm using the Finder Tool to get mouse position of the topmost line of green pixels, but this gives an X and Y. If I use Y for `$line` (assuming it's a horizontal line), do I use x for `$column`? You said `$column` should be before `$line` but your `$column` value seems to be higher than your `$line` value. No matter what value I experiment with I always seem to get zeroes back: expandcollapse popup000000,0000,50.0049 elapsed 000001,0000,54.0431 elapsed 000002,0000,54.8198 elapsed 000003,0000,53.7282 elapsed 000004,0000,56.0365 elapsed 000005,0000,61.0202 elapsed 000006,0000,47.72 elapsed 000007,0000,55.0063 elapsed 000008,0000,53.913 elapsed 000009,0000,54.7191 elapsed 000010,0000,54.0476 elapsed 000011,0000,55.3895 elapsed 000012,0000,55.3364 elapsed 000013,0000,53.8888 elapsed 000014,0000,54.61 elapsed 000015,0000,57.5293 elapsed 000016,0000,52.4981 elapsed 000017,0000,54.5434 elapsed 000018,0000,54.3221 elapsed 000019,0000,55.6746 elapsed 000020,0000,55.1158 elapsed 000021,0000,52.4392 elapsed 000022,0000,73.5602 elapsed 000023,0000,56.2109 elapsed 000024,0000,49.5609 elapsed 000025,0000,56.3362 elapsed 000026,0000,53.4462 elapsed 000027,0000,55.8478 elapsed 000028,0000,53.6302 elapsed 000029,0000,63.1837 elapsed 000030,0000,53.3006 elapsed 000031,0000,59.3485 elapsed 000032,0000,48.4816 elapsed 000033,0000,53.8227 elapsed 000034,0000,54.4319 elapsed 000035,0000,50.9141 elapsed 000036,0000,55.2572 elapsed 000037,0000,53.6521 elapsed 000038,0000,53.3899 elapsed 000039,0000,63.4227 elapsed 000040,0000,48.0815 elapsed 000041,0000,52.6406 elapsed 000042,0000,56.4394 elapsed 000043,0000,54.0514 elapsed 000044,0000,53.8471 elapsed 000045,0000,64.8552 elapsed 000046,0000,63.9074 elapsed 000047,0000,52.5829 elapsed 000048,0000,54.945 elapsed 000049,0000,54.3817 elapsed 000050,0000,55.7925 elapsed examples.zip Edited Friday at 12:07 AM by Hashim
Nine Posted Friday at 12:42 AM Posted Friday at 12:42 AM (edited) I get perfect match with the new files you gave us. The problem you have to solve is "where those images are located in your real world". You need to help yourself. Ok maybe my explaination was not good enough : $LINE must be the first line (top most) where the bright green color appears (the Y value) $COLUMN can be located somewhere before the digits (the X value) $ENDX can be anywhere right after the 4 digits (...) $ENDY can be anywhere below under the 4 digits (...) ps. only important value is $LINE, rest does not need to be precise : $COLUMN can be 0, $ENDX can be @DESKTOPwIDTH, $ENDY can be @desktopHEIGHT Here a picture of the pixel you want : $LINE is the Y and $COLUMN is the X (in absolute screen coordinates) Edited Friday at 01:59 PM by Nine “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Screen Scraping Multi-Threading Made Easy
argumentum Posted Friday at 03:24 AM Posted Friday at 03:24 AM 3 hours ago, Hashim said: ...but can't seem to get... I butcher the heck out of it Spoiler expandcollapse popup#Region includes Opt('MustDeclareVars', 1) ;#include <GUIConstants.au3> #include <GDIPlus.au3> #include <ScreenCapture.au3> #include <string.au3> #include <WinAPI.au3> #include <WindowsConstants.au3> #EndRegion includes _GDIPlus_Startup() ;;; https://www.autoitscript.com/forum/topic/212651-another-bitmap-brute-forcing-thread/#findComment-1540438 Global $hTimer = TimerInit() Dim $BitmapFilename Dim $BMPData = "", $BMPWidth = 0, $BMPHeight = 0, $BMPLineWidth = 0, $imgBytes = 2 Dim $binaryLine, $startColumn Dim $lineData11, $lineData27, $lineData41, $NumberWidth = 15, $NumberCount = 4 ; added by argumentum ;~ for each picture file For $i = 0 To 9 ;~ $BitmapFilename = @TempDir & "\" & "pic" & String($i) & ".png" $BitmapFilename = @ScriptDir & "\" & String($i) & ".png" $BMPData = "" $BMPWidth = 0 $BMPHeight = 0 $BMPLineWidth = 0 $imgBytes = 1 ConsoleWrite(@CRLF & $BitmapFilename & @TAB) ; Load the bitmap to find GetImage($BitmapFilename, $BMPData, $BMPWidth, $BMPHeight, $BMPLineWidth, $imgBytes) ;~ See the height and width and dump the data on screen ;~ ConsoleWrite($BMPHeight & " ; " & $BMPWidth & @CRLF) ;~ ConsoleWrite(" 0 1 2 3 4 5 6 7 8 9 x x x x " & @CRLF) ;~ ConsoleWrite(" 01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" & @CRLF) ;~ For $iLine = 11 To $BMPHeight - 12 For $iLine = 0 To $BMPHeight - $NumberWidth ;~ From the screenshots we can ignore the first 16 bytes (remember in text its 2 characters ;~ $binaryLine=BinaryMid($bmp1Data,($i*$BMP1LineWidth)+16,$BMP1LineWidth) ;~ and we only need 4 digits which takes about 28 characters and 1 character separator = $binaryLine = BinaryMid($BMPData, ($iLine * $BMPLineWidth) + $NumberWidth, $NumberWidth * $NumberCount) ;~ $binaryLine=$bmpData ;~ Lets make it readable $binaryLine = StringReplace($binaryLine, "0", ".") ;~ ConsoleWrite($iLine & " : " & $binaryLine & @CRLF) Next ;~ lets recognise For $iNumber = 1 To $NumberCount ;~ ConsoleWrite(@CRLF) ;~ ConsoleWrite("0 - 1 2 3 4 5 6 7 8 9 x x x x " & @CRLF) ;~ ConsoleWrite("01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" & @CRLF) ;~ Its hard to determine the column for each digit in a formula ;~ If $iNumber = 1 Then $startColumn = 16 ;~ If $iNumber = 2 Then $startColumn = 30 ;~ If $iNumber = 3 Then $startColumn = 45 ;~ If $iNumber = 4 Then $startColumn = 59 $startColumn = $NumberWidth * $iNumber ;~ Only a few lines in the png are of interest ;~ For $iLine = 11 To $BMPHeight - 12 ;~ ;~ $binaryLine=BinaryMid($bmpData,($iLine *$BMPLineWidth)+16+(($iNumber-1)*14),15) ;~ $binaryLine = BinaryMid($BMPData, ($iLine * $BMPLineWidth) + $startColumn, 15) ;~ $binaryLine = StringReplace($binaryLine, "0", " ") ;~ ConsoleWrite($iLine & " : " & $binaryLine & @CRLF) ;~ Next ;~ if on line 11 at position 28 I have a B it can be a 4 ;~ It seems to be easier to revert back to a string when we have the data $lineData11 = StringStripWS(StringRegExpReplace(BinaryMid($BMPData, (11 * $BMPLineWidth) + $startColumn, $NumberWidth), "[x0]", " "), 3) $lineData27 = StringStripWS(StringRegExpReplace(BinaryMid($BMPData, (27 * $BMPLineWidth) + $startColumn, $NumberWidth), "[x0]", " "), 3) $lineData41 = StringStripWS(StringRegExpReplace(BinaryMid($BMPData, (41 * $BMPLineWidth) + $startColumn, $NumberWidth), "[x0]", " "), 3) ;~ ConsoleWrite(String($lineData11) & " - ") ;~ ConsoleWrite(String($lineData27) & " - ") ;~ ConsoleWrite(String($lineData41) & @CRLF) ;~ And here determine the magic lines If (($lineData11 = "BBB") And ($lineData27 = "B222B B222B")) Then ConsoleWrite("4") If (($lineData11 = "BBB BBB") And ($lineData27 = "B222BB222BB222BB222B")) Then ConsoleWrite("6") If (($lineData11 = "BBB BBB BBB") And ($lineData27 = "B222BB222BB222BB222B")) Then ConsoleWrite("9") If (($lineData11 = "BBB") And ($lineData27 = "B222B")) Then ConsoleWrite("1") If (($lineData11 = "BBB BBB BBB") And ($lineData27 = "B222BB222BB222B")) Then ConsoleWrite("8") If (($lineData11 = "BBB BBB BBB") And ($lineData27 = "B222B B222B B222B")) Then ConsoleWrite("0") If (($lineData11 = "BBB BBB BBB") And ($lineData27 = "B222BB222B") And ($lineData41 = "BBB BBB BBB")) Then ConsoleWrite("3") If (($lineData11 = "BBB BBB BBB") And ($lineData27 = "B222BB222B") And ($lineData41 = "BBB BBB BBB BBB BBB")) Then ConsoleWrite("2") If (($lineData11 = "BBB BBB BBB BBB BBB") And ($lineData27 = "B222B") And ($lineData41 = "BBB")) Then ConsoleWrite("7") If (($lineData11 = "BBB BBB BBB BBB BBB") And ($lineData27 = "B222B") And ($lineData41 = "BBB BBB BBB")) Then ConsoleWrite("5") Next ;~ ConsoleWrite(@CRLF) Next ConsoleWrite(@CRLF & "TimerDiff: " & TimerDiff($hTimer) & @CRLF) _GDIPlus_Shutdown() Func GetImage($BMPFile, ByRef $BMPDataStart, ByRef $Width, ByRef $Height, ByRef $Stride, $imgBytes = 3) Local $Scan0, $pixelData, $hbScreen, $pBitmap, $pBitmapCap, $handle, $bitMapdata, $pixelFormat ; 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) ;~ $hBitmap = _GDIPlus_ImageLoadFromFile($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 = 1) Then $BitmapData = _GDIPlus_BitmapLockBits($pBitmap, 0, 0, _GDIPlus_ImageGetWidth($pBitmap), _GDIPlus_ImageGetHeight($pBitmap), $GDIP_ILMREAD, $GDIP_PXF04INDEXED) EndIf 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) EndIf If ($imgBytes = 3) Then $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 and I hope that by doing so, it makes more sense. Maybe. Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting.
Werty Posted Friday at 05:16 PM Posted Friday at 05:16 PM 17 hours ago, Hashim said: done and uploaded Well, appears it would be as simple a loop as the first one... Func Getnumber($result) Local $code[4] = [0,0,0,0], $value = 64, $pixels = DllStructCreate('dword[2816]') DllCall('gdi32.dll', 'dword', 'GetBitmapBits', 'ptr', $capture, 'dword', DllStructGetSize($pixels), 'ptr', DllStructGetPtr($pixels)) For $loop = 1 To 2816 Step 440 $code[0] += DllStructGetData($pixels, 1, $loop ) > 4278190080 ? $value:0 $code[1] += DllStructGetData($pixels, 1, $loop+29) > 4278190080 ? $value:0 $code[2] += DllStructGetData($pixels, 1, $loop+58) > 4278190080 ? $value:0 $code[3] += DllStructGetData($pixels, 1, $loop+87) > 4278190080 ? $value:0 $value /= 2 Next Return String($digit[$code[0]]) & String($digit[$code[1]]) & String($digit[$code[2]]) & String($digit[$code[3]]) EndFunc Runable example (requires the images from above)... expandcollapse popup#include <GDIPlus.au3> #include <WinAPI.au3> HotKeySet("{ESC}", "_exit") ;Be sure $posx and $posy is pointing at the correct spot! Global $posx = 1715, $posy = 705, $result = "", $code[4], $capture ;Lookup table to avoid searching Global $digit[115] = [1,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0, _ 0,0,0,0,0,0,0,0,0,0,6,0,0,0,3,2,0,0,0,0, _ 0,0,0,0,0,0,0,0,9,0,0,0,0,0,8,0,0,0,0,0, _ 0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, _ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, _ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,5] ;Test section ;-------------------------------------------------------------- $gui = GUICreate("Getnumber", 640, 480, -1, -1) GUISetState() WinWaitActive($gui); <--- necessary or screencapture fails _GDIPlus_Startup() $graphics = _GDIPlus_GraphicsCreateFromHWND($gui) $image = _GDIPlus_BitmapCreateFromFile("9.png") _GDIPlus_GraphicsDrawImageRect($graphics, $image, 280, 200, 176, 56) Sleep(10); <------- necessary because drawimagerect() is too slow, script occasionally fails without ;-------------------------------------------------------------- ;/Test section $hDDC = _WinAPI_GetDC(0) $hCDC = _WinAPI_CreateCompatibleDC($hDDC) $capture = _WinAPI_CreateCompatibleBitmap($hDDC, 88, 32) _WinAPI_SelectObject($hCDC, $capture) _WinAPI_BitBlt($hCDC, 0, 0, 88, 32, $hDDC, $posx, $posy, 0x00CC0020) _WinAPI_DeleteDC($hCDC) $result = Getnumber($result) Consolewrite("Result: " & $result & @crlf) While 1 Sleep(10) WEnd Func Getnumber($result) Local $code[4] = [0,0,0,0], $value = 64, $pixels = DllStructCreate('dword[2816]') DllCall('gdi32.dll', 'dword', 'GetBitmapBits', 'ptr', $capture, 'dword', DllStructGetSize($pixels), 'ptr', DllStructGetPtr($pixels)) For $loop = 1 To 2816 Step 440 $code[0] += DllStructGetData($pixels, 1, $loop ) > 4278190080 ? $value:0 $code[1] += DllStructGetData($pixels, 1, $loop+29) > 4278190080 ? $value:0 $code[2] += DllStructGetData($pixels, 1, $loop+58) > 4278190080 ? $value:0 $code[3] += DllStructGetData($pixels, 1, $loop+87) > 4278190080 ? $value:0 $value /= 2 Next Return String($digit[$code[0]]) & String($digit[$code[1]]) & String($digit[$code[2]]) & String($digit[$code[3]]) EndFunc Func _exit() _GDIPlus_Shutdown() Exit EndFunc And as in the previous thread and as Nine posted above, the $Posx and $Posy must point at the correct spot, which in this case is here (red spot)... Some guy's script + some other guy's script = my script!
junkew Posted 10 hours ago Posted 10 hours ago (edited) Quote If I understood how it worked I'd do it myself @Hashim Some try to give you more understanding ChatGpt was not a misunderstanding just a different approach: https://dorik.com/blog/how-to-use-chatgpt-api but lets assume nobody has done this from AutoIt. There are different approaches to "read" from a screen Have access to the sourcecode or internals of the program (probably Delphi) and based on that you can define your strategy Intercept Win32 API calls like drawtext (win 32 hooks) Check the default functions like ControlGetText see Faq 31,34,40 and helpfile. Take the more difficult route pixelmanipulation (with GDI32 functions) @Nine has made a nice library for that which he used on above answer Use OCR and AI tools like ChatGPT API: https://dorik.com/blog/how-to-use-chatgpt-api ..... Looking at the thread(s) and screenshots approach 4 looks the most realistic one 😉 The theory around this you can learn here (and google offcourse) bitblt: https://en.wikipedia.org/wiki/Bit_blit bitmap: https://en.wikipedia.org/wiki/Bitmap You should start with: https://www.autoitscript.com/autoit3/docs/functions/PixelGetColor.htm https://www.autoitscript.com/autoit3/docs/functions/PixelChecksum.htm your constants misunderstanding Quote constants like 680 and 16 and 32 That was for a 3 digit approach to identify the matrix where your digits are. You shared pictures of 176 width and 56 height and we have to guess where they are on the screen. How did you make the screenshots of the numbers? by hand? automated? In your previous thread with 3 digits it was TTabsheet1 Share a full screenshot of the application that can help Share information when you hover over the application with au3inf or other spy tools. Based on what you shared before it looks like a delphi application The matrix The bitblt function takes an x,y and height, width to create a matrix of pixels. Based on that height and width you get the magic constants like 680. We can only assume with 4 digits of 176 width and 56 height that 4*176=704 width in pixels total matrix and if a pixel takes 2 bytes you come to 1 line of 2816. Then this can be hard to read but basically says look at the (First) line 7 times and do a calculation For $loop = 1 To 2816 Step 440 $code[0] += DllStructGetData($pixels, 1, $loop ) > 4278190080 ? $value:0 $code[1] += DllStructGetData($pixels, 1, $loop+29) > 4278190080 ? $value:0 $code[2] += DllStructGetData($pixels, 1, $loop+58) > 4278190080 ? $value:0 $code[3] += DllStructGetData($pixels, 1, $loop+87) > 4278190080 ? $value:0 $value /= 2 Next So look at these pixels (the algorithm that was determined to be enough to discriminate numbers from each other): [1 30 59 88], [441 470 499 528],[881 910 939 968],[1321 1350 1379 1408],[1761 1790 1819 1848],[2201 2230 2259 2288],[2641 2670 2699 2728] 1 pixel can be described in multiple bits (black/white/monochrome, grey, colour, 16 bits color, 24 bits color, ....) so far we take the approach 16 bits per pixelcolor. The algorithm Maybe this helps from long ago when I started to learn bitblt and pixelmanipulation. If you merge all 10 numbers in this thread you will know which (minimum number of) pixels you need to check to discriminate 0-9 and the other examples given above are alternative algorithms. Edited 10 hours ago by junkew FAQ 31 How to click some elements, FAQ 40 Test automation with AutoIt, Multithreading CLR .NET Powershell CMDLets
Nine Posted 7 hours ago Posted 7 hours ago (edited) Here a more comprehensive version of the script I made above. I may add the following as an additional example of my UDF. With this new version, you do not have to find the top line of the bright-green color, it will do it for you. You just need to provide the top, left, right, bottom of the whole black square, along with the number of digits to read. (in absolute screen coordinates) expandcollapse popup#include "C:\Apps\AutoIt\GetScreen\GetScreen.au3" #include <Color.au3> Opt("MustDeclareVars", True) Local $hWnd = WinActivate("Microsoft Office Picture Manager") WinWaitActive($hWnd) Global $aDigit = DefineNum() _GetScreen_Initialize(@DesktopWidth, @DesktopHeight) For $i = 1 To 10 ; number of pictures I test ReadNumber(535, 397, 710, 451, 4) ; top-left of the square .. bottom-right of the square .. Number of digits to read Send("{RIGHT}") ; move to the next picture Sleep(500) Next Func ReadNumber($iLeft, $iTop, $iRight, $iBottom, $iNumDigit) Local $hTimer = TimerInit() _GetScreen_GetScreen() ; Static will execute this only once, since top bright-green pixel is always located on the same top Y Local Static $iPosY = SearchColor($iLeft, $iTop, $iRight, $iBottom) Local $iPosX = $iLeft, $sValue For $i = 1 To $iNumDigit $sValue &= GetDigit($iPosX, $iPosY, $iRight) $iPosX = @extended Next ConsoleWrite($sValue & @CRLF) ConsoleWrite(TimerDiff($hTimer) & @CRLF) Return Int($sValue) ; in case you want to return the integer read EndFunc ;==>ReadNumber Func GetDigit($iStart, $iTop, $iEndX) For $i = $iStart To $iEndX If IsColor(_GetScreen_GetPixel($i, $iTop)) Then For $j = 0 To UBound($aDigit) - 1 For $k = 0 To UBound($aDigit[$j][2]) - 1 If Not IsColor(_GetScreen_GetPixel($i + ($aDigit[$j][2])[$k][0], $iTop + ($aDigit[$j][2])[$k][1])) Then ContinueLoop 2 Next Return SetExtended($i + $aDigit[$j][1], $aDigit[$j][0]) Next Return SetError(1) ; no digit found EndIf Next Return SetError(2) ; no green bright color found EndFunc ;==>GetDigit Func DefineNum() Local $aNum[10][3] = [[0, 14, 0], [1, 4, 0], [2, 14, 0], [8, 14, 0], [3, 14, 0], [5, 24, 0], [7, 24, 0], [4, 4, 0], [9, 24, 0], [6, 10, 0]] Local $aTmp = [[13, 15], [-3, 20], [9, 10]] ; 0 $aNum[0][2] = $aTmp Local $aTmp = [[-1, 10], [-2, 15], [-9, 30]] ; 1 $aNum[1][2] = $aTmp Local $aTmp = [[-3, 20], [-9, 30], [11, 30]] ; 2 $aNum[2][2] = $aTmp Local $aTmp = [[-4, 10], [-8, 20], [-2, 15]] ; 8 $aNum[3][2] = $aTmp Local $aTmp = [[8, 15], [3, 15], [-6, 5], [11, 25]] ; 3 $aNum[4][2] = $aTmp Local $aTmp = [[20, 0], [4, 10], [9, 10]] ; 5 $aNum[5][2] = $aTmp Local $aTmp = [[20, 0], [19, 5], [2, 20]] ; 7 $aNum[6][2] = $aTmp Local $aTmp = [[2, 20], [-18, 20], [-4, 25]] ; 4 $aNum[7][2] = $aTmp Local $aTmp = [[-6, 10], [-2, 15], [6, 25]] ; 9 $aNum[8][2] = $aTmp Local $aTmp = [[-12, 15], [-14, 25], [6, 25]] ; 6 $aNum[9][2] = $aTmp Return $aNum EndFunc ;==>DefineNum Func IsColor($nColor) Return Not _ColorGetRed($nColor) And Not _ColorGetBlue($nColor) And _ColorGetGreen($nColor) > Dec("FA") EndFunc ;==>IsColor Func SearchColor($iX1, $iY1, $iX2, $iY2) Local $nColor, $iMin = 99999, $aPos For $i = 251 To 255 $nColor = Dec(Hex($i) & "00") $aPos = _GetScreen_SearchArea($iX1, $iY1, $iX2, $iY2, $nColor) If @error Then ContinueLoop If $aPos[1] < $iMin Then $iMin = $aPos[1] Next If $iMin = 99999 Then Return SetError(1) Return $iMin EndFunc ;==>SearchColor It now reads many pictures one at a time. All results match. Edited 7 hours ago by Nine “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Screen Scraping Multi-Threading Made Easy
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