the latest TH is disable the screen capture where ahk use the same/similar api for imagesearch function.
my own wriiten lod mages and vyr wizard ahk script which use imagesearch to capture skill cooldown status
the latest TH is disable the screen capture where ahk use the same/similar api for imagesearch function.
my own wriiten lod mages and vyr wizard ahk script which use imagesearch to capture skill cooldown status
Code or link?
solved.........using gdi+ to read d3 screen
I'd like to continue your discussion from here:
https://www.ownedcore.com/forums/dia...ml#post4071403 (Permanent closure of the plugin API and the removal of China/Asia realm support)
In exchange for some help with an image based rotation such as you are using.
What I found was that Gdip_BitmapFromHWND forces you to capture the whole window simply because that is what they programmed it to do. Comparing the code with Gdip_BitmapFromScreen showed it was nearly the same except they left out all x|y|w|h stuff.
Another oddity is there are multiple Gdip_All.ahk versions from different maintainers. The one that seemed to be the most up to date is GitHub - marius-sucan/AHK-GDIp-Library-Compilation: Gdip_All library mega-compilation of user contributions, compatible with AHK v1.1 and AHK v2 which is missing Gdip_ImageSearch for some reason. I just used a standalone version of that.
The original Gdip_BitmapFromHWND looks like this:
I simply changed it to this:Code:;##################################################################################### ; Function Gdip_BitmapFromHWND ; Description Uses PrintWindow to get a handle to the specified window and return a bitmap from it ; ; hwnd handle to the window to get a bitmap from ; return If the function succeeds, the return value is a pointer to a gdi+ bitmap ; ; notes Window must not be not minimised in order to get a handle to it's client area Gdip_BitmapFromHWND(hwnd) { Ptr := A_PtrSize ? "UPtr" : "UInt" GetWindowRect(hwnd, Width, Height) hbm := CreateDIBSection(Width, Height), hdc := CreateCompatibleDC(), obm := SelectObject(hdc, hbm) PrintWindow(hwnd, hdc) pBitmap := Gdip_CreateBitmapFromHBITMAP(hbm) SelectObject(hdc, obm), DeleteObject(hbm), DeleteDC(hdc) return pBitmap } ;#####################################################################################
I then adapted the screenshot ahk from the other thread to use the new method and was able to clip the entire skill bar instead of the whole screen:Code:;##################################################################################### ; Function Gdip_BitmapFromHWND ; Description Uses PrintWindow to get a handle to the specified window and return a bitmap from it ; ; hwnd handle to the window to get a bitmap from ; Screen 0 = All screens ; Any numerical value = Just that screen ; x|y|w|h = Take specific coordinates with a width and height ; Raster raster operation code ; ; return If the function succeeds, the return value is a pointer to a gdi+ bitmap ; -1: one or more of x,y,w,h parameters were not passed properly ; ; return If the function succeeds, the return value is a pointer to a gdi+ bitmap ; ; notes Window must not be not minimised in order to get a handle to it's client area Gdip_BitmapFromHWND(hwnd, Screen:=0, Raster:="") { hhdc := 0 Ptr := A_PtrSize ? "UPtr" : "UInt" if (Screen = 0) { _x := DllCall("GetSystemMetrics", "Int", 76 ) _y := DllCall("GetSystemMetrics", "Int", 77 ) _w := DllCall("GetSystemMetrics", "Int", 78 ) _h := DllCall("GetSystemMetrics", "Int", 79 ) } else if (SubStr(Screen, 1, 5) = "hwnd:") { Screen := SubStr(Screen, 6) if !WinExist("ahk_id " Screen) return -2 GetWindowRect(Screen, _w, _h) _x := _y := 0 hhdc := GetDCEx(Screen, 3) } else if IsInteger(Screen) { M := GetMonitorInfo(Screen) _x := M.Left, _y := M.Top, _w := M.Right-M.Left, _h := M.Bottom-M.Top } else { S := StrSplit(Screen, "|") _x := S[1], _y := S[2], _w := S[3], _h := S[4] } if (_x = "") || (_y = "") || (_w = "") || (_h = "") return -1 chdc := CreateCompatibleDC(), hbm := CreateDIBSection(_w, _h, chdc) obm := SelectObject(chdc, hbm), hhdc := hhdc ? hhdc : GetDC() BitBlt(chdc, 0, 0, _w, _h, hhdc, _x, _y, Raster) ReleaseDC(hhdc) pBitmap := Gdip_CreateBitmapFromHBITMAP(hbm) SelectObject(chdc, obm), DeleteObject(hbm), DeleteDC(hhdc), DeleteDC(chdc) return pBitmap } ;#####################################################################################
*note you may need to create the Screenshot_ folder in your script directory firstCode:#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases. ; #Warn ; Enable warnings to assist with detecting common errors. SendMode Input ; Recommended for new scripts due to its superior speed and reliability. SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory. #Include GDIP_All.ahk Screenshot(outfile, screen) { pToken := Gdip_Startup() hwnd := WinExist("ahk_exe Diablo III64.exe") ;;; D3 64 bit client pBitmap := Gdip_BitmapFromHWND(hwnd, "350|425|200|100") Gdip_SaveBitmapToFile(pBitmap, outfile, 100) Gdip_DisposeImage(pBitmap) Gdip_Shutdown(pToken) } !F5:: ;;ALT-F5 Screenshot(A_ScriptDir "\Screenshot_\" A_Now ".png") ; screen: X|Y|W|H Return
20191027184832.png20191027184552.png
Last edited by DeeThree; 10-30-2019 at 10:24 PM.
Dee.......many thanks~~~~~~~~~
I will make a test with ur modification of code of that function call
The _all.ahk version is worked for both ahk 32 and 64bit while gdip.ahk is worked for 32bit only
Edit: The Gdip_BitmapFromHWND function is not working. When turbohud enabled, a black screen captured.
Meaning that, it is not using the game hwnd handle to retrieve screen bitmap info
Last edited by takayo72; 10-31-2019 at 05:58 PM.
I am curious about these several if statments.
There is code statement to deal with the new function argument hwnd. That's Gdip_BitmapFromHWND is still using printscreen to capture screen as of Gdip_BitmapFromScreen
This is a string text, not the hwnd function parameterCode:if (Screen = 0) { _x := DllCall("GetSystemMetrics", "Int", 76 ) _y := DllCall("GetSystemMetrics", "Int", 77 ) _w := DllCall("GetSystemMetrics", "Int", 78 ) _h := DllCall("GetSystemMetrics", "Int", 79 ) } else if (SubStr(Screen, 1, 5) = "hwnd:") { Screen := SubStr(Screen, 6) if !WinExist("ahk_id " Screen) return -2 GetWindowRect(Screen, _w, _h) _x := _y := 0 hhdc := GetDCEx(Screen, 3) }
Code:if (SubStr(Screen, 1, 5) = "hwnd:")
As of reading these code segment. I'm thinking of if hwnd is passed to that function,
we need few more code to game window ahk_id from hwnd handle
These code segment use ahk_id to get the screen
Code:else if (SubStr(Screen, 1, 5) = "hwnd:") { Screen := SubStr(Screen, 6) if !WinExist("ahk_id " Screen) return -2 GetWindowRect(Screen, _w, _h) _x := _y := 0 hhdc := GetDCEx(Screen, 3) }
Last edited by takayo72; 10-31-2019 at 06:24 PM.
After a few testing, i ensured that Gdip_BitmapFromScreen is not just add a hwnd arugment to handle window handle
After studying the function, here is working Gdip_BitmapFromHWND function support selection area capture same as Gdip_BitmapFromScreen.
At least the screenshot test ahk is working
I added following code segment
Code:if (hwnd <> "") { hwnd_id := hwnd if !WinExist("ahk_id " hwnd_id) return -2 hhdc := GetDCEx(hwnd_id, 3) S := StrSplit(Screen, "|") _x := S[1], _y := S[2], _w := S[3], _h := S[4] } else
Full code
I maynot check for some conditions, so the code may have bugsCode:;##################################################################################### ; Function Gdip_BitmapFromHWND ; Description Uses PrintWindow to get a handle to the specified window and return a bitmap from it ; ; hwnd handle to the window to get a bitmap from ; Screen 0 = All screens ; Any numerical value = Just that screen ; x|y|w|h = Take specific coordinates with a width and height ; Raster raster operation code ; ; return If the function succeeds, the return value is a pointer to a gdi+ bitmap ; -1: one or more of x,y,w,h parameters were not passed properly ; ; return If the function succeeds, the return value is a pointer to a gdi+ bitmap ; ; notes Window must not be not minimised in order to get a handle to it's client area Gdip_BitmapFromHWND(hwnd:="", Screen:=0, Raster:="") { hhdc := 0 Ptr := A_PtrSize ? "UPtr" : "UInt" if (hwnd <> "") { hwnd_id := hwnd if !WinExist("ahk_id " hwnd_id) return -2 hhdc := GetDCEx(hwnd_id, 3) S := StrSplit(Screen, "|") _x := S[1], _y := S[2], _w := S[3], _h := S[4] } else if (Screen = 0) { _x := DllCall("GetSystemMetrics", "Int", 76 ) _y := DllCall("GetSystemMetrics", "Int", 77 ) _w := DllCall("GetSystemMetrics", "Int", 78 ) _h := DllCall("GetSystemMetrics", "Int", 79 ) } else if (SubStr(Screen, 1, 5) = "hwnd:") { Screen := SubStr(Screen, 6) if !WinExist("ahk_id " Screen) return -2 GetWindowRect(Screen, _w, _h) _x := _y := 0 hhdc := GetDCEx(Screen, 3) } else if IsInteger(Screen) { M := GetMonitorInfo(Screen) _x := M.Left, _y := M.Top, _w := M.Right-M.Left, _h := M.Bottom-M.Top } else { S := StrSplit(Screen, "|") _x := S[1], _y := S[2], _w := S[3], _h := S[4] } if (_x = "") || (_y = "") || (_w = "") || (_h = "") return -1 chdc := CreateCompatibleDC(), hbm := CreateDIBSection(_w, _h, chdc) obm := SelectObject(chdc, hbm), hhdc := hhdc ? hhdc : GetDC() BitBlt(chdc, 0, 0, _w, _h, hhdc, _x, _y, Raster) ReleaseDC(hhdc) pBitmap := Gdip_CreateBitmapFromHBITMAP(hbm) SelectObject(chdc, obm), DeleteObject(hbm), DeleteDC(hhdc), DeleteDC(chdc) return pBitmap } ;#####################################################################################
Next i can go for frame rate test on gameplay
I will post the result
Last edited by takayo72; 10-31-2019 at 07:40 PM.
Excellent work! Tested again with D3 and THUD running (embarrassed I skipped that...) and it grabbed the cropped image of the skill bar as expected.
I have been tested in game play thoroughly, no more frame rate dropped
I'm wondering the code can go further optimization, some of the code is not necessary
You don't need to be faster than frame rate and using BitBlt should grant you enough time to do all image processing you need.
I'm using C# and do initial gdi32.BitBlt from the whole screen and then Bitmap.Clone to copy buttons and other interesting portions of screen to individual bitmaps to processing (comparing them etc.).
I can do about thousand BitBlt per sec and hundreds of thousands of image comparisons per sec.
But you could take systems calls like GetSystemMetrics and GetMonitorInfo out of your inner loop and just calculate those results once.
They will never change.
optimized code which can capture whole window screen or specify the capture area by x|y|w|h
Code:;##################################################################################### ; Function Gdip_BitmapFromHWND2 ; Description Uses PrintWindow to get a handle to the specified window and return a bitmap from it ; ; hwnd handle to the window to get a bitmap from ; Screen 0 = whole screen ; x|y|w|h = Take specific coordinates with a width and height ; Raster raster operation code ; ; return If the function succeeds, the return value is a pointer to a gdi+ bitmap ; -1: one or more of x,y,w,h parameters were not passed properly ; ; return If the function succeeds, the return value is a pointer to a gdi+ bitmap ; ; notes Window must not be not minimised in order to get a handle to it's client area Gdip_BitmapFromHWND2(hwnd:="", Screen:=0, Raster:="") { hhdc := 0 Ptr := A_PtrSize ? "UPtr" : "UInt" if (hwnd <> "") { hwnd_id := hwnd if !WinExist("ahk_id " hwnd_id) return -2 if (Screen = 0) { GetWindowRect(hwnd_id, _w, _h) _x := _y := 0 hhdc := GetDCEx(hwnd_id, 3) } else { hhdc := GetDCEx(hwnd_id, 3) S := StrSplit(Screen, "|") _x := S[1], _y := S[2], _w := S[3], _h := S[4] } } chdc := CreateCompatibleDC(), hbm := CreateDIBSection(_w, _h, chdc) obm := SelectObject(chdc, hbm), hhdc := hhdc ? hhdc : GetDC() BitBlt(chdc, 0, 0, _w, _h, hhdc, _x, _y, Raster) ReleaseDC(hhdc) pBitmap := Gdip_CreateBitmapFromHBITMAP(hbm) SelectObject(chdc, obm), DeleteObject(hbm), DeleteDC(hhdc), DeleteDC(chdc) return pBitmap }
Hate to ask but can you give some details on how you made your imagesearch macro work? :
https://www.ownedcore.com/forums/dia...ml#post4071348 (Permanent closure of the plugin API and the removal of China/Asia realm support)
I am not finding good information on how to use gdip_imagesearch in a macro for a game, and not enough in that snippet for me to extrapolate it out. Help would be appreciated, Thanks!Code:global gdipToken := Gdip_Startup() , hwnd := WinExist("ahk_exe Diablo III64.exe") , ArchonImage = Archon.png // part of archon skill image in the the skill bar gameBitmap := Gdip_BitmapFromHWND(hwnd) // d3 game screen skillBitmap := Gdip_CreateBitmapFromFile(ArchonImage) // // similar as ahk builtin imagesearch // where var1,var2,var3,var4 is the search area of a image (d3 screen) // 30 is variation vRet := Gdip_ImageSearch(gameBitmap, skillBitmap, vPosXY, Var1, Var2, Var3, Var4, 30) if vRet = 1 { ; found do something } else if vRet=0 { ; not found do otherthing }
Here's a snippet from my script:
The needles were previously defined:Code:KeyLoop: While _RunFlag { If WinActive("ahk_class D3 Main Window Class") { bmpHaystack := Gdip_BitmapFromHWNDCropped(d3hwnd, _x "|" _y "|" _w "|" _h) sready := Gdip_ImageSearch(bmpHaystack,vengeanceNeedle,LIST,0,0,0,0,0,0xFFFFFF,1,0) if (sready == 1) { Send %Key3% } sready := Gdip_ImageSearch(bmpHaystack,companionNeedle,LIST,0,0,0,0,0,0xFFFFFF,1,0) if (sready == 1) { Send %Key4% } Gdip_DisposeImage(bmpHaystack) RandomSleep(40, 125) } } Return
Code:vengeanceNeedle := Gdip_CreateBitmapFromFile("IMG/vengeance.bmp") companionNeedle := Gdip_CreateBitmapFromFile("IMG/companion.bmp")
I'm also using a simpler function than takayo72:
Code:Gdip_BitmapFromHWNDCropped(hwnd, Screen) { Raster := "" Ptr := A_PtrSize ? "UPtr" : "UInt" hhdc := GetDCEx(hwnd, 3) S := StrSplit(Screen, "|") _x := S[1], _y := S[2], _w := S[3], _h := S[4] chdc := CreateCompatibleDC(), hbm := CreateDIBSection(_w, _h, chdc) obm := SelectObject(chdc, hbm), hhdc := hhdc ? hhdc : GetDC() BitBlt(chdc, 0, 0, _w, _h, hhdc, _x, _y, Raster) ReleaseDC(hhdc) pBitmap := Gdip_CreateBitmapFromHBITMAP(hbm) SelectObject(chdc, obm), DeleteObject(hbm), DeleteDC(hhdc), DeleteDC(chdc) return pBitmap }