FindText - Capture screen image into text and then find it

Post your working scripts, libraries and tools for AHK v1.1 and older
feiyue
Posts: 349
Joined: 08 Aug 2014, 04:08

Re: FindText - Capture screen image into text and then find it

06 Dec 2019, 22:33

@maxkill
You may need to know coordinates and coordinate calculations. :beer:
The coordinates of two points determine a rectangular range,
The first four parameters of the FindText() function require two screen coordinates,
So you can do this:

Code: Select all

CoordMode, Mouse, Screen
MouseGetPos, x, y
ok:=FindText(x-150, y-150, x+150, y+150, 0, 0, Text) ; 150 can be adjusted by yourself
The returned variable "ok" is a second-order array, and ok.1 is the first result found,
ok.1 is an associative array--> {1:X, 2:Y, 3:W, 4:H, x:X+W//2, y:Y+H//2, id:Comment},
Where ok.1.1 is the X coordinate of the upper left corner of the found image,
and ok.1.2 is the 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 is the identifying text of the found image, which is included in the <> of its parameter.
So if you need to Click the coordinates of the lower right corner of the found image,
you can do this:

Code: Select all

if (ok)
{
  x:=ok.1.1, y:=ok.1.2, w:=ok.1.3, h:=ok.1.4
  Click, % x+w-1, % y+h-1
}
In fact, the auto generated code is just an example that can be run,
To really use it in your own scripts,
You need to see the introduction of the function,
and understand the meaning of parameters and return values.

Of course, it's mainly because my English is not very good,
and the output of English depends on automatic translation, :D
so there is no detailed description of the function parameters,
return values and use methods, which makes it inconvenient for everyone to use.
Last edited by feiyue on 07 Dec 2019, 00:06, edited 4 times in total.
thebbandit
Posts: 45
Joined: 02 Jul 2019, 11:34

Re: FindText - Capture screen image into text and then find it

06 Dec 2019, 22:41

I found another adjustment you may be interested in.

When the user captures an image and hits OK, it should select the line below the Text:="|<>####" so that it can go directly into another capture without needing to select the proper location within the editbox. While I was at it, I figured why not show the preview automatically as well? :D At the very end of the capture section, I placed this there to achieve this.
Select correct line after Capture, and automatically preview in top editbox
feiyue
Posts: 349
Joined: 08 Aug 2014, 04:08

Re: FindText - Capture screen image into text and then find it

06 Dec 2019, 22:55

@thebbandit If you think it's necessary, you can do it in one line.

Code: Select all

    WinWaitClose, % "ahk_id " WinExist()
    GuiControl, ft_Main:, MyPic, % Trim(ASCII(Result),"`n")  ;<-- Add this line
    ;-------------------------------- 
    if (Event="ButtonOK")
Of course, this is a good suggestion. :thumbup:
Maybe I should not modify the script frequently,
but should collect these good suggestions
and improve the script once in a version update.
thebbandit
Posts: 45
Joined: 02 Jul 2019, 11:34

Re: FindText - Capture screen image into text and then find it

07 Dec 2019, 01:57

@feiyue Pretty cool, that is a much more direct way of getting it displayed :)

I mentioned moving the cursor of the editbox, because you are using the cursor location for AddAll. So if the user captures a string, and then goes straight to another capture, the input will actually end up at the top of the script. I move the cursor to below the line where it needs to be inserted automatically, so you dont have to click the correct line before adding another capture.

These are all small little things, and I simply use a comparison tool to see what has been changed :) I have become used to looking at your edit count :P

I reworked the way you have your keybindings, but you may not be interested since its using another library. Let me know otherwise, and I can share the lib with you.
Using Hotkey Lib
maxkill
Posts: 158
Joined: 11 Apr 2016, 13:03

Re: FindText - Capture screen image into text and then find it

07 Dec 2019, 21:00

@feiyue
Thanks a lot for your answer appreciate it.

I tried putting code into the script but I screwed something up, says I need a % sign on line 13.
I'm also unsure if I should paste the actual text image into the script like on page 2 of this topic or like I have it now without it. And also at the end of the script or beginning (like I have it now).

(I only changed the top part of the script) :idea:

Code: Select all

; #Include <FindText>
+a::

t1:=A_TickCount

Text:="|<>#[email protected]$42.0000000000000003zzzs000000000000000U"

CoordMode, Mouse, Screen
MouseGetPos, x, y
if (ok:=FindText(409-150000, 1904-150000, 150000, 150000, 0, 0, Text))
ok:=FindText(x-150, y-150, x+150, y+150, 0, 0, Text) ; 150 can be adjusted by yourself

if (ok)
{
  x:=ok.1.1, y:=ok.1.2, w:=ok.1.3, h:=ok.1.4
  Click, % x+w-1, % y+h-1
}



;===== Copy The Following Functions To Your Own Code Just once =====


;--------------------------------
; FindText - Capture screen image into text and then find it
;--------------------------------
; X1, Y1 --> the search scope's upper left corner coordinates
; X2, Y2 --> the search scope's lower right corner coordinates
; err1, err0 --> character "0" or "_" fault-tolerant in percentage
; 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 the value is 1, Join all Text for combination lookup
; offsetX, offsetY --> Set the Max text offset for combination lookup
; ruturn --> the function returns a second-order array
; containing all lookup results, Any result is an associative array
; {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.
;--------------------------------

FindText( x1, y1, x2, y2, err1, err0, text, ScreenShot=1
  , FindAll=1, JoinText=0, offsetX=20, offsetY=10 )
{
  local  ; Unaffected by Super-global variables
  bch:=A_BatchLines
  SetBatchLines, -1
  x:=(x1<x2 ? x1:x2), y:=(y1<y2 ? y1:y2)
  , w:=Abs(x2-x1)+1, h:=Abs(y2-y1)+1
  , xywh2xywh(x,y,w,h,x,y,w,h)
  if (w<1 or h<1)
  {
    SetBatchLines, %bch%
    return, 0
  }
  ;-------------------------------
  GetBitsFromScreen(x,y,w,h,Scan0,Stride,ScreenShot,zx,zy)
  ;-------------------------------
  sx:=x-zx, sy:=y-zy, sw:=w, sh:=h
  , arr:=[], info:=[], allv:=""
  Loop, Parse, text, |
  {
    v:=A_LoopField
    IfNotInString, v, $, Continue
    comment:="", e1:=err1, e0:=err0, set_e1_e0:=0
    ; You Can Add Comment Text within The <>
    if RegExMatch(v,"<([^>]*)>",r)
      v:=StrReplace(v,r), comment:=Trim(r1)
    ; You can Add two fault-tolerant in the [], separated by commas
    if RegExMatch(v,"\[([^\]]*)]",r)
    {
      v:=StrReplace(v,r), r1.=","
      StringSplit, r, r1, `,
      e1:=r1, e0:=r2, set_e1_e0:=1
    }
    StringSplit, r, v, $
    color:=r1, v:=r2
    StringSplit, r, v, .
    w1:=r1, v:=base64tobit(r2), h1:=StrLen(v)//w1
    if (r0<2 or h1<1 or w1>sw or h1>sh or StrLen(v)!=w1*h1)
      Continue
    mode:=InStr(color,"-") ? 4 : InStr(color,"#") ? 3
      : InStr(color,"**") ? 2 : InStr(color,"*") ? 1 : 0
    if (mode=4)
    {
      color:=StrReplace(color,"0x")
      StringSplit, r, color, -
      color:="0x" . r1, n:="0x" . r2
    }
    else
    {
      color:=RegExReplace(color,"[*#]") . "@"
      StringSplit, r, color, @
      color:=(mode=3 ? ((r1-1)//w1)*Stride+Mod(r1-1,w1)*4 : r1)
      , n:=Round(r2,2)+(!r2), n:=Floor(9*255*255*(1-n)*(1-n))
    }
    StrReplace(v,"1","",len1), len0:=StrLen(v)-len1
    , e1:=Round(len1*e1), e0:=Round(len0*e0)
    , info.Push( [StrLen(allv),w1,h1,len1,len0,e1,e0
    , mode,color,n,comment,set_e1_e0] ), allv.=v
  }
  if (allv="" or !Stride)
  {
    SetBatchLines, %bch%
    return, 0
  }
  num:=info.MaxIndex(), VarSetCapacity(input, num*7*4)
  , VarSetCapacity(gs, sw*sh)
  , VarSetCapacity(ss, sw*sh), k:=StrLen(allv)*4
  , VarSetCapacity(s1, k), VarSetCapacity(s0, k)
  , allpos_max:=(FindAll ? 1024 : 1)
  , VarSetCapacity(allpos, allpos_max*4)
  ;-------------------------------------
  Loop, 2
  {
  if (num>1 and err1=0 and err0=0)
  {
    err1:=err0:=0.05
    For i,j in info
      if (!j.12)
        j.6:=Round(j.4*err1), j.7:=Round(j.5*err0)
  }
  if (JoinText)
  {
    j:=info[1], mode:=j.8, color:=j.9, n:=j.10
    , w1:=-1, h1:=j.3, comment:="", k:=0
    Loop, % num
    {
      j:=info[A_Index], w1+=j.2+1, comment.=j.11
      Loop, 7
        NumPut(j[A_Index], input, 4*(k++), "int")
    }
    ok:=PicFind( mode,color,n,offsetX,offsetY
      ,Scan0,Stride,sx,sy,sw,sh,gs,ss,allv,s1,s0
      ,input,num*7,allpos,allpos_max )
    Loop, % ok
      pos:=NumGet(allpos, 4*(A_Index-1), "uint")
      , rx:=(pos&0xFFFF)+zx, ry:=(pos>>16)+zy
      , arr.Push( {1:rx, 2:ry, 3:w1, 4:h1
      , x:rx+w1//2, y:ry+h1//2, id:comment} )
  }
  else
  {
    For i,j in info
    {
      mode:=j.8, color:=j.9, n:=j.10, comment:=j.11
      , w1:=j.2, h1:=j.3, v:=SubStr(allv, j.1+1, w1*h1)
      Loop, 7
        NumPut(j[A_Index], input, 4*(A_Index-1), "int")
      NumPut(0, input, "int")
      ok:=PicFind( mode,color,n,offsetX,offsetY
        ,Scan0,Stride,sx,sy,sw,sh,gs,ss,v,s1,s0
        ,input,7,allpos,allpos_max )
      Loop, % ok
        pos:=NumGet(allpos, 4*(A_Index-1), "uint")
        , rx:=(pos&0xFFFF)+zx, ry:=(pos>>16)+zy
        , arr.Push( {1:rx, 2:ry, 3:w1, 4:h1
        , x:rx+w1//2, y:ry+h1//2, id:comment} )
      if (ok and !FindAll)
        Break
    }
  }
  if (num=1 and err1=0 and err0=0 and !arr.MaxIndex())
  {
    err1:=err0:=0.05, k:=0
    For i,j in info
      if (!j.12)
        j.6:=Round(j.4*err1), j.7:=Round(j.5*err0), k:=1
    IfEqual, k, 0, Break
  }
  else Break
  }
  SetBatchLines, %bch%
  return, arr.MaxIndex() ? arr:0
}

PicFind(mode, color, n, offsetX, offsetY
  , Scan0, Stride, sx, sy, sw, sh
  , ByRef gs, ByRef ss, ByRef text, ByRef s1, ByRef s0
  , ByRef input, num, ByRef allpos, allpos_max)
{
  static MyFunc, Ptr:=A_PtrSize ? "UPtr" : "UInt"
  static init:=PicFind(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
  if (!MyFunc)
  {
    x32:="5557565383EC788B8424CC0000008BBC24CC000000C7442"
    . "424000000008B40048B7F148944243C8B8424CC000000897C2"
    . "42C8BBC24CC0000008B40088B7F18894424348B8424CC00000"
    . "0897C24308B400C89C6894424288B8424CC0000008B401039C"
    . "6894424200F4DC68944241C8B8424D000000085C00F8E15010"
    . "0008BB424CC0000008B44242489F78B0C868B7486048B44870"
    . "88974241085C0894424180F8ED700000089CD894C2414C7442"
    . "40C00000000C744240800000000C744240400000000890C248"
    . "D76008DBC27000000008B5C24108B7424088B4C24148B54240"
    . "C89DF89F029F101F78BB424C000000001CE85DB7E5E8B0C248"
    . "9EB893C2489D7EB198BAC24C800000083C70483C00189548D0"
    . "083C101390424742C83BC248C0000000389FA0F45D0803C063"
    . "175D48BAC24C400000083C70483C00189549D0083C30139042"
    . "475D48B7424100174241489DD890C2483442404018BB424B00"
    . "000008B442404017424088BBC24A4000000017C240C3944241"
    . "80F8554FFFFFF83442424078B442424398424D00000000F8FE"
    . "BFEFFFF83BC248C000000030F84A00600008B8424A40000008"
    . "BB424A80000000FAF8424AC0000008BBC248C0000008D2CB08"
    . "B8424B00000008BB424A4000000F7D885FF8D0486894424100"
    . "F84F702000083BC248C000000010F845F08000083BC248C000"
    . "000020F84130900008B8424900000008B9C24940000000FB6B"
    . "C24940000000FB6B42490000000C744241800000000C744242"
    . "400000000C1E8100FB6DF0FB6D08B84249000000089D10FB6C"
    . "4894424088B842494000000C1E8100FB6C029C101D08904248"
    . "B442408894C24408B4C240801D829D9894424088D043E894C2"
    . "40489F129F9894424148BBC24B40000008B8424B0000000894"
    . "C240C89E98B6C2440C1E00285FF894424380F8EBA0000008BB"
    . "424B000000085F60F8E910000008B8424A00000008B5424240"
    . "39424BC00000001C8034C243889CF894C244003BC24A000000"
    . "0EB3D8D76008DBC2700000000391C247C3D394C24047F37394"
    . "C24087C3189F30FB6F33974240C0F9EC3397424140F9DC183C"
    . "00483C20121D9884AFF39F8741E0FB658020FB648010FB6303"
    . "9DD7EBE31C983C00483C201884AFF39F875E28BBC24B000000"
    . "0017C24248B4C24408344241801034C24108B442418398424B"
    . "40000000F8546FFFFFF8B8424B00000002B44243C8944240C8"
    . "B8424B40000002B442434894424600F884D0900008B4424288"
    . "BBC24C40000008B74243CC744241000000000C744243800000"
    . "000C7442434000000008D3C8789C583EE01897C246C8974247"
    . "48B44240C85C00F88E70000008B7C24388B8424AC000000BE0"
    . "0000000C704240000000001F8C1E0108944246889F82B84249"
    . "C0000000F49F08B84249C000000897424640FAFB424B000000"
    . "001F8894424708974245C8DB6000000008B04240344241089C"
    . "1894424088B442430394424200F84AA0100008B5C241C89C60"
    . "38C24BC00000031C08B54242C85DB0F8EC8010000897424048"
    . "B7C2420EB2D39C77E1C8BB424C80000008B1C8601CB803B007"
    . "40B836C240401782B8D74260083C0013944241C0F849101000"
    . "039C57ECF8BB424C40000008B1C8601CB803B0174BE83EA017"
    . "9B9830424018B04243944240C0F8D68FFFFFF83442438018BB"
    . "424B00000008B44243801742410394424600F8DEFFEFFFF8B4"
    . "C243483C47889C85B5E5F5DC250008B8424900000008BB424B"
    . "4000000C744240C00000000C744241400000000C1E8100FB6C"
    . "08904248B8424900000000FB6C4894424040FB684249000000"
    . "0894424088B8424B0000000C1E00285F68944242489E88BAC2"
    . "4940000000F8E24FEFFFF8B9C24B000000085DB7E758B9C24A"
    . "00000008B7424148BBC24A000000003B424BC00000001C3034"
    . "424248944241801C78D76008DBC27000000000FB643020FB64"
    . "B012B04242B4C24040FB6132B5424080FAFC00FAFC98D04400"
    . "FAFD28D04888D045039C50F930683C30483C60139DF75C98BB"
    . "C24B0000000017C24148B4424188344240C01034424108B742"
    . "40C39B424B40000000F8566FFFFFFE985FDFFFF85ED7E358B7"
    . "424088BBC24BC00000031C08B54242C8D1C378BB424C400000"
    . "08B0C8601D9803901740983EA010F8890FEFFFF83C00139C57"
    . "5E683BC24D0000000070F8EAA0100008B442474030424C7442"
    . "44007000000896C2444894424288B8424CC00000083C020894"
    . "4243C8B44243C8B9424B00000008B7C24288B0029C28944245"
    . "08B84249800000001F839C20F4EC289C68944244C39FE0F8C0"
    . "90100008B44243C8B700C8B78148B6808897424148B7010897"
    . "C245489C7897424248BB424B40000002B700489F08B7424703"
    . "9C60F4EC68BB424C4000000894424188B47FC89442404C1E00"
    . "201C6038424C8000000894424588B4424648B7C2428037C245"
    . "C3B442418894424040F8F8700000085ED7E268B8C24BC00000"
    . "08B54242431C08D1C398B0C8601D9803901740583EA01784A8"
    . "3C00139C575EA8B4424148B4C245439C8747E85C07E7A8B9C2"
    . "4BC000000896C244831C08B6C245801FBEB0983C0013944241"
    . "4745C8B54850001DA803A0074EC83E90179E78B6C244890834"
    . "424040103BC24B00000008B442404394424180F8D79FFFFFF8"
    . "3442428018B4424283944244C0F8D4CFFFFFF830424018B6C2"
    . "4448B04243944240C0F8D7EFCFFFFE911FDFFFF8B4424288B7"
    . "4245083442440078344243C1C8D4430FF894424288B4424403"
    . "98424D00000000F8F7FFEFFFF8B6C24448B7C24348B0424038"
    . "424A80000008BB424D40000000B4424688D4F01398C24D8000"
    . "0008904BE0F8ED8FCFFFF85ED7E278B7424088BBC24BC00000"
    . "08B8424C40000008D1C378B74246C8B1083C00401DA39F0C60"
    . "20075F283042401894C24348B04243944240C0F8DDEFBFFFFE"
    . "971FCFFFF89F68DBC27000000008B8424B0000000038424A80"
    . "000002B44243C894424248B8424AC000000038424B40000002"
    . "B442434398424AC000000894424380F8F520400008B8424A40"
    . "000008BB424A80000000FAF8424AC000000C74424180000000"
    . "08D04B0038424900000008BB424A0000000894424348B44242"
    . "4398424A80000000F8F2B0100008B8424AC000000C1E010894"
    . "4243C8B442434894424148B8424A8000000894424088B44241"
    . "40FB67C060289C52BAC2490000000893C240FB67C0601897C2"
    . "4040FB63C068B44241C85C00F8E140100008B4424308944241"
    . "08B44242C8944240C31C0EB5D394424207E4A8B9C24C800000"
    . "08B0C8301E90FB6540E020FB65C0E012B14242B5C24040FB60"
    . "C0E0FAFD20FAFDB29F98D14520FAFC98D149A8D144A3994249"
    . "4000000720C836C2410017865908D74260083C0013944241C0"
    . "F84A3000000394424287E9D8B9C24C40000008B0C8301E90FB"
    . "6540E020FB65C0E012B14242B5C24040FB60C0E0FAFD20FAFD"
    . "B29F98D14520FAFC98D149A8D144A3B9424940000000F865BF"
    . "FFFFF836C240C010F8950FFFFFF834424080183442414048B4"
    . "42408394424240F8DF6FEFFFF838424AC000000018BBC24A40"
    . "000008B442438017C24343B8424AC0000000F8DA0FEFFFF8B4"
    . "C241883C4785B5E89C85F5DC250008D7426008B7C24188B442"
    . "43C0B4424088B9C24D40000008D4F013B8C24D80000008904B"
    . "B0F8D84FAFFFF894C2418EB848B8424900000008B8C24B4000"
    . "000C7042400000000C74424040000000083C001C1E00789C78"
    . "B8424B0000000C1E00285C98944240889E889FD0F8ECFF8FFF"
    . "F8B9424B000000085D27E5F8B8C24A00000008B5C2404039C2"
    . "4BC00000001C1034424088944240C038424A000000089C70FB"
    . "651020FB641010FB6316BC04B6BD22601C289F0C1E00429F00"
    . "1D039C50F970383C10483C30139F975D58BBC24B0000000017"
    . "C24048B44240C83042401034424108B342439B424B40000007"
    . "582E94CF8FFFF8B8424B0000000C7042400000000C74424040"
    . "0000000C1E002894424088B8424B400000085C00F8E9200000"
    . "08B8424B000000085C07E6F8B8C24A00000008B5C24048BB42"
    . "4B800000001E9036C240801DE039C24BC000000896C240C03A"
    . "C24A00000000FB651020FB6410183C1040FB679FC83C60183C"
    . "3016BC04B6BD22601C289F8C1E00429F801D0C1F8078846FFC"
    . "643FF0039CD75CC8BB424B0000000017424048B6C240C83042"
    . "401036C24108B0424398424B40000000F856EFFFFFF83BC24B"
    . "4000000020F8E80F7FFFF8B8424BC000000038424B00000008"
    . "BAC24B800000003AC24B0000000C7442404010000008944240"
    . "88B8424B400000083E8018944240C8B8424B000000083C0018"
    . "944241083BC24B0000000027E798B44241089E92B8C24B0000"
    . "0008B5C240889EA8D34288D45FE8904240FB642010FB63A038"
    . "4249000000039F87C360FB67A0239F87C2E0FB6790139F87C2"
    . "60FB63E39F87C1F0FB63939F87C180FB6790239F87C100FB67"
    . "EFF39F87C080FB67E0139F87D04C643010183C20183C30183C"
    . "10183C6013B0C2475A3834424040103AC24B00000008B44240"
    . "48BB424B0000000017424083944240C0F8558FFFFFFE98FF6F"
    . "FFF83C47831C95B89C85E5F5DC2500090909090909090"
    x64:="4157415641554154555756534881EC88000000488B84245"
    . "0010000488BB42450010000448B94245801000089542428448"
    . "944240844898C24E80000008B40048B76144C8BBC244001000"
    . "04C8BB42448010000C74424180000000089442430488B84245"
    . "00100008974241C488BB424500100008B40088B76188944243"
    . "C488B842450010000897424388B400C89C789442440488B842"
    . "4500100008B401039C7894424100F4DC74585D289442454488"
    . "B84245001000048894424200F8ECB000000488B442420448B0"
    . "8448B68048B400885C0894424040F8E940000004489CE44890"
    . "C244531E431FF31ED0F1F8400000000004585ED7E614863142"
    . "4418D5C3D0089F848039424380100004589E0EB1D0F1F0083C"
    . "0014D63D94183C0044183C1014883C20139C34789149E74288"
    . "3F9034589C2440F45D0803A3175D783C0014C63DE4183C0048"
    . "3C6014883C20139C34789149F75D844012C2483C50103BC241"
    . "80100004403A42400010000396C24047582834424180748834"
    . "424201C8B442418398424580100000F8F35FFFFFF83F9030F8"
    . "43D0600008B8424000100008BBC24080100000FAF842410010"
    . "0008BB424000100008D3CB88B842418010000F7D885C9448D2"
    . "C860F841101000083F9010F842008000083F9020F84BF08000"
    . "08B742428C744240400000000C74424180000000089F0440FB"
    . "6CEC1E8104589CC0FB6D84889F08B7424080FB6D44189DB89F"
    . "0440FB6C64889F1C1E8100FB6CD89D60FB6C08D2C0A8B94242"
    . "00100004129C301C3438D040129CE4529C48904248B8424180"
    . "10000C1E00285D2894424080F8E660100004C89BC244001000"
    . "0448BBC24180100004585FF0F8E91040000488B8C24F800000"
    . "04863C74C6354241831D24C03942430010000488D440102EB3"
    . "A0F1F80000000004439C37C4039CE7F3C39CD7C384539CC410"
    . "F9EC044390C240F9DC14421C141880C124883C2014883C0044"
    . "139D70F8E2D040000440FB6000FB648FF440FB648FE4539C37"
    . "EBB31C9EBD58B5C2428448B8C242001000031ED4531E44889D"
    . "84189DB0FB6DB0FB6F48B84241801000041C1EB10450FB6DBC"
    . "1E0024585C98904240F8EA10000004C89BC24400100004C89B"
    . "42448010000448B7C2408448BB424180100004585F67E60488"
    . "B8C24F80000004D63D44C039424300100004863C74531C94C8"
    . "D440102410FB600410FB648FF410FB650FE4429D829F10FAFC"
    . "029DA0FAFC98D04400FAFD28D04888D04504139C7430F93040"
    . "A4983C1014983C0044539CE7FC4033C244501F483C5014401E"
    . "F39AC2420010000758C4C8BBC24400100004C8BB4244801000"
    . "08B8424180100002B4424308904248B8424200100002B44243"
    . "C894424680F88540800008B7C24404D89F5488BAC243001000"
    . "0448B7424104C89FEC74424040000000048C74424280000000"
    . "0C74424200000000089F883E801498D4487044189FF4889442"
    . "4088B44243083E801894424788B042485C00F88D9000000488"
    . "B5C24288B8424100100004D89EC448B6C245401D8C1E010894"
    . "4247089D82B8424F000000089C7B8000000000F49C731FF894"
    . "4246C0FAF842418010000894424648B8424F000000001D8894"
    . "42474908B442404897C24188D1C388B4424384139C60F84AB0"
    . "000004189C131C04585ED448B44241C7F36E9C30000000F1F4"
    . "0004139CE7E1B418B148401DA4863D2807C150000740B4183E"
    . "901782E0F1F4400004883C0014139C50F8E920000004139C78"
    . "9C17ECC8B148601DA4863D2807C15000174BD4183E80179B74"
    . "883C701393C240F8D7AFFFFFF4D89E54883442428018B9C241"
    . "8010000488B442428015C2404394424680F8DFCFEFFFF8B4C2"
    . "42089C84881C4880000005B5E5F5D415C415D415E415FC3458"
    . "5FF7E278B4C241C4C8B4424084889F28B0201D84898807C050"
    . "001740583E90178934883C2044939D075E583BC24580100000"
    . "70F8EE60100008B442478488B8C24500100000344241844896"
    . "C2450448BAC241801000044897C24404883C1204889742410C"
    . "744243C07000000448974244448897C24484989CF895C247C8"
    . "9C64C89642430418B074489EA29C28944245C8B8424E800000"
    . "001F039C20F4EC239F0894424580F8CD0000000418B47148BB"
    . "C2420010000412B7F0449635FFC458B4F08458B670C8944246"
    . "08B442474458B771039C70F4FF8488B44241048C1E3024C8D1"
    . "41848035C24308B442464448D04068B44246C39F84189C37F7"
    . "2904585C97E234489F131D2418B04924401C04898807C05000"
    . "1740583E90178464883C2014139D17FE28B4424604139C40F8"
    . "4AA0000004585E40F8EA100000089C131D2EB0D4883C201413"
    . "9D40F8E8E0000008B04934401C04898807C05000074E483E90"
    . "179DF4183C3014501E84439DF7D8F83C601397424580F8D6EF"
    . "FFFFF488B7C2448448B7C2440448B742444448B6C2450488B7"
    . "424104C8B6424304883C701393C240F8D97FDFFFFE918FEFFF"
    . "F6690037C240844017C241883442404014401EF8B442404398"
    . "424200100000F854DFBFFFF4C8BBC2440010000E996FCFFFF8"
    . "B44245C8344243C074983C71C8D7406FF8B44243C398424580"
    . "100000F8F87FEFFFF448B7C2440448B742444448B6C2450488"
    . "B7C24488B5C247C488B7424104C8B64243048634424208B542"
    . "418039424080100004C8B9C24600100000B5424708D4801398"
    . "C2468010000418914830F8E9AFDFFFF4585FF7E1D4C8B44240"
    . "84889F08B104883C00401DA4C39C04863D2C64415000075EB4"
    . "883C701393C24894C24200F8DBAFCFFFFE93BFDFFFF0F1F440"
    . "0008B842418010000038424080100002B442430894424308B8"
    . "42410010000038424200100002B44243C39842410010000894"
    . "424440F8F230400008B8424000100008BBC24080100000FAF8"
    . "42410010000448B642440448B6C24544C8B8C24F8000000C74"
    . "42420000000008D04B8034424288944243C8B4424303984240"
    . "80100000F8F2F0100008B8424100100008B6C243CC1E010894"
    . "424408B8424080100008904248D450289EF2B7C24284585ED4"
    . "898450FB61C018D45014898410FB61C014863C5410FB634010"
    . "F8E140100008B442438894424188B44241C8944240431C0EB6"
    . "244395424107E4E418B0C8601F98D5102448D41014863C9410"
    . "FB60C094863D24D63C0410FB61411470FB6040129F10FAFC94"
    . "429DA4129D80FAFD2450FAFC08D1452428D14828D144A39542"
    . "4087207836C241801786B4883C0014139C50F8E9E000000413"
    . "9C44189C27E96418B0C8701F98D5102448D41014863C9410FB"
    . "60C094863D24D63C0410FB61411470FB6040129F10FAFC9442"
    . "9DA4129D80FAFD2450FAFC08D1452428D14828D144A3B54240"
    . "80F864BFFFFFF836C2404010F8940FFFFFF8304240183C5048"
    . "B0424394424300F8DEDFEFFFF83842410010000018BBC24000"
    . "100008B442444017C243C3B8424100100000F8D9CFEFFFFE97"
    . "CFBFFFF0F1F0048634424208B5424400B1424488BBC2460010"
    . "0008D48013B8C24680100008914870F8D56FBFFFF830424018"
    . "3C504894C24208B0424394424300F8D82FEFFFFEB93448B5C2"
    . "428448B84242001000031DB8B84241801000031F6448B94241"
    . "80100004183C30141C1E3074585C08D2C85000000000F8E8CF"
    . "9FFFF4585D27E57488B8C24F80000004C63CE4C038C2430010"
    . "0004863C74531C0488D4C01020FB6110FB641FF440FB661FE6"
    . "BC04B6BD22601C24489E0C1E0044429E001D04139C3430F970"
    . "4014983C0014883C1044539C27FCC01EF4401D683C3014401E"
    . "F399C24200100007595E91CF9FFFF8B8C24200100008B84241"
    . "801000031DB31F6448B8C241801000085C98D2C85000000007"
    . "E7D4585C97E694C63C6488B8C24F80000004863C74D89C24C0"
    . "38424300100004C0394242801000031D2488D4C0102440FB61"
    . "90FB641FF4883C104440FB661FA6BC04B456BDB264101C3448"
    . "9E0C1E0044429E04401D8C1F8074188041241C60410004883C"
    . "2014139D17FC401EF4401CE83C3014401EF399C24200100007"
    . "58383BC2420010000020F8E6CF8FFFF4863B424180100008B9"
    . "C24180100008BBC2420010000488D5601448D67FFBF0100000"
    . "04889D0480394243001000048038424280100004889D58D53F"
    . "D4C8D6A0183BC241801000002488D1C067E7E4989C04D8D5C0"
    . "5004989D94929F04889E90FB610440FB650FF035424284439D"
    . "27C44440FB650014439D27C3A450FB6104439D27C31450FB61"
    . "14439D27C28450FB650FF4439D27C1E450FB650014439D27C1"
    . "4450FB651FF4439D27C0A450FB651014439D27D03C60101488"
    . "3C0014983C1014883C1014983C0014C39D8759383C7014801F"
    . "54889D84139FC0F8562FFFFFFE989F7FFFF31C9E9FAF8FFFF9"
    . "0909090909090909090909090"
    MCode(MyFunc, A_PtrSize=8 ? x64:x32)
    IfLess, Scan0, 10, return
  }
  return, DllCall(&MyFunc, "int",mode, "uint",color
    , "uint",n, "int",offsetX, "int",offsetY, Ptr,Scan0
    , "int",Stride, "int",sx, "int",sy, "int",sw, "int",sh
    , Ptr,&gs, Ptr,&ss, "AStr",text, Ptr,&s1, Ptr,&s0
    , Ptr,&input, "int",num, Ptr,&allpos, "int",allpos_max)
}

xywh2xywh(x1,y1,w1,h1,ByRef x,ByRef y,ByRef w,ByRef h)
{
  SysGet, zx, 76
  SysGet, zy, 77
  SysGet, zw, 78
  SysGet, zh, 79
  left:=x1, right:=x1+w1-1, up:=y1, down:=y1+h1-1
  left:=left<zx ? zx:left, right:=right>zx+zw-1 ? zx+zw-1:right
  up:=up<zy ? zy:up, down:=down>zy+zh-1 ? zy+zh-1:down
  x:=left, y:=up, w:=right-left+1, h:=down-up+1
}

GetBitsFromScreen(x, y, w, h, ByRef Scan0="", ByRef Stride=""
  , ScreenShot=1, ByRef zx="", ByRef zy="", ByRef zw="", ByRef zh="")
{
  static bits, oldx, oldy, oldw, oldh, bpp:=32
  static Ptr:=A_PtrSize ? "UPtr" : "UInt"
  if (ScreenShot or x<oldx or y<oldy
    or x+w>oldx+oldw or y+h>oldy+oldh) and !(w<1 or h<1)
  {
    oldx:=x, oldy:=y, oldw:=w, oldh:=h, ScreenShot:=1
    VarSetCapacity(bits, w*h*4)
  }
  Scan0:=&bits, Stride:=((oldw*bpp+31)//32)*4
  , zx:=oldx, zy:=oldy, zw:=oldw, zh:=oldh
  if (!ScreenShot or w<1 or h<1)
    return
  win:=DllCall("GetDesktopWindow", Ptr)
  hDC:=DllCall("GetWindowDC", Ptr,win, Ptr)
  mDC:=DllCall("CreateCompatibleDC", Ptr,hDC, Ptr)
  ;-------------------------
  VarSetCapacity(bi, 40, 0), NumPut(40, bi, 0, "int")
  NumPut(w, bi, 4, "int"), NumPut(-h, bi, 8, "int")
  NumPut(1, bi, 12, "short"), NumPut(bpp, bi, 14, "short")
  ;-------------------------
  if (hBM:=DllCall("CreateDIBSection", Ptr,mDC, Ptr,&bi
    , "int",0, Ptr "*",ppvBits, Ptr,0, "int",0, Ptr))
  {
    oBM:=DllCall("SelectObject", Ptr,mDC, Ptr,hBM, Ptr)
    DllCall("BitBlt", Ptr,mDC, "int",0, "int",0, "int",w, "int",h
      , Ptr,hDC, "int",x, "int",y, "uint",0x00CC0020|0x40000000)
    DllCall("RtlMoveMemory", Ptr,Scan0, Ptr,ppvBits, Ptr,Stride*h)
    DllCall("SelectObject", Ptr,mDC, Ptr,oBM)
    DllCall("DeleteObject", Ptr,hBM)
  }
  DllCall("DeleteDC", Ptr,mDC)
  DllCall("ReleaseDC", Ptr,win, Ptr,hDC)
}

MCode(ByRef code, hex)
{
  bch:=A_BatchLines
  SetBatchLines, -1
  VarSetCapacity(code, len:=StrLen(hex)//2)
  lls:=A_ListLines=0 ? "Off" : "On"
  ListLines, Off
  Loop, % len
    NumPut("0x" SubStr(hex,2*A_Index-1,2),code,A_Index-1,"uchar")
  ListLines, %lls%
  Ptr:=A_PtrSize ? "UPtr" : "UInt", PtrP:=Ptr . "*"
  DllCall("VirtualProtect",Ptr,&code, Ptr,len,"uint",0x40,PtrP,0)
  SetBatchLines, %bch%
}

base64tobit(s)
{
  Chars:="0123456789+/ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    . "abcdefghijklmnopqrstuvwxyz"
  SetFormat, IntegerFast, d
  StringCaseSense, On
  lls:=A_ListLines=0 ? "Off" : "On"
  ListLines, Off
  Loop, Parse, Chars
  {
    i:=A_Index-1, v:=(i>>5&1) . (i>>4&1)
      . (i>>3&1) . (i>>2&1) . (i>>1&1) . (i&1)
    s:=StrReplace(s,A_LoopField,v)
  }
  ListLines, %lls%
  StringCaseSense, Off
  s:=SubStr(s,1,InStr(s,"1",0,0)-1)
  s:=RegExReplace(s,"[^01]+")
  return, s
}

bit2base64(s)
{
  s:=RegExReplace(s,"[^01]+")
  s.=SubStr("100000",1,6-Mod(StrLen(s),6))
  s:=RegExReplace(s,".{6}","|$0")
  Chars:="0123456789+/ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    . "abcdefghijklmnopqrstuvwxyz"
  SetFormat, IntegerFast, d
  lls:=A_ListLines=0 ? "Off" : "On"
  ListLines, Off
  Loop, Parse, Chars
  {
    i:=A_Index-1, v:="|" . (i>>5&1) . (i>>4&1)
      . (i>>3&1) . (i>>2&1) . (i>>1&1) . (i&1)
    s:=StrReplace(s,v,A_LoopField)
  }
  ListLines, %lls%
  return, s
}

ASCII(s)
{
  if RegExMatch(s,"\$(\d+)\.([\w+/]+)",r)
  {
    s:=RegExReplace(base64tobit(r2),".{" r1 "}","$0`n")
    s:=StrReplace(StrReplace(s,"0","_"),"1","0")
  }
  else s=
  return, s
}

; You can put the text library at the beginning of the script,
; and Use Pic(Text,1) to add the text library to Pic()'s Lib,
; Use Pic("comment1|comment2|...") to get text images from Lib

Pic(comments, add_to_Lib=0)
{
  static Lib:=[]
  SetFormat, IntegerFast, d
  if (add_to_Lib)
  {
    re:="<([^>]*)>[^$]+\$\d+\.[\w+/]+"
    Loop, Parse, comments, |
      if RegExMatch(A_LoopField,re,r)
      {
        s1:=Trim(r1), s2:=""
        Loop, Parse, s1
          s2.="_" . Ord(A_LoopField)
        Lib[s2]:=r
      }
    Lib[""]:=""
  }
  else
  {
    Text:=""
    Loop, Parse, comments, |
    {
      s1:=Trim(A_LoopField), s2:=""
      Loop, Parse, s1
        s2.="_" . Ord(A_LoopField)
      Text.="|" . Lib[s2]
    }
    return, Text
  }
}

PicN(Number)
{
  return, Pic( RegExReplace(Number, ".", "|$0") )
}

; Use PicX(Text) to automatically cut into multiple characters
; Can't be used in ColorPos mode, because it can cause position errors

PicX(Text)
{
  if !RegExMatch(Text,"\|([^$]+)\$(\d+)\.([\w+/]+)",r)
    return, Text
  w:=r2, v:=base64tobit(r3), Text:=""
  c:=StrLen(StrReplace(v,"0"))<=StrLen(v)//2 ? "1":"0"
  wz:=RegExReplace(v,".{" w "}","$0`n")
  SetFormat, IntegerFast, d
  While InStr(wz,c)
  {
    While !(wz~="m`n)^" c)
      wz:=RegExReplace(wz,"m`n)^.")
    i:=0
    While (wz~="m`n)^.{" i "}" c)
      i++
    v:=RegExReplace(wz,"m`n)^(.{" i "}).*","$1")
    wz:=RegExReplace(wz,"m`n)^.{" i "}")
    if (v!="")
      Text.="|" r1 "$" i "." bit2base64(v)
  }
  return, Text
}

; Screenshot and retained as the last screenshot.

ScreenShot(x1="", y1="", x2="", y2="")
{
  if (x1+y1+x2+y2="")
    n:=150000, x:=y:=-n, w:=h:=2*n
  else
    x:=(x1<x2 ? x1:x2), y:=(y1<y2 ? y1:y2)
    , w:=Abs(x2-x1)+1, h:=Abs(y2-y1)+1
  xywh2xywh(x,y,w,h,x,y,w,h)
  GetBitsFromScreen(x,y,w,h)
}

; Get the RGB color of a point from the last screenshot.
; If the point to get the color is beyond the range of
; the last screenshot, an empty string will return.

ScreenShot_GetColor(x,y)
{
  local  ; Unaffected by Super-global variables
  GetBitsFromScreen(0,0,0,0,Scan0,Stride,0,zx,zy,zw,zh)
  return, (x<zx or x>zx+zw-1 or y<zy or y>zy+zh-1 or !Stride)
    ? "" : Format("0x{:06X}",NumGet(Scan0
    +(y-zy)*Stride+(x-zx)*4,"uint")&0xFFFFFF)
}

; Identify a line of text or verification code
; based on the result returned by FindText()
; Return Association array {ocr:Text, x:X, y:Y}

OcrOK(ok, offsetX=20, offsetY=20)
{
  ocr_Text:=ocr_X:=ocr_Y:=min_X:=""
  For k,v in ok
    x:=v.1
    , min_X:=(A_Index=1 or x<min_X ? x : min_X)
    , max_X:=(A_Index=1 or x>max_X ? x : max_X)
  While (min_X!="" and min_X<=max_X)
  {
    LeftX:=""
    For k,v in ok
    {
      x:=v.1, y:=v.2, w:=v.3, h:=v.4
      if (x<min_X) or Abs(y-ocr_Y)>offsetY
        Continue
      ; Get the leftmost X coordinates
      if (LeftX="" or x<LeftX)
        LeftX:=x, LeftY:=y, LeftW:=w, LeftH:=h, LeftOCR:=v.id
      else if (x=LeftX)
      {
        Loop, 100
        {
          err:=(A_Index-1)/100+0.000001
          if FindText(LeftX,LeftY,LeftX+LeftW-1,LeftY+LeftH-1,err,err,Text,0)
            Break
          if FindText(x, y, x+w-1, y+h-1, err, err, Text, 0)
          {
            LeftX:=x, LeftY:=y, LeftW:=w, LeftH:=h, LeftOCR:=v.id
            Break
          }
        }
      }
    }
    if (ocr_X="")
      ocr_X:=LeftX, ocr_Y:=LeftY
    ; If the interval exceeds the set value, add "*" to the result
    ocr_Text.=(ocr_Text!="" and LeftX-min_X>offsetX ? "*":"") . LeftOCR
    ; Update min_X for next search
    min_X:=LeftX+LeftW
  }
  return, {ocr:ocr_Text, x:ocr_X, y:ocr_Y}
}

; Sort the results returned by FindText() from left to right
; and top to bottom, ignore slight height difference

SortOK(ok, dy=10)
{
  if !IsObject(ok)
    return, ok
  SetFormat, IntegerFast, d
  ypos:=[]
  For k,v in ok
  {
    x:=v.x, y:=v.y, add:=1
    For k2,v2 in ypos
      if Abs(y-v2)<=dy
      {
        y:=v2, add:=0
        Break
      }
    if (add)
      ypos.Push(y)
    n:=(y*150000+x) "." k, s:=A_Index=1 ? n : s "-" n
  }
  Sort, s, N D-
  ok2:=[]
  Loop, Parse, s, -
    ok2.Push( ok[(StrSplit(A_LoopField,".")[2])] )
  return, ok2
}

; Reordering according to the nearest distance

SortOK2(ok, px, py)
{
  if !IsObject(ok)
    return, ok
  SetFormat, IntegerFast, d
  For k,v in ok
  {
    x:=v.1+v.3//2, y:=v.2+v.4//2
    n:=((x-px)**2+(y-py)**2) "." k
    s:=A_Index=1 ? n : s "-" n
  }
  Sort, s, N D-
  ok2:=[]
  Loop, Parse, s, -
    ok2.Push( ok[(StrSplit(A_LoopField,".")[2])] )
  return, ok2
}

; Prompt mouse position in remote assistance

MouseTip(x="", y="")
{
  if (x="")
  {
    VarSetCapacity(pt,16,0), DllCall("GetCursorPos","ptr",&pt)
    x:=NumGet(pt,0,"uint"), y:=NumGet(pt,4,"uint")
  }
  x:=Round(x-10), y:=Round(y-10), w:=h:=2*10+1
  ;-------------------------
  Gui, _MouseTip_: +AlwaysOnTop -Caption +ToolWindow +Hwndmyid +E0x08000000
  Gui, _MouseTip_: Show, Hide w%w% h%h%
  ;-------------------------
  dhw:=A_DetectHiddenWindows
  DetectHiddenWindows, On
  d:=4, i:=w-d, j:=h-d
  s=0-0 %w%-0 %w%-%h% 0-%h% 0-0
  s=%s%  %d%-%d% %i%-%d% %i%-%j% %d%-%j% %d%-%d%
  WinSet, Region, %s%, ahk_id %myid%
  DetectHiddenWindows, %dhw%
  ;-------------------------
  Gui, _MouseTip_: Show, NA x%x% y%y%
  Loop, 4
  {
    Gui, _MouseTip_: Color, % A_Index & 1 ? "Red" : "Blue"
    Sleep, 500
  }
  Gui, _MouseTip_: Destroy
}


/***** C source code of machine code *****

int __attribute__((__stdcall__)) PicFind(
  int mode, unsigned int c, unsigned int n
  , int offsetX, int offsetY, unsigned char * Bmp
  , int Stride, int sx, int sy, int sw, int sh
  , unsigned char * gs, char * ss, char * text
  , int * s1, int * s0, int * input, int num
  , unsigned int * allpos, int allpos_max)
{
  int o, i, j, x, y, r, g, b, rr, gg, bb, max, e1, e0, ok;
  int o1, x1, y1, w1, h1, sx1, sy1, len1, len0, err1, err0;
  int o2, x2, y2, w2, h2, sx2, sy2, len21, len20, err21, err20;
  int r_min, r_max, g_min, g_max, b_min, b_max;
  //----------------------
  ok=0; w1=input[1]; h1=input[2];
  len1=input[3]; len0=input[4];
  err1=input[5]; err0=input[6];
  max=len1>len0 ? len1 : len0;
  //----------------------
  // Generate Lookup Table
  for (j=0; j<num; j+=7)
  {
    o=o1=o2=input[j]; w2=input[j+1]; h2=input[j+2];
    for (y=0; y<h2; y++)
    {
      for (x=0; x<w2; x++)
      {
        i=(mode==3) ? y*Stride+x*4 : y*sw+x;
        if (text[o++]=='1')
          s1[o1++]=i;
        else
          s0[o2++]=i;
      }
    }
  }
  // Color Position Mode
  // This mode is not support combination lookup
  // only used to recognize multicolored Verification Code
  if (mode==3)
  {
    sx1=sx+sw-w1; sy1=sy+sh-h1;
    for (y=sy; y<=sy1; y++)
    {
      for (x=sx; x<=sx1; x++)
      {
        o=y*Stride+x*4; e1=err1; e0=err0;
        j=o+c; rr=Bmp[2+j]; gg=Bmp[1+j]; bb=Bmp[j];
        for (i=0; i<max; i++)
        {
          if (i<len1)
          {
            j=o+s1[i]; r=Bmp[2+j]-rr; g=Bmp[1+j]-gg; b=Bmp[j]-bb;
            if (3*r*r+4*g*g+2*b*b>n && (--e1)<0)
              goto NoMatch3;
          }
          if (i<len0)
          {
            j=o+s0[i]; r=Bmp[2+j]-rr; g=Bmp[1+j]-gg; b=Bmp[j]-bb;
            if (3*r*r+4*g*g+2*b*b<=n && (--e0)<0)
              goto NoMatch3;
          }
        }
        allpos[ok++]=y<<16|x;
        if (ok>=allpos_max)
          goto Return1;
        NoMatch3:
        continue;
      }
    }
    goto Return1;
  }
  // Generate Two Value Image
  o=sy*Stride+sx*4; j=Stride-4*sw; i=0;
  if (mode==0)  // Color Mode
  {
    rr=(c>>16)&0xFF; gg=(c>>8)&0xFF; bb=c&0xFF;
    for (y=0; y<sh; y++, o+=j)
      for (x=0; x<sw; x++, o+=4, i++)
      {
        r=Bmp[2+o]-rr; g=Bmp[1+o]-gg; b=Bmp[o]-bb;
        ss[i]=(3*r*r+4*g*g+2*b*b<=n) ? 1:0;
      }
  }
  else if (mode==1)  // Gray Threshold Mode
  {
    c=(c+1)*128;
    for (y=0; y<sh; y++, o+=j)
      for (x=0; x<sw; x++, o+=4, i++)
        ss[i]=(Bmp[2+o]*38+Bmp[1+o]*75+Bmp[o]*15<c) ? 1:0;
  }
  else if (mode==2)  // Gray Difference Mode
  {
    for (y=0; y<sh; y++, o+=j)
    {
      for (x=0; x<sw; x++, o+=4, i++)
      {
        gs[i]=(Bmp[2+o]*38+Bmp[1+o]*75+Bmp[o]*15)>>7;
        ss[i]=0;
      }
    }
    sx1=sw-2; sy1=sh-2;
    for (y=1; y<=sy1; y++)
      for (x=1; x<=sx1; x++)
      {
        i=y*sw+x; j=gs[i]+c;
        if ( gs[i-1]>j || gs[i+1]>j
          || gs[i-sw]>j || gs[i+sw]>j
          || gs[i-sw-1]>j || gs[i-sw+1]>j
          || gs[i+sw-1]>j || gs[i+sw+1]>j )
            ss[i]=1;
      }
  }
  else // (mode==4) Color Difference Mode
  {
    r=(c>>16)&0xFF; g=(c>>8)&0xFF; b=c&0xFF;
    rr=(n>>16)&0xFF; gg=(n>>8)&0xFF; bb=n&0xFF;
    r_min=r-rr; g_min=g-gg; b_min=b-bb;
    r_max=r+rr; g_max=g+gg; b_max=b+bb;
    for (y=0; y<sh; y++, o+=j)
      for (x=0; x<sw; x++, o+=4, i++)
      {
        r=Bmp[2+o]; g=Bmp[1+o]; b=Bmp[o];
        ss[i]=(r>=r_min && r<=r_max
            && g>=g_min && g<=g_max
            && b>=b_min && b<=b_max) ? 1:0;
      }
  }
  // Start Lookup
  sx1=sw-w1; sy1=sh-h1;
  for (y=0; y<=sy1; y++)
  {
    for (x=0; x<=sx1; x++)
    {
      o=y*sw+x; e1=err1; e0=err0;
      if (e0==len0)
      {
        for (i=0; i<len1; i++)
          if (ss[o+s1[i]]!=1 && (--e1)<0)
            goto NoMatch1;
      }
      else
      {
        for (i=0; i<max; i++)
        {
          if (i<len1 && ss[o+s1[i]]!=1 && (--e1)<0)
            goto NoMatch1;
          if (i<len0 && ss[o+s0[i]]!=0 && (--e0)<0)
            goto NoMatch1;
        }
      }
      //------------------
      // Combination lookup
      if (num>7)
      {
        x1=x+w1-1; y1=y-offsetY; if (y1<0) y1=0;
        for (j=7; j<num; j+=7)
        {
          o2=input[j]; w2=input[j+1]; h2=input[j+2];
          len21=input[j+3]; len20=input[j+4];
          err21=input[j+5]; err20=input[j+6];
          sx2=sw-w2; i=x1+offsetX; if (i<sx2) sx2=i;
          sy2=sh-h2; i=y+offsetY; if (i<sy2) sy2=i;
          for (x2=x1; x2<=sx2; x2++)
          {
            for (y2=y1; y2<=sy2; y2++)
            {
              o1=y2*sw+x2; e1=err21; e0=err20;
              for (i=0; i<len21; i++)
              {
                if (ss[o1+s1[o2+i]]!=1 && (--e1)<0)
                  goto NoMatch2;
              }
              if (e0!=len20)
              {
                for (i=0; i<len20; i++)
                  if (ss[o1+s0[o2+i]]!=0 && (--e0)<0)
                    goto NoMatch2;
              }
              goto MatchOK;
              NoMatch2:
              continue;
            }
          }
          goto NoMatch1;
          MatchOK:
          x1=x2+w2-1;
        }
      }
      //------------------
      allpos[ok++]=(sy+y)<<16|(sx+x);
      if (ok>=allpos_max)
        goto Return1;
      // Clear the image that has been found
      for (i=0; i<len1; i++)
        ss[o+s1[i]]=0;
      NoMatch1:
      continue;
    }
  }
  Return1:
  return ok;
}

*/

;================= The End =================

;
fiddled around with it a bit kind of got it working a bit

Code: Select all

; #Include <FindText>
+a::

CoordMode, Mouse, Screen
MouseGetPos, x, y

Text:="|<sadfsadf>#[email protected]$42.0000000000000003zzzs000000000000000U"
if (ok:=FindText(x-50, y-30, x+50, y+30, 0, 0, Text)) ; 150 can be adjusted by yourself
;if (ok:=FindText(409-150000, 1904-150000, 150000, 150000, 0, 0, Text))

CoordMode, Mouse, Screen
MouseGetPos, x, y
{
  x:=ok.1.1, y:=ok.1.2, w:=ok.1.3, h:=ok.1.4
  mousemove, x, y+2
}


;===== Copy The Following Functions To Your Own Code Just once =====
So guess I answered 2 of my questions, you don't need the actual text copied from image only the image code number thingie that's in the text:=.....
and you can paste the code infront of all other code, pasting at the end not necessary.

Currently having some issues with it finding the image sometimes sometimes not. It's a line on different backgrounds and at times it is bit smaller and bigger (thinner thicker), not sure if I can improve the success rate of finding the image. Cool that the search around mousepointer seems to be working not though and that it finds image sometimes, two steps in right direction :xmas:

The lines have 2 different colors I'd like it to search for though, so maybe that could be a way for it to find them easier if possible?

edit: I checked it some more now, it accurately seems to find the lines now IF the lines are a certain length then when the length increases it stops finding them :crazy:

Any tips and tricks to get around this?

edit2: I solved it by changing the linesearch from this
__________________________________________
__________________________________________
__________00000000000000000000000_________
__________________________________________
__________________________________________

to this

00000000000000000000
00000_______________
00000000000000000000

so it only searches the side of the line I want. Can't thank you enough this will help tremendously!! !! !!! :beer: :clap:

So for noobs reading this if you want to test different captured images all you do is capture the image like normal using the ahk "app" on the first page (the code on openingpost of this thread obviously) then go into your saved script and swap this line after the arrow below to your new text image code you captured. If the image doesn't show click inside the code underneath (the same code as after arrow).
Text:="|<sadfsadf> ----> #[email protected]$42.0000000000000003zzzs000000000000000U"

my full code now looks like this

Code: Select all

; #Include <FindText>
ö::

CoordMode, Mouse, Screen
MouseGetPos, x, y

Text:="|<sadfsadf>#[email protected]$42.0000000000000003zzzs000000000000000U"
if (ok:=FindText(x-34, y-24, x+34, y+24, 0, 0, Text)) ; 150 can be adjusted by yourself
;if (ok:=FindText(409-150000, 1904-150000, 150000, 150000, 0, 0, Text))

CoordMode, Mouse, Screen
MouseGetPos, x, y
{
  x:=ok.1.1, y:=ok.1.2, w:=ok.1.3, h:=ok.1.4
  mousemove, x+9, y+2
}


;===== Copy The Following Functions To Your Own Code Just once =====


;--------------------------------
; FindText - Capture screen image into text and then find it
;--------------------------------
; X1, Y1 --> the search scope's upper left corner coordinates
; X2, Y2 --> the search scope's lower right corner coordinates
; err1, err0 --> character "0" or "_" fault-tolerant in percentage
; 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 the value is 1, Join all Text for combination lookup
; offsetX, offsetY --> Set the Max text offset for combination lookup
; ruturn --> the function returns a second-order array
; containing all lookup results, Any result is an associative array
; {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.
;--------------------------------

FindText( x1, y1, x2, y2, err1, err0, text, ScreenShot=1
  , FindAll=1, JoinText=0, offsetX=20, offsetY=10 )
{
  local  ; Unaffected by Super-global variables
  bch:=A_BatchLines
  SetBatchLines, -1
  x:=(x1<x2 ? x1:x2), y:=(y1<y2 ? y1:y2)
  , w:=Abs(x2-x1)+1, h:=Abs(y2-y1)+1
  , xywh2xywh(x,y,w,h,x,y,w,h)
  if (w<1 or h<1)
  {
    SetBatchLines, %bch%
    return, 0
  }
  ;-------------------------------
  GetBitsFromScreen(x,y,w,h,Scan0,Stride,ScreenShot,zx,zy)
  ;-------------------------------
  sx:=x-zx, sy:=y-zy, sw:=w, sh:=h
  , arr:=[], info:=[], allv:=""
  Loop, Parse, text, |
  {
    v:=A_LoopField
    IfNotInString, v, $, Continue
    comment:="", e1:=err1, e0:=err0, set_e1_e0:=0
    ; You Can Add Comment Text within The <>
    if RegExMatch(v,"<([^>]*)>",r)
      v:=StrReplace(v,r), comment:=Trim(r1)
    ; You can Add two fault-tolerant in the [], separated by commas
    if RegExMatch(v,"\[([^\]]*)]",r)
    {
      v:=StrReplace(v,r), r1.=","
      StringSplit, r, r1, `,
      e1:=r1, e0:=r2, set_e1_e0:=1
    }
    StringSplit, r, v, $
    color:=r1, v:=r2
    StringSplit, r, v, .
    w1:=r1, v:=base64tobit(r2), h1:=StrLen(v)//w1
    if (r0<2 or h1<1 or w1>sw or h1>sh or StrLen(v)!=w1*h1)
      Continue
    mode:=InStr(color,"-") ? 4 : InStr(color,"#") ? 3
      : InStr(color,"**") ? 2 : InStr(color,"*") ? 1 : 0
    if (mode=4)
    {
      color:=StrReplace(color,"0x")
      StringSplit, r, color, -
      color:="0x" . r1, n:="0x" . r2
    }
    else
    {
      color:=RegExReplace(color,"[*#]") . "@"
      StringSplit, r, color, @
      color:=(mode=3 ? ((r1-1)//w1)*Stride+Mod(r1-1,w1)*4 : r1)
      , n:=Round(r2,2)+(!r2), n:=Floor(9*255*255*(1-n)*(1-n))
    }
    StrReplace(v,"1","",len1), len0:=StrLen(v)-len1
    , e1:=Round(len1*e1), e0:=Round(len0*e0)
    , info.Push( [StrLen(allv),w1,h1,len1,len0,e1,e0
    , mode,color,n,comment,set_e1_e0] ), allv.=v
  }
  if (allv="" or !Stride)
  {
    SetBatchLines, %bch%
    return, 0
  }
  num:=info.MaxIndex(), VarSetCapacity(input, num*7*4)
  , VarSetCapacity(gs, sw*sh)
  , VarSetCapacity(ss, sw*sh), k:=StrLen(allv)*4
  , VarSetCapacity(s1, k), VarSetCapacity(s0, k)
  , allpos_max:=(FindAll ? 1024 : 1)
  , VarSetCapacity(allpos, allpos_max*4)
  ;-------------------------------------
  Loop, 2
  {
  if (num>1 and err1=0 and err0=0)
  {
    err1:=err0:=0.05
    For i,j in info
      if (!j.12)
        j.6:=Round(j.4*err1), j.7:=Round(j.5*err0)
  }
  if (JoinText)
  {
    j:=info[1], mode:=j.8, color:=j.9, n:=j.10
    , w1:=-1, h1:=j.3, comment:="", k:=0
    Loop, % num
    {
      j:=info[A_Index], w1+=j.2+1, comment.=j.11
      Loop, 7
        NumPut(j[A_Index], input, 4*(k++), "int")
    }
    ok:=PicFind( mode,color,n,offsetX,offsetY
      ,Scan0,Stride,sx,sy,sw,sh,gs,ss,allv,s1,s0
      ,input,num*7,allpos,allpos_max )
    Loop, % ok
      pos:=NumGet(allpos, 4*(A_Index-1), "uint")
      , rx:=(pos&0xFFFF)+zx, ry:=(pos>>16)+zy
      , arr.Push( {1:rx, 2:ry, 3:w1, 4:h1
      , x:rx+w1//2, y:ry+h1//2, id:comment} )
  }
  else
  {
    For i,j in info
    {
      mode:=j.8, color:=j.9, n:=j.10, comment:=j.11
      , w1:=j.2, h1:=j.3, v:=SubStr(allv, j.1+1, w1*h1)
      Loop, 7
        NumPut(j[A_Index], input, 4*(A_Index-1), "int")
      NumPut(0, input, "int")
      ok:=PicFind( mode,color,n,offsetX,offsetY
        ,Scan0,Stride,sx,sy,sw,sh,gs,ss,v,s1,s0
        ,input,7,allpos,allpos_max )
      Loop, % ok
        pos:=NumGet(allpos, 4*(A_Index-1), "uint")
        , rx:=(pos&0xFFFF)+zx, ry:=(pos>>16)+zy
        , arr.Push( {1:rx, 2:ry, 3:w1, 4:h1
        , x:rx+w1//2, y:ry+h1//2, id:comment} )
      if (ok and !FindAll)
        Break
    }
  }
  if (num=1 and err1=0 and err0=0 and !arr.MaxIndex())
  {
    err1:=err0:=0.05, k:=0
    For i,j in info
      if (!j.12)
        j.6:=Round(j.4*err1), j.7:=Round(j.5*err0), k:=1
    IfEqual, k, 0, Break
  }
  else Break
  }
  SetBatchLines, %bch%
  return, arr.MaxIndex() ? arr:0
}

PicFind(mode, color, n, offsetX, offsetY
  , Scan0, Stride, sx, sy, sw, sh
  , ByRef gs, ByRef ss, ByRef text, ByRef s1, ByRef s0
  , ByRef input, num, ByRef allpos, allpos_max)
{
  static MyFunc, Ptr:=A_PtrSize ? "UPtr" : "UInt"
  static init:=PicFind(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
  if (!MyFunc)
  {
    x32:="5557565383EC788B8424CC0000008BBC24CC000000C7442"
    . "424000000008B40048B7F148944243C8B8424CC000000897C2"
    . "42C8BBC24CC0000008B40088B7F18894424348B8424CC00000"
    . "0897C24308B400C89C6894424288B8424CC0000008B401039C"
    . "6894424200F4DC68944241C8B8424D000000085C00F8E15010"
    . "0008BB424CC0000008B44242489F78B0C868B7486048B44870"
    . "88974241085C0894424180F8ED700000089CD894C2414C7442"
    . "40C00000000C744240800000000C744240400000000890C248"
    . "D76008DBC27000000008B5C24108B7424088B4C24148B54240"
    . "C89DF89F029F101F78BB424C000000001CE85DB7E5E8B0C248"
    . "9EB893C2489D7EB198BAC24C800000083C70483C00189548D0"
    . "083C101390424742C83BC248C0000000389FA0F45D0803C063"
    . "175D48BAC24C400000083C70483C00189549D0083C30139042"
    . "475D48B7424100174241489DD890C2483442404018BB424B00"
    . "000008B442404017424088BBC24A4000000017C240C3944241"
    . "80F8554FFFFFF83442424078B442424398424D00000000F8FE"
    . "BFEFFFF83BC248C000000030F84A00600008B8424A40000008"
    . "BB424A80000000FAF8424AC0000008BBC248C0000008D2CB08"
    . "B8424B00000008BB424A4000000F7D885FF8D0486894424100"
    . "F84F702000083BC248C000000010F845F08000083BC248C000"
    . "000020F84130900008B8424900000008B9C24940000000FB6B"
    . "C24940000000FB6B42490000000C744241800000000C744242"
    . "400000000C1E8100FB6DF0FB6D08B84249000000089D10FB6C"
    . "4894424088B842494000000C1E8100FB6C029C101D08904248"
    . "B442408894C24408B4C240801D829D9894424088D043E894C2"
    . "40489F129F9894424148BBC24B40000008B8424B0000000894"
    . "C240C89E98B6C2440C1E00285FF894424380F8EBA0000008BB"
    . "424B000000085F60F8E910000008B8424A00000008B5424240"
    . "39424BC00000001C8034C243889CF894C244003BC24A000000"
    . "0EB3D8D76008DBC2700000000391C247C3D394C24047F37394"
    . "C24087C3189F30FB6F33974240C0F9EC3397424140F9DC183C"
    . "00483C20121D9884AFF39F8741E0FB658020FB648010FB6303"
    . "9DD7EBE31C983C00483C201884AFF39F875E28BBC24B000000"
    . "0017C24248B4C24408344241801034C24108B442418398424B"
    . "40000000F8546FFFFFF8B8424B00000002B44243C8944240C8"
    . "B8424B40000002B442434894424600F884D0900008B4424288"
    . "BBC24C40000008B74243CC744241000000000C744243800000"
    . "000C7442434000000008D3C8789C583EE01897C246C8974247"
    . "48B44240C85C00F88E70000008B7C24388B8424AC000000BE0"
    . "0000000C704240000000001F8C1E0108944246889F82B84249"
    . "C0000000F49F08B84249C000000897424640FAFB424B000000"
    . "001F8894424708974245C8DB6000000008B04240344241089C"
    . "1894424088B442430394424200F84AA0100008B5C241C89C60"
    . "38C24BC00000031C08B54242C85DB0F8EC8010000897424048"
    . "B7C2420EB2D39C77E1C8BB424C80000008B1C8601CB803B007"
    . "40B836C240401782B8D74260083C0013944241C0F849101000"
    . "039C57ECF8BB424C40000008B1C8601CB803B0174BE83EA017"
    . "9B9830424018B04243944240C0F8D68FFFFFF83442438018BB"
    . "424B00000008B44243801742410394424600F8DEFFEFFFF8B4"
    . "C243483C47889C85B5E5F5DC250008B8424900000008BB424B"
    . "4000000C744240C00000000C744241400000000C1E8100FB6C"
    . "08904248B8424900000000FB6C4894424040FB684249000000"
    . "0894424088B8424B0000000C1E00285F68944242489E88BAC2"
    . "4940000000F8E24FEFFFF8B9C24B000000085DB7E758B9C24A"
    . "00000008B7424148BBC24A000000003B424BC00000001C3034"
    . "424248944241801C78D76008DBC27000000000FB643020FB64"
    . "B012B04242B4C24040FB6132B5424080FAFC00FAFC98D04400"
    . "FAFD28D04888D045039C50F930683C30483C60139DF75C98BB"
    . "C24B0000000017C24148B4424188344240C01034424108B742"
    . "40C39B424B40000000F8566FFFFFFE985FDFFFF85ED7E358B7"
    . "424088BBC24BC00000031C08B54242C8D1C378BB424C400000"
    . "08B0C8601D9803901740983EA010F8890FEFFFF83C00139C57"
    . "5E683BC24D0000000070F8EAA0100008B442474030424C7442"
    . "44007000000896C2444894424288B8424CC00000083C020894"
    . "4243C8B44243C8B9424B00000008B7C24288B0029C28944245"
    . "08B84249800000001F839C20F4EC289C68944244C39FE0F8C0"
    . "90100008B44243C8B700C8B78148B6808897424148B7010897"
    . "C245489C7897424248BB424B40000002B700489F08B7424703"
    . "9C60F4EC68BB424C4000000894424188B47FC89442404C1E00"
    . "201C6038424C8000000894424588B4424648B7C2428037C245"
    . "C3B442418894424040F8F8700000085ED7E268B8C24BC00000"
    . "08B54242431C08D1C398B0C8601D9803901740583EA01784A8"
    . "3C00139C575EA8B4424148B4C245439C8747E85C07E7A8B9C2"
    . "4BC000000896C244831C08B6C245801FBEB0983C0013944241"
    . "4745C8B54850001DA803A0074EC83E90179E78B6C244890834"
    . "424040103BC24B00000008B442404394424180F8D79FFFFFF8"
    . "3442428018B4424283944244C0F8D4CFFFFFF830424018B6C2"
    . "4448B04243944240C0F8D7EFCFFFFE911FDFFFF8B4424288B7"
    . "4245083442440078344243C1C8D4430FF894424288B4424403"
    . "98424D00000000F8F7FFEFFFF8B6C24448B7C24348B0424038"
    . "424A80000008BB424D40000000B4424688D4F01398C24D8000"
    . "0008904BE0F8ED8FCFFFF85ED7E278B7424088BBC24BC00000"
    . "08B8424C40000008D1C378B74246C8B1083C00401DA39F0C60"
    . "20075F283042401894C24348B04243944240C0F8DDEFBFFFFE"
    . "971FCFFFF89F68DBC27000000008B8424B0000000038424A80"
    . "000002B44243C894424248B8424AC000000038424B40000002"
    . "B442434398424AC000000894424380F8F520400008B8424A40"
    . "000008BB424A80000000FAF8424AC000000C74424180000000"
    . "08D04B0038424900000008BB424A0000000894424348B44242"
    . "4398424A80000000F8F2B0100008B8424AC000000C1E010894"
    . "4243C8B442434894424148B8424A8000000894424088B44241"
    . "40FB67C060289C52BAC2490000000893C240FB67C0601897C2"
    . "4040FB63C068B44241C85C00F8E140100008B4424308944241"
    . "08B44242C8944240C31C0EB5D394424207E4A8B9C24C800000"
    . "08B0C8301E90FB6540E020FB65C0E012B14242B5C24040FB60"
    . "C0E0FAFD20FAFDB29F98D14520FAFC98D149A8D144A3994249"
    . "4000000720C836C2410017865908D74260083C0013944241C0"
    . "F84A3000000394424287E9D8B9C24C40000008B0C8301E90FB"
    . "6540E020FB65C0E012B14242B5C24040FB60C0E0FAFD20FAFD"
    . "B29F98D14520FAFC98D149A8D144A3B9424940000000F865BF"
    . "FFFFF836C240C010F8950FFFFFF834424080183442414048B4"
    . "42408394424240F8DF6FEFFFF838424AC000000018BBC24A40"
    . "000008B442438017C24343B8424AC0000000F8DA0FEFFFF8B4"
    . "C241883C4785B5E89C85F5DC250008D7426008B7C24188B442"
    . "43C0B4424088B9C24D40000008D4F013B8C24D80000008904B"
    . "B0F8D84FAFFFF894C2418EB848B8424900000008B8C24B4000"
    . "000C7042400000000C74424040000000083C001C1E00789C78"
    . "B8424B0000000C1E00285C98944240889E889FD0F8ECFF8FFF"
    . "F8B9424B000000085D27E5F8B8C24A00000008B5C2404039C2"
    . "4BC00000001C1034424088944240C038424A000000089C70FB"
    . "651020FB641010FB6316BC04B6BD22601C289F0C1E00429F00"
    . "1D039C50F970383C10483C30139F975D58BBC24B0000000017"
    . "C24048B44240C83042401034424108B342439B424B40000007"
    . "582E94CF8FFFF8B8424B0000000C7042400000000C74424040"
    . "0000000C1E002894424088B8424B400000085C00F8E9200000"
    . "08B8424B000000085C07E6F8B8C24A00000008B5C24048BB42"
    . "4B800000001E9036C240801DE039C24BC000000896C240C03A"
    . "C24A00000000FB651020FB6410183C1040FB679FC83C60183C"
    . "3016BC04B6BD22601C289F8C1E00429F801D0C1F8078846FFC"
    . "643FF0039CD75CC8BB424B0000000017424048B6C240C83042"
    . "401036C24108B0424398424B40000000F856EFFFFFF83BC24B"
    . "4000000020F8E80F7FFFF8B8424BC000000038424B00000008"
    . "BAC24B800000003AC24B0000000C7442404010000008944240"
    . "88B8424B400000083E8018944240C8B8424B000000083C0018"
    . "944241083BC24B0000000027E798B44241089E92B8C24B0000"
    . "0008B5C240889EA8D34288D45FE8904240FB642010FB63A038"
    . "4249000000039F87C360FB67A0239F87C2E0FB6790139F87C2"
    . "60FB63E39F87C1F0FB63939F87C180FB6790239F87C100FB67"
    . "EFF39F87C080FB67E0139F87D04C643010183C20183C30183C"
    . "10183C6013B0C2475A3834424040103AC24B00000008B44240"
    . "48BB424B0000000017424083944240C0F8558FFFFFFE98FF6F"
    . "FFF83C47831C95B89C85E5F5DC2500090909090909090"
    x64:="4157415641554154555756534881EC88000000488B84245"
    . "0010000488BB42450010000448B94245801000089542428448"
    . "944240844898C24E80000008B40048B76144C8BBC244001000"
    . "04C8BB42448010000C74424180000000089442430488B84245"
    . "00100008974241C488BB424500100008B40088B76188944243"
    . "C488B842450010000897424388B400C89C789442440488B842"
    . "4500100008B401039C7894424100F4DC74585D289442454488"
    . "B84245001000048894424200F8ECB000000488B442420448B0"
    . "8448B68048B400885C0894424040F8E940000004489CE44890"
    . "C244531E431FF31ED0F1F8400000000004585ED7E614863142"
    . "4418D5C3D0089F848039424380100004589E0EB1D0F1F0083C"
    . "0014D63D94183C0044183C1014883C20139C34789149E74288"
    . "3F9034589C2440F45D0803A3175D783C0014C63DE4183C0048"
    . "3C6014883C20139C34789149F75D844012C2483C50103BC241"
    . "80100004403A42400010000396C24047582834424180748834"
    . "424201C8B442418398424580100000F8F35FFFFFF83F9030F8"
    . "43D0600008B8424000100008BBC24080100000FAF842410010"
    . "0008BB424000100008D3CB88B842418010000F7D885C9448D2"
    . "C860F841101000083F9010F842008000083F9020F84BF08000"
    . "08B742428C744240400000000C74424180000000089F0440FB"
    . "6CEC1E8104589CC0FB6D84889F08B7424080FB6D44189DB89F"
    . "0440FB6C64889F1C1E8100FB6CD89D60FB6C08D2C0A8B94242"
    . "00100004129C301C3438D040129CE4529C48904248B8424180"
    . "10000C1E00285D2894424080F8E660100004C89BC244001000"
    . "0448BBC24180100004585FF0F8E91040000488B8C24F800000"
    . "04863C74C6354241831D24C03942430010000488D440102EB3"
    . "A0F1F80000000004439C37C4039CE7F3C39CD7C384539CC410"
    . "F9EC044390C240F9DC14421C141880C124883C2014883C0044"
    . "139D70F8E2D040000440FB6000FB648FF440FB648FE4539C37"
    . "EBB31C9EBD58B5C2428448B8C242001000031ED4531E44889D"
    . "84189DB0FB6DB0FB6F48B84241801000041C1EB10450FB6DBC"
    . "1E0024585C98904240F8EA10000004C89BC24400100004C89B"
    . "42448010000448B7C2408448BB424180100004585F67E60488"
    . "B8C24F80000004D63D44C039424300100004863C74531C94C8"
    . "D440102410FB600410FB648FF410FB650FE4429D829F10FAFC"
    . "029DA0FAFC98D04400FAFD28D04888D04504139C7430F93040"
    . "A4983C1014983C0044539CE7FC4033C244501F483C5014401E"
    . "F39AC2420010000758C4C8BBC24400100004C8BB4244801000"
    . "08B8424180100002B4424308904248B8424200100002B44243"
    . "C894424680F88540800008B7C24404D89F5488BAC243001000"
    . "0448B7424104C89FEC74424040000000048C74424280000000"
    . "0C74424200000000089F883E801498D4487044189FF4889442"
    . "4088B44243083E801894424788B042485C00F88D9000000488"
    . "B5C24288B8424100100004D89EC448B6C245401D8C1E010894"
    . "4247089D82B8424F000000089C7B8000000000F49C731FF894"
    . "4246C0FAF842418010000894424648B8424F000000001D8894"
    . "42474908B442404897C24188D1C388B4424384139C60F84AB0"
    . "000004189C131C04585ED448B44241C7F36E9C30000000F1F4"
    . "0004139CE7E1B418B148401DA4863D2807C150000740B4183E"
    . "901782E0F1F4400004883C0014139C50F8E920000004139C78"
    . "9C17ECC8B148601DA4863D2807C15000174BD4183E80179B74"
    . "883C701393C240F8D7AFFFFFF4D89E54883442428018B9C241"
    . "8010000488B442428015C2404394424680F8DFCFEFFFF8B4C2"
    . "42089C84881C4880000005B5E5F5D415C415D415E415FC3458"
    . "5FF7E278B4C241C4C8B4424084889F28B0201D84898807C050"
    . "001740583E90178934883C2044939D075E583BC24580100000"
    . "70F8EE60100008B442478488B8C24500100000344241844896"
    . "C2450448BAC241801000044897C24404883C1204889742410C"
    . "744243C07000000448974244448897C24484989CF895C247C8"
    . "9C64C89642430418B074489EA29C28944245C8B8424E800000"
    . "001F039C20F4EC239F0894424580F8CD0000000418B47148BB"
    . "C2420010000412B7F0449635FFC458B4F08458B670C8944246"
    . "08B442474458B771039C70F4FF8488B44241048C1E3024C8D1"
    . "41848035C24308B442464448D04068B44246C39F84189C37F7"
    . "2904585C97E234489F131D2418B04924401C04898807C05000"
    . "1740583E90178464883C2014139D17FE28B4424604139C40F8"
    . "4AA0000004585E40F8EA100000089C131D2EB0D4883C201413"
    . "9D40F8E8E0000008B04934401C04898807C05000074E483E90"
    . "179DF4183C3014501E84439DF7D8F83C601397424580F8D6EF"
    . "FFFFF488B7C2448448B7C2440448B742444448B6C2450488B7"
    . "424104C8B6424304883C701393C240F8D97FDFFFFE918FEFFF"
    . "F6690037C240844017C241883442404014401EF8B442404398"
    . "424200100000F854DFBFFFF4C8BBC2440010000E996FCFFFF8"
    . "B44245C8344243C074983C71C8D7406FF8B44243C398424580"
    . "100000F8F87FEFFFF448B7C2440448B742444448B6C2450488"
    . "B7C24488B5C247C488B7424104C8B64243048634424208B542"
    . "418039424080100004C8B9C24600100000B5424708D4801398"
    . "C2468010000418914830F8E9AFDFFFF4585FF7E1D4C8B44240"
    . "84889F08B104883C00401DA4C39C04863D2C64415000075EB4"
    . "883C701393C24894C24200F8DBAFCFFFFE93BFDFFFF0F1F440"
    . "0008B842418010000038424080100002B442430894424308B8"
    . "42410010000038424200100002B44243C39842410010000894"
    . "424440F8F230400008B8424000100008BBC24080100000FAF8"
    . "42410010000448B642440448B6C24544C8B8C24F8000000C74"
    . "42420000000008D04B8034424288944243C8B4424303984240"
    . "80100000F8F2F0100008B8424100100008B6C243CC1E010894"
    . "424408B8424080100008904248D450289EF2B7C24284585ED4"
    . "898450FB61C018D45014898410FB61C014863C5410FB634010"
    . "F8E140100008B442438894424188B44241C8944240431C0EB6"
    . "244395424107E4E418B0C8601F98D5102448D41014863C9410"
    . "FB60C094863D24D63C0410FB61411470FB6040129F10FAFC94"
    . "429DA4129D80FAFD2450FAFC08D1452428D14828D144A39542"
    . "4087207836C241801786B4883C0014139C50F8E9E000000413"
    . "9C44189C27E96418B0C8701F98D5102448D41014863C9410FB"
    . "60C094863D24D63C0410FB61411470FB6040129F10FAFC9442"
    . "9DA4129D80FAFD2450FAFC08D1452428D14828D144A3B54240"
    . "80F864BFFFFFF836C2404010F8940FFFFFF8304240183C5048"
    . "B0424394424300F8DEDFEFFFF83842410010000018BBC24000"
    . "100008B442444017C243C3B8424100100000F8D9CFEFFFFE97"
    . "CFBFFFF0F1F0048634424208B5424400B1424488BBC2460010"
    . "0008D48013B8C24680100008914870F8D56FBFFFF830424018"
    . "3C504894C24208B0424394424300F8D82FEFFFFEB93448B5C2"
    . "428448B84242001000031DB8B84241801000031F6448B94241"
    . "80100004183C30141C1E3074585C08D2C85000000000F8E8CF"
    . "9FFFF4585D27E57488B8C24F80000004C63CE4C038C2430010"
    . "0004863C74531C0488D4C01020FB6110FB641FF440FB661FE6"
    . "BC04B6BD22601C24489E0C1E0044429E001D04139C3430F970"
    . "4014983C0014883C1044539C27FCC01EF4401D683C3014401E"
    . "F399C24200100007595E91CF9FFFF8B8C24200100008B84241"
    . "801000031DB31F6448B8C241801000085C98D2C85000000007"
    . "E7D4585C97E694C63C6488B8C24F80000004863C74D89C24C0"
    . "38424300100004C0394242801000031D2488D4C0102440FB61"
    . "90FB641FF4883C104440FB661FA6BC04B456BDB264101C3448"
    . "9E0C1E0044429E04401D8C1F8074188041241C60410004883C"
    . "2014139D17FC401EF4401CE83C3014401EF399C24200100007"
    . "58383BC2420010000020F8E6CF8FFFF4863B424180100008B9"
    . "C24180100008BBC2420010000488D5601448D67FFBF0100000"
    . "04889D0480394243001000048038424280100004889D58D53F"
    . "D4C8D6A0183BC241801000002488D1C067E7E4989C04D8D5C0"
    . "5004989D94929F04889E90FB610440FB650FF035424284439D"
    . "27C44440FB650014439D27C3A450FB6104439D27C31450FB61"
    . "14439D27C28450FB650FF4439D27C1E450FB650014439D27C1"
    . "4450FB651FF4439D27C0A450FB651014439D27D03C60101488"
    . "3C0014983C1014883C1014983C0014C39D8759383C7014801F"
    . "54889D84139FC0F8562FFFFFFE989F7FFFF31C9E9FAF8FFFF9"
    . "0909090909090909090909090"
    MCode(MyFunc, A_PtrSize=8 ? x64:x32)
    IfLess, Scan0, 10, return
  }
  return, DllCall(&MyFunc, "int",mode, "uint",color
    , "uint",n, "int",offsetX, "int",offsetY, Ptr,Scan0
    , "int",Stride, "int",sx, "int",sy, "int",sw, "int",sh
    , Ptr,&gs, Ptr,&ss, "AStr",text, Ptr,&s1, Ptr,&s0
    , Ptr,&input, "int",num, Ptr,&allpos, "int",allpos_max)
}

xywh2xywh(x1,y1,w1,h1,ByRef x,ByRef y,ByRef w,ByRef h)
{
  SysGet, zx, 76
  SysGet, zy, 77
  SysGet, zw, 78
  SysGet, zh, 79
  left:=x1, right:=x1+w1-1, up:=y1, down:=y1+h1-1
  left:=left<zx ? zx:left, right:=right>zx+zw-1 ? zx+zw-1:right
  up:=up<zy ? zy:up, down:=down>zy+zh-1 ? zy+zh-1:down
  x:=left, y:=up, w:=right-left+1, h:=down-up+1
}

GetBitsFromScreen(x, y, w, h, ByRef Scan0="", ByRef Stride=""
  , ScreenShot=1, ByRef zx="", ByRef zy="", ByRef zw="", ByRef zh="")
{
  static bits, oldx, oldy, oldw, oldh, bpp:=32
  static Ptr:=A_PtrSize ? "UPtr" : "UInt"
  if (ScreenShot or x<oldx or y<oldy
    or x+w>oldx+oldw or y+h>oldy+oldh) and !(w<1 or h<1)
  {
    oldx:=x, oldy:=y, oldw:=w, oldh:=h, ScreenShot:=1
    VarSetCapacity(bits, w*h*4)
  }
  Scan0:=&bits, Stride:=((oldw*bpp+31)//32)*4
  , zx:=oldx, zy:=oldy, zw:=oldw, zh:=oldh
  if (!ScreenShot or w<1 or h<1)
    return
  win:=DllCall("GetDesktopWindow", Ptr)
  hDC:=DllCall("GetWindowDC", Ptr,win, Ptr)
  mDC:=DllCall("CreateCompatibleDC", Ptr,hDC, Ptr)
  ;-------------------------
  VarSetCapacity(bi, 40, 0), NumPut(40, bi, 0, "int")
  NumPut(w, bi, 4, "int"), NumPut(-h, bi, 8, "int")
  NumPut(1, bi, 12, "short"), NumPut(bpp, bi, 14, "short")
  ;-------------------------
  if (hBM:=DllCall("CreateDIBSection", Ptr,mDC, Ptr,&bi
    , "int",0, Ptr "*",ppvBits, Ptr,0, "int",0, Ptr))
  {
    oBM:=DllCall("SelectObject", Ptr,mDC, Ptr,hBM, Ptr)
    DllCall("BitBlt", Ptr,mDC, "int",0, "int",0, "int",w, "int",h
      , Ptr,hDC, "int",x, "int",y, "uint",0x00CC0020|0x40000000)
    DllCall("RtlMoveMemory", Ptr,Scan0, Ptr,ppvBits, Ptr,Stride*h)
    DllCall("SelectObject", Ptr,mDC, Ptr,oBM)
    DllCall("DeleteObject", Ptr,hBM)
  }
  DllCall("DeleteDC", Ptr,mDC)
  DllCall("ReleaseDC", Ptr,win, Ptr,hDC)
}

MCode(ByRef code, hex)
{
  bch:=A_BatchLines
  SetBatchLines, -1
  VarSetCapacity(code, len:=StrLen(hex)//2)
  lls:=A_ListLines=0 ? "Off" : "On"
  ListLines, Off
  Loop, % len
    NumPut("0x" SubStr(hex,2*A_Index-1,2),code,A_Index-1,"uchar")
  ListLines, %lls%
  Ptr:=A_PtrSize ? "UPtr" : "UInt", PtrP:=Ptr . "*"
  DllCall("VirtualProtect",Ptr,&code, Ptr,len,"uint",0x40,PtrP,0)
  SetBatchLines, %bch%
}

base64tobit(s)
{
  Chars:="0123456789+/ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    . "abcdefghijklmnopqrstuvwxyz"
  SetFormat, IntegerFast, d
  StringCaseSense, On
  lls:=A_ListLines=0 ? "Off" : "On"
  ListLines, Off
  Loop, Parse, Chars
  {
    i:=A_Index-1, v:=(i>>5&1) . (i>>4&1)
      . (i>>3&1) . (i>>2&1) . (i>>1&1) . (i&1)
    s:=StrReplace(s,A_LoopField,v)
  }
  ListLines, %lls%
  StringCaseSense, Off
  s:=SubStr(s,1,InStr(s,"1",0,0)-1)
  s:=RegExReplace(s,"[^01]+")
  return, s
}

bit2base64(s)
{
  s:=RegExReplace(s,"[^01]+")
  s.=SubStr("100000",1,6-Mod(StrLen(s),6))
  s:=RegExReplace(s,".{6}","|$0")
  Chars:="0123456789+/ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    . "abcdefghijklmnopqrstuvwxyz"
  SetFormat, IntegerFast, d
  lls:=A_ListLines=0 ? "Off" : "On"
  ListLines, Off
  Loop, Parse, Chars
  {
    i:=A_Index-1, v:="|" . (i>>5&1) . (i>>4&1)
      . (i>>3&1) . (i>>2&1) . (i>>1&1) . (i&1)
    s:=StrReplace(s,v,A_LoopField)
  }
  ListLines, %lls%
  return, s
}

ASCII(s)
{
  if RegExMatch(s,"\$(\d+)\.([\w+/]+)",r)
  {
    s:=RegExReplace(base64tobit(r2),".{" r1 "}","$0`n")
    s:=StrReplace(StrReplace(s,"0","_"),"1","0")
  }
  else s=
  return, s
}

; You can put the text library at the beginning of the script,
; and Use Pic(Text,1) to add the text library to Pic()'s Lib,
; Use Pic("comment1|comment2|...") to get text images from Lib

Pic(comments, add_to_Lib=0)
{
  static Lib:=[]
  SetFormat, IntegerFast, d
  if (add_to_Lib)
  {
    re:="<([^>]*)>[^$]+\$\d+\.[\w+/]+"
    Loop, Parse, comments, |
      if RegExMatch(A_LoopField,re,r)
      {
        s1:=Trim(r1), s2:=""
        Loop, Parse, s1
          s2.="_" . Ord(A_LoopField)
        Lib[s2]:=r
      }
    Lib[""]:=""
  }
  else
  {
    Text:=""
    Loop, Parse, comments, |
    {
      s1:=Trim(A_LoopField), s2:=""
      Loop, Parse, s1
        s2.="_" . Ord(A_LoopField)
      Text.="|" . Lib[s2]
    }
    return, Text
  }
}

PicN(Number)
{
  return, Pic( RegExReplace(Number, ".", "|$0") )
}

; Use PicX(Text) to automatically cut into multiple characters
; Can't be used in ColorPos mode, because it can cause position errors

PicX(Text)
{
  if !RegExMatch(Text,"\|([^$]+)\$(\d+)\.([\w+/]+)",r)
    return, Text
  w:=r2, v:=base64tobit(r3), Text:=""
  c:=StrLen(StrReplace(v,"0"))<=StrLen(v)//2 ? "1":"0"
  wz:=RegExReplace(v,".{" w "}","$0`n")
  SetFormat, IntegerFast, d
  While InStr(wz,c)
  {
    While !(wz~="m`n)^" c)
      wz:=RegExReplace(wz,"m`n)^.")
    i:=0
    While (wz~="m`n)^.{" i "}" c)
      i++
    v:=RegExReplace(wz,"m`n)^(.{" i "}).*","$1")
    wz:=RegExReplace(wz,"m`n)^.{" i "}")
    if (v!="")
      Text.="|" r1 "$" i "." bit2base64(v)
  }
  return, Text
}

; Screenshot and retained as the last screenshot.

ScreenShot(x1="", y1="", x2="", y2="")
{
  if (x1+y1+x2+y2="")
    n:=150000, x:=y:=-n, w:=h:=2*n
  else
    x:=(x1<x2 ? x1:x2), y:=(y1<y2 ? y1:y2)
    , w:=Abs(x2-x1)+1, h:=Abs(y2-y1)+1
  xywh2xywh(x,y,w,h,x,y,w,h)
  GetBitsFromScreen(x,y,w,h)
}

; Get the RGB color of a point from the last screenshot.
; If the point to get the color is beyond the range of
; the last screenshot, an empty string will return.

ScreenShot_GetColor(x,y)
{
  local  ; Unaffected by Super-global variables
  GetBitsFromScreen(0,0,0,0,Scan0,Stride,0,zx,zy,zw,zh)
  return, (x<zx or x>zx+zw-1 or y<zy or y>zy+zh-1 or !Stride)
    ? "" : Format("0x{:06X}",NumGet(Scan0
    +(y-zy)*Stride+(x-zx)*4,"uint")&0xFFFFFF)
}

; Identify a line of text or verification code
; based on the result returned by FindText()
; Return Association array {ocr:Text, x:X, y:Y}

OcrOK(ok, offsetX=20, offsetY=20)
{
  ocr_Text:=ocr_X:=ocr_Y:=min_X:=""
  For k,v in ok
    x:=v.1
    , min_X:=(A_Index=1 or x<min_X ? x : min_X)
    , max_X:=(A_Index=1 or x>max_X ? x : max_X)
  While (min_X!="" and min_X<=max_X)
  {
    LeftX:=""
    For k,v in ok
    {
      x:=v.1, y:=v.2, w:=v.3, h:=v.4
      if (x<min_X) or Abs(y-ocr_Y)>offsetY
        Continue
      ; Get the leftmost X coordinates
      if (LeftX="" or x<LeftX)
        LeftX:=x, LeftY:=y, LeftW:=w, LeftH:=h, LeftOCR:=v.id
      else if (x=LeftX)
      {
        Loop, 100
        {
          err:=(A_Index-1)/100+0.000001
          if FindText(LeftX,LeftY,LeftX+LeftW-1,LeftY+LeftH-1,err,err,Text,0)
            Break
          if FindText(x, y, x+w-1, y+h-1, err, err, Text, 0)
          {
            LeftX:=x, LeftY:=y, LeftW:=w, LeftH:=h, LeftOCR:=v.id
            Break
          }
        }
      }
    }
    if (ocr_X="")
      ocr_X:=LeftX, ocr_Y:=LeftY
    ; If the interval exceeds the set value, add "*" to the result
    ocr_Text.=(ocr_Text!="" and LeftX-min_X>offsetX ? "*":"") . LeftOCR
    ; Update min_X for next search
    min_X:=LeftX+LeftW
  }
  return, {ocr:ocr_Text, x:ocr_X, y:ocr_Y}
}

; Sort the results returned by FindText() from left to right
; and top to bottom, ignore slight height difference

SortOK(ok, dy=10)
{
  if !IsObject(ok)
    return, ok
  SetFormat, IntegerFast, d
  ypos:=[]
  For k,v in ok
  {
    x:=v.x, y:=v.y, add:=1
    For k2,v2 in ypos
      if Abs(y-v2)<=dy
      {
        y:=v2, add:=0
        Break
      }
    if (add)
      ypos.Push(y)
    n:=(y*150000+x) "." k, s:=A_Index=1 ? n : s "-" n
  }
  Sort, s, N D-
  ok2:=[]
  Loop, Parse, s, -
    ok2.Push( ok[(StrSplit(A_LoopField,".")[2])] )
  return, ok2
}

; Reordering according to the nearest distance

SortOK2(ok, px, py)
{
  if !IsObject(ok)
    return, ok
  SetFormat, IntegerFast, d
  For k,v in ok
  {
    x:=v.1+v.3//2, y:=v.2+v.4//2
    n:=((x-px)**2+(y-py)**2) "." k
    s:=A_Index=1 ? n : s "-" n
  }
  Sort, s, N D-
  ok2:=[]
  Loop, Parse, s, -
    ok2.Push( ok[(StrSplit(A_LoopField,".")[2])] )
  return, ok2
}

; Prompt mouse position in remote assistance

MouseTip(x="", y="")
{
  if (x="")
  {
    VarSetCapacity(pt,16,0), DllCall("GetCursorPos","ptr",&pt)
    x:=NumGet(pt,0,"uint"), y:=NumGet(pt,4,"uint")
  }
  x:=Round(x-10), y:=Round(y-10), w:=h:=2*10+1
  ;-------------------------
  Gui, _MouseTip_: +AlwaysOnTop -Caption +ToolWindow +Hwndmyid +E0x08000000
  Gui, _MouseTip_: Show, Hide w%w% h%h%
  ;-------------------------
  dhw:=A_DetectHiddenWindows
  DetectHiddenWindows, On
  d:=4, i:=w-d, j:=h-d
  s=0-0 %w%-0 %w%-%h% 0-%h% 0-0
  s=%s%  %d%-%d% %i%-%d% %i%-%j% %d%-%j% %d%-%d%
  WinSet, Region, %s%, ahk_id %myid%
  DetectHiddenWindows, %dhw%
  ;-------------------------
  Gui, _MouseTip_: Show, NA x%x% y%y%
  Loop, 4
  {
    Gui, _MouseTip_: Color, % A_Index & 1 ? "Red" : "Blue"
    Sleep, 500
  }
  Gui, _MouseTip_: Destroy
}


/***** C source code of machine code *****

int __attribute__((__stdcall__)) PicFind(
  int mode, unsigned int c, unsigned int n
  , int offsetX, int offsetY, unsigned char * Bmp
  , int Stride, int sx, int sy, int sw, int sh
  , unsigned char * gs, char * ss, char * text
  , int * s1, int * s0, int * input, int num
  , unsigned int * allpos, int allpos_max)
{
  int o, i, j, x, y, r, g, b, rr, gg, bb, max, e1, e0, ok;
  int o1, x1, y1, w1, h1, sx1, sy1, len1, len0, err1, err0;
  int o2, x2, y2, w2, h2, sx2, sy2, len21, len20, err21, err20;
  int r_min, r_max, g_min, g_max, b_min, b_max;
  //----------------------
  ok=0; w1=input[1]; h1=input[2];
  len1=input[3]; len0=input[4];
  err1=input[5]; err0=input[6];
  max=len1>len0 ? len1 : len0;
  //----------------------
  // Generate Lookup Table
  for (j=0; j<num; j+=7)
  {
    o=o1=o2=input[j]; w2=input[j+1]; h2=input[j+2];
    for (y=0; y<h2; y++)
    {
      for (x=0; x<w2; x++)
      {
        i=(mode==3) ? y*Stride+x*4 : y*sw+x;
        if (text[o++]=='1')
          s1[o1++]=i;
        else
          s0[o2++]=i;
      }
    }
  }
  // Color Position Mode
  // This mode is not support combination lookup
  // only used to recognize multicolored Verification Code
  if (mode==3)
  {
    sx1=sx+sw-w1; sy1=sy+sh-h1;
    for (y=sy; y<=sy1; y++)
    {
      for (x=sx; x<=sx1; x++)
      {
        o=y*Stride+x*4; e1=err1; e0=err0;
        j=o+c; rr=Bmp[2+j]; gg=Bmp[1+j]; bb=Bmp[j];
        for (i=0; i<max; i++)
        {
          if (i<len1)
          {
            j=o+s1[i]; r=Bmp[2+j]-rr; g=Bmp[1+j]-gg; b=Bmp[j]-bb;
            if (3*r*r+4*g*g+2*b*b>n && (--e1)<0)
              goto NoMatch3;
          }
          if (i<len0)
          {
            j=o+s0[i]; r=Bmp[2+j]-rr; g=Bmp[1+j]-gg; b=Bmp[j]-bb;
            if (3*r*r+4*g*g+2*b*b<=n && (--e0)<0)
              goto NoMatch3;
          }
        }
        allpos[ok++]=y<<16|x;
        if (ok>=allpos_max)
          goto Return1;
        NoMatch3:
        continue;
      }
    }
    goto Return1;
  }
  // Generate Two Value Image
  o=sy*Stride+sx*4; j=Stride-4*sw; i=0;
  if (mode==0)  // Color Mode
  {
    rr=(c>>16)&0xFF; gg=(c>>8)&0xFF; bb=c&0xFF;
    for (y=0; y<sh; y++, o+=j)
      for (x=0; x<sw; x++, o+=4, i++)
      {
        r=Bmp[2+o]-rr; g=Bmp[1+o]-gg; b=Bmp[o]-bb;
        ss[i]=(3*r*r+4*g*g+2*b*b<=n) ? 1:0;
      }
  }
  else if (mode==1)  // Gray Threshold Mode
  {
    c=(c+1)*128;
    for (y=0; y<sh; y++, o+=j)
      for (x=0; x<sw; x++, o+=4, i++)
        ss[i]=(Bmp[2+o]*38+Bmp[1+o]*75+Bmp[o]*15<c) ? 1:0;
  }
  else if (mode==2)  // Gray Difference Mode
  {
    for (y=0; y<sh; y++, o+=j)
    {
      for (x=0; x<sw; x++, o+=4, i++)
      {
        gs[i]=(Bmp[2+o]*38+Bmp[1+o]*75+Bmp[o]*15)>>7;
        ss[i]=0;
      }
    }
    sx1=sw-2; sy1=sh-2;
    for (y=1; y<=sy1; y++)
      for (x=1; x<=sx1; x++)
      {
        i=y*sw+x; j=gs[i]+c;
        if ( gs[i-1]>j || gs[i+1]>j
          || gs[i-sw]>j || gs[i+sw]>j
          || gs[i-sw-1]>j || gs[i-sw+1]>j
          || gs[i+sw-1]>j || gs[i+sw+1]>j )
            ss[i]=1;
      }
  }
  else // (mode==4) Color Difference Mode
  {
    r=(c>>16)&0xFF; g=(c>>8)&0xFF; b=c&0xFF;
    rr=(n>>16)&0xFF; gg=(n>>8)&0xFF; bb=n&0xFF;
    r_min=r-rr; g_min=g-gg; b_min=b-bb;
    r_max=r+rr; g_max=g+gg; b_max=b+bb;
    for (y=0; y<sh; y++, o+=j)
      for (x=0; x<sw; x++, o+=4, i++)
      {
        r=Bmp[2+o]; g=Bmp[1+o]; b=Bmp[o];
        ss[i]=(r>=r_min && r<=r_max
            && g>=g_min && g<=g_max
            && b>=b_min && b<=b_max) ? 1:0;
      }
  }
  // Start Lookup
  sx1=sw-w1; sy1=sh-h1;
  for (y=0; y<=sy1; y++)
  {
    for (x=0; x<=sx1; x++)
    {
      o=y*sw+x; e1=err1; e0=err0;
      if (e0==len0)
      {
        for (i=0; i<len1; i++)
          if (ss[o+s1[i]]!=1 && (--e1)<0)
            goto NoMatch1;
      }
      else
      {
        for (i=0; i<max; i++)
        {
          if (i<len1 && ss[o+s1[i]]!=1 && (--e1)<0)
            goto NoMatch1;
          if (i<len0 && ss[o+s0[i]]!=0 && (--e0)<0)
            goto NoMatch1;
        }
      }
      //------------------
      // Combination lookup
      if (num>7)
      {
        x1=x+w1-1; y1=y-offsetY; if (y1<0) y1=0;
        for (j=7; j<num; j+=7)
        {
          o2=input[j]; w2=input[j+1]; h2=input[j+2];
          len21=input[j+3]; len20=input[j+4];
          err21=input[j+5]; err20=input[j+6];
          sx2=sw-w2; i=x1+offsetX; if (i<sx2) sx2=i;
          sy2=sh-h2; i=y+offsetY; if (i<sy2) sy2=i;
          for (x2=x1; x2<=sx2; x2++)
          {
            for (y2=y1; y2<=sy2; y2++)
            {
              o1=y2*sw+x2; e1=err21; e0=err20;
              for (i=0; i<len21; i++)
              {
                if (ss[o1+s1[o2+i]]!=1 && (--e1)<0)
                  goto NoMatch2;
              }
              if (e0!=len20)
              {
                for (i=0; i<len20; i++)
                  if (ss[o1+s0[o2+i]]!=0 && (--e0)<0)
                    goto NoMatch2;
              }
              goto MatchOK;
              NoMatch2:
              continue;
            }
          }
          goto NoMatch1;
          MatchOK:
          x1=x2+w2-1;
        }
      }
      //------------------
      allpos[ok++]=(sy+y)<<16|(sx+x);
      if (ok>=allpos_max)
        goto Return1;
      // Clear the image that has been found
      for (i=0; i<len1; i++)
        ss[o+s1[i]]=0;
      NoMatch1:
      continue;
    }
  }
  Return1:
  return ok;
}

*/

;================= The End =================

;
Thanks again, you are a genius :xmas:
thebbandit
Posts: 45
Joined: 02 Jul 2019, 11:34

Re: FindText - Capture screen image into text and then find it

09 Dec 2019, 16:04

This tool is so amazing, I keep playing with it and finding ways to help you improve it.

One thing is to actually find the edges of the screen instead of adding or subtracting 150000.

So I added a new subfunction to the ft_Gui called Edges which creates local variables for use in the script template
Find the edges of the screen space
Then we can apply them

I have been playing with the OCR tools, and they are very useful. But the limitation I am finding is that my use case has several variations of text. I need to have three text libraries to search using OCR. One is normal letters with lowercase and capital, other is all capital with big and small for showing caps, then another is a seperate font. I looked at the code for the pic library, and it doesn't take much to allow for an index. Here is how I acheived that:
Indexed Text library


The last thing is a question, what is the purpose of the PicFind function? I have searched through the forum thread for anyone else asking about it, but I cannot find any info. There are a ton of input variables and a lot of byref, I am not sure what I am supposed to input and what is its intended function. I am assuming its a way to do FindText search from a screenshot? Or maybe its for using with the Pic function?
feiyue
Posts: 349
Joined: 08 Aug 2014, 04:08

Re: FindText - Capture screen image into text and then find it

10 Dec 2019, 15:43

Updated to 7.1 version - 2019/12/10
.... 1. Add: A new function PicInfo() is added to ensure that each text parameter
....... is parsed only once, which slightly improves the efficiency of loop execution.
.... 2. Add: A sub window is added to the capture image window to process the captured image.
....... This sub window can scroll, so it can support larger captured image.
....... Therefore, the capture range can be adjusted at any time in the main window interface.
.... 3. Modify: Pic() is renamed as PicLib(). In addition, a sequence number parameter
....... has been added, so that multiple text libraries can be set up and used.
.... 4. Some details have been improved to make it easy for users to use.
.... 5. Fixed some minor bugs in ft_ShowScreenShot() and OcrOk().

Thanks for @thebbandit's test and many good suggestions.
feiyue
Posts: 349
Joined: 08 Aug 2014, 04:08

Re: FindText - Capture screen image into text and then find it

10 Dec 2019, 16:40

thebbandit wrote:
09 Dec 2019, 16:04
One thing is to actually find the edges of the screen instead of adding or subtracting 150000.
It's not really necessary, because the FindText() function has been
internally limited to finding images within the edge of the virtual screen.
So it doesn't matter if the range goes beyond the virtual screen edge. :dance:
thebbandit wrote:
09 Dec 2019, 16:04
I looked at the code for the pic library, and it doesn't take much to allow for an index. Here is how I acheived that:
......
This way it preserves the way it works for any code already written, but now supports an indexed method of having several text libraries.
This is a good idea. The Pic() function is just a simple implementation,
Because I seldom use it myself, I don't think about it well. Thank you for your improvement. :bravo:
thebbandit wrote:
09 Dec 2019, 16:04
The last thing is a question, what is the purpose of the PicFind function?
This is the DllCall call function of machine code in C language, which is only used by FindText(), please ignore it. :xmas:
maxkill
Posts: 158
Joined: 11 Apr 2016, 13:03

Re: FindText - Capture screen image into text and then find it

11 Dec 2019, 04:03

@feiyue
Hello, it's really working great. There is just one thing I don't get
See here, this works for searching inside active window:

Code: Select all

f2::
CoordMode, Screen
Text:="|<>*84$18.zzzk01zzzzzzzzzzzzy0Tz0zzVzznzzzzzzzzzzzzzzzzzzzU"
WinGetPos, wX, wY, wW, wH, % needle

if (ok:=FindText(wX, wY, wW, wH, 0, 0, Text))
{
  X:=ok.1.x, Y:=ok.1.y, Comment:=ok.1.id
  mousemove, X-20, Y-1
click left
}
return
However this does not work for searching inside window (the image tested is found consistantly when choosing "test"):

Code: Select all

q::
Coordmode, screen
Text:="|<>[email protected]$71.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000DYE000000000E0U000000000U100000000010W7U0000000214F000000007W8V0000000084Hy00000000E8Y000000000UF40000000010W8E0000000214D000000000000000000000000000000000000000000000000000000000000000000000001"
;Text:="|<>[email protected]$25.0000DkES60sNX0I8FU248k124TUV2A0EV608EX048FU26Ez11s0000E"
WinGetPos, wX, wY, wW, wH, % needle

if (ok:=FindText(wX, wY, wW, wH, 0, 0, Text))
{
  X:=ok.1.x, Y:=ok.1.y, Comment:=ok.1.id
  mousemove, X-20, Y-1
}
return
Same image that was not found above was found when using this around mouse pointer:

Code: Select all

a::
BlockInput, on
CoordMode, Mouse, Screen
MouseGetPos, xx, yy

Text:="|<>[email protected]$71.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000DYE000000000E0U000000000U100000000010W7U0000000214F000000007W8V0000000084Hy00000000E8Y000000000UF40000000010W8E0000000214D000000000000000000000000000000000000000000000000000000000000000000000001"
if (ok:=FindText(xx-5000, yy-5000, xx+5000, yy+5000, 0, 0, Text)) ; 150 can be adjusted by yourself

{
  xx:=ok.1.1, yy:=ok.1.2, w:=ok.1.3, h:=ok.1.4
  mousemove, xx+200, yy-450
}
BlockInput, off	
return
I also had a problem with identical code to top example searching for another image in the same window that was closer to edge of window that was not found while the test found it easily.
So not sure what's going since code is identical (apart from image search code) yet images aren't found in some instances when using the active window search.
feiyue
Posts: 349
Joined: 08 Aug 2014, 04:08

Re: FindText - Capture screen image into text and then find it

11 Dec 2019, 04:29

FindText(wX, wY, wX+wW, wY+wH, ......)
maxkill
Posts: 158
Joined: 11 Apr 2016, 13:03

Re: FindText - Capture screen image into text and then find it

11 Dec 2019, 05:08

feiyue wrote:
11 Dec 2019, 04:29
FindText(wX, wY, wX+wW, wY+wH, ......)
Great!

It now finds it, however, it seems to go way off target to get to the image see the compensated mousemove to move it to picture
(tested with several pictures)

Code: Select all

q::
Coordmode, screen
;Text:="|<>[email protected]$71.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000DYE000000000E0U000000000U100000000010W7U0000000214F000000007W8V0000000084Hy00000000E8Y000000000UF40000000010W8E0000000214D000000000000000000000000000000000000000000000000000000000000000000000001"
;Text:="|<>[email protected]$25.0000DkES60sNX0I8FU248k124TUV2A0EV608EX048FU26Ez11s0000E"
Text:="|<>[email protected]$49.00000000DU0k2000600M1000300A0U001UD6Dksgsk8nAMWMUT89YAVAEA44m2TYA622N1821X11AVY10NUlaMn4U8k7X7cyEw00000000E"
WinGetPos, wX, wY, wW, wH, % needle

if (ok:=FindText(wX, wY, wX+wW, wY+wH, 0, 0, Text))
{
  X:=ok.1.x, Y:=ok.1.y, Comment:=ok.1.id
  mousemove, X-1400, Y-700
}
return
User avatar
tank
Posts: 3122
Joined: 28 Sep 2013, 22:15
Location: CarrolltonTX
Contact:

Re: FindText - Capture screen image into text and then find it

11 Dec 2019, 06:47

How have i never noticed such an incredibly useful well documentd n useful thread.
We are troubled on every side‚ yet not distressed; we are perplexed‚
but not in despair; Persecuted‚ but not forsaken; cast down‚ but not destroyed;
Telegram is the best way to reach me
https://t.me/ttnnkkrr
If you have forum suggestions please submit a
Check Out WebWriter
maxkill
Posts: 158
Joined: 11 Apr 2016, 13:03

Re: FindText - Capture screen image into text and then find it

11 Dec 2019, 09:53

feiyue wrote:
11 Dec 2019, 04:29
FindText(wX, wY, wX+wW, wY+wH, ......)
I guess you meant should not have w (remember I am not a programmer it's not easy to see then so better if you explain more clearly) I put the w's in and forgot to change the command to the same however still don't work

Code: Select all

q::
Coordmode, screen
;Text:="|<>[email protected]$71.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000DYE000000000E0U000000000U100000000010W7U0000000214F000000007W8V0000000084Hy00000000E8Y000000000UF40000000010W8E0000000214D000000000000000000000000000000000000000000000000000000000000000000000001"
;Text:="|<>[email protected]$25.0000DkES60sNX0I8FU248k124TUV2A0EV608EX048FU26Ez11s0000E"
Text:="|<>[email protected]$49.00000000DU0k2000600M1000300A0U001UD6Dksgsk8nAMWMUT89YAVAEA44m2TYA622N1821X11AVY10NUlaMn4U8k7X7cyEw00000000E"
WinGetPos, X, Y, W, H, % needle

if (ok:=FindText(X, Y, X+W, Y+H, 0, 0, Text))
{
   X:=ok.1.x, Y:=ok.1.y, Comment:=ok.1.id
   ;  x:=ok.1.1, y:=ok.1.2, w:=ok.1.3, h:=ok.1.4
  ;mousemove, X-1400, Y-700
mousemove, % X+W, % Y+H
}
return
No idea why it doesn't move to it accurately like the mouse pointer option does.
feiyue
Posts: 349
Joined: 08 Aug 2014, 04:08

Re: FindText - Capture screen image into text and then find it

11 Dec 2019, 12:07

Code: Select all

Coordmode, screen  ----> CoordMode, Mouse, Screen
Such a simple mistake, I thought you would find it yourself.
maxkill
Posts: 158
Joined: 11 Apr 2016, 13:03

Re: FindText - Capture screen image into text and then find it

11 Dec 2019, 12:27

feiyue wrote:
11 Dec 2019, 12:07

Code: Select all

Coordmode, screen  ----> CoordMode, Mouse, Screen
Such a simple mistake, I thought you would find it yourself.
Indeed it was, thanks a lot I got it now :dance:

Code: Select all

q::
CoordMode, mouse, Screen
Text:="|<>[email protected]$71.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000DYE000000000E0U000000000U100000000010W7U0000000214F000000007W8V0000000084Hy00000000E8Y000000000UF40000000010W8E0000000214D000000000000000000000000000000000000000000000000000000000000000000000001"
;Text:="|<>[email protected]$25.0000DkES60sNX0I8FU248k124TUV2A0EV608EX048FU26Ez11s0000E"
;Text:="|<>[email protected]$49.00000000DU0k2000600M1000300A0U001UD6Dksgsk8nAMWMUT89YAVAEA44m2TYA622N1821X11AVY10NUlaMn4U8k7X7cyEw00000000E"
WinGetPos, X, Y, W, H, % needle

if (ok:=FindText(X, Y, X+W, Y+H, 0, 0, Text))
{
x:=ok.1.1, y:=ok.1.2, w:=ok.1.3, h:=ok.1.4
  ;mousemove, X-1400, Y-700
mousemove, % X+W-1, % Y+H-1
}
return
Paul H 81
Posts: 9
Joined: 11 Dec 2019, 22:19

Re: FindText - Capture screen image into text and then find it

12 Dec 2019, 08:28

[/Codebox][/Codebox]Okay everyone...I am the noob of all noobs. Can someone explain to me how to use this like you were explaining it to a 4-year-old? I have absolutely ZERO coding experience. I do SUPER basic stuff in AHK mostly interfacing with Chrome. All I want is to write code that will reliably click on something and the built-in Image Search thing seems pretty inconsistent. I've downloaded and ran the Capture Image To Text and Find Text Tool. I capture something and it spits out some code. I watched a Joe Glines video from 8/27/17 where he walks you through how FindText works and that super helpful...but his follow up video showing you how to use the FindText output in your own script was more advanced and I didn't understand. I just want to be able to take the output, paste it into a script, and make my computer click on the image it found. Here's a script I wrote using the built-in image search feature - I'd like to be able to paste the results from FindText into the script where the "ImageSearch" line is and have it work more reliably.

Code: Select all

#SingleInstance, force


^!r::

ImageSearch,Loc_X, Loc_Y, 0, 0, 1300,715,C:\Users\Connections\Desktop\AHK Scripts\Saved Clips\Saved Clip 20191211140012.png
MouseMove, Loc_X, Loc_Y
Click
This works some of the time but is very unreliable. I've tried recapturing the image but it doesn't seem to help. When I run the test in FindText, it finds the text...I just need to know how to incorporate it into my script. Also, not sure if this is relevant, but here is an error message I get when I was playing with trying to incorporate the FindText

Code: Select all

>"C:\Program Files\AutoHotkey\AutoHotkey.exe" /ErrorStdOut "C:\Users\Connections\Desktop\AHK Scripts\Find CPT.ahk"    
C:\Users\Connections\Desktop\AHK Scripts\Find CPT.ahk (11) : ==> Call to nonexistent function.
     Specifically: FindText(790-150000, 392-150000, 150000, 150000, 0, 0, Text))
>Exit code: 2    Time: 0.2071
Any help anyone can provide would be GREATLY appreciated :D
thebbandit
Posts: 45
Joined: 02 Jul 2019, 11:34

Re: FindText - Capture screen image into text and then find it

12 Dec 2019, 21:08

@Paul H 81
Ok so lets start with the basics. For simplicity, You should create a file within the autohotkey Lib folder and place this library file within it.

You should end up with a file like so:
C:\YourUserName\Documents\AutoHotKey\Lib\FindText.ahk

Create the file and paste the entire contents of the code in the first post into that file.

Now you can simply add the library to the file when you make new scripts with one line:
#Include <FindText>

put that anywhere in your script, preferably at the very end. That will let you use the function that you are getting an error about.


Then when it comes to using the Function to do a search, you will need to understand how X1, Y1, X2, Y2 coordinates work. Think of them as the corners of a box. X1, Y1 is the top left corner, and X2, Y2 are the bottom right corner

Now that you understand how to input the coordinates, you need to learn how to use the output...

Code: Select all

 X1:=Y1:=0, X2:=A_ScreenWidth, Y2:=A_ScreenHeight
 ; The above line will set the search coordinates to 0, 0, 1920, 1080 for 1080p for example
Result := FindText(X1, Y1, X2, Y2, 0, 0, Text)

If Result
{
MsgBox % "Wow you found something`nAt: " Result.1.1 " x position, " Result.1.2 " y position, " Result.1.3 " width, " Result.1.4 " height`nOr use the Provided Center coordinates: " Result.1.x " , " Result.1.y
}
Else
{
MsgBox Nothing Found
}
ArkuS
Posts: 4
Joined: 29 Nov 2019, 22:54

Re: FindText - Capture screen image into text and then find it

13 Dec 2019, 19:12

@thebbandit

Do you know how to add SortOK to this code from this post?
I can't deal with it.

https://www.autohotkey.com/boards/viewtopic.php?p=303663#p303663
feiyue
Posts: 349
Joined: 08 Aug 2014, 04:08

Re: FindText - Capture screen image into text and then find it

14 Dec 2019, 01:05

@ArkuS I think if you want to use ControlClick, you can do this:

Code: Select all

WinGetPos, winx, winy,,, %title%
X-=winx, Y-=winy
ControlClick, x%X% y%Y%, ......
ArkuS
Posts: 4
Joined: 29 Nov 2019, 22:54

Re: FindText - Capture screen image into text and then find it

14 Dec 2019, 11:26

@feiyue

Thanks for devoting time to a newbie like me, but my problem is not ControlClick (ControlClick works in the code to which I gave the link above). My problem is two the same words, which causes FindText to go crazy and choose none of them. As is shown in the image.

Bez tytułu.png
Bez tytułu.png (53.71 KiB) Viewed 4962 times

I tried to add SortOK that you told me, but there is little examples of how to use it and not give advice to use it.

Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: No registered users and 122 guests