发表回复 
屏幕抓字生成字库工具与找字函数 v7.3
2013-12-21, 03 : 39 (这个帖子最后修改于: 2019-12-21 02 : 54 by feiyue.)
Heart 屏幕抓字生成字库工具与找字函数 v7.3

这是一个简单的辅助工具,用于生成屏幕文字或图像的单行字符串
字库。配合强大的“查找文字()”函数,在脚本中非常好用!

在编写自动化脚本时,如果采用先抓图,再制作小图,再用
ImageSearch,操作太复杂,且不能仅使用脚本,还要打包图片。

如果仅仅采用颜色判断,显而易见太简陋了,不能精确判断
当前的屏幕文字(或图像),及精确定位。

所以这个工具就应运而生了,生成“0_”字符组成的形象化图像描述,
并且自动生成“查找文字()”的调用代码,复制到自己的脚本中就行了。

这可是我的独门秘技哦(^_^)!

【由于内容长度超出限制,后半部分放到4楼去了】

代码: (全选)
;/*
;===========================================
;  FindText - 屏幕抓字生成字库工具与找字函数
;
;  脚本作者 :  FeiYue
;  最新版本 :  7.3
;  更新时间 :  2019-12-21
;
;  用法:
;  1. 将本脚本保存为“FindText.ahk”并复制到AHK程序的Lib子目录中
;  2. 抓图并生成调用FindText()的代码
;     2.1 直接点击“抓图”按钮
;     2.2 先设定截屏热键,使用热键截屏,再点击“截屏抓图”按钮
;  3. 测试一下调用的代码是否成功:直接点击“测试”按钮
;  4. 复制调用的代码到自己的脚本中
;     4.1 直接点击“复制”按钮,然后粘贴到自己的脚本中
;     4.2 取消“附加FindText()函数”的选框,然后点击“复制”按钮,
;         然后粘贴到自己的脚本中,然后在自己的脚本开头加上一行:
;         #Include <FindText>  ; Lib目录中必须有FindText.ahk
;
;===========================================
;  函数的参数和返回值:
;
;  返回变量 := FindText(
;      X1 --> 查找范围的左上角X坐标
;    , Y1 --> 查找范围的左上角Y坐标
;    , X2 --> 查找范围的右下角X坐标
;    , Y2 --> 查找范围的右下角Y坐标
;    , err1 --> 文字的黑点容错百分率(0.1=10%)
;    , err0 --> 背景的白点容错百分率(0.1=10%)
;    , Text --> 由工具生成的查找图像的数据,可以一次查找多个,用“|”分隔
;    , ScreenShot --> 是否截屏,为0则使用上一次的截屏数据
;    , FindAll -->    是否搜索所有位置,为0则找到一个位置就返回
;    , JoinText -->   是否组合图像,为1则多个数据组合为一幅图来查找
;    , offsetX --> 组合图像的每个字和前一个字的最大横向间隔
;    , offsetY --> 组合图像的每个字和第一个字的最大高低间隔
;  )
;  返回变量 --> 如果没找到结果会返回0。否则返回一个二级数组,
;      第一级是每个结果对象,第二级是结果对象的具体信息数组:
;      { 1:左上角X, 2:左上角Y, 3:图像宽度W, 4:图像高度H
;        , x:中心点X, y:中心点Y, id:图像识别文本 }
;
;  坐标都是相对于屏幕,颜色使用RGB格式,组合查找必须使用统一的颜色模式
;===========================================
;*/

if (!A_IsCompiled and A_LineFile=A_ScriptFullPath)
  ft_Gui("Show")

ft_Gui(cmd)
{
  static
  if (cmd="Show")
  {
    Gui, ft_Main:+LastFoundExist
    IfWinExist
    {
      Gui, ft_Main:Show, Center
      return
    }
    if (!ft_FuncBind1)
      ft_FuncBind1:=Func("ft_Gui").Bind("Show")
    #NoEnv
    Menu, Tray, Add
    Menu, Tray, Add, 查找文字工具, %ft_FuncBind1%
    if (!A_IsCompiled and A_LineFile=A_ScriptFullPath)
    {
      Menu, Tray, Default, 查找文字工具
      Menu, Tray, Click, 1
      Menu, Tray, Icon, Shell32.dll, 23
    }
    ft_BatchLines:=A_BatchLines
    ft_IsCritical:=A_IsCritical
    Critical
    ww:=35, hh:=12, WindowColor:="0xDDEEFF"
    ft_Gui("MakeCaptureWindow")
    ft_Gui("MakeSubPicWindow")
    ft_Gui("MakeMainWindow")
    OnMessage(0x100, Func("ft_EditEvents1"))  ; WM_KEYDOWN
    OnMessage(0x201, Func("ft_EditEvents2"))  ; WM_LBUTTONDOWN
    OnMessage(0x200, Func("ft_ShowToolTip"))  ; WM_MOUSEMOVE
    Gui, ft_Main:Show, Center
    GuiControl, ft_Main:Focus, scr
    Critical, %ft_IsCritical%
    SetBatchLines, %ft_BatchLines%
    return
    ;-------------------
    ft_Run:
    Critical
    ft_Gui(Trim(A_GuiControl))
    return
  }
  if (cmd="MakeCaptureWindow")
  {
    Gui, ft_Capture:New
    Gui, +AlwaysOnTop -DPIScale
    Gui, Margin, 15, 15
    Gui, Color, %WindowColor%
    Gui, Font, s12, Verdana
    Gui, Add, Text, xm w855 h315 +HwndhPic
    Gui, Add, Slider, ym h315 vMySlider2 gft_Run
      +Center Page20 Line20 NoTicks AltSubmit +Vertical
    Gui, Add, Slider, xm w855 vMySlider1 gft_Run
      +Center Page20 Line20 NoTicks AltSubmit
    GuiControlGet, Pic, Pos, %hPic%
    PicW:=Round(PicW), PicH:=Round(PicH), MySlider1:=MySlider2:=0
    Gui, Add, Button, xm+125 w50 vRepU  gft_Run, -上
    Gui, Add, Button, x+0    wp  vCutU  gft_Run, 上
    Gui, Add, Button, x+0    wp  vCutU3 gft_Run, 上3
    ;--------------
    Gui, Add, Text,   x+50 yp+3 Section, 灰度
    Gui, Add, Edit,   x+3 yp-3 w60 vSelGray ReadOnly
    Gui, Add, Text,   x+15 ys, 颜色
    Gui, Add, Edit,   x+3 yp-3 w120 vSelColor ReadOnly
    Gui, Add, Text,   x+15 ys, 红
    Gui, Add, Edit,   x+3 yp-3 w60 vSelR ReadOnly
    Gui, Add, Text,   x+5 ys, 绿
    Gui, Add, Edit,   x+3 yp-3 w60 vSelG ReadOnly
    Gui, Add, Text,   x+5 ys, 蓝
    Gui, Add, Edit,   x+3 yp-3 w60 vSelB ReadOnly
    ;--------------
    Gui, Add, Button, xm     w50 vRepL  gft_Run, -左
    Gui, Add, Button, x+0    wp  vCutL  gft_Run, 左
    Gui, Add, Button, x+0    wp  vCutL3 gft_Run, 左3
    Gui, Add, Button, x+15   w70 vAuto  gft_Run, 自动
    Gui, Add, Button, x+15   w50 vRepR  gft_Run, -右
    Gui, Add, Button, x+0    wp  vCutR  gft_Run, 右
    Gui, Add, Button, x+0    wp  vCutR3 gft_Run Section, 右3
    Gui, Add, Button, xm+125 w50 vRepD  gft_Run, -下
    Gui, Add, Button, x+0    wp  vCutD  gft_Run, 下
    Gui, Add, Button, x+0    wp  vCutD3 gft_Run, 下3
    ;--------------
    Gui, Add, Tab3,   ys-8 -Wrap, 灰度阈值|灰度差值|颜色相似|颜色位置|颜色分量
    Gui, Tab, 1
    Gui, Add, Text,   x+15 y+15, 灰度阈值
    Gui, Add, Edit,   x+15 w100 vThreshold
    Gui, Add, Button, x+15 yp-3 vGray2Two gft_Run, 灰度阈值二值化
    Gui, Tab, 2
    Gui, Add, Text,   x+15 y+15, 灰度差值
    Gui, Add, Edit,   x+15 w100 vGrayDiff, 50
    Gui, Add, Button, x+15 yp-3 vGrayDiff2Two gft_Run, 灰度差值二值化
    Gui, Tab, 3
    Gui, Add, Text,   x+15 y+15, 相似度 0
    Gui, Add, Slider, x+0 w100 vSimilar1 gft_Run
      +Center Page1 NoTicks ToolTip, 100
    Gui, Add, Text,   x+0, 100
    Gui, Add, Button, x+15 yp-3 vColor2Two gft_Run, 颜色相似二值化
    Gui, Tab, 4
    Gui, Add, Text,   x+15 y+15, 相似度 0
    Gui, Add, Slider, x+0 w100 vSimilar2 gft_Run
      +Center Page1 NoTicks ToolTip, 100
    Gui, Add, Text,   x+0, 100
    Gui, Add, Button, x+15 yp-3 vColorPos2Two gft_Run, 颜色位置二值化
    Gui, Tab, 5
    Gui, Add, Text,   x+10 y+15, 红
    Gui, Add, Edit,   x+2 w70 vDiffR Limit3
    Gui, Add, UpDown, vdR Range0-255
    Gui, Add, Text,   x+5, 绿
    Gui, Add, Edit,   x+2 w70 vDiffG Limit3
    Gui, Add, UpDown, vdG Range0-255
    Gui, Add, Text,   x+5, 蓝
    Gui, Add, Edit,   x+2 w70 vDiffB Limit3
    Gui, Add, UpDown, vdB Range0-255
    Gui, Add, Button, x+5 yp-3 vColorDiff2Two gft_Run, 颜色分量二值化
    Gui, Tab
    ;--------------
    Gui, Add, Button, xm vReset gft_Run, 重读
    Gui, Add, Checkbox, x+15 yp+5 vModify gft_Run, 修改
    Gui, Add, Text,   x+30, 识别文字
    Gui, Add, Edit,   x+5 yp-2 w150 vComment
    Gui, Add, Button, x+30 yp-3 vSplitAdd gft_Run, 分割添加
    Gui, Add, Button, x+10 vAllAdd gft_Run, 整体添加
    Gui, Add, Button, x+10 w80 vButtonOK gft_Run, 确定
    Gui, Add, Button, x+10 wp vClose gCancel, 关闭
    Gui, Add, Button, xm   vBind1 gft_Run, 绑定窗口
    Gui, Add, Button, x+15 vBind2 gft_Run, 绑定窗口+
    Gui, Show, Hide, 图像二值化及分割
    return
  }
  if (cmd="MakeSubPicWindow")
  {
    Gui, ft_SubPic:New
    Gui, +AlwaysOnTop -Caption +ToolWindow -DPIScale +Parent%hPic%
    Gui, Margin, 0, 0
    Gui, Color, %WindowColor%
    Gui, -Theme
    nW:=2*ww+1, nH:=2*hh+1, C_:=[], w:=11
    Loop, % nW*(nH+1)
    {
      i:=A_Index, j:=i=1 ? "x0 y0" : Mod(i,nW)=1 ? "x0 y+1" : "x+1"
      j.=i>nW*nH ? " cRed BackgroundFFFFAA" : ""
      Gui, Add, Progress, w%w% h%w% %j% +Hwndid
      Control, ExStyle, -0x20000,, ahk_id %id%
      C_[i]:=id
    }
    Gui, +Theme
    GuiControlGet, SubPic, Pos, %id%
    SubPicW:=Round(SubPicX+SubPicW), SubPicH:=Round(SubPicY+SubPicH)
    Gui, Show, NA x0 y0 w%SubPicW% h%SubPicH%, SubPic
    i:=(SubPicW>PicW), j:=(SubPicH>PicH)
    Gui, ft_Capture:Default
    GuiControl, Enable%i%, MySlider1
    GuiControl, Enable%j%, MySlider2
    GuiControl,, MySlider1, % MySlider1:=0
    GuiControl,, MySlider2, % MySlider2:=0
    return
  }
  if (cmd="MakeMainWindow")
  {
    Gui, ft_Main:New
    Gui, +AlwaysOnTop -DPIScale
    Gui, Margin, 15, 15
    Gui, Color, %WindowColor%
    Gui, Font, s12 cBlack, Verdana
    Gui, Add, GroupBox, xm y10 w250 h45 vMyGroup
    Gui, Add, Text, xp+10 yp+18 Section, % "宽度: "
    Gui, Add, Text, x+0 w50, %ww%
    Gui, Add, UpDown, vMyww Range1-50, %ww%
    Gui, Add, Text, x+15 ys, % "高度: "
    Gui, Add, Text, x+0 w50, %hh%
    Gui, Add, UpDown, vMyhh Range1-40, %hh%
    GuiControlGet, p, Pos, Myhh
    GuiControl, Move, MyGroup, % "w" px+pw " h" py+ph
    Gui, Add, Checkbox, x+30 ys Checked vAddFunc, 附加 FindText()
    GuiControlGet, p, Pos, AddFunc
    w:=720+15-(px+pw)-15
    Gui, Add, Button, x+15 ys-8 w%w% vTestClip gft_Run, 复制后测试
    Gui, Add, Text, xm, 截屏热键
    Gui, Add, Edit, x+5 w150 vNowHotkey ReadOnly
    Gui, Add, Hotkey, x+5 w180 vSetHotkey1
    Gui, Add, DDL, x+5 w150 vSetHotkey2
      , % "||F1|F2|F3|F4|F5|F6|F7|F8|F9|F10|F11|F12|MButton"
      . "|ScrollLock|CapsLock|Ins|Esc|BS|Del|Tab|Home|End|PgUp|PgDn"
      . "|NumpadDot|NumpadSub|NumpadAdd|NumpadDiv|NumpadMult"
    GuiControlGet, p, Pos, SetHotkey2
    w:=720+15-(px+pw)-5
    Gui, Add, Button, x+5 yp-3 w%w% vApply gft_Run, 应用
    Gui, Font, s6 bold, Verdana
    Gui, Add, Edit, xm w720 r25 vMyPic -Wrap
    Gui, Font, s12 norm, Verdana
    Gui, Add, Button, w180 vCapture gft_Run, 抓图
    Gui, Add, Button, x+0 wp vCaptureS gft_Run, 截屏抓图
    Gui, Add, Button, x+0 wp vTest gft_Run, 测试
    Gui, Add, Button, x+0 wp vCopy gft_Run Section, 复制
    Gui, Font, s12 cBlue, Verdana
    Gui, Add, Edit, xm w720 h350 vscr Hwndhscr -Wrap HScroll
    Gui, Show, Hide, 抓图生成字库及找字代码
    return
  }
  if (cmd="Capture") or (cmd="CaptureS")
  {
    Gui, ft_Main:Default
    Gui, +LastFound
    WinMinimize
    Gui, Hide
    ShowScreenShot:=(cmd="CaptureS")
    if (ShowScreenShot)
      ft_ShowScreenShot(1)
    ;----------------------
    Gui, ft_Mini:New
    Gui, +LastFound +AlwaysOnTop -Caption +ToolWindow -DPIScale +E0x08000000
    Gui, Color, Red
    d:=2, w:=nW+2*d, h:=nH+2*d, i:=w-d, j:=h-d
    Gui, Show, Hide w%w% h%h%
    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%
    ;------------------------------
    Hotkey, $*RButton, ft_RButton_Off, On
    lls:=A_ListLines=0 ? "Off" : "On"
    ListLines, Off
    CoordMode, Mouse
    KeyWait, RButton
    KeyWait, Ctrl
    oldx:=oldy:=""
    Loop
    {
      Sleep, 50
      MouseGetPos, x, y, Bind_ID
      if (oldx=x and oldy=y)
        Continue
      oldx:=x, oldy:=y
      ;---------------
      Gui, Show, % "NA x" (x-w//2) " y" (y-h//2)
      ToolTip, % "鼠标位置 : " x "," y
        . "`n先点击右键一次确定选框"
        . "`n再移开鼠标避免鼠标影响"
        . "`n再点击右键一次完成抓图"
    }
    Until GetKeyState("RButton","P") or GetKeyState("Ctrl","P")
    KeyWait, RButton
    KeyWait, Ctrl
    px:=x, py:=y, oldx:=oldy:=""
    Loop
    {
      Sleep, 50
      MouseGetPos, x, y
      if (oldx=x and oldy=y)
        Continue
      oldx:=x, oldy:=y
      ;---------------
      ToolTip, % "选框位置 : " px "," py
        . "`n先点击右键一次确定选框"
        . "`n再移开鼠标避免鼠标影响"
        . "`n再点击右键一次完成抓图"
    }
    Until GetKeyState("RButton","P") or GetKeyState("Ctrl","P")
    KeyWait, RButton
    KeyWait, Ctrl
    ToolTip
    ListLines, %lls%
    Gui, Destroy
    WinWaitClose,,, 10
    cors:=ft_getc(px,py,ww,hh,!ShowScreenShot)
    Hotkey, $*RButton, ft_RButton_Off, Off
    if (ShowScreenShot)
      ft_ShowScreenShot(0)
    ;--------------------------------
    Gui, ft_Capture:Default
    k:=nW*nH+1
    Loop, % nW
      GuiControl,, % C_[k++], 0
    Loop, 6
      GuiControl,, Edit%A_Index%
    GuiControl,, Modify, % Modify:=0
    GuiControl,, GrayDiff, 50
    GuiControl, Focus, Gray2Two
    GuiControl, +Default, Gray2Two
    ft_Gui("Reset")
    Gui, Show, Center
    Event:=Result:=""
    DetectHiddenWindows, Off
    Gui, +LastFound
    Critical, Off
    WinWaitClose, % "ahk_id " WinExist()
    Gui, ft_Main:Default
    ;--------------------------------
    if (cors.bind!="")
    {
      WinGetTitle, tt, ahk_id %Bind_ID%
      WinGetClass, tc, ahk_id %Bind_ID%
      tt:=Trim(SubStr(tt,1,30) (tc ? " ahk_class " tc:""))
      tt:=StrReplace(RegExReplace(tt,"[;``]","``$0"),"""","""""")
      Result:="`nSetTitleMatchMode, 2`nid:=WinExist(""" tt """)"
        . "`nBindWindow(id" (cors.bind ? ",1":"")
        . ")  `; 解绑窗口使用 Bindwindow(0)`n`n" Result
    }
    if (Event="ButtonOK")
    {
      if (!A_IsCompiled)
      {
        FileRead, s, %A_LineFile%
        s:=SubStr(s, s~="i)\n[;=]+ Copy The")
      }
      else s:=""
      GuiControl,, scr, % Result "`n" s
      GuiControl,, MyPic, % Trim(ASCII(Result),"`n")
      Result:=s:=""
    }
    else if (Event="SplitAdd") or (Event="AllAdd")
    {
      GuiControlGet, s,, scr
      i:=j:=0, r:="\|<[^>\n]*>[^$\n]+\$\d+\.[\w+/]+"
      While j:=RegExMatch(s,r,"",j+1)
        i:=InStr(s,"`n",0,j)
      GuiControl,, scr, % SubStr(s,1,i-1) . Result . SubStr(s,i+1)
      GuiControl,, MyPic, % Trim(ASCII(Result),"`n")
      Result:=s:=""
    }
    ;----------------------
    Gui, Show
    GuiControl, Focus, scr
    ft_RButton_Off:
    return
  }
  if (cmd="Bind1") or (cmd="Bind2")
  {
    BindWindow(Bind_ID, (cmd="Bind2"))
    Hotkey, $*RButton, ft_RButton_Off, On
    lls:=A_ListLines=0 ? "Off" : "On"
    ListLines, Off
    CoordMode, Mouse
    KeyWait, RButton
    KeyWait, Ctrl
    oldx:=oldy:=""
    Loop
    {
      Sleep, 50
      MouseGetPos, x, y
      if (oldx=x and oldy=y)
        Continue
      oldx:=x, oldy:=y
      ;---------------
      cors:=ft_getc(px:=x,py:=y,ww,hh)
      ft_Gui("Reset")
      ToolTip, % "鼠标位置 : " x "," y
        . "`n穿透显示绑定窗口"
        . "`n点击右键完成抓图"
    }
    Until GetKeyState("RButton","P") or GetKeyState("Ctrl","P")
    KeyWait, RButton
    KeyWait, Ctrl
    ToolTip
    ListLines, %lls%
    Hotkey, $*RButton, ft_RButton_Off, Off
    BindWindow(0), cors.bind:=(cmd="Bind2")
    return
  }
  if (cmd="Test") or (cmd="TestClip")
  {
    Critical, Off
    Gui, ft_Main:Default
    Gui, +LastFound
    WinMinimize
    Gui, Hide
    DetectHiddenWindows, Off
    WinWaitClose, % "ahk_id " WinExist()
    Sleep, 100
    ;----------------------
    if (cmd="Test")
      GuiControlGet, s,, scr
    else
      s:=Clipboard
    if (!A_IsCompiled) and InStr(s,"MCode(") and (cmd="Test")
    {
      s:="`n#NoEnv`nMenu, Tray, Click, 1`n"
        . "Gui, ft_ok_:Show, Hide, ft_ok_`n"
        . s "`nExitApp`n"
      ft_Exec(s)
      DetectHiddenWindows, On
      WinWait, ft_ok_ ahk_class AutoHotkeyGUI,, 3
      if (!ErrorLevel)
        WinWaitClose,,, 30
    }
    else
    {
      Gui, +OwnDialogs
      t:=A_TickCount, n:=150000
      , RegExMatch(s,"\|<[^>\n]*>[^$\n]+\$\d+\.[\w+/]+",v)
      , ok:=FindText(-n, -n, n, n, 0, 0, v)
      , X:=ok.1.x, Y:=ok.1.y, Comment:=ok.1.id
      MsgBox, 4096, 提示, % "找到:`t" Round(ok.MaxIndex()) "`n`n"
        . "时间:`t" (A_TickCount-t) " 毫秒`n`n"
        . "位置:`t" X ", " Y "`n`n"
        . "结果:`t" (ok ? "成功 ! " Comment : "失败 !"), 3
      for i,v in ok
        if (i<=2)
          MouseTip(ok[i].x, ok[i].y)
      ok:=""
    }
    ;----------------------
    Gui, Show
    GuiControl, Focus, scr
    return
  }
  if (cmd="Copy")
  {
    Gui, ft_Main:Default
    ControlGet, s, Selected,,, ahk_id %hscr%
    if (s="")
    {
      GuiControlGet, s,, scr
      GuiControlGet, r,, AddFunc
      if (r != 1)
        s:=RegExReplace(s,"\n\K[\s;=]+ Copy The[\s\S]*")
    }
    Clipboard:=RegExReplace(s,"\R","`r`n")
    ;----------------------
    Gui, Hide
    Sleep, 100
    Gui, Show
    GuiControl, Focus, scr
    return
  }
  if (cmd="MySlider1") or (cmd="MySlider2")
  {
    x:=SubPicW>PicW ? -(SubPicW-PicW)*MySlider1//100 : 0
    y:=SubPicH>PicH ? -(SubPicH-PicH)*MySlider2//100 : 0
    Gui, ft_SubPic:Show, NA x%x% y%y%
    return
  }
  if (cmd="Reset")
  {
    if !IsObject(ascii)
      ascii:=[], gray:=[], show:=[]
    CutLeft:=CutRight:=CutUp:=CutDown:=k:=0, bg:=""
    Loop, % nW*nH
    {
      show[++k]:=1, c:=cors[k]
      gray[k]:=(((c>>16)&0xFF)*38+((c>>8)&0xFF)*75+(c&0xFF)*15)>>7
      ft_Gui("SetColor")
    }
    Loop, % cors.CutLeft
      ft_Gui("CutL")
    Loop, % cors.CutRight
      ft_Gui("CutR")
    Loop, % cors.CutUp
      ft_Gui("CutU")
    Loop, % cors.CutDown
      ft_Gui("CutD")
    return
  }
  if (cmd="SetColor")
  {
    c:=c="Black" ? 0x000000 : c="White" ? 0xFFFFFF
      : ((c&0xFF)<<16)|(c&0xFF00)|((c&0xFF0000)>>16)
    SendMessage, 0x2001, 0, c,, % "ahk_id " . C_[k]
    return
  }
  if (cmd="RepColor")
  {
    show[k]:=1, c:=(bg="" ? cors[k] : ascii[k]
      ? "Black":"White"), ft_Gui("SetColor")
    return
  }
  if (cmd="CutColor")
  {
    show[k]:=0, c:=WindowColor, ft_Gui("SetColor")
    return
  }
  if (cmd="RepL")
  {
    if (CutLeft<=cors.CutLeft)
    or (bg!="" and InStr(color,"**")
    and CutLeft=cors.CutLeft+1)
      return
    k:=CutLeft-nW, CutLeft--
    Loop, %nH%
      k+=nW, (A_Index>CutUp and A_Index<nH+1-CutDown
        ? ft_Gui("RepColor") : "")
    return
  }
  if (cmd="CutL")
  {
    if (CutLeft+CutRight>=nW)
      return
    CutLeft++, k:=CutLeft-nW
    Loop, %nH%
      k+=nW, (A_Index>CutUp and A_Index<nH+1-CutDown
        ? ft_Gui("CutColor") : "")
    return
  }
  if (cmd="CutL3")
  {
    Loop, 3
      ft_Gui("CutL")
    return
  }
  if (cmd="RepR")
  {
    if (CutRight<=cors.CutRight)
    or (bg!="" and InStr(color,"**")
    and CutRight=cors.CutRight+1)
      return
    k:=1-CutRight, CutRight--
    Loop, %nH%
      k+=nW, (A_Index>CutUp and A_Index<nH+1-CutDown
        ? ft_Gui("RepColor") : "")
    return
  }
  if (cmd="CutR")
  {
    if (CutLeft+CutRight>=nW)
      return
    CutRight++, k:=1-CutRight
    Loop, %nH%
      k+=nW, (A_Index>CutUp and A_Index<nH+1-CutDown
        ? ft_Gui("CutColor") : "")
    return
  }
  if (cmd="CutR3")
  {
    Loop, 3
      ft_Gui("CutR")
    return
  }
  if (cmd="RepU")
  {
    if (CutUp<=cors.CutUp)
    or (bg!="" and InStr(color,"**")
    and CutUp=cors.CutUp+1)
      return
    k:=(CutUp-1)*nW, CutUp--
    Loop, %nW%
      k++, (A_Index>CutLeft and A_Index<nW+1-CutRight
        ? ft_Gui("RepColor") : "")
    return
  }
  if (cmd="CutU")
  {
    if (CutUp+CutDown>=nH)
      return
    CutUp++, k:=(CutUp-1)*nW
    Loop, %nW%
      k++, (A_Index>CutLeft and A_Index<nW+1-CutRight
        ? ft_Gui("CutColor") : "")
    return
  }
  if (cmd="CutU3")
  {
    Loop, 3
      ft_Gui("CutU")
    return
  }
  if (cmd="RepD")
  {
    if (CutDown<=cors.CutDown)
    or (bg!="" and InStr(color,"**")
    and CutDown=cors.CutDown+1)
      return
    k:=(nH-CutDown)*nW, CutDown--
    Loop, %nW%
      k++, (A_Index>CutLeft and A_Index<nW+1-CutRight
        ? ft_Gui("RepColor") : "")
    return
  }
  if (cmd="CutD")
  {
    if (CutUp+CutDown>=nH)
      return
    CutDown++, k:=(nH-CutDown)*nW
    Loop, %nW%
      k++, (A_Index>CutLeft and A_Index<nW+1-CutRight
        ? ft_Gui("CutColor") : "")
    return
  }
  if (cmd="CutD3")
  {
    Loop, 3
      ft_Gui("CutD")
    return
  }
  if (cmd="Gray2Two")
  {
    Gui, ft_Capture:Default
    GuiControl, Focus, Threshold
    GuiControlGet, Threshold
    if (Threshold="")
    {
      pp:=[]
      Loop, 256
        pp[A_Index-1]:=0
      Loop, % nW*nH
        if (show[A_Index])
          pp[gray[A_Index]]++
      IP:=IS:=0
      Loop, 256
        k:=A_Index-1, IP+=k*pp[k], IS+=pp[k]
      Threshold:=Floor(IP/IS)
      Loop, 20
      {
        LastThreshold:=Threshold
        IP1:=IS1:=0
        Loop, % LastThreshold+1
          k:=A_Index-1, IP1+=k*pp[k], IS1+=pp[k]
        IP2:=IP-IP1, IS2:=IS-IS1
        if (IS1!=0 and IS2!=0)
          Threshold:=Floor((IP1/IS1+IP2/IS2)/2)
        if (Threshold=LastThreshold)
          Break
      }
      GuiControl,, Threshold, %Threshold%
    }
    Threshold:=Round(Threshold)
    color:="*" Threshold, k:=i:=0
    Loop, % nW*nH
    {
      ascii[++k]:=v:=(gray[k]<=Threshold)
      if (show[k])
        i:=(v?i+1:i-1), c:=(v?"Black":"White"), ft_Gui("SetColor")
    }
    bg:=i>0 ? "1":"0"
    return
  }
  if (cmd="GrayDiff2Two")
  {
    Gui, ft_Capture:Default
    GuiControlGet, GrayDiff
    if (GrayDiff="")
    {
      Gui, +OwnDialogs
      MsgBox, 4096, 提示, `n  请先设定灰度差值 !  `n, 1
      return
    }
    if (CutLeft=cors.CutLeft)
      ft_Gui("CutL")
    if (CutRight=cors.CutRight)
      ft_Gui("CutR")
    if (CutUp=cors.CutUp)
      ft_Gui("CutU")
    if (CutDown=cors.CutDown)
      ft_Gui("CutD")
    GrayDiff:=Round(GrayDiff)
    color:="**" GrayDiff, k:=i:=0
    Loop, % nW*nH
    {
      j:=gray[++k]+GrayDiff
      , ascii[k]:=v:=( gray[k-1]>j or gray[k+1]>j
      or gray[k-nW]>j or gray[k+nW]>j
      or gray[k-nW-1]>j or gray[k-nW+1]>j
      or gray[k+nW-1]>j or gray[k+nW+1]>j )
      if (show[k])
        i:=(v?i+1:i-1), c:=(v?"Black":"White"), ft_Gui("SetColor")
    }
    bg:=i>0 ? "1":"0"
    return
  }
  if (cmd="Color2Two") or (cmd="ColorPos2Two")
  {
    Gui, ft_Capture:Default
    GuiControlGet, c,, SelColor
    if (c="")
    {
      Gui, +OwnDialogs
      MsgBox, 4096, Tip, `n  请先选择核心颜色 !  `n, 1
      return
    }
    UsePos:=(cmd="ColorPos2Two") ? 1:0
    GuiControlGet, n,, Similar1
    n:=Round(n/100,2), color:=c "@" n
    , n:=Floor(9*255*255*(1-n)*(1-n)), k:=i:=0
    , rr:=(c>>16)&0xFF, gg:=(c>>8)&0xFF, bb:=c&0xFF
    Loop, % nW*nH
    {
      c:=cors[++k], r:=((c>>16)&0xFF)-rr
      , g:=((c>>8)&0xFF)-gg, b:=(c&0xFF)-bb
      , ascii[k]:=v:=(3*r*r+4*g*g+2*b*b<=n)
      if (show[k])
        i:=(v?i+1:i-1), c:=(v?"Black":"White"), ft_Gui("SetColor")
    }
    bg:=i>0 ? "1":"0"
    return
  }
  if (cmd="ColorDiff2Two")
  {
    Gui, ft_Capture:Default
    GuiControlGet, c,, SelColor
    if (c="")
    {
      Gui, +OwnDialogs
      MsgBox, 4096, Tip, `n 请先选择核心颜色 !  `n, 1
      return
    }
    GuiControlGet, dR
    GuiControlGet, dG
    GuiControlGet, dB
    rr:=(c>>16)&0xFF, gg:=(c>>8)&0xFF, bb:=c&0xFF
    , n:=Format("{:06X}",(dR<<16)|(dG<<8)|dB)
    , color:=StrReplace(c "-" n,"0x"), k:=i:=0
    Loop, % nW*nH
    {
      c:=cors[++k], r:=(c>>16)&0xFF, g:=(c>>8)&0xFF
      , b:=c&0xFF, ascii[k]:=v:=(Abs(r-rr)<=dR
      and Abs(g-gg)<=dG and Abs(b-bb)<=dB)
      if (show[k])
        i:=(v?i+1:i-1), c:=(v?"Black":"White"), ft_Gui("SetColor")
    }
    bg:=i>0 ? "1":"0"
    return
  }
  if (cmd="Modify")
  {
    GuiControlGet, Modify, ft_Capture:, Modify
    return
  }
  if (cmd="Similar1")
  {
    GuiControl, ft_Capture:, Similar2, %Similar1%
    return
  }
  if (cmd="Similar2")
  {
    GuiControl, ft_Capture:, Similar1, %Similar2%
    return
  }
  if (cmd="getwz")
  {
    wz:=""
    if (bg="")
      return
    k:=0
    Loop, %nH%
    {
      v:=""
      Loop, %nW%
        v.=!show[++k] ? "" : ascii[k] ? "1":"0"
      wz.=v="" ? "" : v "`n"
    }
    return
  }
  if (cmd="Auto")
  {
    ft_Gui("getwz")
    if (wz="")
    {
      Gui, ft_Capture:+OwnDialogs
      MsgBox, 4096, Tip, `n请先将图像二值化 !, 1
      return
    }
    While InStr(wz,bg)
    {
      if (wz~="^" bg "+\n")
        wz:=RegExReplace(wz,"^" bg "+\n"), ft_Gui("CutU")
      else if !(wz~="m`n)[^\n" bg "]$")
        wz:=RegExReplace(wz,"m`n)" bg "$"), ft_Gui("CutR")
      else if (wz~="\n" bg "+\n$")
        wz:=RegExReplace(wz,"\n\K" bg "+\n$"), ft_Gui("CutD")
      else if !(wz~="m`n)^[^\n" bg "]")
        wz:=RegExReplace(wz,"m`n)^" bg), ft_Gui("CutL")
      else Break
    }
    wz:=""
    return
  }
  if (cmd="ButtonOK") or (cmd="SplitAdd") or (cmd="AllAdd")
  {
    Gui, ft_Capture:Default
    Gui, +OwnDialogs
    ft_Gui("getwz")
    if (wz="")
    {
      MsgBox, 4096, Tip, `n请先将图像二值化 !, 1
      return
    }
    if InStr(color,"@") and (UsePos)
    {
      StringSplit, r, color, @
      k:=i:=j:=0
      Loop, % nW*nH
      {
        if (!show[++k])
          Continue
        i++
        if (k=cors.SelPos)
        {
          j:=i
          Break
        }
      }
      if (j=0)
      {
        MsgBox, 4096, 提示, 请再次选择核心颜色 !, 3
        return
      }
      color:="#" (j-1) "@" r2
    }
    GuiControlGet, Comment
    if (cmd="SplitAdd")
    {
      if InStr(color,"#")
      {
        MsgBox, 4096, 提示
          , % "不能用于颜色位置二值化模式, "
          . "因为分割后会导致位置错误", 3
        return
      }
      SetFormat, IntegerFast, d
      bg:=StrLen(StrReplace(wz,"0"))
        > StrLen(StrReplace(wz,"1")) ? "1":"0"
      s:="", i:=0, k:=nW*nH+1+CutLeft
      Loop, % w:=nW-CutLeft-CutRight
      {
        i++
        GuiControlGet, j,, % C_[k++]
        if (j=0 and A_Index<w)
          Continue
        v:=RegExReplace(wz,"m`n)^(.{" i "}).*","$1")
        wz:=RegExReplace(wz,"m`n)^.{" i "}"), i:=0
        While InStr(v,bg)
        {
          if (v~="^" bg "+\n")
            v:=RegExReplace(v,"^" bg "+\n")
          else if !(v~="m`n)[^\n" bg "]$")
            v:=RegExReplace(v,"m`n)" bg "$")
          else if (v~="\n" bg "+\n$")
            v:=RegExReplace(v,"\n\K" bg "+\n$")
          else if !(v~="m`n)^[^\n" bg "]")
            v:=RegExReplace(v,"m`n)^" bg)
          else Break
        }
        if (v!="")
        {
          v:=Format("{:d}",InStr(v,"`n")-1) "." bit2base64(v)
          s.="`nText.=""|<" SubStr(Comment,1,1) ">" color "$" v """`n"
          Comment:=SubStr(Comment, 2)
        }
      }
      Event:=cmd, Result:=s
      Gui, Hide
      return
    }
    wz:=Format("{:d}",InStr(wz,"`n")-1) "." bit2base64(wz)
    s:="`nText.=""|<" Comment ">" color "$" wz """`n"
    if (cmd="AllAdd")
    {
      Event:=cmd, Result:=s
      Gui, Hide
      return
    }
    x:=px-ww+CutLeft+(nW-CutLeft-CutRight)//2
    y:=py-hh+CutUp+(nH-CutUp-CutDown)//2
    s:=StrReplace(s, "Text.=", "Text:=")
    s=
    (
`; #Include <FindText>

t1:=A_TickCount
%s%
if (ok:=FindText(%x%-150000, %y%-150000, %x%+150000, %y%+150000, 0, 0, Text))
{
  CoordMode, Mouse
  X:=ok.1.x, Y:=ok.1.y, Comment:=ok.1.id
  ; Click, `%X`%, `%Y`%
}

MsgBox, 4096, 提示, `% "找到:``t" Round(ok.MaxIndex()) "``n``n"
  . "时间:``t" (A_TickCount-t1) " 毫秒``n``n"
  . "位置:``t" X ", " Y "``n``n"
  . "结果:``t" (ok ? "成功 ! " Comment : "失败 !")

for i,v in ok
  if (i<=2)
    MouseTip(ok[i].x, ok[i].y)

)
    Event:=cmd, Result:=s
    Gui, Hide
    return
  }
  if (cmd="ShowPic")
  {
    Critical
    ControlGet, i, CurrentLine,,, ahk_id %hscr%
    ControlGet, s, Line, %i%,, ahk_id %hscr%
    GuiControl, ft_Main:, MyPic, % Trim(ASCII(s),"`n")
    return
  }
  if (cmd="WM_LBUTTONDOWN")
  {
    Critical
    MouseGetPos,,,, j
    IfNotInString, j, progress
      return
    MouseGetPos,,,, j, 2
    Gui, ft_Capture:Default
    For k,v in C_
    {
      if (v!=j)
        Continue
      if (k>nW*nH)
      {
        GuiControlGet, i,, %v%
        GuiControl,, %v%, % i ? 0:100
      }
      else if (Modify and bg!="" and show[k])
      {
        ascii[k]:=!ascii[k]
        , c:=(ascii[k] ? "Black":"White")
        , ft_Gui("SetColor")
      }
      else
      {
        c:=cors[k], cors.SelPos:=k
        r:=(c>>16)&0xFF, g:=(c>>8)&0xFF, b:=c&0xFF
        GuiControl,, SelGray, % gray[k]
        GuiControl,, SelColor, %c%
        GuiControl,, SelR, %r%
        GuiControl,, SelG, %g%
        GuiControl,, SelB, %b%
      }
      Break
    }
    return
  }
  if (cmd="Apply")
  {
    if (!ft_FuncBind2)
      ft_FuncBind2:=Func("ft_Gui").Bind("ScreenShot")
    Gui, ft_Main:Default
    GuiControlGet, NowHotkey
    GuiControlGet, SetHotkey1
    GuiControlGet, SetHotkey2
    if (NowHotkey!="")
      Hotkey, *%NowHotkey%,, Off UseErrorLevel
    k:=SetHotkey1!="" ? SetHotkey1 : SetHotkey2
    if (k!="")
      Hotkey, *%k%, %ft_FuncBind2%, On UseErrorLevel
    GuiControl,, NowHotkey, %k%
    GuiControl,, SetHotkey1
    GuiControl, Choose, SetHotkey2, 0
    ;------------------------
    GuiControlGet, Myww
    GuiControlGet, Myhh
    if (Myww!=ww or Myhh!=hh)
    {
      Gui, Hide
      ww:=Myww, hh:=Myhh, ft_Gui("MakeSubPicWindow")
      Gui, ft_Main:Show, Center
    }
    return
  }
  if (cmd="ScreenShot")
  {
    Critical
    ScreenShot()
    Gui, ft_Tip:New
    ; WS_EX_NOACTIVATE:=0x08000000, WS_EX_TRANSPARENT:=0x20
    Gui, +LastFound +AlwaysOnTop +ToolWindow -Caption -DPIScale +E0x08000020
    Gui, Color, Yellow
    Gui, Font, cRed s48 bold
    Gui, Add, Text,, 截屏成功
    WinSet, Transparent, 200
    Gui, Show, NA y0, 截屏提示
    Sleep, 1000
    Gui, Destroy
    return
  }
}

ft_Load_ToolTip_Text()
{
  s=
(LTrim
Myww       = 调整捕获范围的宽度
Myhh       = 调整捕获范围的高度
AddFunc    = 将 FindText() 函数代码一起复制
NowHotkey  = 当前的截屏热键
SetHotkey1 = 第一优先级的截屏热键
SetHotkey2 = 第二优先级的截屏热键
Apply      = 应用新的截屏热键和调整后的捕获范围值
TestClip   = 将文字代码复制到剪贴板然后测试
Capture    = 开始屏幕抓图
CaptureS   = 先恢复上一次的截屏到屏幕再开始抓图
Test       = 测试生成的代码是否可以找字成功
Copy       = 复制代码到剪贴板
Reset      = 重新读取原来的彩色图像
SplitAdd   = 使用黄色的标签来分割图像为单个的图像数据,添加到旧代码中
AllAdd     = 将文字数据整体添加到旧代码中
ButtonOK   = 生成全新的代码替换旧代码
Close      = 关闭窗口不做任何事
Gray2Two      = 灰度小于阈值的为黑色其余白色
GrayDiff2Two  = 某点与周围灰度之差大于差值的为黑色其余白色
Color2Two     = 指定颜色及相似色为黑色其余白色
ColorPos2Two  = 指定颜色及相似色为黑色其余白色,但是记录该色的位置
ColorDiff2Two = 指定颜色及颜色分量小于允许值的为黑色其余白色
SelGray    = 选定颜色的灰度值 (0-255)
SelColor   = 选定颜色的RGB颜色值
SelR       = 选定颜色的红色分量
SelG       = 选定颜色的绿色分量
SelB       = 选定颜色的蓝色分量
RepU       = 撤销裁剪上边缘1个像素
CutU       = 裁剪上边缘1个像素
CutU3      = 裁剪上边缘3个像素
RepL       = 撤销裁剪左边缘1个像素
CutL       = 裁剪左边缘1个像素
CutL3      = 裁剪左边缘3个像素
Auto       = 二值化之后自动裁剪空白边缘
RepR       = 撤销裁剪右边缘1个像素
CutR       = 裁剪右边缘1个像素
CutR3      = 裁剪右边缘3个像素
RepD       = 撤销裁剪下边缘1个像素
CutD       = 裁剪下边缘1个像素
CutD3      = 裁剪下边缘3个像素
Modify     = 二值化后允许修改黑白点
Comment    = 识别文本 (包含在<>中),分割添加时也会分解成单个文字
Threshold  = 灰度阈值 (0-255)
GrayDiff   = 灰度差值 (0-255)
Similar1   = 与选定颜色的相似度
Similar2   = 与选定颜色的相似度
DiffR      = 红色分量允许的偏差 (0-255)
DiffG      = 绿色分量允许的偏差 (0-255)
DiffB      = 蓝色分量允许的偏差 (0-255)
Bind1      = 绑定窗口从而可以后台查找这个窗口的图像
Bind2      = 先修改窗口使它支持透明属性再绑定窗口
)
  return, s
}

ft_EditEvents1()
{
  static ft_FuncBind3:=Func("ft_Gui").Bind("ShowPic")
  ListLines, Off
  if (A_Gui="ft_Main" && A_GuiControl="scr")
    SetTimer, %ft_FuncBind3%, -150
}

ft_EditEvents2()
{
  ListLines, Off
  if (A_Gui="ft_SubPic")
    ft_Gui("WM_LBUTTONDOWN")
  else
    ft_EditEvents1()
}

ft_ShowToolTip(cmd:="")
{
  static
  ListLines, Off
  if (!ToolTip_Text)
    ToolTip_Text:=ft_Load_ToolTip_Text()
  if (!ft_FuncBind4)
    ft_FuncBind4:=Func("ft_ShowToolTip").Bind("ToolTip")
  if (!ft_FuncBind5)
    ft_FuncBind5:=Func("ft_ShowToolTip").Bind("ToolTipOff")
  if (cmd="ToolTip")
  {
    MouseGetPos,,, _TT
    WinGetClass, _TT, ahk_id %_TT%
    if (_TT = "AutoHotkeyGUI")
      ToolTip, % RegExMatch(ToolTip_Text
      , "im`n)^" CurrControl "\K\s*=.*", _TT)
      ? StrReplace(Trim(_TT,"`t ="),"\n","`n") : ""
    return
  }
  if (cmd="ToolTipOff")
  {
    ToolTip
    return
  }
  CurrControl:=A_GuiControl
  if (CurrControl!=PrevControl)
  {
    PrevControl:=CurrControl, _TT:=(CurrControl!="")
    SetTimer, %ft_FuncBind4%, % _TT ? -500  : "Off"
    SetTimer, %ft_FuncBind5%, % _TT ? -5500 : "Off"
    ToolTip
  }
}

ft_getc(px, py, ww, hh, ScreenShot:=1)
{
  xywh2xywh(px-ww,py-hh,2*ww+1,2*hh+1,x,y,w,h)
  if (w<1 or h<1)
    return
  bch:=A_BatchLines
  SetBatchLines, -1
  if (ScreenShot)
    ScreenShot()
  cors:=[], k:=0
  lls:=A_ListLines=0 ? "Off" : "On"
  ListLines, Off
  Loop, % 2*hh+1
  {
    j:=py-hh+A_Index-1
    Loop, % 2*ww+1
      i:=px-ww+A_Index-1, cors[++k]:=ScreenShot_GetColor(i,j)
  }
  ListLines, %lls%
  cors.CutLeft:=Abs(px-ww-x)
  cors.CutRight:=Abs(px+ww-(x+w-1))
  cors.CutUp:=Abs(py-hh-y)
  cors.CutDown:=Abs(py+hh-(y+h-1))
  SetBatchLines, %bch%
  return, cors
}

ft_ShowScreenShot(Show:=1) {
  local  ; 避免超级全局变量的影响
  static hBM, Ptr:=A_PtrSize ? "UPtr" : "UInt"
  Gui, ft_ScreenShot:Destroy
  if (hBM)
    DllCall("DeleteObject",Ptr,hBM), hBM:=""
  bits:=GetBitsFromScreen(0,0,0,0,0,zx,zy,zw,zh)
  if (!Show or !bits.1 or zw<1 or zh<1)
    return
  ;---------------------
  VarSetCapacity(bi, 40, 0), NumPut(40, bi, 0, "int")
  NumPut(zw, bi, 4, "int"), NumPut(-zh, bi, 8, "int")
  NumPut(1, bi, 12, "short"), NumPut(bpp:=32, bi, 14, "short")
  if (hBM:=DllCall("CreateDIBSection", Ptr,0, Ptr,&bi
  , "int",0, Ptr "*",ppvBits, Ptr,0, "int",0, Ptr))
    DllCall("RtlMoveMemory",Ptr,ppvBits,Ptr,bits.1,Ptr,bits.2*zh)
  ;-------------------------
  win:=DllCall("GetDesktopWindow", Ptr)
  hDC:=DllCall("GetWindowDC", Ptr,win, Ptr)
  mDC:=DllCall("CreateCompatibleDC", Ptr,hDC, Ptr)
  oBM:=DllCall("SelectObject", Ptr,mDC, Ptr,hBM, Ptr)
  hBrush:=DllCall("CreateSolidBrush", "uint",0xFFFFFF, Ptr)
  oBrush:=DllCall("SelectObject", Ptr,mDC, Ptr,hBrush, Ptr)
  DllCall("BitBlt", Ptr,mDC, "int",0, "int",0, "int",zw, "int",zh
    , Ptr,mDC, "int",0, "int",0, "uint",0xC000CA)
  DllCall("SelectObject", Ptr,mDC, Ptr,oBrush)
  DllCall("DeleteObject", Ptr,hBrush)
  DllCall("SelectObject", Ptr,mDC, Ptr,oBM)
  DllCall("DeleteDC", Ptr,mDC)
  DllCall("ReleaseDC", Ptr,win, Ptr,hDC)
  ;-------------------------
  Gui, ft_ScreenShot:+AlwaysOnTop -Caption +ToolWindow -DPIScale +E0x08000000
  Gui, ft_ScreenShot:Margin, 0, 0
  Gui, ft_ScreenShot:Add, Picture, x0 y0 w%zw% h%zh% +HwndhPic +0xE
  SendMessage, 0x172, 0, hBM,, ahk_id %hPic%
  Gui, ft_ScreenShot:Show, NA x%zx% y%zy% w%zw% h%zh%, Show ScreenShot
}

ft_Exec(s)
{
  Ahk:=A_IsCompiled ? A_ScriptDir "\AutoHotkey.exe":A_AhkPath
  s:=RegExReplace(s, "\R", "`r`n")
  Try
  {
    shell:=ComObjCreate("WScript.Shell")
    oExec:=shell.Exec(Ahk " /f /ErrorStdOut *")
    oExec.StdIn.Write(s)
    oExec.StdIn.Close()
  }
  catch
  {
    f:=A_Temp "\~test1.tmp"
    s:="`r`n FileDelete, " f "`r`n" s
    FileDelete, %f%
    FileAppend, %s%, %f%
    Run, %Ahk% /f "%f%",, UseErrorLevel
  }
}

;
查找这个用户的全部帖子
表示感谢 引用并回复 移动视图置页面顶端
[+] 25用户表示感谢feiyue
2013-12-21, 16 : 40
RE: 【快捷抓取屏幕文字/图像字符串】
试了下,效果不错。 就是速度确实很慢。。。

这方面,推荐用大漠插件。它可以直接做字库,直接查图像什么的,速度都很快。

版本的话,论坛管理员曾发过一个好版本,虽然不能直接下载了,不过可以搜索从别处下载。
查找这个用户的全部帖子
表示感谢 引用并回复 移动视图置页面顶端
[+] 1用户表示感谢兔子
2013-12-22, 00 : 28
RE: 【快捷抓取屏幕文字/图像字符串】
算法用C写一遍看看
查找这个用户的全部帖子
表示感谢 引用并回复 移动视图置页面顶端
2013-12-22, 18 : 45 (这个帖子最后修改于: 2019-12-21 19 : 05 by feiyue.)
RE: 【快捷抓取屏幕文字/图像字符串】
主贴已更新,分享了我自己的【查找屏幕文字/图像字符串】函数。
在我的各种自动化脚本中,主要就是采用了这个函数,非常好用。
【由于主贴内容长度超出限制,所以后半部分放到4楼来了】

代码: (全选)
;===== Copy The Following Functions To Your Own Code Just once =====


;--------------------------------
;  FindText - 屏幕找字函数
;--------------------------------
;  返回变量 := FindText(
;      X1 --> 查找范围的左上角X坐标
;    , Y1 --> 查找范围的左上角Y坐标
;    , X2 --> 查找范围的右下角X坐标
;    , Y2 --> 查找范围的右下角Y坐标
;    , err1 --> 文字的黑点容错百分率(0.1=10%)
;    , err0 --> 背景的白点容错百分率(0.1=10%)
;    , Text --> 由工具生成的查找图像的数据,可以一次查找多个,用“|”分隔
;    , ScreenShot --> 是否截屏,为0则使用上一次的截屏数据
;    , FindAll -->    是否搜索所有位置,为0则找到一个位置就返回
;    , JoinText -->   是否组合图像,为1则多个数据组合为一幅图来查找
;    , offsetX --> 组合图像的每个字和前一个字的最大横向间隔
;    , offsetY --> 组合图像的每个字和第一个字的最大高低间隔
;  )
;  返回变量 --> 如果没找到结果会返回0。否则返回一个二级数组,
;      第一级是每个结果对象,第二级是结果对象的具体信息数组:
;      { 1:左上角X, 2:左上角Y, 3:图像宽度W, 4:图像高度H
;        , x:中心点X, y:中心点Y, id:图像识别文本 }
;  坐标都是相对于屏幕,颜色使用RGB格式,组合查找必须使用统一的颜色模式
;--------------------------------

FindText( x1, y1, x2, y2, err1, err0, text, ScreenShot:=1
  , FindAll:=1, JoinText:=0, offsetX:=20, offsetY:=10 )
{
  local  ; 避免超级全局变量的影响
  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,zx,zy,zw,zh)
  if (w<1 or h<1)
  {
    SetBatchLines, %bch%
    return, 0
  }
  bits:=GetBitsFromScreen(x,y,w,h,ScreenShot,zx,zy,zw,zh)
  sx:=x-zx, sy:=y-zy, sw:=w, sh:=h, arr:=[], info:=[]
  Loop, Parse, text, |
    if IsObject(j:=PicInfo(A_LoopField))
      info.Push(j)
  if (!(num:=info.MaxIndex()) or !bits.1)
  {
    SetBatchLines, %bch%
    return, 0
  }
  VarSetCapacity(input, num*7*4), k:=0
  Loop, % num
    k+=Round(info[A_Index].2 * info[A_Index].3)
  VarSetCapacity(s1, k*4), VarSetCapacity(s0, k*4)
  , VarSetCapacity(gs, sw*sh), VarSetCapacity(ss, sw*sh)
  , allpos_max:=(FindAll ? 1024 : 1)
  , VarSetCapacity(allpos, allpos_max*4)
  Loop, 2
  {
    if (err1=0 and err0=0) and (num>1 or A_Index>1)
      err1:=0.1, err0:=0.05
    if (JoinText)
    {
      j:=info[1], mode:=j.8, color:=j.9, n:=j.10
      , w1:=-1, h1:=j.3, comment:="", v:="", i:=0
      Loop, % num
      {
        j:=info[A_Index], w1+=j.2+1, comment.=j.11
        Loop, 7
          NumPut((A_Index=1 ? StrLen(v)
          : A_Index=6 and err1 and !j.12 ? Round(j.4*err1)
          : A_Index=7 and err0 and !j.12 ? Round(j.5*err0)
          : j[A_Index]), input, 4*(i++), "int")
        v.=j.1
      }
      ok:=PicFind( mode,color,n,offsetX,offsetY
      , bits,sx,sy,sw,sh,gs,ss,v,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:=j.1
        Loop, 7
          NumPut((A_Index=1 ? 0
          : A_Index=6 and err1 and !j.12 ? Round(j.4*err1)
          : A_Index=7 and err0 and !j.12 ? Round(j.5*err0)
          : j[A_Index]), input, 4*(A_Index-1), "int")
        ok:=PicFind( mode,color,n,offsetX,offsetY
        , bits,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 (err1=0 and err0=0 and num=1 and !arr.MaxIndex())
    {
      k:=0
      For i,j in info
        k+=(!j.12)
      IfEqual, k, 0, Break
    }
    else Break
  }
  SetBatchLines, %bch%
  return, arr.MaxIndex() ? arr:0
}

; 绑定窗口从而可以后台查找这个窗口的图像
; 相当于始终在前台。解绑窗口使用 Bindwindow(0)

BindWindow(window_id:=0, set_exstyle:=0, get:=0)
{
  static id, old, Ptr:=A_PtrSize ? "UPtr" : "UInt"
  if (get)
    return, id
  if (window_id)
  {
    id:=window_id, old:=0
    if (set_exstyle)
    {
      WinGet, old, ExStyle, ahk_id %id%
      WinSet, Transparent, 255, ahk_id %id%
      Loop, 30
      {
        Sleep, 100
        WinGet, i, Transparent, ahk_id %id%
      }
      Until (i=255)
    }
  }
  else
  {
    if (old)
      WinSet, ExStyle, %old%, ahk_id %id%
    id:=old:=0
  }
}

xywh2xywh(x1,y1,w1,h1, ByRef x,ByRef y,ByRef w,ByRef h
  , ByRef zx:="", ByRef zy:="", ByRef zw:="", ByRef zh:="")
{
  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, ScreenShot:=1
  , ByRef zx:="", ByRef zy:="", ByRef zw:="", ByRef zh:="")
{
  local  ; 避免超级全局变量的影响
  static hBM, oldzx, oldzy, oldzw, oldzh, bits:=[]
  static Ptr:=A_PtrSize ? "UPtr" : "UInt"
  static init:=!GetBitsFromScreen(0,0,0,0,1)
  if (!ScreenShot)
  {
    zx:=oldzx, zy:=oldzy, zw:=oldzw, zh:=oldzh
    return, bits
  }
  bch:=A_BatchLines, cri:=A_IsCritical
  Critical
  if (zw<1 or zh<1)
  {
    SysGet, zx, 76
    SysGet, zy, 77
    SysGet, zw, 78
    SysGet, zh, 79
  }
  if (zw>oldzw or zh>oldzh or !hBM)
  {
    DllCall("DeleteObject", Ptr,hBM), hBM:="", bpp:=32
    VarSetCapacity(bi, 40, 0), NumPut(40, bi, 0, "int")
    NumPut(zw, bi, 4, "int"), NumPut(-zh, bi, 8, "int")
    NumPut(1, bi, 12, "short"), NumPut(bpp, bi, 14, "short")
    hBM:=DllCall("CreateDIBSection", Ptr,0, Ptr,&bi
      , "int",0, Ptr "*",ppvBits, Ptr,0, "int",0, Ptr)
    Scan0:=(!hBM ? 0:ppvBits), Stride:=((zw*bpp+31)//32)*4
    bits.1:=Scan0, bits.2:=Stride
    oldzx:=zx, oldzy:=zy, oldzw:=zw, oldzh:=zh
    x:=zx, y:=zy, w:=zw, h:=zh
  }
  if (hBM) and !(w<1 or h<1)
  {
    win:=DllCall("GetDesktopWindow", Ptr)
    hDC:=DllCall("GetWindowDC", Ptr,win, Ptr)
    mDC:=DllCall("CreateCompatibleDC", Ptr,hDC, Ptr)
    oBM:=DllCall("SelectObject", Ptr,mDC, Ptr,hBM, Ptr)
    DllCall("BitBlt",Ptr,mDC,"int",x-zx,"int",y-zy,"int",w,"int",h
      , Ptr,hDC, "int",x, "int",y, "uint",0x00CC0020|0x40000000)
    DllCall("ReleaseDC", Ptr,win, Ptr,hDC)
    if (id:=BindWindow(0,0,1))
      WinGet, id, ID, ahk_id %id%
    if (id)
    {
      WinGetPos, wx, wy, ww, wh, ahk_id %id%
      left:=x, right:=x+w-1, up:=y, down:=y+h-1
      left:=left<wx ? wx:left, right:=right>wx+ww-1 ? wx+ww-1:right
      up:=up<wy ? wy:up, down:=down>wy+wh-1 ? wy+wh-1:down
      x:=left, y:=up, w:=right-left+1, h:=down-up+1
    }
    if (id) and !(w<1 or h<1)
    {
      hDC2:=DllCall("GetDCEx", Ptr,id, Ptr,0, "int",3, Ptr)
      DllCall("BitBlt",Ptr,mDC,"int",x-zx,"int",y-zy,"int",w,"int",h
        , Ptr,hDC2, "int",x-wx, "int",y-wy, "uint",0x00CC0020|0x40000000)
      DllCall("ReleaseDC", Ptr,id, Ptr,hDC2)
    }
    DllCall("SelectObject", Ptr,mDC, Ptr,oBM)
    DllCall("DeleteDC", Ptr,mDC)
  }
  Critical, %cri%
  SetBatchLines, %bch%
  return, bits
}

PicInfo(text)
{
  static info:=[]
  IfNotInString, text, $, return
  if (info[text])
    return, info[text]
  v:=text, comment:="", e1:=e0:=0, 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 (w1<1 or h1<1 or StrLen(v)!=w1*h1)
    return
  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:=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)
  return, info[text]:=[v,w1,h1,len1,len0,e1,e0
    , mode,color,n,comment,set_e1_e0]
}

PicFind(mode, color, n, offsetX, offsetY
  , bits, 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"
  if (!MyFunc)
  {
    x32:="5557565383EC788B8424CC0000008BBC24CC000000C7442"
    . "424000000008B40048B7F148944243C8B8424CC000000897C2"
    . "42C8BBC24CC0000008B40088B7F18894424388B8424CC00000"
    . "0897C24308B400C89C6894424288B8424CC0000008B401039C"
    . "6894424200F4DC68944241C8B8424D000000085C00F8E15010"
    . "0008BB424CC0000008B44242489F78B0C868B7486048B44870"
    . "88974241085C0894424180F8ED700000089CD894C2414C7442"
    . "40C00000000C744240800000000C744240400000000890C248"
    . "D76008DBC27000000008B5C24108B7424088B4C24148B54240"
    . "C89DF89F029F101F78BB424C000000001CE85DB7E5E8B0C248"
    . "9EB893C2489D7EB198BAC24C800000083C70483C00189548D0"
    . "083C101390424742C83BC248C0000000389FA0F45D0803C063"
    . "175D48BAC24C400000083C70483C00189549D0083C30139042"
    . "475D48B7424100174241489DD890C2483442404018BB424B00"
    . "000008B442404017424088BBC24A4000000017C240C3944241"
    . "80F8554FFFFFF83442424078B442424398424D00000000F8FE"
    . "BFEFFFF83BC248C000000030F84A00600008B8424A40000008"
    . "BB424A80000000FAF8424AC0000008BBC24A40000008D2CB08"
    . "B8424B0000000F7D88D04878BBC248C0000008944241085FF0"
    . "F84F702000083BC248C000000010F847F08000083BC248C000"
    . "000020F84330900008B8424900000008B9C24940000000FB6B"
    . "C24940000000FB6B42490000000C744241800000000C744242"
    . "400000000C1E8100FB6DF0FB6D08B84249000000089D10FB6C"
    . "4894424088B842494000000C1E8100FB6C029C101D08904248"
    . "B442408894C24408B4C240801D829D9894424088D043E894C2"
    . "40489F129F9894424148BBC24B40000008B8424B0000000894"
    . "C240C89E98B6C2440C1E00285FF894424340F8EBA0000008BB"
    . "424B000000085F60F8E910000008B8424A00000008B5424240"
    . "39424BC00000001C8034C243489CF894C244003BC24A000000"
    . "0EB3D8D76008DBC2700000000391C247C3D394C24047F37394"
    . "C24087C3189F30FB6F33974240C0F9EC3397424140F9DC183C"
    . "00483C20121D9884AFF39F8741E0FB658020FB648010FB6303"
    . "9DD7EBE31C983C00483C201884AFF39F875E28BB424B000000"
    . "0017424248B4C24408344241801034C24108B442418398424B"
    . "40000000F8546FFFFFF8B8424B00000002B44243C8944240C8"
    . "B8424B40000002B442438894424600F886D0900008B4424288"
    . "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"
    . "90100008B44243C8B700C8B78108B6808897424148B7014897"
    . "C242489C7897424548BB424B40000002B700489F08B7424703"
    . "9C60F4EC68BB424C4000000894424188B47FC89442404C1E00"
    . "201C6038424C8000000894424588B4424648B7C2428037C245"
    . "C3B442418894424040F8F8700000085ED7E268B8C24BC00000"
    . "08B54242431C08D1C398B0C8601D9803901740583EA01784A8"
    . "3C00139C575EA8B4424148B4C245439C8747E85C07E7A8B9C2"
    . "4BC000000896C244831C08B6C245801FBEB0983C0013944241"
    . "4745C8B54850001DA803A0074EC83E90179E78B6C244890834"
    . "424040103BC24B00000008B442404394424180F8D79FFFFFF8"
    . "3442428018B4424283944244C0F8D4CFFFFFF830424018B6C2"
    . "4448B04243944240C0F8D7EFCFFFFE911FDFFFF8B4424288B7"
    . "C245083442440078344243C1C8D4438FF894424288B4424403"
    . "98424D00000000F8F7FFEFFFF8B6C24448B7C24348B0424038"
    . "424A80000008BB424D40000000B4424688D4F01398C24D8000"
    . "0008904BE0F8ED8FCFFFF85ED7E278B7424088BBC24BC00000"
    . "08B8424C40000008D1C378B74246C8B1083C00401DA39F0C60"
    . "20075F283042401894C24348B04243944240C0F8DDEFBFFFFE"
    . "971FCFFFF89F68DBC27000000008B74243C8B8424900000003"
    . "1D2F7F60FAF8424A40000008D0490894424188B8424B000000"
    . "0038424A800000029F0894424348B8424AC000000038424B40"
    . "000002B442438398424AC0000008944243C0F8F560400008B8"
    . "424A40000008BB424A80000000FAF8424AC000000C74424240"
    . "00000008D04B0034424188BB424A0000000894424388B44243"
    . "4398424A80000000F8F320100008B8424AC000000C1E010894"
    . "424408B442438894424148B8424A8000000894424088B44241"
    . "40FB67C060289C52B6C2418893C240FB67C0601897C24040FB"
    . "63C068B44241C85C00F8E1E0100008B442430894424108B442"
    . "42C8944240C31C0EB678D76008DBC2700000000394424207E4"
    . "A8B9C24C80000008B0C8301E90FB6540E020FB65C0E012B142"
    . "42B5C24040FB60C0E0FAFD20FAFDB29F98D14520FAFC98D149"
    . "A8D144A39942494000000720C836C2410017865908D7426008"
    . "3C0013944241C0F84A3000000394424287E9D8B9C24C400000"
    . "08B0C8301E90FB6540E020FB65C0E012B14242B5C24040FB60"
    . "C0E0FAFD20FAFDB29F98D14520FAFC98D149A8D144A3B94249"
    . "40000000F865BFFFFFF836C240C010F8950FFFFFF834424080"
    . "183442414048B442408394424340F8DEFFEFFFF838424AC000"
    . "000018BBC24A40000008B44243C017C24383B8424AC0000000"
    . "F8D99FEFFFF8B4C242483C4785B5E89C85F5DC250008D74260"
    . "08B7C24248B4424400B4424088B9C24D40000008D4F013B8C2"
    . "4D80000008904BB0F8D64FAFFFF894C2424EB848B842490000"
    . "0008B8C24B4000000C7042400000000C74424040000000083C"
    . "001C1E00789C68B8424B0000000C1E00285C98944240889E88"
    . "9F50F8EAFF8FFFF8B9424B000000085D27E5F8B8C24A000000"
    . "08B5C2404039C24BC00000001C1034424088944240C038424A"
    . "000000089C70FB651020FB641010FB6316BC04B6BD22601C28"
    . "9F0C1E00429F001D039C50F970383C10483C30139F975D58BB"
    . "424B0000000017424048B44240C83042401034424108B34243"
    . "9B424B40000007582E92CF8FFFF8B8424B0000000C70424000"
    . "00000C744240400000000C1E002894424088B8424B40000008"
    . "5C00F8E920000008B8424B000000085C07E6F8B8C24A000000"
    . "08B5C24048BB424B800000001E9036C240801DE039C24BC000"
    . "000896C240C03AC24A00000000FB651020FB6410183C1040FB"
    . "679FC83C60183C3016BC04B6BD22601C289F8C1E00429F801D"
    . "0C1F8078846FFC643FF0039CD75CC8BBC24B0000000017C240"
    . "48B6C240C83042401036C24108B0424398424B40000000F856"
    . "EFFFFFF83BC24B4000000020F8E60F7FFFF8B8424BC0000000"
    . "38424B00000008BAC24B800000003AC24B0000000C74424040"
    . "1000000894424088B8424B400000083E8018944240C8B8424B"
    . "000000083C0018944241083BC24B0000000027E798B4424108"
    . "9E92B8C24B00000008B5C240889EA8D34288D45FE8904240FB"
    . "642010FB63A0384249000000039F87C360FB67A0239F87C2E0"
    . "FB6790139F87C260FB63E39F87C1F0FB63939F87C180FB6790"
    . "239F87C100FB67EFF39F87C080FB67E0139F87D04C64301018"
    . "3C20183C30183C10183C6013B0C2475A3834424040103AC24B"
    . "00000008B4424048BBC24B0000000017C24083944240C0F855"
    . "8FFFFFFE96FF6FFFF83C47831C95B89C85E5F5DC2500090909"
    . "090909090"
    x64:="4157415641554154555756534881EC88000000488B84245"
    . "0010000488BB42450010000448B94245801000089542428448"
    . "944240844898C24E80000008B40048B76144C8BBC244001000"
    . "04C8BB42448010000C74424180000000089442430488B84245"
    . "00100008974241C488BB424500100008B40088B76188944243"
    . "C488B842450010000897424388B400C89C789442440488B842"
    . "4500100008B401039C7894424100F4DC74585D289442454488"
    . "B84245001000048894424200F8ECB000000488B442420448B0"
    . "8448B68048B400885C0894424040F8E940000004489CE44890"
    . "C244531E431FF31ED0F1F8400000000004585ED7E614863142"
    . "4418D5C3D0089F848039424380100004589E0EB1D0F1F0083C"
    . "0014D63D94183C0044183C1014883C20139C34789149E74288"
    . "3F9034589C2440F45D0803A3175D783C0014C63DE4183C0048"
    . "3C6014883C20139C34789149F75D844012C2483C50103BC241"
    . "80100004403A42400010000396C24047582834424180748834"
    . "424201C8B442418398424580100000F8F35FFFFFF83F9030F8"
    . "43D0600008B8424000100008BBC24080100000FAF842410010"
    . "0008BB424000100008D3CB88B842418010000F7D885C9448D2"
    . "C860F841101000083F9010F844108000083F9020F84E008000"
    . "08B742428C744240400000000C74424180000000089F0440FB"
    . "6CEC1E8104589CC0FB6D84889F08B7424080FB6D44189DB89F"
    . "0440FB6C64889F1C1E8100FB6CD89D60FB6C08D2C0A8B94242"
    . "00100004129C301C3438D040129CE4529C48904248B8424180"
    . "10000C1E00285D2894424080F8E660100004C89BC244001000"
    . "0448BBC24180100004585FF0F8E91040000488B8C24F800000"
    . "04863C74C6354241831D24C03942430010000488D440102EB3"
    . "A0F1F80000000004439C37C4039CE7F3C39CD7C384539CC410"
    . "F9EC044390C240F9DC14421C141880C124883C2014883C0044"
    . "139D70F8E2D040000440FB6000FB648FF440FB648FE4539C37"
    . "EBB31C9EBD58B5C2428448B8C242001000031ED4531E44889D"
    . "84189DB0FB6DB0FB6F48B84241801000041C1EB10450FB6DBC"
    . "1E0024585C98904240F8EA10000004C89BC24400100004C89B"
    . "42448010000448B7C2408448BB424180100004585F67E60488"
    . "B8C24F80000004D63D44C039424300100004863C74531C94C8"
    . "D440102410FB600410FB648FF410FB650FE4429D829F10FAFC"
    . "029DA0FAFC98D04400FAFD28D04888D04504139C7430F93040"
    . "A4983C1014983C0044539CE7FC4033C244501F483C5014401E"
    . "F39AC2420010000758C4C8BBC24400100004C8BB4244801000"
    . "08B8424180100002B4424308904248B8424200100002B44243"
    . "C894424680F88750800008B7C24404D89F5488BAC243001000"
    . "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"
    . "0008B7C24308B44242831D2F7F70FAF8424000100008D04908"
    . "94424208B8424180100000384240801000029F8894424308B8"
    . "42410010000038424200100002B44243C39842410010000894"
    . "424440F8F2B0400008B8424000100008BBC24080100000FAF8"
    . "42410010000448B642440448B6C24544C8B8C24F8000000C74"
    . "42428000000008D04B8034424208944243C8B4424303984240"
    . "80100000F8F360100008B8424100100008B6C243CC1E010894"
    . "424408B8424080100008904248D450289EF2B7C24204585ED4"
    . "898450FB61C018D45014898410FB61C014863C5410FB634010"
    . "F8E1C0100008B442438894424188B44241C8944240431C0EB6"
    . "90F1F800000000044395424107E4E418B0C8601F98D5102448"
    . "D41014863C9410FB60C094863D24D63C0410FB61411470FB60"
    . "40129F10FAFC94429DA4129D80FAFD2450FAFC08D1452428D1"
    . "4828D144A395424087207836C241801786B4883C0014139C50"
    . "F8E9F0000004139C44189C27E96418B0C8701F98D5102448D4"
    . "1014863C9410FB60C094863D24D63C0410FB61411470FB6040"
    . "129F10FAFC94429DA4129D80FAFD2450FAFC08D1452428D148"
    . "28D144A3B5424080F864BFFFFFF836C2404010F8940FFFFFF8"
    . "304240183C5048B0424394424300F8DE6FEFFFF83842410010"
    . "000018BBC24000100008B442444017C243C3B8424100100000"
    . "F8D95FEFFFF8B4C2428E95CFBFFFF48634424288B5424400B1"
    . "424488BBC24600100008D48013B8C24680100008914870F8D3"
    . "5FBFFFF8304240183C504894C24288B0424394424300F8D7AF"
    . "EFFFFEB92448B5C2428448B84242001000031DB8B842418010"
    . "00031F6448B9424180100004183C30141C1E3074585C08D2C8"
    . "5000000000F8E6BF9FFFF4585D27E57488B8C24F80000004C6"
    . "3CE4C038C24300100004863C74531C0488D4C01020FB6110FB"
    . "641FF440FB661FE6BC04B6BD22601C24489E0C1E0044429E00"
    . "1D04139C3430F9704014983C0014883C1044539C27FCC01EF4"
    . "401D683C3014401EF399C24200100007595E9FBF8FFFF8B8C2"
    . "4200100008B84241801000031DB31F6448B8C241801000085C"
    . "98D2C85000000007E7D4585C97E694C63C6488B8C24F800000"
    . "04863C74D89C24C038424300100004C0394242801000031D24"
    . "88D4C0102440FB6190FB641FF4883C104440FB661FA6BC04B4"
    . "56BDB264101C34489E0C1E0044429E04401D8C1F8074188041"
    . "241C60410004883C2014139D17FC401EF4401CE83C3014401E"
    . "F399C2420010000758383BC2420010000020F8E4BF8FFFF486"
    . "3B424180100008B9C24180100008BBC2420010000488D56014"
    . "48D67FFBF010000004889D0480394243001000048038424280"
    . "100004889D58D53FD4C8D6A0183BC241801000002488D1C067"
    . "E7E4989C04D8D5C05004989D94929F04889E90FB610440FB65"
    . "0FF035424284439D27C44440FB650014439D27C3A450FB6104"
    . "439D27C31450FB6114439D27C28450FB650FF4439D27C1E450"
    . "FB650014439D27C14450FB651FF4439D27C0A450FB65101443"
    . "9D27D03C601014883C0014983C1014883C1014983C0014C39D"
    . "8759383C7014801F54889D84139FC0F8562FFFFFFE968F7FFF"
    . "F31C9E9D9F8FFFF909090909090909090909090"
    MCode(MyFunc, A_PtrSize=8 ? x64:x32)
  }
  return, !bits.1 ? 0:DllCall(&MyFunc, "int",mode, "uint",color
    , "uint",n, "int",offsetX, "int",offsetY, Ptr,bits.1
    , "int",bits.2, "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)
}

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
}

; 可以在脚本的开头用 PicLib(Text,1) 导入字库,
; 然后使用 PicLib("说明文字1|说明文字2|...") 获取字库中的数据

PicLib(comments, add_to_Lib:=0, index:=1)
{
  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[index,s2]:=r
      }
    Lib[index,""]:=""
  }
  else
  {
    Text:=""
    Loop, Parse, comments, |
    {
      s1:=Trim(A_LoopField), s2:=""
      Loop, Parse, s1
        s2.="_" . Ord(A_LoopField)
      Text.="|" . Lib[index,s2]
    }
    return, Text
  }
}

PicN(Number, index:=1)
{
  return, PicLib(RegExReplace(Number,".","|$0"), 0, index)
}

; 使用 PicX(Text) 可以将文字分割成多个单字的组合,从而适应间隔变化
; 但是不能用于“颜色位置二值化”模式, 因为位置是与整体图像相关的

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(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,zx,zy,zw,zh)
  GetBitsFromScreen(x,y,w,h,1,zx,zy,zw,zh)
}

; 从“上一次的截屏”中快速获取指定坐标的RGB颜色
; 如果坐标超出了屏幕范围,将返回白色

ScreenShot_GetColor(x,y)
{
  bits:=GetBitsFromScreen(0,0,0,0,0,zx,zy,zw,zh)
  return, (x<zx or x>zx+zw-1 or y<zy or y>zy+zh-1 or !bits.1)
    ? "0xFFFFFF" : Format("0x{:06X}",NumGet(bits.1
    +(y-zy)*bits.2+(x-zx)*4,"uint")&0xFFFFFF)
}

; 根据 FindText() 的结果识别一行文字或验证码
; offsetX 为两个文字的最大间隔,超过会插入*号
; offsetY 为后续文字与第一个文字的最大高度差
; 最后返回数组:{ocr:识别结果, 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}
}

; 按照从左到右、从上到下的顺序排序FindText()的结果
; 忽略轻微的Y坐标差距,返回排序后的数组对象

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
}

; 以指定点为中心,按从近到远排序FindText()的结果
; 返回排序后的数组对象

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
}

; 提示某个坐标的位置,或远程控制中当前鼠标的位置

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语言 源代码 *****

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;
  //----------------------
  // 生成查表需要的表格
  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;
      }
    }
  }
  // 颜色位置模式
  // 此模式不支持文字组合查找,仅用于多色验证码的识别
  if (mode==3)
  {
    c=(c/w1)*Stride+(c%w1)*4;
    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;
  }
  // 生成二值化图像
  o=sy*Stride+sx*4; j=Stride-4*sw; i=0;
  if (mode==0)  // 颜色相似二值化
  {
    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)  // 灰度阈值二值化
  {
    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)  // 灰度差值二值化
  {
    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) 颜色分量二值化
  {
    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;
      }
  }
  // 开始查找
  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;
        }
      }
      //------------------
      // 组合查找
      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;
      // 清空已经找到的图像
      for (i=0; i<len1; i++)
        ss[o+s1[i]]=0;
      NoMatch1:
      continue;
    }
  }
  Return1:
  return ok;
}

*/

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

;
查找这个用户的全部帖子
表示感谢 引用并回复 移动视图置页面顶端
2014-06-28, 16 : 53 (这个帖子最后修改于: 2014-06-28 16 : 59 by feiyue.)
RE: 【快捷抓取屏幕文字/图像字符串】
这个抓取文字字符串功能及找字函数很好用呀,是AHK找图功能的很好补充,怎么没有多少人关注呢?
我的自动化脚本中都是用它来识别文字和图像,希望大家多来使用。也请高手改进一下提高查找效率。
查找这个用户的全部帖子
表示感谢 引用并回复 移动视图置页面顶端
[+] 1用户表示感谢feiyue
2014-06-28, 17 : 07 (这个帖子最后修改于: 2014-06-28 17 : 07 by robertL.)
RE: 【快捷抓取屏幕文字/图像字符串】
嗯,很厉害,很实用!
想分离出里面的算法,慢慢研究~
待找个好的分类,汇总进去..

One for all, but man for himself

帮推广:AHK知乎专栏
查找这个用户的全部帖子
表示感谢 引用并回复 移动视图置页面顶端
2014-07-06, 03 : 06 (这个帖子最后修改于: 2014-07-06 03 : 07 by feiyue.)
RE: 【快捷抓取屏幕文字/图像字符串】
v2.0 改进:
1、灰度阀值模式与颜色模式的查找速度已基本一致。
2、可输入阀值来二值化,方便生成统一阀值的字库。
查找这个用户的全部帖子
表示感谢 引用并回复 移动视图置页面顶端
2014-07-06, 23 : 27
RE: 【快捷抓取屏幕文字/图像字符串】
手机先赞。很实用。
查找这个用户的全部帖子
表示感谢 引用并回复 移动视图置页面顶端
2014-07-10, 15 : 16
RE: 【快捷抓取屏幕文字/图像字符串】
太有用了,测试通过,缩小搜索范围之后速度基本在200ms以下,已经很理想了。感谢分享。
查找这个用户的全部帖子
表示感谢 引用并回复 移动视图置页面顶端
2014-08-17, 10 : 58
RE: 【快捷抓取屏幕文字/图像字符串】
非常棒!谢谢
查找这个用户的全部帖子
表示感谢 引用并回复 移动视图置页面顶端
[+] 1用户表示感谢Komakashiko
2014-11-19, 22 : 44
RE: 【快捷抓取屏幕文字/图像字符串】
很好很强大,谢谢了
查找这个用户的全部帖子
表示感谢 引用并回复 移动视图置页面顶端
2014-12-03, 23 : 04
RE: 【快捷抓取屏幕文字/图像字符串】
这个看不懂,要怎么验证呢 我把它做成了ank文件,然后 按下热键“LWin”(可改为自己喜欢的)不放,移动鼠标到目标位置,然后松开热键,半秒后什么都没有反应

按F1或F2只有用时234ms  再者是提示 查找失败

这个要到底怎么用?
查找这个用户的全部帖子
表示感谢 引用并回复 移动视图置页面顶端
2015-05-01, 08 : 44
RE: 【快捷抓取屏幕文字/图像字符串】
(2014-06-28 16 : 53)feiyue 提到:  这个抓取文字字符串功能及找字函数很好用呀,是AHK找图功能的很好补充,怎么没有多少人关注呢?
我的自动化脚本中都是用它来识别文字和图像,希望大家多来使用。也请高手改进一下提高查找效率。

这个没有你的通用识别码 高效 截取框太小
查找这个用户的全部帖子
表示感谢 引用并回复 移动视图置页面顶端
2015-06-04, 10 : 55
RE: 【快捷抓取屏幕文字/图像字符串】
加油!感谢分享!

简单,再简单一点儿
博客 http://blog.csdn.net/liuyukuan
访问这个用户的网站 查找这个用户的全部帖子
表示感谢 引用并回复 移动视图置页面顶端
2015-07-15, 20 : 38
RE: 【快捷抓取屏幕文字/图像字符串】
没明白这个的用途。
查找这个用户的全部帖子
表示感谢 引用并回复 移动视图置页面顶端
2015-10-29, 23 : 04 (这个帖子最后修改于: 2015-10-29 23 : 32 by feiyue.)
Heart RE: 【快捷抓取屏幕文字/图像字符串】

主贴已更新。“查找文字”函数新增了机器码查找,使颜色模式的查找速度达到极速,已经可以取代AHK自带的“ImageSearch”功能了,但灰度阀值模式的速度还没有​增强。

它的用法是:先用【LWin】热键抓字(或图像)生成图像字符串,然后粘贴到自己的脚本中,再用“查找文字”函数在屏幕的某个范围内查找就行了。要测试的话,粘贴到此示范​脚本的F1、F2的代码片段中,按【F12】重启脚本,然后按【F1】、【F2】就可测试这两种模式的效果了。

查找这个用户的全部帖子
表示感谢 引用并回复 移动视图置页面顶端
[+] 1用户表示感谢feiyue
2015-11-01, 18 : 02
RE: 【快捷抓取、查找屏幕文字/图像字符串】
试过好多次,都是查找失败,有没有成功的?

(2013-12-21 03 : 39)feiyue 提到:  
这是一个简单的辅助工具,用于生成屏幕文字(或图像)的形象化
二值化字符串(同时提供查找文字函数),用在脚本中非常好用!

在编写自动化脚本时,如果采用先抓图,再制作小图,再用
ImageSearch,操作太复杂,且不能仅使用脚本,还要打包图片。

如果仅仅采用颜色判断,显而易见太简陋了,不能精确判断
当前的屏幕文字(或图像),及精确定位。

所以这个工具就应运而生了,生成“0_”字符串组成的形象化
图像描述,然后在脚本中使用“查找文字()”函数就行了。
这可是我的独门秘技哦(^_^)!

代码: (全选)
/*
==================================================
  【快捷抓取、查找屏幕文字/图像字符串】v3.0  By FeiYue
==================================================

  v3.0 改进:颜色模式改用机器码搜索,速度超快!

  使用说明:

  1、按下热键“LWin”(可改为自己喜欢的)不放,移动
     鼠标到目标位置,然后松开热键,半秒后即可抓取。

  2、松开热键后有半秒的时间允许自己把鼠标移开,
     来避免鼠标处于这个位置导致的影响(如变色)。

  3、抓取了屏幕文字/图像的二值化字符串后(复制到
     剪贴板),可使用下面我的【查找文字】函数
     在屏幕某个范围内查找这个字符串,速度比较快。

==================================================

查找文字(X,Y,颜色,wenzi,左右偏移W,上下偏移H,返回X,返回Y)

灰度阀值模式查找速度测试:(测试设备:网吧电脑)

1、查找范围  800×600, 耗时平均为: 265 毫秒
2、查找范围 1024×768, 耗时平均为: 430 毫秒
3、查找范围 1440×900, 耗时平均为: 702 毫秒
4、查找范围 1680×1050,耗时平均为: 951 毫秒

结论:查找的范围不要太大,全屏查找要消耗较长时间。

==========================================
*/
Goto, _Start


;//下面用两种模式查找窗口菜单文字“文件”


F1::  ;//按【F1】测试颜色模式,请先粘贴正确的数据


color=0x000000
wenzi=
(
_____0__________0____0___
______0_________0_0__0___
000000000000___0__0__0___
___0____0______0__000000_
___0____0_____00_0___0___
____0___0____0_0_____0___
____0__0_______0_00000000
_____0_0_______0_____0___
______0________0_____0___
_____0_0_______0_____0___
___00___00_____0_____0___
000_______00___0_____0___
)


Goto, 执行查找
Return


F2::  ;//按【F2】测试灰度阀值模式,请先粘贴正确的数据


color=*116
wenzi=
(
_____0__________0____0___
______0_________0_0__0___
000000000000___0__0__0___
___0____0______0__000000_
___0____0_____00_0___0___
____0___0____0_0_____0___
____0__0_______0_00000000
_____0_0_______0_____0___
______0________0_____0___
_____0_0_______0_____0___
___00___00_____0_____0___
000_______00___0_____0___
)


Goto, 执行查找
Return


执行查找:
t1:=A_TickCount
Loop 5 {    ;//查找几次取平均值
  i:=A_Index
  ok:=查找文字(0,0,color,wenzi,800000,600000,返回X,返回Y)
  if !ok
    Break
  ToolTip, 成功第 %i% 次!
}
t1:=A_TickCount-t1
MsgBox, 4096,, % "`n平均耗时 " t1//i " 毫秒"
  . ",找到的位置:" 返回X "," 返回Y
Tooltip
if ok
  MouseMove, 返回X, 返回Y
else
  MsgBox, 查找失败!
Return



F12::    ;//保存并重启热键【F12】
SplitPath, A_ScriptName,,,, name
IfWinExist, %name%
{
  ControlSend, ahk_parent, {Ctrl Down}s{Ctrl Up}
  Sleep, 500
}
Reload
Return


;==============================


_Start:
#NoEnv
#SingleInstance Force
SetBatchLines, -1
CoordMode, Mouse
CoordMode, Pixel
CoordMode, ToolTip
SetWorkingDir, %A_ScriptDir%
ww:=20, hh:=8    ;//左右上下抓取文字的范围
nW:=2*ww+1, nH:=2*hh+1
Gosub, 生成抓字窗口
Return


生成抓字窗口:
Gui, 5:+LastFound +AlwaysOnTop +Owner -MinimizeBox
Gui, 5:Margin, 0, 15
Gui, 5:Font, s20
k:=1
Loop, %nH% {
  Loop, %nW% {
    v:=(A_Index=1 ? "x0 y+0":"x+0") " vc_" k++
    Gui, 5:Add, Progress, w20 h20 %v%
  }
}
Gui, 5:Add, Text, xm+15, 选色
Gui, 5:Add, Edit, x+15 w150
Gui, 5:Add, Button, x+10 gRun, 颜色二值化
Gui, 5:Add, Text, x+15, 阀值
Gui, 5:Add, Edit, x+15 w100
Gui, 5:Add, Button, x+10 gRun, 自动二值化
Gui, 5:Add, Button, xm+15 g5GuiClose Default, 取消
Gui, 5:Add, Button, x+15 gRun, 重读
Gui, 5:Add, Button, x+30 gRun, 左删
Gui, 5:Add, Button, x+10 gRun, 右删
Gui, 5:Add, Button, x+10 gRun, 上删
Gui, 5:Add, Button, x+10 gRun, 下删
Gui, 5:Add, Button, x+10 gRun, 智删
Gui, 5:Add, Button, x+30 gRun, 确定
Gui, 5:Show, Hide, 抓字生成二值化字符串
WinGet, gui5_id
Return



*LWin::    ;//抓字热键初定为键盘左下边的Win键
;----------------------------
IfWinExist, ahk_id %gui5_id%    ;//再次按就关闭抓字窗口
  Goto, 5GuiClose
;----------------------------
;//先用一个微型GUI提示抓字范围
Gui, 9:+LastFound +AlwaysOnTop
  -Caption +ToolWindow +E0x08000000
WinSet, Transparent, 100
Gui, 9:Color, Red
Gui, 9:Show, Hide w%nW% h%nH%
key:=RegExReplace(A_ThisHotkey,"[~!#\$\*\+\^]")
Loop {
  MouseGetPos, px, py
  Gui, 9:Show, % "NA x" px-ww " y" py-hh
  ToolTip, 当前坐标:%x% %y%`n松开热键后有半秒`n可以让你移开鼠标
  if not GetKeyState(key,"P")
    Break
  Sleep, 50
}
Gui, 9:Destroy
ToolTip
;----------------------------
Sleep, 500    ;//延时半秒允许鼠标移开原位置【重要!】
;----------------------------
cc:=getc(px,py,ww,hh)
GuiControl, 5:, Edit1
GuiControl, 5:, Edit2
Gosub, 重读
Gui, 5:Show, Center
SetTimer, 选色, 50
Return


Run:
k:=A_GuiControl
if !IsLabel(k)
  Return
if (InStr(k,"删") and wz="")
{
  MsgBox, 4096,, `n请先进行一种二值化!`n,1
  Return
}
Thread, NoTimers
Goto, %k%
Return

5GuiClose:
SetTimer, 选色, Off
Gui, 5:Hide
Return

选色:
if not GetKeyState("LButton","P")
  Return
MouseGetPos, a, b, id, class
if (id=gui5_id) and InStr(class,"Progress")
{
  PixelGetColor, c, a, b, RGB
  GuiControl, 5:, Edit1, %c%
}
Return

重读:
wz:="", k:=0
Loop, % nH*nW {
  c:=cc[++k]
  GuiControl, 5:+Background%c%, c_%k%
}
Return

颜色二值化:
GuiControlGet, color, 5:, Edit1
if color=
{
  MsgBox, 4096,, `n请先进行选色!`n, 1
  Return
}
up:=down:=left:=right:=0
wz:="", k:=0
Loop, %nH% {
  Loop, %nW% {
    ok:=cc[++k]=color, c:=ok ? "Black":"White"
    , wz.=ok ? "0":"_"
    GuiControl, 5:+Background%c%, c_%k%
  }
  wz.="`n"
}
判断背景色:
StringReplace, wz, wz, 0, 0, UseErrorLevel
bg:=ErrorLevel
StringReplace, wz, wz, _, _, UseErrorLevel
bg:=ErrorLevel>=bg ? "_":"0"
Return

自动二值化:
;//生成灰度图像,并统计灰度直方图
gg:=[], pp:=[], k:=0
Loop, 256
  pp[A_Index-1]:=0
Loop, % nH*nW    ;//为了快速查找,仅取绿色作为灰度值
  c:=cc[++k]>>8&0xFF, gg[k]:=c, pp[c]++
GuiControlGet, fazhi, 5:, Edit2
if fazhi=
{
  ;//迭代法求二值化阈值,最多迭代20次,这个算法非常快速
  IP:=IS:=0
  Loop, 256
    k:=A_Index-1, IP+=k*pp[k], IS+=pp[k]
  Newfazhi:=Floor(IP/IS)
  Loop, 20 {
    fazhi:=Newfazhi
    IP1:=IS1:=0
    Loop, % fazhi+1
      k:=A_Index-1, IP1+=k*pp[k], IS1+=pp[k]
    IP2:=IP-IP1, IS2:=IS-IS1
    if (IS1<>0 and IS2<>0)
      Newfazhi:=Floor((IP1/IS1+IP2/IS2)/2)
    if (Newfazhi=fazhi)
      Break
  }
  GuiControl, 5:, Edit2, %fazhi%
}
;//根据阈值处理输出(wz)和显示
up:=down:=left:=right:=0
wz:="", k:=0, color:="*" fazhi
Loop, %nH% {
  Loop, %nW% {
    ok:=gg[++k]<=fazhi, c:=ok ? "Black":"White"
    , wz.=ok ? "0":"_"
    GuiControl, 5:+Background%c%, c_%k%
  }
  wz.="`n"
}
Gosub, 判断背景色
Return

左删:
left++, k:=0
Loop, %nH% {
  Loop, %nW% {
    k++
    if (A_Index=left)
      GuiControl, 5:+BackgroundDefault, c_%k%
  }
}
wz:=RegExReplace(wz,"m`n)^[^\n]")
Return

右删:
right++, k:=0
Loop, %nH% {
  Loop, %nW% {
    k++
    if (A_Index=nW+1-right)
      GuiControl, 5:+BackgroundDefault, c_%k%
  }
}
wz:=RegExReplace(wz,"m`n)[^\n]$")
Return

上删:
up++, k:=0
Loop, %nH% {
  j:=A_Index
  Loop, %nW% {
    k++
    if (j=up)
      GuiControl, 5:+BackgroundDefault, c_%k%
  }
}
wz:=RegExReplace(wz,"^[^\n]+\n")
Return

下删:
down++, k:=0
Loop, %nH% {
  j:=A_Index
  Loop, %nW% {
    k++
    if (j=nH+1-down)
      GuiControl, 5:+BackgroundDefault, c_%k%
  }
}
wz:=RegExReplace(wz,"[^\n]+\n$")
Return


智删:
Loop {
  k:=0
  if RegExMatch(wz,"^" bg "+\n")
    Gosub, 上删
  if RegExReplace(wz,"m`n)[^\n]$",bg)=wz
    Gosub, 右删
  if RegExMatch(wz,"(?:^|\n)" bg "+\n$")
    Gosub, 下删
  if RegExReplace(wz,"m`n)^[^\n]",bg)=wz
    Gosub, 左删
  if (k=0 or wz="")
    Break
}
Return


确定:
Gosub, 5GuiClose
IfEqual, wz,, Return
px:=Floor(px+(left-right)/2)
py:=Floor(py+(up-down)/2)
s:="`ncolor=" color "`nwenzi=`n(`n" wz ")`n"
  . "`n;-- 添加查找代码 -- if 查找文字("
  . px "," py ",color,wenzi,150,150,X,Y)`n"
Clipboard:=RegExReplace(s,"\n","`r`n")
MsgBox, 4096
  ,, 抓取的文字已复制到剪贴板!`n%s%
Return


;---------- 下面是函数 -----------


;------------------------------
; 【简单获取图像的颜色数组】
;------------------------------
getc(x,y,w=20,h=8) {
  arr:=[], k:=0, nW:=2*w+1, nH:=2*h+1
  Loop, %nH% {
    j:=A_Index
    Loop, %nW% {
      i:=A_Index
      PixelGetColor, c, x-w-1+i, y-h-1+j, RGB
      arr[++k]:=c
    }
  }
  Return, arr
}

;-----------------------------
; 【查找屏幕文字/图像字符串】
;-----------------------------
查找文字(a,b,color,wenzi,w=150,h=150,ByRef rx="",ByRef ry="")
{
  ; 计算屏幕查找范围,a,b为中心,w,h为左右上下幅度
  nx:=ny:=0, nw:=A_ScreenWidth, nh:=A_ScreenHeight
  left:=a-w, right:=a+w, top:=b-h, end:=b+h
  if (left>nw-1 or top>nh-1 or right<0 or end<0)
    Return, 0
  left:=left<0 ? 0:left, right:=right>nw-1 ? nw-1:right
  top:=top<0 ? 0:top, end:=end>nh-1 ? nh-1:end
  width:=right-left+1, height:=end-top+1

  ; 整理字符串,过滤首行全是一种字符的行
  if i:=InStr(wenzi,"wenzi")
    wenzi:=SubStr(wenzi,i)
  wz:=RegExReplace(wenzi,"[^_0\n|]+")
  wz:=Trim(RegExReplace(wz,"[\n|]+","`n"),"`n")
  wz:=RegExReplace(RegExReplace(wz,"0","1"),"_","0")
  cut_top:=0
  While RegExMatch(wz,"^0+\n|^1+\n")
    wz:=SubStr(wz,InStr(wz,"`n")+1), cut_top++
  IfNotInString, wz, 1
    Return, 0

  ; 计算字符串可生成的图像长宽
  Width2:=0, Height2:=0
  Loop, Parse, wz, `n
    Height2++, i:=StrLen(A_LoopField)
    , Width2:=i>Width2 ? i:Width2

  ; 启动GDI+,获取屏幕图像
  BatchLines:=A_BatchLines
  Critical
  if !(pToken:=Gdip_Startup())
  {
    MsgBox, 4096, gdiplus error!, Gdiplus failed to start.
    ExitApp
  }
  HayStack:=ScreenShot(left, top, width, height, color)

  ; 两种模式查找字符串
  IfNotInString, color, *    ;//颜色模式,机器码查找
  {
    Needle:=Gdip_CreateBitmap(Width2, Height2)
    G:=Gdip_GraphicsFromImage(Needle), c:=0xFF000000
      , Gdip_GraphicsClear(G,c), Gdip_DeleteGraphics(G)
    E:=Gdip_LockBits(Needle,0,0,Width2,Height2,Stride,Scan0,tmp)
    i:=-4, c:=0xFFFFFFFF
    Loop, Parse, wz, `n
    {
      IfInString, A_LoopField, 1
        Loop, Parse, A_LoopField
          if A_LoopField=1
            NumPut(c, Scan0+0, A_Index*4+i, "UInt")
      i+=Stride
    }
    Gdip_UnlockBits(Needle, tmp)
    Gdip_ImageSearch(x, y, HayStack, Needle)
    Gdip_DisposeImage(Needle)
  }
  else    ;//灰度阀值模式,正则表达式查找
  {
    fazhi:=Round(RegExReplace(color,"\*"))
    VarSetCapacity(ss, height*width*(A_IsUnicode ? 2:1))
    E:=Gdip_LockBits(HayStack,0,0,width,height,Stride,Scan0,tmp)
    i:=-4, j:=Stride-width*4
    i++    ;//为了快速查找,仅取绿色作为灰度值
    Loop, %height% {
      Loop, %width%
        ss.=NumGet(Scan0+0,i+=4,"UChar")<=fazhi ? "1":"0"
      i+=j
    }
    Gdip_UnlockBits(HayStack,tmp)
    re:=s:=""
    Loop, %width%
      s.="."
    Loop, Parse, wz, `n
      re.=SubStr(A_LoopField . s, 1, width)
    re:=RegExReplace(re,"\.+$"), i:=RegExMatch(re,"10|01")
    re:=SubStr(re,i+=!i), x:=y:=-1
    if p:=RegExMatch(ss,re)
      p-=i-1, x:=Mod(p-1,width), y:=(p-1)//width
  }

  ; 清除图像,退出GDI+
  Gdip_DisposeImage(HayStack)
  Gdip_Shutdown(pToken)
  Critical, Off
  SetBatchLines, %BatchLines%

  ; 返回结果,坐标为字符串图像的中心位置
  if (x<>-1 or y<>-1)
  {
    rx:=Floor(left+x+(Width2-1)/2)
    ry:=Floor(top+y-cut_top+(cut_top+Height2-1)/2)
    Return, 1
  }
  Return, 0
}

;---------------------------------------
;  获取屏幕图像,若颜色模式则转黑白图
;---------------------------------------
ScreenShot(nx, ny, nw, nh, color)
{
  mDC1:=CreateCompatibleDC(), hBM1:=CreateDIBSection(nw, nh, mDC1)
    , oBM1:=SelectObject(mDC1, hBM1)
  BitBlt(mDC1, 0, 0, nw, nh, hDC:=GetDC(), nx, ny, SRCCOPY:=0x00CC0020)
    , ReleaseDC(hDC)
  IfNotInString, color, *    ;//颜色模式则转化为黑白图
  {
    c:=Round(color), BGR:=(c&0xFF)<<16|(c&0xFF00)|(c&0xFF0000)>>16
    mDC2:=CreateCompatibleDC(), hBM2:=CreateDIBSection(nw, nh, mDC2)
      , oBM2:=SelectObject(mDC2, hBM2)
    hBrush:=DllCall("CreateSolidBrush", "UInt", ~BGR & 0xFFFFFF)
      , CreateRect(Rect, 0, 0, nw, nh)
      , DllCall("FillRect", "Ptr", mDC2, "Ptr", &Rect, "Ptr", hBrush)
      , DeleteObject(hBrush)
    DllCall( "msimg32.dll\TransparentBlt", "ptr", mDC2
      , "int", 0, "int", 0, "int", nw, "int", nh, "ptr", mDC1
      , "int", 0, "int", 0, "int", nw, "int", nh, "UInt", BGR )
    BitBlt(mDC2, 0, 0, nw, nh, mDC1, 0, 0, SRCINVERT:=0x00660046)
    pBitmap:=Gdip_CreateBitmapFromHBITMAP(hBM2)
    SelectObject(mDC2,oBM2), DeleteObject(hBM2), DeleteDC(mDC2)
  }
  else pBitmap:=Gdip_CreateBitmapFromHBITMAP(hBM1)
  SelectObject(mDC1,oBM1), DeleteObject(hBM1), DeleteDC(mDC1)
  Return, pBitmap
}

;-------------------------------------
;  我在网上找到一个较好的机器码搜图代码 (thanks Tic)
;  http://autohotkey.com/board/topic/71100-gdip-imagesearch/
;-------------------------------------
Gdip_ImageSearch(ByRef x, ByRef y, HayStack, Needle)
{
  static Gdip_ImageSearch, mcode_ok:=0
  if !mcode_ok
  {
    MCode(Gdip_ImageSearch,"83EC108B44242C9983E2"
    . "0303C28BC88B4424309983E20303C253C1F802558"
    . "94424148B44244056C1F9023B44244C578944244"
    . "80F8DCA0000008B7C24348D148D000000000FAFC"
    . "88B442444895424148B54242403C88D1C8A8B4C2"
    . "44C895C24183BC1894424407D7A895C24108D642"
    . "4008B6C2428C744243C000000008D6424008B4424"
    . "3C3B4424380F8D9400000033C985FF7E178BD58BF"
    . "38B063B02752283C10183C20483C6043BCF7CED8"
    . "B44241C035C24148344243C0103C003C003E8EBC"
    . "08B4424408B5C24108B4C244C83C00183C3043BC"
    . "189442440895C24107C928B4424448B5424488B5"
    . "C2418035C241483C2013B54245089542448895C2"
    . "4180F8C5DFFFFFF8B5424548B4424585F5EC702FF"
    . "FFFFFF5DC700FFFFFFFF83C8FF5B83C410C38B4C2"
    . "4548B5424408B4424585F89118B4C24445E5D890"
    . "833C05B83C410C3"), mcode_ok:=1
  }

  /*
  int Gdip_ImageSearch1(unsigned int * HayStack, unsigned int * Needle
    , int w1, int h1, int w2, int h2, int Stride1, int Stride2
    , int sx, int sy, int w, int h, int * x, int * y)
  {
    int tx, ty;
    int offset1 = Stride1/4, offset2 = Stride2/4;
    for (int y1 = sy; y1 < h; ++y1)
    {
      for (int x1 = sx; x1 < w; ++x1)
      {
        ty = y1;
        for (int y2 = 0; y2 < h2; ++y2)
        {
          tx = x1;
          for (int x2 = 0; x2 < w2; ++x2)
          {
            if (HayStack[tx+(ty*offset1)] != Needle[x2+(y2*offset2)])
              goto NoMatch;
            tx++;
          }
          ty++;
        }
        x[0] = x1; y[0] = y1;
        return 0;
        NoMatch:
        continue;
      }
    }
    x[0] = -1; y[0] = -1;
    return -1;
  }
  */

  ; 获取图像的宽高
  Width1:=Gdip_GetImageWidth(HayStack)
    , Height1:=Gdip_GetImageHeight(HayStack)
  Width2:=Gdip_GetImageWidth(Needle)
    , Height2:=Gdip_GetImageHeight(Needle)
  if (Width1<Width2 or Height1<Height2)
  {
    x:=y:=-1
    Return
  }

  ; 锁定图像的内存数据
  E1:=Gdip_LockBits(HayStack, 0, 0, Width1, Height1
    , Stride1, Scan01, tmp1)
  E2:=Gdip_LockBits(Needle, 0, 0, Width2, Height2
    , Stride2, Scan02, tmp2)
  if (E1 or E2)
  {
    x:=y:=-1
    Return
  }

  ; 调用机器码,在图像1中搜索图像2
  VarSetCapacity(x, 8, 0), VarSetCapacity(y, 8, 0)
  sx:=sy:=0, w:=Width1-Width2+1, h:=Height1-Height2+1
  E:=DllCall(&Gdip_ImageSearch, "uint", Scan01, "uint", Scan02
  , "int", Width1, "int", Height1, "int", Width2, "int", Height2
  , "int", Stride1, "int", Stride2, "int", sx, "int", sy
  , "int", w, "int", h, "int*", x, "int*", y)

  ; 解锁图像的内存数据
  Gdip_UnlockBits(HayStack, tmp1)
  Gdip_UnlockBits(Needle, tmp2)
}

MCode(ByRef code, hex)
{
  VarSetCapacity(code, StrLen(hex)//2)
  Loop, % StrLen(hex)//2
    NumPut("0x" SubStr(hex, 2*A_Index-1, 2)
    , code, A_Index-1, "char")
}


;========== 用到的 Gdip.ahk 函数 ==========


Gdip_Startup()  ;//必须把si:=chr~(1)换掉才能提交
{
  if !DllCall("GetModuleHandle", "str", "gdiplus")
    DllCall("LoadLibrary", "str", "gdiplus")
  VarSetCapacity(si, 16, 0), NumPut(1, si, "char")
  DllCall("gdiplus\GdiplusStartup", "uintP"
  , pToken, "uint", &si, "uint", 0)
  return pToken
}

Gdip_Shutdown(pToken)
{
  DllCall("gdiplus\GdiplusShutdown", "uint", pToken)
  if hModule := DllCall("GetModuleHandle", "str", "gdiplus")
    DllCall("FreeLibrary", "uint", hModule)
  return 0
}

Gdip_CreateBitmap(Width, Height, Format=0x26200A)
{
  DllCall("gdiplus\GdipCreateBitmapFromScan0"
  , "int", Width, "int", Height, "int", 0, "int", Format
  , "uint", 0, "uint*", pBitmap)
  Return pBitmap
}

Gdip_GraphicsFromImage(pBitmap)
{
  DllCall("gdiplus\GdipGetImageGraphicsContext"
  , "uint", pBitmap, "uint*", pGraphics)
  return pGraphics
}

Gdip_GraphicsClear(pGraphics, ARGB=0x00ffffff)
{
  return DllCall("gdiplus\GdipGraphicsClear"
  , "uint", pGraphics, "int", ARGB)
}

Gdip_DeleteGraphics(pGraphics)
{
  return DllCall("gdiplus\GdipDeleteGraphics"
  , "uint", pGraphics)
}

CreateRect(ByRef Rect, x, y, w, h)
{
  VarSetCapacity(Rect, 16)
  NumPut(x, Rect, 0, "uint"), NumPut(y, Rect, 4, "uint")
  , NumPut(w, Rect, 8, "uint"), NumPut(h, Rect, 12, "uint")
}

Gdip_LockBits(pBitmap, x, y, w, h, ByRef Stride
  , ByRef Scan0, ByRef BitmapData, LockMode = 3
  , PixelFormat = 0x26200A)
{
  CreateRect(Rect, x, y, w, h)
  VarSetCapacity(BitmapData, 21, 0)
  E := DllCall("Gdiplus\GdipBitmapLockBits", "uint"
  , pBitmap, "uint", &Rect, "uint", LockMode, "int"
  , PixelFormat, "uint", &BitmapData)
  Stride := NumGet(BitmapData, 8)
  Scan0 := NumGet(BitmapData, 16)
  return E
}

Gdip_UnlockBits(pBitmap, ByRef BitmapData)
{
  return DllCall("Gdiplus\GdipBitmapUnlockBits"
  , "uint", pBitmap, "uint", &BitmapData)
}

CreateCompatibleDC(hdc=0)
{
  return DllCall("CreateCompatibleDC", "uint", hdc)
}

SelectObject(hdc, hgdiobj)
{
  return DllCall("SelectObject","uint",hdc,"uint",hgdiobj)
}

DeleteObject(hObject)
{
  return DllCall("DeleteObject", "uint", hObject)
}

GetDC(hwnd=0)
{
  return DllCall("GetDC", "uint", hwnd)
}

ReleaseDC(hdc, hwnd=0)
{
  return DllCall("ReleaseDC", "uint", hwnd, "uint", hdc)
}

DeleteDC(hdc)
{
  return DllCall("DeleteDC", "uint", hdc)
}

CreateDIBSection(w, h, hdc="", bpp=32, ByRef ppvBits=0)
{
  hdc2 := hdc ? hdc : GetDC()
  VarSetCapacity(bi, 40, 0)
  NumPut(w, bi, 4), NumPut(h, bi, 8), NumPut(40, bi, 0)
  , NumPut(1, bi, 12, "ushort"), NumPut(0, bi, 16)
  , NumPut(bpp, bi, 14, "ushort")
  hbm := DllCall("CreateDIBSection", "uint", hdc2
  , "uint" , &bi, "uint" , 0, "uint*", ppvBits
  , "uint" , 0, "uint" , 0)

  if !hdc
    ReleaseDC(hdc2)
  return hbm
}

BitBlt(ddc, dx, dy, dw, dh, sdc, sx, sy, Raster="")
{
  return DllCall("gdi32\BitBlt", "uint", dDC, "int"
  , dx, "int", dy, "int", dw, "int", dh
  , "uint", sDC, "int", sx, "int", sy, "uint"
  , Raster ? Raster : 0x00CC0020)
}

Gdip_CreateBitmapFromHBITMAP(hBitmap, Palette=0)
{
  DllCall("gdiplus\GdipCreateBitmapFromHBITMAP"
  , "uint", hBitmap, "uint", Palette, "uint*", pBitmap)
  return pBitmap
}

Gdip_DisposeImage(pBitmap)
{
  return DllCall("gdiplus\GdipDisposeImage", "uint", pBitmap)
}

Gdip_GetImageWidth(pBitmap)
{
  DllCall("gdiplus\GdipGetImageWidth", "uint"
  , pBitmap, "uint*", Width)
  return Width
}

Gdip_GetImageHeight(pBitmap)
{
  DllCall("gdiplus\GdipGetImageHeight", "uint"
  , pBitmap, "uint*", Height)
  return Height
}


;============ 脚本结束 =================

;
查找这个用户的全部帖子
表示感谢 引用并回复 移动视图置页面顶端
2016-02-22, 12 : 50 (这个帖子最后修改于: 2016-03-02 11 : 46 by feiyue.)
RE: 【快捷抓取、查找屏幕文字/图像字符串】

更新到v3.5版。采用了自写的专用图内找字机器码,从而让颜色模式和灰度阀值模式的找字速度都超快!
同时提供容错参数,有几个点不一致也能实现模糊匹配!
另外抓字窗口中现在可以先裁剪成小图再自动二值化,这样得到的阀值准确一些,图像区分得更明显。
有时候自动二值化的图像还不理想,可以手动输入阀值试试,也许可以得到较好的图像。
但是自动二值化的阀值毕竟可靠些,能最大化的把前景和背景区分开,图像颜色稍微改变也影响不大。
而自己随便定的阀值也许加1减1图像就增减几个点,所以这个阀值可能会对图像颜色的改变比较敏感。

查找这个用户的全部帖子
表示感谢 引用并回复 移动视图置页面顶端
2016-03-07, 15 : 23 (这个帖子最后修改于: 2016-03-09 19 : 55 by feiyue.)
Rainbow RE: 【快捷抓取、查找屏幕文字/图像字符串】
更新到v4.0版。添加了OCR字库识别功能,能够胜任简单的OCR应用。
查找这个用户的全部帖子
表示感谢 引用并回复 移动视图置页面顶端
2016-03-08, 15 : 59
RE: 【快捷抓取、查找屏幕文字/图像字符串】
看到好多版本,有点混乱,请问最终版是10楼的吗??
查找这个用户的全部帖子
表示感谢 引用并回复 移动视图置页面顶端
发表回复 


论坛跳转:


联系我们 | Autohotkey 中文站 | 回到顶部 | 回到正文区 | 精简(归档)模式 | RSS 聚合