I have a paint application where I can enter into a console a hex code to change the color. I'm trying to make it so that I can load an image and the bot will examine the pixels, create a unique array of all colors. Afterwards, loop over the image looking for each color and then paint the pixel in every location that the image has a pixel of that color.
What I've written will process the image and get the colors. Then, when looping over the unique color array, it will change the color using the console but often times doesn't paint any pixels. This behavior doesn't make since because it got the colors from the image originally. Therefore, it should be painting at least 1 pixel per color found...
Also, it occasionally switches/pulls a random screen from the background forwards and messes up even more.
Basically:
Shift + Alt + S sets the mouse offset for where the image should be drawn.
Shift + Alt + C sets the location to click within the console window
Alt + S pauses the painting loop
Here is the code:
Any idea what's goin' on and how I can fix it?
Thanks
What I've written will process the image and get the colors. Then, when looping over the unique color array, it will change the color using the console but often times doesn't paint any pixels. This behavior doesn't make since because it got the colors from the image originally. Therefore, it should be painting at least 1 pixel per color found...
Also, it occasionally switches/pulls a random screen from the background forwards and messes up even more.
Basically:
Shift + Alt + S sets the mouse offset for where the image should be drawn.
Shift + Alt + C sets the location to click within the console window
Alt + S pauses the painting loop
Here is the code:
[ autoit ]
;image control from memory coded by UEZ 2011 #include <GUIConstantsEx.au3> #include <GDIPlus.au3> #include <Array.au3> #Include <memory.au3> HotKeySet("!s", "ToggleRunning") HotKeySet("+!s", "SetOffset") HotKeySet("+!c", "SetConsoleBox") _GDIPlus_Startup() Global Const $IMAGE_BITMAP = 0 Global Const $STM_SETIMAGE = 0x0172 Global $msg Global Const $hBmp = Load_BMP_From_Mem(InetRead("https://www.google.com/images/srpr/logo3w.png"), True) ;to load an image from the net Global Const $hBitmap = _GDIPlus_BitmapCreateFromHBITMAP($hBmp) Global Const $iWidth = _GDIPlus_ImageGetWidth($hBitmap) Global Const $iHeight = _GDIPlus_ImageGetHeight($hBitmap) Global Const $hGUI = GUICreate("Display PNG Image in picture control", $iWidth, $iHeight) Global Const $idPic = GUICtrlCreatePic("", 0, 0, $iWidth, $iHeight) _WinAPI_DeleteObject(GUICtrlSendMsg($idPic, $STM_SETIMAGE, $IMAGE_BITMAP, $hBmp)) GUISetState() Global $running = False Global $currX = 0 Global $currY = 0 Global $offset = 0 Global $consoleBox = 0 Global $colorArray[1] ; Color to skip, normally a background color ; you wish to be transparent $colorArray[0] = "#gggggg" ; Process the image For $row = 0 to $iHeight ConsoleWrite("Processing image... Row: " & $row & "/" & $iHeight & @LF) For $col = 0 to $iWidth $color = _GDIPlus_BitmapGetPixel($hBitmap, $row, $col) Local $iIndex = _ArraySearch($colorArray, $color, 0, 0, 0, 1) If @error Then _ArrayAdd( $colorArray, $color ) EndIf Next Next ConsoleWrite("Processing complete... Found " & UBound( $colorArray ) & " colors" & @LF) ; Main loop While True $msg = GUIGetMsg() Switch $msg Case $idPic MsgBox(0, "Information", "PNG image was clicked") Case $GUI_EVENT_CLOSE _WinAPI_DeleteObject($hBmp) _GDIPlus_BitmapDispose($hBitmap) _GDIPlus_Shutdown() GUIDelete($hGUI) Exit EndSwitch ; Drawing loop If Not ($offset == 0) And Not ($consoleBox == 0) And $running Then For $i = 1 to UBound( $colorArray ) - 1 MouseClick ( "left", $consoleBox[0], $consoleBox[1] ) Send("{#}" & $colorArray[ $i ]) Send("{Enter}") For $col = $currY to $iHeight For $row = $currX to $iWidth $color = _GDIPlus_BitmapGetPixel($hBitmap, $row, $col) If $colorArray[ $i ] = $color Then ConsoleWrite($colorArray[ $i ] & " :: " & $color & @LF) MouseClick ( "left", $offset[0] + $currX, $offset[1] + $currY ) Sleep ( 100 ) EndIf $currX += 1 Next $currY += 1 Next $currX = 0 $currY = 0 Sleep ( 3000 ) Next EndIf WEnd Func SetOffset() $offset = MouseGetPos(); EndFunc Func SetConsoleBox() $consoleBox = MouseGetPos(); EndFunc Func ToggleRunning() $running = Not $running; While Not ($running) Sleep( 1000 ) WEnd EndFunc ;====================================================================================== ; Function Name: Load_BMP_From_Mem ; Description: Loads an image which is saved as a binary string and converts it to a bitmap or hbitmap ; ; Parameters: $bImage: the binary string which contains any valid image which is supported by GDI+ ; Optional: $hHBITMAP: if false a bitmap will be created, if true a hbitmap will be created ; ; Remark: hbitmap format is used generally for GUI internal images, $bitmap is more a GDI+ image format ; Don't forget _GDIPlus_Startup() and _GDIPlus_Shutdown() ; ; Requirement(s): GDIPlus.au3, Memory.au3 and _GDIPlus_BitmapCreateDIBFromBitmap() from WinAPIEx.au3 ; Return Value(s): Success: handle to bitmap (GDI+ bitmap format) or hbitmap (WinAPI bitmap format), ; Error: 0 ; Error codes: 1: $bImage is not a binary string ; 2: unable to create stream on HGlobal ; 3: unable to create bitmap from stream ; ; Author(s): UEZ ; Additional Code: thanks to progandy for the MemGlobalAlloc and tVARIANT lines and ; Yashied for _GDIPlus_BitmapCreateDIBFromBitmap() from WinAPIEx.au3 ; Version: v0.97 Build 2012-04-10 Beta ;======================================================================================= Func Load_BMP_From_Mem($bImage, $hHBITMAP = False) If Not IsBinary($bImage) Then Return SetError(1, 0, 0) Local $aResult Local Const $memBitmap = Binary($bImage) ;load image saved in variable (memory) and convert it to binary Local Const $len = BinaryLen($memBitmap) ;get length of image Local Const $hData = _MemGlobalAlloc($len, $GMEM_MOVEABLE) ;allocates movable memory ($GMEM_MOVEABLE = 0x0002) Local Const $pData = _MemGlobalLock($hData) ;translate the handle into a pointer Local $tMem = DllStructCreate("byte[" & $len & "]", $pData) ;create struct DllStructSetData($tMem, 1, $memBitmap) ;fill struct with image data _MemGlobalUnlock($hData) ;decrements the lock count associated with a memory object that was allocated with GMEM_MOVEABLE $aResult = DllCall("ole32.dll", "int", "CreateStreamOnHGlobal", "handle", $pData, "int", True, "ptr*", 0) ;Creates a stream object that uses an HGLOBAL memory handle to store the stream contents If @error Then Return SetError(2, 0, 0) Local Const $hStream = $aResult[3] $aResult = DllCall($ghGDIPDll, "uint", "GdipCreateBitmapFromStream", "ptr", $hStream, "int*", 0) ;Creates a Bitmap object based on an IStream COM interface If @error Then Return SetError(3, 0, 0) Local Const $hBitmap = $aResult[2] Local $tVARIANT = DllStructCreate("word vt;word r1;word r2;word r3;ptr data; ptr") DllCall("oleaut32.dll", "long", "DispCallFunc", "ptr", $hStream, "dword", 8 + 8 * @AutoItX64, _ "dword", 4, "dword", 23, "dword", 0, "ptr", 0, "ptr", 0, "ptr", DllStructGetPtr($tVARIANT)) ;release memory from $hStream to avoid memory leak $tMem = 0 $tVARIANT = 0 If $hHBITMAP Then Local Const $hHBmp = _GDIPlus_BitmapCreateDIBFromBitmap($hBitmap) _GDIPlus_BitmapDispose($hBitmap) Return $hHBmp EndIf Return $hBitmap EndFunc ;==>Load_BMP_From_Mem Func _GDIPlus_BitmapCreateDIBFromBitmap($hBitmap) Local $tBIHDR, $Ret, $tData, $pBits, $hResult = 0 $Ret = DllCall($ghGDIPDll, 'uint', 'GdipGetImageDimension', 'ptr', $hBitmap, 'float*', 0, 'float*', 0) If (@error) Or ($Ret[0]) Then Return 0 $tData = _GDIPlus_BitmapLockBits($hBitmap, 0, 0, $Ret[2], $Ret[3], $GDIP_ILMREAD, $GDIP_PXF32ARGB) $pBits = DllStructGetData($tData, 'Scan0') If Not $pBits Then Return 0 $tBIHDR = DllStructCreate('dword;long;long;ushort;ushort;dword;dword;long;long;dword;dword') DllStructSetData($tBIHDR, 1, DllStructGetSize($tBIHDR)) DllStructSetData($tBIHDR, 2, $Ret[2]) DllStructSetData($tBIHDR, 3, $Ret[3]) DllStructSetData($tBIHDR, 4, 1) DllStructSetData($tBIHDR, 5, 32) DllStructSetData($tBIHDR, 6, 0) $hResult = DllCall('gdi32.dll', 'ptr', 'CreateDIBSection', 'hwnd', 0, 'ptr', DllStructGetPtr($tBIHDR), 'uint', 0, 'ptr*', 0, 'ptr', 0, 'dword', 0) If (Not @error) And ($hResult[0]) Then DllCall('gdi32.dll', 'dword', 'SetBitmapBits', 'ptr', $hResult[0], 'dword', $Ret[2] * $Ret[3] * 4, 'ptr', DllStructGetData($tData, 'Scan0')) $hResult = $hResult[0] Else $hResult = 0 EndIf _GDIPlus_BitmapUnlockBits($hBitmap, $tData) Return $hResult EndFunc ;==>_GDIPlus_BitmapCreateDIBFromBitmap ;The GetPixel method gets the color of a specified pixel in this bitmap. ;GdipBitmapGetPixel(GpBitmap* bitmap, INT x, INT y, ARGB *color) ; Func _GDIPlus_BitmapGetPixel($hBitmap, $iX, $iY) Local $tArgb, $pArgb, $aRet $tArgb = DllStructCreate("dword Argb") $pArgb = DllStructGetPtr($tArgb) $aRet = DllCall($ghGDIPDll, "int", "GdipBitmapGetPixel", "hwnd", $hBitmap, "int", $iX, "int", $iY, "ptr", $pArgb) Return "#" & Hex(DllStructGetData($tArgb, "Argb"), 6) EndFunc
Any idea what's goin' on and how I can fix it?
Thanks