Re: [v2] FindText - Capture screen image into text and then find it
Posted: 14 Aug 2023, 15:42
@hisrRB57 Thank you for your feedback. I didn't read the help file carefully. Please download the script again to fix this bug.
Let's help each other out
https://www.autohotkey.com/boards/
https://www.autohotkey.com/boards/viewtopic.php?f=83&t=116471
Code: Select all
xHelp := FindText().help()
Code: Select all
help()
{
return "
(
;--------------------------------
; FindText - Capture screen image into text and then find it
; Version : 9.1 (2023-07-30)
;--------------------------------
; returnArray:=FindText(
; &OutputX --> The name of the variable used to store the returned X coordinate
; , &OutputY --> The name of the variable used to store the returned Y coordinate
; , X1 --> the search scope's upper left corner X coordinates
; , Y1 --> the search scope's upper left corner Y coordinates
; , X2 --> the search scope's lower right corner X coordinates
; , Y2 --> the search scope's lower right corner Y coordinates
; , err1 --> Fault tolerance percentage of text (0.1=10%)
; , err0 --> Fault tolerance percentage of background (0.1=10%)
; , Text --> can be a lot of text parsed into images, separated by '|'
; , ScreenShot --> if the value is 0, the last screenshot will be used
; , FindAll --> if the value is 0, Just find one result and return
; , JoinText --> if you want to combine find, it can be 1, or an array of words to find
; , offsetX --> Set the max text offset (X) for combination lookup
; , offsetY --> Set the max text offset (Y) for combination lookup
; , dir --> Nine directions for searching: up, down, left, right and center
; , zoomW --> Zoom percentage of image width (1.0=100%)
; , zoomH --> Zoom percentage of image height (1.0=100%)
; )
;
; The function returns an Array containing all lookup results,
; any result is a object with the following values:
; {1:X, 2:Y, 3:W, 4:H, x:X+W//2, y:Y+H//2, id:Comment}
; If no image is found, the function returns 0.
; All coordinates are relative to Screen, colors are in RGB format
;
; If the return variable is set to 'ok', ok[1] is the first result found.
; ok[1].1, ok[1].2 is the X, Y coordinate of the upper left corner of the found image,
; ok[1].3 is the width of the found image, and ok[1].4 is the height of the found image,
; ok[1].x <==> ok[1].1+ok[1].3//2 ( is the Center X coordinate of the found image ),
; ok[1].y <==> ok[1].2+ok[1].4//2 ( is the Center Y coordinate of the found image ),
; ok[1].id is the comment text, which is included in the <> of its parameter.
;
; If OutputX is equal to 'wait' or 'wait1'(appear), or 'wait0'(disappear)
; it means using a loop to wait for the image to appear or disappear.
; the OutputY is the wait time in seconds, time less than 0 means infinite waiting
; Timeout means failure, return 0, and return other values means success
; If you want to appear and the image is found, return the found array object
; If you want to disappear and the image cannot be found, return 1
; Example 1: FindText(&X:='wait', &Y:=3, 0,0,0,0,0,0,Text) ; Wait 3 seconds for appear
; Example 2: FindText(&X:='wait0', &Y:=-1, 0,0,0,0,0,0,Text) ; Wait indefinitely for disappear
;--------------------------------
)"
}
Code: Select all
#Requires AutoHotkey v2
; #Include <FindText>
t1:=A_TickCount, Text:=X:=Y:=""
Text:="|<>**50$19.zzzk00E000003s7l4282041020U10EEU/sE6080040020010DkU80E4082041021U17UDU003"
if (ok:=FindText(&X, &Y, 115-150000, 659-150000, 115+150000, 659+150000, 0, 0, Text))
{
; FindText().Click(X, Y, "L")
}
; ok:=FindText(&X:="wait", &Y:=3, 0,0,0,0,0,0,Text) ; Wait 3 seconds for appear
; ok:=FindText(&X:="wait0", &Y:=-1, 0,0,0,0,0,0,Text) ; Wait indefinitely for disappear
MsgBox("Found:`t" (IsObject(ok)?ok.Length:ok)
. "`n`nTime:`t" (A_TickCount-t1) " ms"
. "`n`nPos:`t" X ", " Y
. "`n`nResult:`t<" (IsObject(ok)?ok[1].id:"") ">", "Tip", 4096)
try For i,v in ok ; ok value can be get from ok:=FindText().ok
Highlight(v.1, v.2, v.3, v.4, 0)
catch
ExitApp
Esc::ExitApp
/**
* Highlights an area with a colorful border. If called without arguments then all highlightings
* are removed. This function also supports named parameters.
* @param x Screen X-coordinate of the top left corner of the highlight
* @param y Screen Y-coordinate of the top left corner of the highlight
* @param w Width of the highlight
* @param h Height of the highlight
* @param showTime Can be one of the following:
* * Unset - if highlighting exists then removes the highlighting, otherwise highlights for 2 seconds. This is the default value.
* * 0 - Indefinite highlighting
* * Positive integer (eg 2000) - will highlight and pause for the specified amount of time in ms
* * Negative integer - will highlight for the specified amount of time in ms, but script execution will continue
* * "clear" - removes the highlighting unconditionally
* @param color The color of the highlighting. Default is red.
* @param d The border thickness of the highlighting in pixels. Default is 2.
*/
Highlight(x?, y?, w?, h?, showTime?, color:="Red", d:=2) {
static guis := Map(), timers := Map()
if IsSet(x) { ; if x is set then check whether a highlight already exists at those coords
if IsObject(x) {
d := x.HasOwnProp("d") ? x.d : d, color := x.HasOwnProp("color") ? x.color : color, showTime := x.HasOwnProp("showTime") ? x.showTime : showTime
, h := x.HasOwnProp("h") ? x.h : h, w := x.HasOwnProp("w") ? x.w : h, y := x.HasOwnProp("y") ? x.y : y, x := x.HasOwnProp("x") ? x.x : unset
}
if !(IsSet(x) && IsSet(y) && IsSet(w) && IsSet(h))
throw ValueError("x, y, w and h arguments must all be provided for a highlight", -1)
for k, v in guis {
if k.x = x && k.y = y && k.w = w && k.h = h { ; highlight exists, so either remove it, or update
if !IsSet(showTime) || (IsSet(showTime) && showTime = "clear")
TryRemoveTimer(k), TryDeleteGui(k)
else if showTime = 0
TryRemoveTimer(k)
else if IsInteger(showTime) {
if showTime < 0 {
if !timers.Has(k)
timers[k] := Highlight.Bind(x,y,w,h)
SetTimer(timers[k], showTime)
} else {
TryRemoveTimer(k)
Sleep showTime
TryDeleteGui(k)
}
} else
throw ValueError('Invalid showTime value "' (!IsSet(showTime) ? "unset" : IsObject(showTime) ? "{Object}" : showTime) '"', -1)
return
}
}
} else { ; if x is not set (eg Highlight()) then delete all highlights
for k, v in timers
SetTimer(v, 0)
for k, v in guis
v.Destroy()
guis := Map(), timers := Map()
return
}
if (showTime := showTime ?? 2000) = "clear"
return
else if !IsInteger(showTime)
throw ValueError('Invalid showTime value "' (!IsSet(showTime) ? "unset" : IsObject(showTime) ? "{Object}" : showTime) '"', -1)
; Otherwise this is a new highlight
loc := {x:x, y:y, w:w, h:h}
guis[loc] := Gui("+AlwaysOnTop -Caption +ToolWindow -DPIScale +E0x08000000")
GuiObj := guis[loc]
GuiObj.BackColor := color
iw:= w+d, ih:= h+d, w:=w+d*2, h:=h+d*2, x:=x-d, y:=y-d
WinSetRegion("0-0 " w "-0 " w "-" h " 0-" h " 0-0 " d "-" d " " iw "-" d " " iw "-" ih " " d "-" ih " " d "-" d, GuiObj.Hwnd)
GuiObj.Show("NA x" . x . " y" . y . " w" . w . " h" . h)
if showTime > 0 {
Sleep(showTime)
TryDeleteGui(loc)
} else if showTime < 0
SetTimer(timers[loc] := Highlight.Bind(loc.x,loc.y,loc.w,loc.h), showTime)
TryRemoveTimer(key) {
if timers.Has(key)
SetTimer(timers[key], 0), timers.Delete(key)
}
TryDeleteGui(key) {
if guis.Has(key)
guis[key].Destroy(), guis.Delete(key)
}
}
Code: Select all
Try FindText_SubPic.Destroy()
FindText_SubPic:=_Gui:=Gui()
_Gui.Opt "+Parent" parent_id " +AlwaysOnTop -Caption +ToolWindow -DPIScale"
_Gui.MarginX:=0, _Gui.MarginY:=0
_Gui.BackColor:="White"
id:=_Gui.Add("Pic", "x0 y0 w500 h500"), sub_hpic:=id.Hwnd
_Gui.Title:="SubPic"
_Gui.Show "NA x0 y0"
Code: Select all
#Include <FindText>
class a {
static x:=0,y:=0
}
Text:="|<>*86$13.zzlzuTxryxzTTjnrwvzBzqy7RjgrlNxqzvTyTzzU"
if (ok:=FindText(&a.X, &a.Y, 23-150000, 125-150000, 23+150000, 125+150000, 0, 0, Text))
{
}
Code: Select all
Error: Parameter #5 of FindTextClass.Prototype.xywh2xywh requires a variable reference, but received an Integer.
Thanks for the correct sequence, works great.
Seems like GetRange would be a very quick and easy way to define a small search area, rather than having to look at WindowSpy and write down coordinates.
Thanks for the explanation @Descolada. I can see how it would be useful for OCR.Descolada wrote: ↑23 May 2024, 03:09@redrum it probably wouldn't be much of use in that case, perhaps only for organisatory purposes (instead of using multiple global variables, you put them in PicLib and access them via their comment name). I primarily use it to do OCR: I capture images of individual characters and add them into a PicLib, then I can use FindText().PicN to construct a combination of those characters for a combination search. Eg I add Text of characters "h", "o", and "t" into the PicLib, and then I can use FindText().PicN("tho") in a combination search to search the screen for the word "tho".