;~ 在屏幕上搜索图片并返回图片所在位置的坐标的AutoHotkey脚本源代码(类似大漠插件)
; https://www.autohotkey.com/boards/viewtopic.php?t=17834
;~ 在屏幕上搜索图片并返回图片所在位置的坐标的AutoHotkey脚本源代码(类似大漠插件) ; https://www.autohotkey.com/boards/viewtopic.php?t=17834 ;=========================================== ;~ 以前此文章的标题不太好所以重新修改标题后重新发布 ;~ 此脚本的优点是速度快,功能可靠,用途广泛,不依赖JPG图片和DLL文件,纯AHK代码实现,非常干净,非常纯洁,非常完美 ;~ 此脚本的缺点是,修改电脑屏幕分辨率或缩放窗口界面后无法找到图片位置,兼容性,通用性,可靠性有点差劲,不太好 ;~ 这个脚本是 FeiYue 写的, ;~ 我复制(搬运)到这里便于大家今后测试,研究,收藏,分类,整理,分享,改进,重复利用到自己的脚本中去 ;~ 本文的段落分割符号是一行连续的等于号 ;=========================================== ;~ http://www.autoahk.com/?p=16306 ;~ https://gitee.com/weiyunwps618/codes/t41vlkhpy0m3wr9568cua42 ;~ https://www.cnblogs.com/delphixx/p/11835278.html ; ; 本文的最后修改日期是 公元2019年11月16日 ; 本文的网址是 https://gitee.com/weiyunwps618/codes ; 本文的网址是 https://www.cnblogs.com/delphixx ; 晓亮(weiyunwps618)的腾讯QQ邮箱地址是 595076941@qq.com ) ; 晓亮(weiyunwps618)的中国移动手机号码是 138####5488 ) ; 此AHK脚本的测试环境是 Windows 7 Pro SP1 VL 和 AutoHotkey v1.1.30.01 ; ;~ The Source Code Version 6.9 ;~ I wrote a useful function to share with you. ;~ It is used to find text or images on the screen. ;~ Hope you like it ! :) ;~ Detailed usage can refer to: ;~ 1、The introduction by ed1chandler. ;~ 2、The introduction by c4p (latest). ;~ This function is similar to the AHK built-in command "ImageSearch", ;~ but it can convert images into strings, written into the script without ;~ saving as an external image, so it is easier to use than "ImageSearch". :beer: ;~ << Main changes of the function after multiple updates >> ;~ 1. Now, the way to capture images has become right-click twice. ;~ Previously, the way to capture images was to left click and remove 100 pixels. ;~ 2. Now, the first four range parameters of FindText() function are similar to the usage of ;~ internal command WinGetPos, using the upper left corner coordinate, width and height. ;~ Many people don't understand the width and height of the range. ;~ If you use the upper left corner (x1, Y1) and the lower right corner (X2, Y2) ;~ to determine a rectangular range, then the width is x2-x1 and the height is y2-y1. ;~ Previously, the first four parameters of FindText() function using the central coordinates ;~ and left-right, up-down offsets, which were more complex. ;~ 3. Now, the array returned by the FindText() function becomes a two-level array. ;~ Each item in the first level array represents a search result, ;~ and each search result is an array containing 5 items, so it is a two-level array. ;~ Previously, the function returned an array with only one level, so when extracting the result, ;~ every 5 items should be decomposed into one result, which is more complex. ;~ 4. Now, it is recommended to save the script as "FindText.ahk" and copy it to the ;~ Lib directory of the main program. When clicking the copy button, ;~ do not select the check box of "Additional FindText() in Copy". ;~ And insert "#Include <FindText.ahk>" at the beginning of the user script to import the library. ;~ Previously, clicking the copy button would copy the FindText() function ;~ and all the following functions, resulting in a huge user script. ;=========================================== ;~ <<< Update history >>> ;~ Updated to 6.9 version - 2019/10/30 ;~ .... 1. The ScreenShot_GetColor() function is added. ;~ .... Before using it, you usually need to update the last screenshot with the ScreenShot() function. ;~ .... FindText() function can also update the last screenshot, So you can use FindText() instead of ScreenShot(). ;~ Updated to 6.8 version - 2019/10/25 ;~ .... 1. Fixed case insensitive key names in internal array of Pic() function. ;~ .... 2. In order to facilitate this script to be included in other scripts as a library (#Include <FindText.ahk>), ;~ .... no custom global variables are used, and the label of subprogram is greatly reduced. ;~ Updated to 6.7 version - 2019/04/13 ;~ .... 1. Merge FindText() and FindText2() functions. ;~ .... 2. The color difference mode is added to adjust the matching range accurately. ;~ .... 3. Add a parameter "FindAll" that allows you to find only one result and return it immediately. ;~ Updated to 6.6 version - 2019/04/11 ;~ .... 1. FindText(), FindText2() share the same machine code, reduces the code size. ;~ Updated to 6.5 version - 2019/04/07 ;~ .... 1. Add Gray Difference Mode, so there are four modes. ;~ .... 2. Fixed SplitAdd/AllAdd buttons doesn't work(broken by v6.4). ;~ Updated to 6.4 version - 2019/02/04 ;~ .... 1. Change the label name and function name to make it easier ;~ .... for “#Include” to be integrated into other scripts as libraries. ;~ .... 2. After including library, you can open the tool directly by calling: ft_Gui("Show"). ;~ Updated to 6.3 version - 2018/12/18 ;~ .... 1. Changed the way to capture, Now first click the right mouse button, ;~ .... you can move the mouse, and then click the right mouse button again. ;~ .... 2. Add MouseTip(). It is used to prompt mouse position in remote assistance. ;~ Updated to 6.2 version - 2018/11/11 ;~ .... 1. A parameter is added at the end of the function to allow the last screenshot to be used. ;~ .... Of course, saving the last screenshot will take up a certain amount of memory. ;~ .... 2. Add ScreenShot(). It can be used before the loop. ;~ Updated to 6.1 version - 2018/10/07 ;~ .... 1. The specific color mode has been restored, so there are three modes. ;~ .... 2. Add SortOK(), SortOK2(). It is used to sort the array by coordinates. ;~ Updated to 6.0 version - 2018/09/21 ;~ .... 1. Slightly modified the machine code. ;~ .... The image that has been found will be cleaned up in the same color. ;~ .... Avoid matching the next row (column) when using tolerance lookup. ;~ .... 2. After upgrading to v6.0, the search area uses WinAPI's ;~ .... upper left corner X, Y coordinates, and width, height. ;~ .... This will be better understood and used. ;~ Updated to 5.9 version - 2018/07/21 ;~ .... 1. Add PicX(). It is used to divide the Text ;~ .... and then use the FindText2() function to find it. ;~ Updated to 5.8 version - 2018/04/27 ;~ .... 1. Using "gcc.exe -O2" to generate machine code (MCode). ;~ Updated to 5.7 version - 2018/01/17 ;~ .... 1. I changed the way to capture, Before, click the left button of the mouse, ;~ .... and then move the mouse out of 100 pixels. ;~ .... Now, press down the right button of the mouse, ;~ .... and then move a certain distance and release the right button. ;~ .... 2. I updated the "Capture Image To Text" window, ;~ .... allowing the use of tags to split the text at one time ;~ .... and generate multiple text libraries. ;~ Updated to 5.6 version - 2017/12/06 ;~ .... 1. Add FindText2(). It is used for combination lookup. ;~ .... for example, a 0-9 text library has been set up, ;~ .... then any ID number can be found. ;~ .... Use Pic(Text,1) and PicN(number) when using. ;~ .... 2. Add PicN(). It is used in combination with Pic(). ;~ Updated to 5.5 version - 2017/11/23 ;~ .... 1. Change the Color mode to Color position mode. ;~ .... in order to identify a variety of color verification code, ;~ .... now it can adapt to various colors. ;~ Updated to 5.4 version - 2017/08/03 ;~ .... 1. Now can find out all the positions of a picture in the screen. ;~ Updated to 5.3 version - 2017/07/30 ;~ .... 1. Changing the returned value of the object. Now, a two level array is used. ;~ .... 2. Add FindTextOCR(). It can identify simple verification code. ;~ Updated to 5.2 version - 2017/06/10 ;~ .... 1. Using CreateDIBSection instead of GetDIBits to speed up screen capture. ;~ .... 2. Add Pic(). 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. ;~ Updated to 5.1 version - 2017/05/06 ;~ .... 1. Thank c4p very much. He helped me improve the interface and control hints. ;~ Updated to 5.0 version - 2017/03/20 ;~ .... 1. Add sensitivity slider for color mode. ;~ .... 2. Text parameters are converted to one line using Base64. ;~ .... 3. Text parameters can be a lot of text to find, separated by "|". ;~ Updated to 4.5 version - 2016/05/24 ;~ .... 1. Support Fault-Tolerant. ;~ Updated to 4.0 version - 2016/05/23 ;~ .... 1. Using machine code (MCode) instead of RegExMatch() to speed up search. ;~ Last edited by feiyue on 30 Oct 2019, 00:29, edited 61 times in total. ;=========================================== ;~ In addition to searching for screen text and images, ;~ This function can also be used for simple text recognition. ;~ Here is an example of a simple identification Numbers. ;~ FindTextOCR() function can also be used to identify simple verification code. /* F2:: ; To identify the number near the mouse ; For identification, we need to create a text library, ; Of course, the following text library is not strong enough, ; Perhaps in other computers, other screen resolutions, ; Other browser magnification, different fonts, need to regenerate. ; You can add the newly generated to the following existing text library, ; To enhance the generality of this text library. Text:="|<0>*147$6.SnVVVVVnSU" Text.="|<1>*147$5.9kV248Hw" Text.="|<2>*148$6.yX11248EzU" Text.="|<3>*149$6.yX13C11XyU" Text.="|<4>*149$6.66+GmWz22U" Text.="|<5>*149$6.TEES311XyU" Text.="|<6>*148$6.CEUyXVVnSU" Text.="|<7>*149$6.z1224A8MEU" Text.="|<8>*148$6.SnVnSVVnSU" Text.="|<9>*148$6.SnVVlT12QU" CoordMode, Mouse MouseGetPos, x, y t1:=A_TickCount ;------------------------------ OCR:=FindTextOCR(x, y, 150, 20, 0.2, 0.1, Text) ;------------------------------ t1:=A_TickCount-t1 MsgBox, 4096, OCR, OCR Result: [%OCR%] in %t1% ms. Return FindTextOCR(nX, nY, nW, nH, err1, err0, Text, Interval=20) { OCR:="", Right_X:=nX+nW-1 While (ok:=FindText(nX, nY, nW, nH, err1, err0, Text)) { ; For multi text search, This is the number of text images found Loop, % ok.MaxIndex() { ; X is the X coordinates of the upper left corner ; and W is the width of the image have been found i:=A_Index, x:=ok[i].1, y:=ok[i].2 , w:=ok[i].3, h:=ok[i].4, comment:=ok[i].5 ; We need the leftmost X coordinates if (A_Index=1 or x<Left_X) Left_X:=x, Left_W:=w, Left_OCR:=comment } ; If the interval exceeds the set value, add "*" to the result OCR.=(A_Index>1 and Left_X-nX-1>Interval ? "*":"") . Left_OCR ; Update nX and nW for next search nX:=Left_X+Left_W-1, nW:=Right_X-nX+1 } Return, OCR } */ ;=========================================== ;~ Want to make sure I'm understanding use case and usage: ;~ 1) Download script and run it. This pops up the "Catch Image To Text And Find Text Tool" box with "Catch", "Test", and "Copy" buttons. ;~ 2) Click the "Catch" button and the cursor is accompanied by a transparent red box. ;~ 3) Move the red box over the text you want to search for and click, then move the box more than 100 px in any direction to trigger capture. ;~ 4) This brings up the "Catch Image To Text" box with a magnified view of the captured text. ;~ 5) The lower left portion of that GUI has a series of "trimming" buttons, used to trim the edges of the captured region. I'm not sure what the abbreviations are supposed to stand for, but it appears that "LD" trims one pixel from the left edge, "LD3" trims three pixels, and the other buttons do the same for "up", "down", and "right." Use those buttons to trim the region down to what you really want to search for. ;~ 6) Click somewhere on the magnified capture to select a pixel with the color you want to use for matching. When you do, the text box next to the "Color2Two" button will populate with the hex value of the color corresponding with the pixel you chose. ;~ It appears there are two modes: color and greyscale. If you want to use color, it appears to go something like this: ;~ 7a) After selecting a pixel (step 6), if you click the "Color2Two" button, it appears to convert the magnified image into a two-tone version where all pixels of the selected color are converted to black and all other pixels are converted to white. ;~ And if you want to use greyscale, it goes something like this: ;~ 7b) After selecting a pixel (step 6), if you click the "Gray2Two" button, it appears to make a "best guess" at a threshold, then convert the magnified image into a two-tone black/white version where all pixels on one side of the threshold are black and all others are white. It also appears that you can change the threshold and click the button again if you want to adjust the program's guess. ;~ 8) Once you've got the two-tone image you want, click the "Ok" button. This returns a GUI with a "Text=..." block of text and a related function call. You can click the "Test" button to test that the search will actually find what you're looking for, then click the "Copy" button to copy the text block and the related function call to the clipboard. The "Exchange" button will negate the image and the "Load" button will reload the original capture. ;~ 9) Copy that block of text and the function call into the script from which the search will be run ... and be sure the script can "see" the FindText() function. ;~ 10) Modify and enjoy. ;~ What I'm *not* quite following is how to modify the function parameters. The "w" and "h" parameters say that they're "offsets" but what does that *mean*? (i.e. What's the effect of changing them?) The default is 150, but the capture tool seeds these to 150000. What is this changing? ;~ @ed1chandler, your description for use is very detailed, very good! :bravo: ;~ Because my English is not very good, so the message is less in front, ;~ thank you for your description. I add a few points: ;~ 1, LD meaning is the abbreviation of Left-Del, appear to be quite strange. :D ;~ 2, You can cut the edge first, then Make the image into black and white, ;~ Can also be, first to make the image into black and white, and then cut the edge. ;~ I recommend the way back, Because click "Auto" button can automatically cut edge. ;~ (Slight correction)the Gray2Two button don't use the Selected color, will automatically ;~ calculate a threshold, if you want to customize can manually enter the threshold. ;~ 3, the parameters of X, Y, W, H to determine a range: ;~ the upper left corner (X-W, Y-H), the lower right corner of (X+W, Y+H), ;~ So X, Y is the center point of the range, W, H is the distance between the center point ;~ of the offset distance. The advantage is that the location of the search results is returned ;~ Text / image center, and the parameters can be compared to know the relative text / image ;~ as the origin of the offset. ;~ 4, In the default generated code, I use the offset 150000, So it's all around the screen, ;~ it is full screen search. The actual use of the time required to select the appropriate scope, ;~ such as use 150, in accordance with (3) to determine the scope of the search. ;~ (Machine automatic translation) ;~ Useage: ;~ 1. Catch the image to text string. ;~ 2. Test find the text string on full Screen. ;~ 3. When test is successful, copy the code ;~ and paste it into your own script. ;~ 4. Copy the "FindText()" function and the function ;~ of the back, paste it into your own script. ;~ You didn't do the fourth step, to copy the functions to your application. ;~ Actual use of the time, you may also need to modify the scope of the search ( W, H offset), ;~ the default (offset 150000) full screen to find a longer time and find the location may not be what you need. ;~ Last edited by feiyue on 20 May 2016, 15:13, edited 1 time in total. ;~ Find this line at the end of My source code, ;~ Copy and paste the following into your script. ;~ My source code on Post 1,that is: ;~ Code: [Select all] [Expand] [Download] ;~ ------------------------------------------ ;~ …… ;~ …… ;~ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;======== Copy The Next Functions To Your Code ======== ;===== Copy The Following Functions To Your Own Code Just once ===== ;~ ------------------------------------------ /* ;=========================================== ; FindText - Capture screen image into text and then find it ; https://autohotkey.com/boards/viewtopic.php?f=6&t=17834 ; ; Author : FeiYue ; Version : 6.9 ; Date : 2019-10-30 ; ; Usage: ; 1. Capture the image to text string. ; 2. Test find the text string on full Screen. ; 3. When test is successful, you may copy the code ; and paste it into your own script. ; Note: Copy the "FindText()" function and the following ; functions and paste it into your own script Just once. ; ; Note: ; After upgrading to v6.0, the search scope using WinAPI's ; upper left corner X, Y coordinates, and width, height. ; This will be better understood and used. ; ;=========================================== ; Introduction of function parameters: ; ; returnArray := FindText( ; X --> the search scope's upper left corner X coordinates ; , Y --> the search scope's upper left corner Y coordinates ; , W --> the search scope's Width ; , H --> the search scope's Height ; , Character "0" fault-tolerant in percentage --> 0.1=10% ; , Character "_" fault-tolerant in percentage --> 0.1=10% ; , Text --> can be a lot of text parsed into images, separated by "|" ; , ScreenShot --> if the value is 0, the last screenshot will be used ; , FindAll --> if the value is 0, Just find one result and return ; , JoinText --> if the value is 1, Join all Text for combination lookup ; , offsetX --> Set the max text offset for combination lookup ; , offsetY --> Set the max text offset for combination lookup ; ) ; ; The range used by AHK is determined by the upper left ; corner and the lower right corner: (x1, y1, x2, y2), ; it can be converted to: FindText(x1, y1, x2-x1+1, y2-y1+1, ...). ; ; return a second-order array contains the [X,Y,W,H,Comment] of Each Find, ; if no image is found, the function returns 0. ; ;=========================================== ;*/ /* if (!A_IsCompiled and A_LineFile=A_ScriptFullPath) ft_Gui("Show") ft_Gui(cmd) { static if (cmd="Show") { Gui, ft_Main:+LastFoundExist IfWinExist Goto, ft_ShowMainWindow #NoEnv Menu, Tray, Add Menu, Tray, Add, FinText, ft_ShowMainWindow if (!A_IsCompiled and A_LineFile=A_ScriptFullPath) { Menu, Tray, Default, FinText Menu, Tray, Click, 1 Menu, Tray, Icon, Shell32.dll, 23 } ft_BatchLines:=A_BatchLines, ft_IsCritical:=A_IsCritical ft_Gui("MakeWindows") Critical, %ft_IsCritical% SetBatchLines, %ft_BatchLines% ;---------------------- ft_ShowMainWindow: Gui, ft_Main:Show, Center return } Critical if (cmd="MakeWindows") { ; The capture range can be changed by adjusting the numbers ;---------------------------- ww:=35, hh:=12 ;---------------------------- nW:=2*ww+1, nH:=2*hh+1 WindowColor:="0xCCDDEE" Gui, ft_Capture:Default Gui, +LastFound +AlwaysOnTop +ToolWindow Gui, Margin, 15, 15 Gui, Color, %WindowColor% Gui, Font, s14, Verdana Gui, -Theme C_:=[], w:=800//nW, h:=(A_ScreenHeight-300)//nH , w:=h<w ? h-1:w-1, w:=w<2 ? 2:w Loop, % nW*(nH+1) { i:=A_Index, j:=i=1 ? "" : Mod(i,nW)=1 ? "xm y+1" : "x+1" j.=i>nW*nH ? " cRed BackgroundFFFFAA" : "" Gui, Add, Progress, w%w% h%w% %j% -E0x20000 +Hwndid C_[i]:=id } Gui, +Theme Gui, Add, Button, xm+95 w45 gft_Run, U Gui, Add, Button, x+0 wp gft_Run, U3 ;-------------- Gui, Add, Text, x+42 yp+3 Section, Gray Gui, Add, Edit, x+3 yp-3 w60 vSelGray ReadOnly Gui, Add, Text, x+15 ys, Color Gui, Add, Edit, x+3 yp-3 w120 vSelColor ReadOnly Gui, Add, Text, x+15 ys, R Gui, Add, Edit, x+3 yp-3 w60 vSelR ReadOnly Gui, Add, Text, x+5 ys, G Gui, Add, Edit, x+3 yp-3 w60 vSelG ReadOnly Gui, Add, Text, x+5 ys, B Gui, Add, Edit, x+3 yp-3 w60 vSelB ReadOnly ;-------------- Gui, Add, Button, xm w45 gft_Run, L Gui, Add, Button, x+0 wp gft_Run, L3 Gui, Add, Button, x+15 w70 gft_Run, Auto Gui, Add, Button, x+15 w45 gft_Run, R Gui, Add, Button, x+0 wp gft_Run Section, R3 Gui, Add, Button, xm+95 w45 gft_Run, D Gui, Add, Button, x+0 wp gft_Run, D3 ;-------------- Gui, Add, Tab3, ys-8 -Wrap, Gray|GrayDiff|Color|ColorPos|ColorDiff Gui, Tab, 1 Gui, Add, Text, x+15 y+15, Gray Threshold Gui, Add, Edit, x+15 w100 vThreshold Gui, Add, Button, x+15 yp-3 gft_Run Default, Gray2Two Gui, Tab, 2 Gui, Add, Text, x+15 y+15, Gray Difference Gui, Add, Edit, x+15 w100 vGrayDiff, 50 Gui, Add, Button, x+15 yp-3 gft_Run, GrayDiff2Two Gui, Tab, 3 Gui, Add, Text, x+15 y+15, Similarity 0 Gui, Add, Slider , x+0 w100 vSimilar gft_Run Page1 NoTicks ToolTip Center, 100 Gui, Add, Text, x+0, 100 Gui, Add, Button, x+15 yp-3 gft_Run, Color2Two Gui, Tab, 4 Gui, Add, Text, x+15 y+15, Similarity 0 Gui, Add, Slider , x+0 w100 vSimilar2 gft_Run Page1 NoTicks ToolTip Center, 100 Gui, Add, Text, x+0, 100 Gui, Add, Button, x+15 yp-3 gft_Run, ColorPos2Two Gui, Tab, 5 Gui, Add, Text, x+15 y+15, R Gui, Add, Edit, x+3 w70 vDiffR Limit3 Gui, Add, UpDown, vdR Range0-255 Gui, Add, Text, x+10, G Gui, Add, Edit, x+3 w70 vDiffG Limit3 Gui, Add, UpDown, vdG Range0-255 Gui, Add, Text, x+10, B Gui, Add, Edit, x+3 w70 vDiffB Limit3 Gui, Add, UpDown, vdB Range0-255 Gui, Add, Button, x+12 yp-3 gft_Run, ColorDiff2Two Gui, Tab ;-------------- Gui, Add, Checkbox, xm gft_Run vModify, Modify Gui, Add, Button, x+5 yp-3 gft_Run, Reset Gui, Add, Text, x+15 yp+3, Comment Gui, Add, Edit, x+5 w132 vComment Gui, Add, Button, x+10 yp-3 gft_Run, SplitAdd Gui, Add, Button, x+10 gft_Run, AllAdd Gui, Add, Button, x+10 w80 gft_Run, OK Gui, Add, Button, x+10 gCancel, Close Gui, Show, Hide, Capture Image To Text ;------------------------------------- Gui, ft_Main:Default Gui, +AlwaysOnTop Gui, Margin, 15, 15 Gui, Color, DDEEFF Gui, Font, s6 bold, Verdana Gui, Add, Edit, xm w660 r25 vMyPic -Wrap -VScroll Gui, Font, s12 norm, Verdana Gui, Add, Button, w220 gft_Run, Capture Gui, Add, Button, x+0 wp gft_Run, Test Gui, Add, Button, x+0 wp gft_Run Section, Copy Gui, Font, s10 Gui, Add, Text, xm , Click Text String to See ASCII Search Text in the Above Gui, Add, Checkbox, xs yp w220 r1 -Wrap Checked vAddFunc , Additional FindText() in Copy Gui, Font, s12 cBlue, Verdana Gui, Add, Edit, xm w660 h350 vscr Hwndhscr -Wrap HScroll Gui, Show, Hide, Capture Image To Text And Find Text Tool ;--------------------------------------- OnMessage(0x100, Func("ft_EditEvents1")) ; WM_KEYDOWN OnMessage(0x201, Func("ft_EditEvents2")) ; WM_LBUTTONDOWN OnMessage(0x200, Func("ft_ShowToolTip")) ; WM_MOUSEMOVE return ;------------------- ft_Run: ft_Gui(A_GuiControl) return } if (cmd="Capture") { WinMinimize Gui, ft_Main:Hide ;---------------------- Gui, ft_Mini:Default Gui, +LastFound +AlwaysOnTop -Caption +ToolWindow +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 ListLines, Off CoordMode, Mouse oldx:=oldy:="" Loop { Sleep, 50 MouseGetPos, x, y if (oldx=x and oldy=y) Continue oldx:=x, oldy:=y ;--------------- Gui, Show, % "NA x" (x-w//2) " y" (y-h//2) ToolTip, % "The Capture Position : " x "," y . "`nFirst click RButton to start capturing" . "`nSecond click RButton to end capture" } Until GetKeyState("RButton", "P") KeyWait, RButton px:=x, py:=y, oldx:=oldy:="" Loop { Sleep, 50 MouseGetPos, x, y if (oldx=x and oldy=y) Continue oldx:=x, oldy:=y ;--------------- ToolTip, % "The Capture Position : " px "," py . "`nFirst click RButton to start capturing" . "`nSecond click RButton to end capture" } Until GetKeyState("RButton", "P") KeyWait, RButton ToolTip ListLines, On Gui, Destroy WinWaitClose cors:=ft_getc(px,py,ww,hh) Hotkey, $*RButton, ft_RButton_Off, Off Event:=Result:="" ;-------------------------------- 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, Threshold ft_Gui("Reset") Gui, Show, Center DetectHiddenWindows, Off Gui, +LastFound Critical, Off WinWaitClose, % "ahk_id " WinExist() ;-------------------------------- if InStr(Event,"OK") { if (!A_IsCompiled) { FileRead, s, %A_LineFile% s:=SubStr(s, s~="i)\n[;=]+ Copy The") } else s:="" GuiControl, ft_Main:, scr, % Result "`n" s Result:=s:="" } else if InStr(Event,"Add") { s:=RegExReplace(Result,"\R","`r`n") ControlGet, i, CurrentCol,,, ahk_id %hscr% if (i>1) ControlSend,, {Home}{Down}, ahk_id %hscr% Control, EditPaste, %s%,, ahk_id %hscr% Result:=s:="" } ;---------------------- Gui, ft_Main:Show GuiControl, ft_Main:Focus, scr ft_RButton_Off: return } if (cmd="Test") { Critical, Off Gui, ft_Main:Default Gui, +LastFound id:=WinExist() WinMinimize Gui, Hide DetectHiddenWindows, Off WinWaitClose, ahk_id %id% ;---------------------- GuiControlGet, s,, scr s:="`n#NoEnv`nMenu, Tray, Click, 1`n" . "Gui, ft_ok_:Show, Hide, ft_ok_`n" . s "`nExitApp`n" if (!A_IsCompiled) and InStr(s,"MCode(") { ft_Exec(s) DetectHiddenWindows, On WinWait, ft_ok_ ahk_class AutoHotkeyGUI,, 3 if (!ErrorLevel) WinWaitClose,,, 30 } else { CoordMode, Mouse t:=A_TickCount, RegExMatch(s,"\[\d+,\s*\d+\]",r) RegExMatch(s,"=""\K[^$\n]+\$\d+\.[\w+/]+",v) ok:=FindText(0, 0, A_ScreenWidth, A_ScreenHeight, 0, 0, v) X:=ok.1.1, Y:=ok.1.2, W:=ok.1.3, H:=ok.1.4, X+=W//2, Y+=H//2 Gui, +OwnDialogs MsgBox, 4096,, % "Time:`t" (A_TickCount-t) " ms`n`n" . "Pos:`t" r " " X ", " Y "`n`n" . "Result:`t" (ok ? "Success !":"Failed !"), 3 if (ok) MouseTip(X, Y) ok:="" } ;---------------------- Gui, Show GuiControl, Focus, scr return } if (cmd="Copy") { Gui, ft_Main:Default GuiControlGet, s,, scr GuiControlGet, r,, AddFunc if (r != 1) s:=RegExReplace(s,"\n\K[\s;=]+ Copy The[\s\S]*") Clipboard:=StrReplace(s,"`n","`r`n") ;---------------------- Gui, Hide Sleep, 100 Gui, Show GuiControl, Focus, scr return } if (cmd="L") or (cmd="L3") { Loop, % InStr(cmd,"3") ? 3:1 { if (left+right>=nW) return left++, k:=left Loop, %nH% ft_Gui("DelColor"), k+=nW } return } if (cmd="R") or (cmd="R3") { Loop, % InStr(cmd,"3") ? 3:1 { if (left+right>=nW) return right++, k:=nW+1-right Loop, %nH% ft_Gui("DelColor"), k+=nW } return } if (cmd="U") or (cmd="U3") { Loop, % InStr(cmd,"3") ? 3:1 { if (up+down>=nH) return up++, k:=(up-1)*nW Loop, %nW% k++, ft_Gui("DelColor") } return } if (cmd="D") or (cmd="D3") { Loop, % InStr(cmd,"3") ? 3:1 { if (up+down>=nH) return down++, k:=(nH-down)*nW Loop, %nW% k++, ft_Gui("DelColor") } return } if (cmd="Gray2Two") { GuiControl, Focus, Threshold GuiControlGet, Threshold if (Threshold="") { pp:=[] Loop, 256 pp[A_Index-1]:=0 Loop, % nW*nH if (ascii[A_Index]!="") pp[gs[A_Index]]++ IP:=IS:=0 Loop, 256 k:=A_Index-1, IP+=k*pp[k], IS+=pp[k] NewThreshold:=Floor(IP/IS) Loop, 20 { Threshold:=NewThreshold IP1:=IS1:=0 Loop, % Threshold+1 k:=A_Index-1, IP1+=k*pp[k], IS1+=pp[k] IP2:=IP-IP1, IS2:=IS-IS1 if (IS1!=0 and IS2!=0) NewThreshold:=Floor((IP1/IS1+IP2/IS2)/2) if (NewThreshold=Threshold) Break } GuiControl,, Threshold, %Threshold% } Threshold:=Round(Threshold) color:="*" Threshold, k:=i:=0 Loop, % nW*nH { if (ascii[++k]="") Continue if (gs[k]<=Threshold) ascii[k]:="0", c:="Black", i++ else ascii[k]:="_", c:="White", i-- ft_Gui("SetColor") } bg:=i>0 ? "0":"_" return } if (cmd="GrayDiff2Two") { GuiControlGet, GrayDiff if (GrayDiff="") { Gui, +OwnDialogs MsgBox, 4096, Tip , `n Please Set Gray Difference First ! `n, 1 return } if (left=cors.LeftCut) ft_Gui("L") if (right=cors.RightCut) ft_Gui("R") if (up=cors.UpCut) ft_Gui("U") if (down=cors.DownCut) ft_Gui("D") GrayDiff:=Round(GrayDiff) color:="**" GrayDiff, k:=i:=0, n:=nW Loop, % nW*nH { if (ascii[++k]="") Continue j:=gs[k]+GrayDiff if ( gs[k-1]>j or gs[k+1]>j or gs[k-n]>j or gs[k+n]>j or gs[k-n-1]>j or gs[k-n+1]>j or gs[k+n-1]>j or gs[k+n+1]>j ) ascii[k]:="0", c:="Black", i++ else ascii[k]:="_", c:="White", i-- ft_Gui("SetColor") } bg:=i>0 ? "0":"_" return } if (cmd="Color2Two") or (cmd="ColorPos2Two") { GuiControlGet, c,, SelColor if (c="") { Gui, +OwnDialogs MsgBox, 4096, Tip , `n Please Select a Color First ! `n, 1 return } UsePos:=(cmd="ColorPos2Two") ? 1:0 GuiControlGet, n,, Similar 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 { if (ascii[++k]="") Continue c:=cors[k], r:=((c>>16)&0xFF)-rr , g:=((c>>8)&0xFF)-gg, b:=(c&0xFF)-bb if (3*r*r+4*g*g+2*b*b<=n) ascii[k]:="0", c:="Black", i++ else ascii[k]:="_", c:="White", i-- ft_Gui("SetColor") } bg:=i>0 ? "0":"_" return } if (cmd="ColorDiff2Two") { GuiControlGet, c,, SelColor if (c="") { Gui, +OwnDialogs MsgBox, 4096, Tip , `n Please Select a Color First ! `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 { if (ascii[++k]="") Continue c:=cors[k], r:=(c>>16)&0xFF, g:=(c>>8)&0xFF, b:=c&0xFF if ( Abs(r-rr)<=dR and Abs(g-gg)<=dG and Abs(b-bb)<=dB ) ascii[k]:="0", c:="Black", i++ else ascii[k]:="_", c:="White", i-- ft_Gui("SetColor") } bg:=i>0 ? "0":"_" return } if (cmd="Modify") { GuiControlGet, Modify return } if (cmd="Similar") { GuiControl,, Similar2, %Similar% return } if (cmd="Similar2") { GuiControl,, Similar, %Similar2% return } if (cmd="Reset") { if !IsObject(ascii) ascii:=[], gs:=[] left:=right:=up:=down:=k:=0, bg:="" Loop, % nW*nH { ascii[++k]:=1, c:=cors[k] gs[k]:=(((c>>16)&0xFF)*38+((c>>8)&0xFF)*75+(c&0xFF)*15)>>7 ft_Gui("SetColor") } Loop, % cors.LeftCut ft_Gui("L") Loop, % cors.RightCut ft_Gui("R") Loop, % cors.UpCut ft_Gui("U") Loop, % cors.DownCut ft_Gui("D") return } if (cmd="Auto") { ft_Gui("getwz") if (wz="") { Gui, +OwnDialogs MsgBox, 4096, Tip , `nPlease Click Color2Two or Gray2Two First !, 1 return } While InStr(wz,bg) { if (wz~="^" bg "+\n") { wz:=RegExReplace(wz,"^" bg "+\n") ft_Gui("U") } else if !(wz~="m`n)[^\n" bg "]$") { wz:=RegExReplace(wz,"m`n)" bg "$") ft_Gui("R") } else if (wz~="\n" bg "+\n$") { wz:=RegExReplace(wz,"\n\K" bg "+\n$") ft_Gui("D") } else if !(wz~="m`n)^[^\n" bg "]") { wz:=RegExReplace(wz,"m`n)^" bg) ft_Gui("L") } else Break } wz:="" return } if (cmd="OK") or (cmd="AllAdd") or (cmd="SplitAdd") { Gui, +OwnDialogs ft_Gui("getwz") if (wz="") { MsgBox, 4096, Tip , `nPlease Click Color2Two or Gray2Two First !, 1 return } if InStr(color,"@") and (UsePos) { StringSplit, r, color, @ k:=i:=j:=0 Loop, % nW*nH { if (ascii[++k]="") Continue i++ if (k=cors.SelPos) { j:=i Break } } if (j=0) { MsgBox, 4096, Tip , Please select the core color again !, 3 return } color:="#" . j . "@" . r2 } GuiControlGet, Comment Event:=cmd if InStr(cmd, "SplitAdd") { if InStr(color,"#") { MsgBox, 4096, Tip , % "Can't be used in ColorPos mode, " . "because it can cause position errors", 3 return } SetFormat, IntegerFast, d bg:=StrLen(StrReplace(wz,"_")) > StrLen(StrReplace(wz,"0")) ? "0":"_" s:="", k:=nW*nH+1+left , i:=0, w:=nW-left-right Loop, % w { 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!="") s.=ft_towz(color, v, SubStr(Comment,1,1)) Comment:=SubStr(Comment, 2) } Result:=s Gui, Hide return } s:=ft_towz(color, wz, Comment) if InStr(cmd, "AllAdd") { Result:=s Gui, Hide return } x:=px-ww+left+(nW-left-right)//2 y:=py-hh+up+(nH-up-down)//2 s:=StrReplace(s, "Text.=", "Text:=") s= ( t1:=A_TickCount %s% if (ok:=FindText(0, 0, A_ScreenWidth, A_ScreenHeight, 0, 0, Text)) { CoordMode, Mouse X:=ok.1.1, Y:=ok.1.2, W:=ok.1.3, H:=ok.1.4, Comment:=ok.1.5, X+=W//2, Y+=H//2 ; Click, `%X`%, `%Y`% } MsgBox, 4096, `% ok.MaxIndex(), `% "Time:``t" (A_TickCount-t1) " ms``n``n" . "Pos:``t[%x%, %y%] " X ", " Y "``n``n" . "Result:``t" (ok ? "Success ! " Comment : "Failed !") for i,v in ok if (i<=2) MouseTip(v.1+v.3//2, v.2+v.4//2) ) Result:=s Gui, Hide return } if (cmd="SetColor") { c:=c="White" ? 0xFFFFFF : c="Black" ? 0x000000 : ((c&0xFF)<<16)|(c&0xFF00)|((c&0xFF0000)>>16) SendMessage, 0x2001, 0, c,, % "ahk_id " . C_[k] return } if (cmd="DelColor") { ascii[k]:="", c:=WindowColor, ft_Gui("SetColor") return } if (cmd="ShowPic") { 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") { 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!="") { c:=ascii[k], ascii[k]:=c="0" ? "_" : c="_" ? "0" : c c:=c="0" ? "White" : c="_" ? "Black" : WindowColor ft_Gui("SetColor") } else { c:=cors[k], cors.SelPos:=k r:=(c>>16)&0xFF, g:=(c>>8)&0xFF, b:=c&0xFF GuiControl,, SelGray, % (r*38+g*75+b*15)>>7 GuiControl,, SelColor, %c% GuiControl,, SelR, %r% GuiControl,, SelG, %g% GuiControl,, SelB, %b% } return } return } if (cmd="getwz") { wz:="" if (bg="") return k:=0 Loop, %nH% { v:="" Loop, %nW% v.=ascii[++k] wz.=v="" ? "" : v "`n" } return } } ft_Load_ToolTip_Text() { s= (LTrim Capture = Initiate Image Capture Sequence Test = Test Results of Code Copy = Copy Code to Clipboard AddFunc = Additional FindText() in Copy U = Cut the Upper Edge by 1 U3 = Cut the Upper Edge by 3 L = Cut the Left Edge by 1 L3 = Cut the Left Edge by 3 R = Cut the Right Edge by 1 R3 = Cut the Right Edge by 3 D = Cut the Lower Edge by 1 D3 = Cut the Lower Edge by 3 SelR = Red component of the selected color SelG = Green component of the selected color SelB = Blue component of the selected color DiffR = Red Difference which Determines Black or White Pixel Conversion (0-255) DiffG = Green Difference which Determines Black or White Pixel Conversion (0-255) DiffB = Blue Difference which Determines Black or White Pixel Conversion (0-255) Auto = Automatic Cutting Edge Similar = Adjust color similarity as Equivalent to The Selected Color Similar2 = Adjust color similarity as Equivalent to The Selected Color SelColor = The selected color SelGray = Gray value of the selected color Threshold = Gray Threshold which Determines Black or White Pixel Conversion (0-255) GrayDiff = Gray Difference which Determines Black or White Pixel Conversion (0-255) UsePos = Use position instead of color value to suit any color Modify = Allows Modify the Black and White Image Reset = Reset to Original Captured Image Comment = Optional Comment used to Label Code ( Within <> ) SplitAdd = Using Markup Segmentation to Generate Text Library AllAdd = Append Another FindText Search Text into Previously Generated Code OK = Create New FindText Code for Testing Close = Close the Window Don't Do Anything Gray2Two = Converts Image Pixels from Grays to Black or White GrayDiff2Two = Converts Image Pixels from Gray Difference to Black or White Color2Two = Converts Image Pixels from Color to Black or White ColorPos2Two = Converts Image Pixels from Color Position to Black or White ColorDiff2Two = Converts Image Pixels from Color Difference to Black or White ) return, s } ft_EditEvents1() { ListLines, Off if (A_Gui="ft_Main" && A_GuiControl="scr") SetTimer, ft_ShowPic, -100 } ft_EditEvents2() { ListLines, Off if (A_Gui="ft_Capture") ft_Gui("WM_LBUTTONDOWN") else ft_EditEvents1() } ft_ShowPic() { ListLines, Off ft_Gui("ShowPic") } ft_ShowToolTip() { static ListLines, Off if (!ToolTip_Text) ToolTip_Text:=ft_Load_ToolTip_Text() CurrControl := A_GuiControl if (CurrControl != PrevControl) { PrevControl := CurrControl ToolTip if (CurrControl != "") SetTimer, ft_DisplayToolTip, -500 } return ;----------------- ft_DisplayToolTip: ListLines, Off MouseGetPos,,, _TT WinGetClass, _TT, ahk_id %_TT% if (_TT = "AutoHotkeyGUI") { ToolTip, % RegExMatch(ToolTip_Text , "m`n)^" CurrControl "\K\s*=.*", _TT) ? StrReplace(Trim(_TT,"`t ="),"\n","`n") : "" SetTimer, ft_RemoveToolTip, -5000 } return ;----------------- ft_RemoveToolTip: ToolTip return } ft_getc(px, py, ww, hh) { local ; Unaffected by Super-global variables xywh2xywh(px-ww,py-hh,2*ww+1,2*hh+1,x,y,w,h) if (w<1 or h<1) return, 0 bch:=A_BatchLines SetBatchLines, -1 ;-------------------------------------- GetBitsFromScreen(x,y,w,h,Scan0,Stride) ;-------------------------------------- cors:=[], k:=0, nW:=2*ww+1, nH:=2*hh+1 lls:=A_ListLines=0 ? "Off" : "On" ListLines, Off Loop, %nH% { j:=py-hh+A_Index-1 Loop, %nW% { i:=px-ww+A_Index-1, k++ cors[k]:=(i<x or i>x+w-1 or j<y or j>y+h-1) ? "0xFFFFFF" : Format("0x{:06X}",NumGet(Scan0 +(j-y)*Stride+(i-x)*4,"uint")&0xFFFFFF) } } ListLines, %lls% cors.LeftCut:=Abs(px-ww-x) cors.RightCut:=Abs(px+ww-(x+w-1)) cors.UpCut:=Abs(py-hh-y) cors.DownCut:=Abs(py+hh-(y+h-1)) SetBatchLines, %bch% return, cors } 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 } } ft_towz(color,wz,comment="") { SetFormat, IntegerFast, d wz:=StrReplace(StrReplace(wz,"0","1"),"_","0") wz:=(InStr(wz,"`n")-1) "." bit2base64(wz) return, "`nText.=""|<" comment ">" color "$" wz """`n" } ;===== Copy The Following Functions To Your Own Code Just once ===== ;-------------------------------- ; FindText - Capture screen image into text and then find it ;-------------------------------- ; X, Y --> the search scope's upper left corner coordinates ; W, H --> the search scope's Width and Height ; 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 --> a second-order array contains the [X,Y,W,H,Comment] of Each Find ;-------------------------------- FindText( x, y, w, h, err1, err0, text, ScreenShot=1 , FindAll=1, JoinText=0, offsetX=20, offsetY=10 ) { local ; Unaffected by Super-global variables xywh2xywh(x,y,w,h,x,y,w,h) if (w<1 or h<1) return, 0 bch:=A_BatchLines SetBatchLines, -1 ;------------------------------- 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 ; 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 } 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] ), 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 (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( [rx,ry,w1,h1,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( [rx,ry,w1,h1,comment] ) if (ok and !FindAll) Break } } if (err1=0 and err0=0 and !arr.MaxIndex()) { err1:=err0:=0.1, k:=0 For i,j in info if (j.6=0 and j.7=0) 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(x="", y="", w="", h="") { if (x+y+w+h="") n:=150000, x:=y:=-n, w:=h:=2*n+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) } FindTextOCR(nX, nY, nW, nH, err1, err0, Text, Interval=20) { OCR:="", RightX:=nX+nW-1, ScreenShot(nX,nY,nW,nH) While (ok:=FindText(nX, nY, nW, nH, err1, err0, Text, 0)) { For k,v in ok { ; X is the X coordinates of the upper left corner ; and W is the width of the image have been found x:=v.1, y:=v.2, w:=v.3, h:=v.4, comment:=v.5 ; We need the leftmost X coordinates if (A_Index=1 or x<LeftX) LeftX:=x, LeftY:=y, LeftW:=w, LeftH:=h, LeftOCR:=comment else if (x=LeftX) { Loop, 100 { err:=(A_Index-1)/100 if FindText(LeftX, LeftY, LeftW, LeftH, err, err, Text, 0) Break if FindText(x, y, w, h, err, err, Text, 0) { LeftX:=x, LeftY:=y, LeftW:=w, LeftH:=h, LeftOCR:=comment Break } } } } ; If the interval exceeds the set value, add "*" to the result OCR.=(A_Index>1 and LeftX-nX-1>Interval ? "*":"") . LeftOCR ; Update nX and nW for next search nX:=LeftX+LeftW-1, nW:=RightX-nX+1 } return, OCR } ; Reordering the objects returned from left to right, ; from top to bottom, ignore slight height difference SortOK(ok, dy=10) { 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 y:=A_Index>1 and Abs(y-lasty)<dy ? lasty : y, lasty:=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; } } //------------------ 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 ================= ; ;=========================================== ;~ The Source Code Version 5.5 /* ahk找字找图,大漠调用实例演示 YanYan?2017年2月21日?11,832?5 =========================================== [快捷抓取、查找屏幕文字/图像字库]v5.5 By FeiYue =========================================== 更新历史: v5.5 改变:取消了后台查找,因为Win7以上系统不太适用。 改进:直接生成单行的字库,用其他控件来显示字库对应的图像。 v5.3 改进:容差增加为两个,分别是0_字符的容许减少百分比。 采用新的算法,提高了带容差参数时的查找速度。 容差为默认值0时,找不到会自动使用 5% 的容差再找一次。 v5.2 改进:新增后台查找,相当于把指定ID的窗口搬到前台再查找。 因此用于前台操作的找字找图代码不用修改就可以转到后台模式。 注:Win7以上系统因PrintWindow不太好用,因此许多窗口不支持。 v5.0 改进:新增了第三种查找模式:边缘灰差模式。 v4.6 改进:增加对多显示器扩展显示的支持。 v4.5 改进:修正了Win10-64位系统的一些兼容性问题。 提高了抓字窗口中二值化、删除操作的反应速度。 v4.3 改进:文字参数中,每个字库文字可以添加用中括号括起来 的容差值,没有中括号才用“查找文字”函数中的容差参数。 v4.2 改进:新增了64位系统的机器码,可用于AHK 64位版。 v4.1 改进:不再使用GDI+获取屏幕图像,直接用GDI实现。 v4.0 改进:文字参数增加竖线分隔的字库形式,可以进行 OCR识别。这种形式也可用于同时查找多幅文字或图片。 v3.5 改进:采用自写的机器码实现图内找字,极大的提高了速度。 使用说明: 1、先抓取文字图像字符串,然后全屏查找测试,测试成功后, 点击复制代码,并粘贴到自己的脚本中,最后将最下面的 “查找文字”函数及后面的函数复制到自己的脚本中就行了。 2、自动灰度二值化的图像如果不满意,可以手动输入阀值试试。 字库输入框可以一次生成多个文字的模板。如果左右结构 的字被分开,可以单独裁剪出这一个字,然后点击插入。 3、由于许多因素会影响屏幕图像,所以换一台电脑一般就要 重新抓字/图。建议使用颜色模式抓字,这样通用性强些。 4、建立多个文字的字库时,要尽量统一阀值才行。第一次抓图 得到的阀值,之后的分割、插入两种操作都要采用这个阀值。 以本人使用来看,采用边缘灰差模式建立字库,容易统一阀值。 =========================================== 是否成功 := 查找文字( 中心点X, 中心点Y, 左右偏移W, 上下偏移H , 文字, 颜色, 返回X, 返回Y, 返回OCR结果 , 0字符减少百分比, _字符减少百分比 ) 其中:颜色带*号的为灰度阀值模式,对于非单色的文字比较好用。 容差参数允许有几个点不同,这对于灰度阀值模式很有用。 =========================================== */ /* #NoEnv #SingleInstance Force SetBatchLines, -1 CoordMode, Mouse CoordMode, Pixel CoordMode, ToolTip SetTitleMatchMode, 2 SetWorkingDir, %A_ScriptDir% ;---------------------------- Menu, Tray, Icon, Shell32.dll, 23 Menu, Tray, Add Menu, Tray, Add, 显示主窗口 Menu, Tray, Default, 显示主窗口 Menu, Tray, Click, 1 ;---------------------------- ww:=35, hh:=12 ; 左右上下抓字抓图的范围 nW:=2*ww+1, nH:=2*hh+1 ;---------------------------- gosub, 生成抓字窗口 gosub, 生成主窗口 OnExit, savescr gosub, readscr return F12:: ; 按[F12]保存修改并重启脚本 SetTitleMatchMode, 2 SplitPath, A_ScriptName,,,, name IfWinExist, %name% { ControlSend, ahk_parent, {Ctrl Down}s{Ctrl Up} Sleep, 500 } Reload return readscr: f=%A_Temp%\~scr1.tmp FileRead, s, %f% GuiControl, Main:, scr, %s% s= return savescr: f=%A_Temp%\~scr1.tmp GuiControlGet, s, Main:, scr FileDelete, %f% FileAppend, %s%, %f% ExitApp 显示主窗口: Gui, Main:Show, CEnter return 生成主窗口: Gui, Main:Default Gui, +AlwaysOnTop +HwndMain_ID Gui, Margin, 15, 15 Gui, Color, EEFFFF, EEFFFF Gui, Font, s5 bold, Verdana Gui, Add, Edit, xm w660 r25 vMyEdit -Wrap -VScroll Gui, Font, s12 norm, Verdana Gui, Add, Button, xm w220 gMainRun, 抓取文字图像 Gui, Add, Button, x+0 wp gMainRun, 全屏查找测试 Gui, Add, Button, x+0 wp gMainRun, 复制代码 Gui, Font, s12 cBlue, Verdana Gui, Add, Edit, xm w660 h350 vscr Hwndhscr -Wrap HScroll Gui, Show, NA, 文字/图像字库生成工具 ;--------------------------------------- OnMessage(0x100, "EditEvents1") ; WM_KEYDOWN OnMessage(0x201, "EditEvents2") ; WM_LButtonDOWN return EditEvents1() { ListLines, Off if (A_Gui="Main") and (A_GuiControl="scr") SetTimer, 显示文字, -100 } EditEvents2() { ListLines, Off if (A_Gui="catch") WM_LBUTTONDOWN() else EditEvents1() } 显示文字: ListLines, Off Critical ControlGet, i, CurrentLine,,, ahk_id %hscr% ControlGet, s, Line, %i%,, ahk_id %hscr% if RegExMatch(s,"(\d+)\.([\w+/]+)",r) { s:=RegExReplace(base64tobit(r2),".{" r1 "}","$0`n") s:=StrReplace(StrReplace(s,"0","_"),"1","0") } else s= GuiControl, Main:, MyEdit, % Trim(s,"`n") return MainRun: k:=A_GuiControl WinMinimize Gui, Hide DetectHiddenWindows, Off WinWaitClose, ahk_id %Main_ID% if IsLabel(k) gosub, %k% Gui, Main:Show GuiControl, Main:Focus, scr return 复制代码: GuiControlGet, s,, scr Clipboard:=StrReplace(s,"`n","`r`n") s= return 抓取文字图像: ;------------------------------ ; 先用一个微型GUI提示抓字范围 Gui, Mini:Default Gui, +LastFound +AlwaysOnTop -Caption +ToolWindow WinSet, Transparent, 100 Gui, Color, Red Gui, Show, Hide w%nW% h%nH% ;------------------------------ ListLines, Off loop { MouseGetPos, px, py if GetKeyState("LButton","P") break Gui, Show, % "NA x" (px-ww) " y" (py-hh) ToolTip, % "当前鼠标位置:" px "," py . "`n请移到目标位置后点击左键" Sleep, 20 } KeyWait, LButton Gui, Color, White loop { MouseGetPos, x, y if Abs(px-x)+Abs(py-y)>100 break Gui, Show, % "NA x" (x-ww) " y" (y-hh) ToolTip, 请把鼠标移开100像素以上 Sleep, 20 } ToolTip ListLines, On Gui, Destroy WinWaitClose cors:=getc(px,py,ww,hh) Gui, catch:Default loop, 4 GuiControl,, Edit%A_Index% GuiControl,, 修改, % xiugai:=0 gosub, 重读 Gui, Show, CEnter DetectHiddenWindows, Off WinWaitClose, ahk_id %catch_ID% return WM_LBUTTONDOWN() { global ListLines, Off MouseGetPos,,,, mclass if !InStr(mclass,"Progress") return MouseGetPos,,,, mid, 2 For k,v in C_ if (v=mid) { if (xiugai and bg!="") { c:=cc[k], cc[k]:=c="0" ? "_" : c="_" ? "0" : c c:=c="0" ? "White" : c="_" ? "Black" : "0xDDEEFF" gosub, SetColor } else { c:=cors[k] GuiControl, catch:, Edit1, %c% c:=((c>>16&0xFF)*38+(c>>8&0xFF)*75+(c&0xFF)*15)>>7 GuiControl, catch:, Edit4, %c% } return } } ; ; 本文的最后修改日期是 公元2019年11月11日 ; 本文的网址是 https://gitee.com/weiyunwps618/codes ; 本文的网址是 https://www.cnblogs.com/delphixx ; 晓亮(weiyunwps618)的腾讯QQ邮箱地址是 595076941@qq.com ) ; 晓亮(weiyunwps618)的中国移动手机号码是 138####5488 ) ; 此AHK脚本的测试环境是 Windows 7 Pro SP1 VL 和 AutoHotkey v1.1.30.01 ; getc(px,py,ww,hh) { xywh2xywh(px-ww,py-hh,2*ww+1,2*hh+1,x,y,w,h) if (w<1 or h<1) return, 0 bch:=A_BatchLines SetBatchLines, -1 ;-------------------------------------- GetBitsFromScreen(x,y,w,h,Scan0,Stride,bits) ;-------------------------------------- cors:=[], k:=0, nW:=2*ww+1, nH:=2*hh+1 ListLines, Off fmt:=A_FormatInteger SetFormat, IntegerFast, H loop, %nH% { j:=py-hh-y+A_Index-1 loop, %nW% { i:=px-ww-x+A_Index-1, k++ if (i>=0 and i<w and j>=0 and j<h) c:=NumGet(Scan0+0,i*4+j*Stride,"uint") , cors[k]:="0x" . SubStr(0x1000000|c,-5) else cors[k]:="0xFFFFFF" } } SetFormat, IntegerFast, %fmt% ListLines, On ; 左右上下超出屏幕边界的值 cors.left:=Abs(px-ww-x) cors.Right:=Abs(px+ww-(x+w-1)) cors.up:=Abs(py-hh-y) cors.down:=Abs(py+hh-(y+h-1)) SetBatchLines, %bch% return, cors } 全屏查找测试: GuiControlGet, s, Main:, scr wenzi= loop, Parse, s, `n if RegExMatch(A_LoopField,"文字\.=""([^\n]+)""",r) wenzi.=r1 if !RegExMatch(s,"查找文字\(([^\n]+)\)",r) return StringSplit, r, r1, `,, "" if r0<6 return t1:=A_TickCount ok:=查找文字(r1,r2,r3,r4,wenzi,r6,X,Y,OCR,r10,r11) t1:=A_TickCount-t1 MsgBox, 4096,, % "查找结果:" (ok ? "成功":"失败") . "`n`n文字识别结果:" OCR . "`n`n耗时:" t1 " 毫秒,找到的位置:" (ok ? X "," Y:"") if ok { MouseMove, X, Y Sleep, 1000 } return 生成抓字窗口: Gui, catch:Default Gui, +LastFound +AlwaysOnTop +ToolWindow +Hwndcatch_ID Gui, Margin, 15, 15 Gui, Color, DDEEFF Gui, Font, s16, Verdana ListLines, Off loop, % nH*nW { j:=A_Index=1 ? "" : Mod(A_Index,nW)=1 ? "xm y+-1" : "x+-1" Gui, Add, Progress, w15 h15 %j% -Theme } ListLines, On Gui, Add, Text, xm y+21 w50 CEnter, 选色 Gui, Add, Edit, x+2 w130 Gui, Add, Button, x+2 yp-6 w140 gRun, 颜色二值化 ;------------------------- Gui, Add, Text, x+10 yp+6 w50 CEnter, 阀值 Gui, Add, Edit, x+2 w70 Gui, Add, Button, x+2 yp-6 w140 gRun Default, 灰度二值化 ;------------------------- Gui, Add, Text, x+10 yp+6 w50 CEnter, 字库 Gui, Add, Edit, x+2 w90 Gui, Add, Checkbox, x+4 yp+6 w80 gRun, 修改 Gui, Add, Button, x+0 yp-6 wp gRun Section, 分割 Gui, Add, Button, x+0 wp gRun, 确定 ;------------------------- Gui, Add, Text, xm y+10 w50 CEnter, 灰度 Gui, Add, Edit, x+2 w130 Gui, Add, Text, x+2 w140 CEnter, 边缘灰度差 Gui, Add, Edit, x+2 w100, 50 Gui, Add, Button, x+2 yp-6 w140 gRun, 灰差二值化 Gui, Add, Button, x+50 w80 gRun, 反色 Gui, Add, Button, xs yp wp gRun, 插入 Gui, Add, Button, x+0 wp gCancel, 关闭 ;------------------------- Gui, Add, Button, xm w80 gRun, 左删 Gui, Add, Button, x+0 wp gRun, 左3删 Gui, Add, Button, x+25 wp gRun, 右删 Gui, Add, Button, x+0 wp gRun, 右3删 Gui, Add, Button, x+25 wp gRun, 上删 Gui, Add, Button, x+0 wp gRun, 上3删 Gui, Add, Button, x+25 wp gRun, 下删 Gui, Add, Button, x+0 wp gRun, 下3删 Gui, Add, Button, x+25 wp gRun, 智删 Gui, Add, Button, x+25 wp gRun, 重读 Gui, Show, Hide, 抓字生成字库 WinGet, s, ControlListHwnd C_:=StrSplit(s,"`n"), s:="" return Run: Critical k:=A_GuiControl if IsLabel(k) goto, %k% return 修改: GuiControlGet, xiugai,, %A_GuiControl% return SetColor: c:=c="White" ? 0xFFFFFF : c="Black" ? 0x000000 : ((c&0xFF)<<16)|(c&0xFF00)|((c&0xFF0000)>>16) SendMessage, 0x2001, 0, c,, % "ahk_id " . C_[k] return 重读: if !IsObject(cc) cc:=[], gg:=[], pp:=[] left:=Right:=up:=down:=k:=0, bg:="" loop, % nH*nW { cc[++k]:=1, c:=cors[k] gg[k]:=((c>>16&0xFF)*38+(c>>8&0xFF)*75+(c&0xFF)*15)>>7 gosub, SetColor } ; 裁剪抓字范围超过屏幕边界的部分 loop, % cors.left gosub, 左删 loop, % cors.Right gosub, 右删 loop, % cors.up gosub, 上删 loop, % cors.down gosub, 下删 return 颜色二值化: GuiControlGet, r,, Edit1 if r= { MsgBox, 4096,, `n 请先进行选色! `n, 1 return } color:=r, k:=i:=0 loop, % nH*nW { if (cc[++k]="") continue if (cors[k]=color) cc[k]:="0", c:="Black", i++ else cc[k]:="_", c:="White", i-- gosub, SetColor } bg:=i>0 ? "0":"_" ; 背景色 return 灰度二值化: ; 可以多次手动输入阀值或清空阀值再次二值化 GuiControl, Focus, Edit2 GuiControlGet, fazhi,, Edit2 if fazhi= { loop, 256 ; 统计灰度直方图 pp[A_Index-1]:=0 loop, % nH*nW if (cc[A_Index]!="") pp[gg[A_Index]]++ ; 迭代法求二值化阈值,最多迭代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,, Edit2, %fazhi% } color:="*" fazhi, k:=i:=0 loop, % nH*nW { if (cc[++k]="") continue if (gg[k]<fazhi+1) cc[k]:="0", c:="Black", i++ else cc[k]:="_", c:="White", i-- gosub, SetColor } bg:=i>0 ? "0":"_" ; 背景色 return 灰差二值化: GuiControlGet, r,, Edit5 if r= { MsgBox, 4096,, `n 请先设置边缘灰度差(比如50)! `n, 1 return } fazhi:=Round(r) if (left=cors.left) gosub, 左删 if (Right=cors.Right) gosub, 右删 if (up=cors.up) gosub, 上删 if (down=cors.down) gosub, 下删 color:="**" fazhi, k:=i:=0 loop, % nH*nW { if (cc[++k]="") continue c:=gg[k]+fazhi if (gg[k-1]>c or gg[k+1]>c or gg[k-nW]>c or gg[k+nW]>c) cc[k]:="0", c:="Black", i++ else cc[k]:="_", c:="White", i-- gosub, SetColor } bg:=i>0 ? "0":"_" ; 背景色 return gui_del: cc[k]:="", c:="0xDDEEFF" gosub, SetColor return 左3删: loop, 3 gosub, 左删 return 左删: if (left+Right>=nW) return left++, k:=left loop, %nH% { gosub, gui_del k+=nW } return 右3删: loop, 3 gosub, 右删 return 右删: if (left+Right>=nW) return Right++, k:=nW+1-Right loop, %nH% { gosub, gui_del k+=nW } return 上3删: loop, 3 gosub, 上删 return 上删: if (up+down>=nH) return up++, k:=(up-1)*nW loop, %nW% { k++ gosub, gui_del } return 下3删: loop, 3 gosub, 下删 return 下删: if (up+down>=nH) return down++, k:=(nH-down)*nW loop, %nW% { k++ gosub, gui_del } return getwz: wz= if bg= return ListLines, Off k:=0 loop, %nH% { v= loop, %nW% v.=cc[++k] wz.=v="" ? "" : v "`n" } ListLines, On return 智删: gosub, getwz if wz= { MsgBox, 4096, 提示, `n请先进行一种二值化!, 1 return } while InStr(wz,bg) { if (wz~="^" bg "+\n") { wz:=RegExReplace(wz,"^" bg "+\n") gosub, 上删 } else if !(wz~="m`n)[^\n" bg "]$") { wz:=RegExReplace(wz,"m`n)" bg "$") gosub, 右删 } else if (wz~="\n" bg "+\n$") { wz:=RegExReplace(wz,"\n\K" bg "+\n$") gosub, 下删 } else if !(wz~="m`n)^[^\n" bg "]") { wz:=RegExReplace(wz,"m`n)^" bg) gosub, 左删 } else break } wz= return 确定: 分割: 反色: gosub, getwz if wz= { MsgBox, 4096, 提示, `n请先进行一种二值化!, 1 return } if A_ThisLabel=反色 { wz:="", k:=0, bg:=bg="0" ? "_":"0" color:=InStr(color,"-") ? StrReplace(color,"-"):"-" color loop, % nH*nW if (c:=cc[++k])!="" { cc[k]:=c="0" ? "_":"0", c:=c="0" ? "White":"Black" gosub, SetColor } return } Gui, Hide ; 生成代码中的坐标为裁剪后整体文字的中心位置 px1:=px-ww+left+(nW-left-Right)//2 py1:=py-hh+up+(nH-up-down)//2 GuiControlGet, ziku,, Edit3 ziku:=Trim(ziku), s:="`n文字=`n" if A_ThisLabel=分割 { SetFormat, IntegerFast, d ; 正则表达式中数字需要十进制 loop { while InStr(wz,bg) and !(wz~="m`n)^[^\n" bg "]") wz:=RegExReplace(wz,"m`n)^.") loop, % InStr(wz,"`n")-1 { i:=A_Index if !(wz~="m`n)^.{" i "}[^\n" bg "]") { ; 自动分割会裁边,小数点等的字库要手动制作 v:=RegExReplace(wz,"m`n)^(.{" i "}).*","$1") v:=RegExReplace(v,"^(" bg "+\n)+") v:=RegExReplace(v,"\n\K(" bg "+\n)+$") k:=SubStr(ziku,1,1), ziku:=SubStr(ziku,2) s.="`n文字.=""|<" k ">" . towz(v) . """`n" wz:=RegExReplace(wz,"m`n)^.{" i "}") continue, 2 } } break } add(s) return } s.="`n文字.=""|<" ziku ">" . towz(wz) . """`n" s.="`nif 查找文字(" px1 "," py1 ",150000,150000,文字,""" . color . """,X,Y,OCR,0,0)`n" . "{`n CoordMode, Mouse`n MouseMove, X, Y`n}`n" GuiControl, Main:, scr, %s% s:=wz:="" return 插入: gosub, getwz if wz= { MsgBox, 4096, 提示, `n请先进行一种二值化!, 1 return } Gui, Hide GuiControlGet, ziku,, Edit3 s:="文字.=""|<" ziku ">" . towz(wz) . """" add(s) return towz(wz) { SetFormat, IntegerFast, d wz:=StrReplace(StrReplace(wz,"0","1"),"_","0") return, InStr(wz,"`n")-1 . "." . bit2base64(wz) } add(s) { global hscr s:=RegExReplace("`n" s "`n","\R","`r`n") ControlGet, i, CurrentCol,,, ahk_id %hscr% if i>1 ControlSend,, {Home}{Down}, ahk_id %hscr% Control, EditPaste, %s%,, ahk_id %hscr% } ;---- 将后面的函数附加到自己的脚本中 ---- ;----------------------------------------- ; 查找屏幕文字/图像字库及OCR识别 ; 注意:参数中的x、y为中心点坐标,w、h为左右上下偏移 ; cha1、cha0分别为0、_字符的容许减少百分比 ;----------------------------------------- 查找文字(x,y,w,h,wz,c,ByRef rx="",ByRef ry="",ByRef ocr="" , cha1=0, cha0=0) { xywh2xywh(x-w,y-h,2*w+1,2*h+1,x,y,w,h) if (w<1 or h<1) return, 0 bch:=A_BatchLines SetBatchLines, -1 ;-------------------------------------- GetBitsFromScreen(x,y,w,h,Scan0,Stride,bits) ;-------------------------------------- ; 设定图内查找范围,注意不要越界 sx:=0, sy:=0, sw:=w, sh:=h if PicOCR(Scan0,Stride,sx,sy,sw,sh,wz,c ,rx,ry,ocr,cha1,cha0) { rx+=x, ry+=y SetBatchLines, %bch% return, 1 } ; 容差为0的若失败则使用 5% 的容差再找一次 if (cha1=0 and cha0=0) and PicOCR(Scan0,Stride,sx,sy,sw,sh,wz,c ,rx,ry,ocr,0.05,0.05) { rx+=x, ry+=y SetBatchLines, %bch% return, 1 } SetBatchLines, %bch% return, 0 } ;-- 规范输入范围在屏幕范围内 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,ByRef bits) { VarSetCapacity(bits, w*h*4, 0) Ptr:=A_PtrSize ? "Ptr" : "UInt" ; 桌面窗口对应包含所有显示器的虚拟屏幕 win:=DllCall("GetDesktopWindow", Ptr) hDC:=DllCall("GetWindowDC", Ptr,win, Ptr) mDC:=DllCall("CreateCompatibleDC", Ptr,hDC, Ptr) hBM:=DllCall("CreateCompatibleBitmap", Ptr,hDC , "int",w, "int",h, 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) ;-------------------------- 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:=32, bi, 14, "short"), NumPut(0, bi, 16, "int") ;-------------------------- DllCall("GetDIBits", Ptr,mDC, Ptr,hBM , "int",0, "int",h, Ptr,&bits, Ptr,&bi, "int",0) DllCall("SelectObject", Ptr,mDC, Ptr,oBM) DllCall("DeleteObject", Ptr,hBM) DllCall("DeleteDC", Ptr,mDC) DllCall("ReleaseDC", Ptr,win, Ptr,hDC) Scan0:=&bits, Stride:=((w*bpp+31)//32)*4 } ;----------------------------------------- ; 图像内查找文字/图像字符串及OCR函数 ;----------------------------------------- PicOCR(Scan0, Stride, sx, sy, sw, sh, wenzi, c , ByRef rx, ByRef ry, ByRef ocr, cha1, cha0) { static MyFunc if !MyFunc { x32:="5589E55383EC608B45200FAF45188B551CC1E20201D0894" . "5F08B5524B80000000029D0C1E00289C28B451801D08945ECC" . "745E800000000C745D400000000C745D0000000008B4524894" . "5CC8B45288945C8C745C400000000837D08000F85B20000008" . "B450CC1E81025FF0000008945C08B450CC1E80825FF0000008" . "945BC8B450C25FF0000008945B8C745F400000000EB75C745F" . "800000000EB5A8B45F083C00289C28B451401D00FB6000FB6C" . "03B45C075368B45F083C00189C28B451401D00FB6000FB6C03" . "B45BC751E8B55F08B451401D00FB6000FB6C03B45B8750B8B5" . "5E88B453001D0C600318345F8018345F0048345E8018B45F83" . "B45247C9E8345F4018B45EC0145F08B45F43B45287C83E9170" . "20000837D08010F85A30000008B450C83C001C1E00789450CC" . "745F400000000EB7DC745F800000000EB628B45F083C00289C" . "28B451401D00FB6000FB6C06BD0268B45F083C00189C18B451" . "401C80FB6000FB6C06BC04B8D0C028B55F08B451401D00FB60" . "00FB6D089D0C1E00429D001C83B450C730B8B55E88B453001D" . "0C600318345F8018345F0048345E8018B45F83B45247C96834" . "5F4018B45EC0145F08B45F43B45280F8C77FFFFFFE96A01000" . "0C745F400000000EB7BC745F800000000EB608B55E88B452C8" . "D0C028B45F083C00289C28B451401D00FB6000FB6C06BD0268" . "B45F083C00189C38B451401D80FB6000FB6C06BC04B8D1C028" . "B55F08B451401D00FB6000FB6D089D0C1E00429D001D8C1F80" . "788018345F8018345F0048345E8018B45F83B45247C988345F" . "4018B45EC0145F08B45F43B45280F8C79FFFFFF8B452483E80" . "18945B48B452883E8018945B0C745F401000000E9B0000000C" . "745F801000000E9940000008B45F40FAF452489C28B45F801D" . "08945E88B55E88B452C01D00FB6000FB6D08B450C01D08945E" . "C8B45E88D50FF8B452C01D00FB6000FB6C03B45EC7F488B45E" . "88D50018B452C01D00FB6000FB6C03B45EC7F328B45E82B452" . "489C28B452C01D00FB6000FB6C03B45EC7F1A8B55E88B45240" . "1D089C28B452C01D00FB6000FB6C03B45EC7E0B8B55E88B453" . "001D0C600318345F8018B45F83B45B40F8C60FFFFFF8345F40" . "18B45F43B45B00F8C44FFFFFFC745E800000000E9E30000008" . "B45E88D1485000000008B454001D08B008945E08B45E08945E" . "48B45E48945F08B45E883C0018D1485000000008B454001D08" . "B008945B48B45E883C0028D1485000000008B454001D08B008" . "945B0C745F400000000EB7CC745F800000000EB678B45F08D5" . "0018955F089C28B453401D00FB6003C3175278B45E48D50018" . "955E48D1485000000008B453801C28B45F40FAF452489C18B4" . "5F801C88902EB258B45E08D50018955E08D1485000000008B4" . "53C01C28B45F40FAF452489C18B45F801C889028345F8018B4" . "5F83B45B47C918345F4018B45F43B45B00F8C78FFFFFF8345E" . "8078B45E83B45440F8C11FFFFFF8B45D00FAF452489C28B45D" . "401D08945F08B45240FAF45C8BA0100000029C289D08945E4C" . "745F800000000E9B5020000C745F400000000E993020000C74" . "5E800000000E9710200008B45E883C0018D1485000000008B4" . "54001D08B008945B48B45E883C0028D1485000000008B45400" . "1D08B008945B08B55F88B45B401D03B45CC0F8F2D0200008B5" . "5F48B45B001D03B45C80F8F1C0200008B45E88D14850000000" . "08B454001D08B008945E08B45E883C0038D1485000000008B4" . "54001D08B008945AC8B45E883C0048D1485000000008B45400" . "1D08B008945A88B45E883C0058D1485000000008B454001D08" . "B008945DC8B45E883C0068D1485000000008B454001D08B008" . "945D88B45AC3945A80F4D45A88945A4C745EC00000000E9820" . "000008B45EC3B45AC7D378B55E08B45EC01D08D14850000000" . "08B453801D08B108B45F001D089C28B453001D00FB6003C317" . "40E836DDC01837DDC000F884E0100008B45EC3B45A87D378B5" . "5E08B45EC01D08D1485000000008B453C01D08B108B45F001D" . "089C28B453001D00FB6003C30740E836DD801837DD8000F881" . "20100008345EC018B45EC3B45A40F8C72FFFFFF837DC4000F8" . "5840000008B551C8B45F801C28B454889108B454883C0048B4" . "D208B55F401CA89108B45488D50088B45B489028B45488D500" . "C8B45B08902C745C4040000008B45F42B45B08945D08B55B08" . "9D001C001D08945C88B55B089D0C1E00201D001C083C064894" . "5CC837DD0007907C745D0000000008B45282B45D03B45C87D2" . "E8B45282B45D08945C8EB238B45F83B45107E1B8B45C48D500" . "18955C48D1485000000008B454801D0C700FFFFFFFF8B45C48" . "D50018955C48D1485000000008B454801D08B55E883C207891" . "0817DC4FD0300007F788B55F88B45B401D00145D48B45242B4" . "5D43B45CC0F8D60FDFFFF8B45242B45D48945CCE952FDFFFF9" . "0EB0490EB01908345E8078B45E83B45440F8C83FDFFFF8345F" . "4018B45240145F08B45F43B45C80F8C61FDFFFF8345F8018B4" . "5E40145F08B45F83B45CC0F8C3FFDFFFF837DC4007508B8000" . "00000EB1B908B45C48D1485000000008B454801D0C70000000" . "000B80100000083C4605B5DC2440090" x64:="554889E54883EC60894D10895518448945204C894D288B4" . "5400FAF45308B5538C1E20201D08945F48B5548B8000000002" . "9D0C1E00289C28B453001D08945F0C745EC00000000C745D80" . "0000000C745D4000000008B45488945D08B45508945CCC745C" . "800000000837D10000F85C90000008B4518C1E81025FF00000" . "08945C48B4518C1E80825FF0000008945C08B451825FF00000" . "08945BCC745F800000000E985000000C745FC00000000EB6A8" . "B45F483C0024863D0488B45284801D00FB6000FB6C03B45C47" . "5438B45F483C0014863D0488B45284801D00FB6000FB6C03B4" . "5C075288B45F44863D0488B45284801D00FB6000FB6C03B45B" . "C75108B45EC4863D0488B45604801D0C600318345FC018345F" . "4048345EC018B45FC3B45487C8E8345F8018B45F00145F48B4" . "5F83B45500F8C6FFFFFFFE959020000837D10010F85B600000" . "08B451883C001C1E007894518C745F800000000E98D000000C" . "745FC00000000EB728B45F483C0024863D0488B45284801D00" . "FB6000FB6C06BD0268B45F483C0014863C8488B45284801C80" . "FB6000FB6C06BC04B8D0C028B45F44863D0488B45284801D00" . "FB6000FB6D089D0C1E00429D001C83B451873108B45EC4863D" . "0488B45604801D0C600318345FC018345F4048345EC018B45F" . "C3B45487C868345F8018B45F00145F48B45F83B45500F8C67F" . "FFFFFE999010000C745F800000000E98D000000C745FC00000" . "000EB728B45EC4863D0488B4558488D0C028B45F483C002486" . "3D0488B45284801D00FB6000FB6C06BD0268B45F483C0014C6" . "3C0488B45284C01C00FB6000FB6C06BC04B448D04028B45F44" . "863D0488B45284801D00FB6000FB6D089D0C1E00429D04401C" . "0C1F80788018345FC018345F4048345EC018B45FC3B45487C8" . "68345F8018B45F00145F48B45F83B45500F8C67FFFFFF8B454" . "883E8018945B88B455083E8018945B4C745F801000000E9CA0" . "00000C745FC01000000E9AE0000008B45F80FAF454889C28B4" . "5FC01D08945EC8B45EC4863D0488B45584801D00FB6000FB6D" . "08B451801D08945F08B45EC4898488D50FF488B45584801D00" . "FB6000FB6C03B45F07F538B45EC4898488D5001488B4558480" . "1D00FB6000FB6C03B45F07F388B45EC2B45484863D0488B455" . "84801D00FB6000FB6C03B45F07F1D8B55EC8B454801D04863D" . "0488B45584801D00FB6000FB6C03B45F07E108B45EC4863D04" . "88B45604801D0C600318345FC018B45FC3B45B80F8C46FFFFF" . "F8345F8018B45F83B45B40F8C2AFFFFFFC745EC00000000E90" . "D0100008B45EC4898488D148500000000488B8580000000480" . "1D08B008945E48B45E48945E88B45E88945F48B45EC4898488" . "3C001488D148500000000488B85800000004801D08B008945B" . "88B45EC48984883C002488D148500000000488B85800000004" . "801D08B008945B4C745F800000000E989000000C745FC00000" . "000EB748B45F48D50018955F44863D0488B45684801D00FB60" . "03C31752C8B45E88D50018955E84898488D148500000000488" . "B45704801C28B45F80FAF454889C18B45FC01C88902EB2A8B4" . "5E48D50018955E44898488D148500000000488B45784801C28" . "B45F80FAF454889C18B45FC01C889028345FC018B45FC3B45B" . "87C848345F8018B45F83B45B40F8C6BFFFFFF8345EC078B45E" . "C3B85880000000F8CE4FEFFFF8B45D40FAF454889C28B45D80" . "1D08945F48B45480FAF45CCBA0100000029C289D08945E8C74" . "5FC00000000E929030000C745F800000000E907030000C745E" . "C00000000E9E20200008B45EC48984883C001488D148500000" . "000488B85800000004801D08B008945B88B45EC48984883C00" . "2488D148500000000488B85800000004801D08B008945B48B5" . "5FC8B45B801D03B45D00F8F8C0200008B55F88B45B401D03B4" . "5CC0F8F7B0200008B45EC4898488D148500000000488B85800" . "000004801D08B008945E48B45EC48984883C003488D1485000" . "00000488B85800000004801D08B008945B08B45EC48984883C" . "004488D148500000000488B85800000004801D08B008945AC8" . "B45EC48984883C005488D148500000000488B8580000000480" . "1D08B008945E08B45EC48984883C006488D148500000000488" . "B85800000004801D08B008945DC8B45B03945AC0F4D45AC894" . "5A8C745F000000000E9920000008B45F03B45B07D3F8B55E48" . "B45F001D04898488D148500000000488B45704801D08B108B4" . "5F401D04863D0488B45604801D00FB6003C31740E836DE0018" . "37DE0000F88790100008B45F03B45AC7D3F8B55E48B45F001D" . "04898488D148500000000488B45784801D08B108B45F401D04" . "863D0488B45604801D00FB6003C30740E836DDC01837DDC000" . "F88350100008345F0018B45F03B45A80F8C62FFFFFF837DC80" . "00F85970000008B55388B45FC01C2488B85900000008910488" . "B85900000004883C0048B4D408B55F801CA8910488B8590000" . "000488D50088B45B88902488B8590000000488D500C8B45B48" . "902C745C8040000008B45F82B45B48945D48B55B489D001C00" . "1D08945CC8B55B489D0C1E00201D001C083C0648945D0837DD" . "4007907C745D4000000008B45502B45D43B45CC7D368B45502" . "B45D48945CCEB2B8B45FC3B45207E238B45C88D50018955C84" . "898488D148500000000488B85900000004801D0C700FFFFFFF" . "F8B45C88D50018955C84898488D148500000000488B8590000" . "0004801D08B55EC83C2078910817DC8FD0300007F7B8B55FC8" . "B45B801D00145D88B45482B45D83B45D00F8DEFFCFFFF8B454" . "82B45D88945D0E9E1FCFFFF90EB0490EB01908345EC078B45E" . "C3B85880000000F8C0FFDFFFF8345F8018B45480145F48B45F" . "83B45CC0F8CEDFCFFFF8345FC018B45E80145F48B45FC3B45D" . "00F8CCBFCFFFF837DC8007508B800000000EB23908B45C8489" . "8488D148500000000488B85900000004801D0C70000000000B" . "8010000004883C4605DC390909090909090909090" MCode(MyFunc, A_PtrSize=8 ? x64:x32) } ;-------------------------------------- ; 统计字库文字的个数和宽高,将解释文字存入数组并删除<> ;-------------------------------------- wenzitab:=[], num:=0, wz:="", j:="" loop, Parse, wenzi, | { v:=A_LoopField, txt:="", e1:=cha1, e0:=cha0 ; 用角括号输入每个字库字符串的识别结果文字 if RegExMatch(v,"<([^>]*)>",r) v:=StrReplace(v,r), txt:=r1 ; 可以用中括号输入每个文字的两个容差,以逗号分隔 if RegExMatch(v,"\[([^\]]*)]",r) { v:=StrReplace(v,r), r2:="" StringSplit, r, r1, `, e1:=r1, e0:=r2 } ; 记录每个文字的起始位置、宽、高、10字符的数量和容差 StringSplit, r, v, . w:=r1, v:=base64tobit(r2), h:=StrLen(v)//w if (r0<2 or w>sw or h>sh or StrLen(v)!=w*h) continue if InStr(c,"-") { r:=e1, e1:=e0, e0:=r, v:=StrReplace(v,"1","_") v:=StrReplace(StrReplace(v,"0","1"),"_","0") } len1:=StrLen(StrReplace(v,"0")) len0:=StrLen(StrReplace(v,"1")) e1:=Round(len1*e1), e0:=Round(len0*e0) j.=StrLen(wz) "|" w "|" h . "|" len1 "|" len0 "|" e1 "|" e0 "|" wz.=v, wenzitab[++num]:=Trim(txt) } IfEqual, wz,, return, 0 ;-------------------------------------- ; wz 使用Astr参数类型可以自动转为ANSI版字符串 ; in 输入各文字的起始位置等信息,out 返回结果 ; ss 等为临时内存,jiange 超过间隔就会加入*号 ;-------------------------------------- mode:=InStr(c,"**") ? 2 : InStr(c,"*") ? 1 : 0 c:=RegExReplace(c,"[*\-]"), jiange:=5, num*=7 VarSetCapacity(in,num*4,0), i:=-4 loop, Parse, j, | if (A_Index<=num) NumPut(A_LoopField, in, i+=4, "int") VarSetCapacity(gs, sw*sh) VarSetCapacity(ss, sw*sh, Asc("0")) k:=StrLen(wz)*4 VarSetCapacity(s1, k, 0), VarSetCapacity(s0, k, 0) VarSetCapacity(out, 1024*4, 0) if DllCall(&MyFunc, "int",mode, "uint",c , "int",jiange, "ptr",Scan0, "int",Stride , "int",sx, "int",sy, "int",sw, "int",sh , "ptr",&gs, "ptr",&ss , "Astr",wz, "ptr",&s1, "ptr",&s0 , "ptr",&in, "int",num, "ptr",&out) { ocr:="", i:=-4 ; 返回第一个文字的中心位置 x:=NumGet(out,i+=4,"int"), y:=NumGet(out,i+=4,"int") w:=NumGet(out,i+=4,"int"), h:=NumGet(out,i+=4,"int") rx:=x+w//2, ry:=y+h//2 while (k:=NumGet(out,i+=4,"int")) v:=wenzitab[k//7], ocr.=v="" ? "*" : v return, 1 } return, 0 } ; ; 本文的最后修改日期是 公元2019年11月11日 ; 本文的网址是 https://gitee.com/weiyunwps618/codes ; 本文的网址是 https://www.cnblogs.com/delphixx ; 晓亮(weiyunwps618)的腾讯QQ邮箱地址是 595076941@qq.com ) ; 晓亮(weiyunwps618)的中国移动手机号码是 138####5488 ) ; 此AHK脚本的测试环境是 Windows 7 Pro SP1 VL 和 AutoHotkey v1.1.30.01 ; MCode(ByRef code, hex) { ListLines, Off bch:=A_BatchLines SetBatchLines, -1 VarSetCapacity(code, StrLen(hex)//2) loop, % StrLen(hex)//2 NumPut("0x" . SubStr(hex,2*A_Index-1,2) , code, A_Index-1, "char") Ptr:=A_PtrSize ? "Ptr" : "UInt" DllCall("VirtualProtect", Ptr,&code, Ptr ,VarSetCapacity(code), "uint",0x40, Ptr . "*",0) SetBatchLines, %bch% ListLines, On } base64tobit(s) { ListLines, Off s:=RegExReplace(s,"\s+") Chars:="0123456789+/ABCDEFGHIJKLMNOPQRSTUVWXYZ" . "abcdefghijklmnopqrstuvwxyz" SetFormat, IntegerFast, d StringCaseSense, On 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) } StringCaseSense, Off s:=SubStr(s,1,InStr(s,"1",0,0)-1) ListLines, On return, s } bit2base64(s) { ListLines, Off s:=RegExReplace(s,"\s+") s.=SubStr("100000",1,6-Mod(StrLen(s),6)) s:=RegExReplace(s,".{6}","|$0") Chars:="0123456789+/ABCDEFGHIJKLMNOPQRSTUVWXYZ" . "abcdefghijklmnopqrstuvwxyz" SetFormat, IntegerFast, d 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, On return, s } */ /************ 机器码的C源码 ************ int __attribute__((__stdcall__)) OCR( int mode , unsigned int c, int jiange, unsigned char * Bmp , int Stride, int sx, int sy, int sw, int sh , unsigned char * gs, char * ss , char * wz, int * s1, int * s0 , int * in, int num, int * out ) { int x, y, o=sy*Stride+sx*4, j=Stride-4*sw, i=0; int o1, o2, w, h, max, len1, len0, e1, e0; int sx1=0, sy1=0, sw1=sw, sh1=sh, Ptr=0; //准备工作一:先将图像各点在ss中转化为01字符 if (mode==0) //颜色模式 { int R=(c>>16)&0xFF, G=(c>>8)&0xFF, B=c&0xFF; for (y=0; y<sh; y++, o+=j) for (x=0; x<sw; x++, o+=4, i++) if (Bmp[2+o]==R && Bmp[1+o]==G && Bmp[o]==B) ss[i]='1'; } 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++) if (Bmp[2+o]*38+Bmp[1+o]*75+Bmp[o]*15<c) ss[i]='1'; } else //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; } w=sw-1; h=sh-1; for (y=1; y<h; y++) { for (x=1; x<w; 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) ss[i]='1'; } } } //准备工作二:生成s1、s0查表数组 for (i=0; i<num; i+=7) { o=o1=o2=in[i]; w=in[i+1]; h=in[i+2]; for (y=0; y<h; y++) { for (x=0; x<w; x++) { if (wz[o++]=='1') s1[o1++]=y*sw+x; else s0[o2++]=y*sw+x; } } } //正式工作:ss中每一点都进行一次全字库匹配 NextWenzi: o=sy1*sw+sx1; o1=1-sw*sh1; for (x=0; x<sw1; x++, o+=o1) { for (y=0; y<sh1; y++, o+=sw) { for (i=0; i<num; i+=7) { w=in[i+1]; h=in[i+2]; if (x+w>sw1 || y+h>sh1) continue; o2=in[i]; len1=in[i+3]; len0=in[i+4]; e1=in[i+5]; e0=in[i+6]; max=len1>len0 ? len1 : len0; for (j=0; j<max; j++) { if (j<len1 && ss[o+s1[o2+j]]!='1' && (--e1)<0) goto NoMatch; if (j<len0 && ss[o+s0[o2+j]]!='0' && (--e0)<0) goto NoMatch; } //成功找到文字或图像 if (Ptr==0) { out[0]=sx+x; out[1]=sy+y; out[2]=w; out[3]=h; Ptr=4; //找到第一个字就确定后续查找的上下范围和右边范围 sy1=y-h; sh1=h*3; sw1=h*10+100; if (sy1<0) sy1=0; if (sh1>sh-sy1) sh1=sh-sy1; } else if (x>jiange) //与前一字间隔较远就添加*号 out[Ptr++]=-1; out[Ptr++]=i+7; if (Ptr>1021) //返回的int数组中元素个数不超过1024 goto ReturnOK; //继续从当前文字右边再次查找 sx1+=x+w; ; ; 本文的最后修改日期是 公元2019年11月11日 ; 本文的网址是 https://gitee.com/weiyunwps618/codes ; 本文的网址是 https://www.cnblogs.com/delphixx ; 晓亮(weiyunwps618)的腾讯QQ邮箱地址是 595076941@qq.com ) ; 晓亮(weiyunwps618)的中国移动手机号码是 138####5488 ) ; 此AHK脚本的测试环境是 Windows 7 Pro SP1 VL 和 AutoHotkey v1.1.30.01 ; if (sw1>sw-sx1) sw1=sw-sx1; goto NextWenzi; //------------ NoMatch: continue; } } } if (Ptr==0) return 0; ReturnOK: out[Ptr]=0; return 1; } */ ;============ 脚本结束 =================; /* =========================================== [屏幕抓字生成字库工具与找字函数]v5.6 By FeiYue =========================================== 更新历史: v5.6 改进:颜色模式增加了对偏色的支持,方便高手在游戏中使用。 v5.5 改变:取消了后台查找,因为Win7以上系统不太适用。 改进:直接生成单行的字库,用其他控件来显示字库对应的图像。 v5.3 改进:容差增加为两个,分别是 0_字符 的容许误差百分比。 采用新的算法,提高了带容差参数时的查找速度。 容差为默认值0时,找不到会自动使用 5% 的容差再找一次。 v5.2 改进:新增后台查找,相当于把指定ID的窗口搬到前台再查找。 因此用于前台操作的找字找图代码不用修改就可以转到后台模式。 注:Win7以上系统因PrintWindow不太好用,因此许多窗口不支持。 v5.0 改进:新增了第三种查找模式:边缘灰差模式。 v4.6 改进:增加对多显示器扩展显示的支持。 v4.5 改进:修正了Win10-64位系统的一些兼容性问题。 提高了抓字窗口中二值化、删除操作的反应速度。 v4.3 改进:文字参数中,每个字库文字可以添加用中括号括起来 的容差值,没有中括号才用“查找文字”函数中的容差参数。 v4.2 改进:新增了64位系统的机器码,可用于AHK 64位版。 v4.1 改进:不再使用GDI+获取屏幕图像,直接用GDI实现。 v4.0 改进:文字参数增加竖线分隔的字库形式,可以进行 OCR识别。这种形式也可用于同时查找多幅文字或图片。 v3.5 改进:采用自写的机器码实现图内找字,极大的提高了速度。 =========== 屏幕抓字生成字库工具 使用说明 =========== 1、先点击主界面的[抓取文字图像],然后[移动鼠标]到你要 抓取的文字或图像,然后[点击鼠标左键],再[移开鼠标] 100像素以上,会弹出“抓字生成字库”界面。 2、抓字界面会显示抓取图像的彩色放大图像,先要将它二值化为 黑白图像。目前提供了三种二值化方式,任意选一种就行。 (1)颜色二值化:如果文字是单色的,最好采取这种方式。 在放大的图像中[点击某种颜色],然后点击[颜色二值化]。 如果不是单色的,则选定主要颜色后,手动输入偏色,也能够 以颜色加减偏色来二值化(如:红色+/-红色偏色都视为同色)。 (2)灰差二值化:手动输入灰差后(或直接采用默认的50), 点击[灰差二值化]。这种方式容易统一阀值,但黑点偏少。 (3)直接点击[灰度二值化]就会自动计算出一个灰度阀值, 并以这个阀值二值化。自动计算是针对整个图像的所有点的, 所以最好先[手动裁剪]图像边缘,留下中心的图像后再二值化。 当然如果对自动计算的阀值不满意,可以手动输入阀值,慢慢 调整看哪个效果好。另外要统一阀值添加字库时也要手动输入。 3、图像二值化后,可以点击[智删]或[左删]等来裁剪边缘,再 点击[确定],即可在主窗口生成调用“查找文字()”的代码。 4、如果要进行OCR文字识别,那么可以在“识别结果文字”输入框中 输入这幅图像或文字的识别结果(随便写),之后如果点击 [字库分割添加],那么结果文字的每个字都对应图像中以空列 分割的一部分,而如果点击[字库整体添加]则结果文字整体 对应于这幅图像的整体。这两种添加都不会改变主窗口的代码。 提示:可以用[修改]清除一些点生成空列来分开连在一起的字。 也可以添加一些点让左右结构的字不要被空列分割开。 这样修改了原始图像后,代码中的两个容差最好都大于0。 另外逗号等自动分割会裁边,建议手动裁剪保留空白边缘。 注意:字库应统一阀值。一般先在第3步点击确定生成代码,然后 再抓字添加字库,这时要统一采用上一次的阀值来二值化。 5、回到主窗口,点击[全屏查找测试],测试成功后,点击 [复制代码],并粘贴到你自己的脚本中,这时还运行不了, 因为你的代码中没有“查找文字()”函数。请在我的源代码的 最后面找到“查找文字()”函数,将它及后面的函数都复制到 你自己的脚本中就行了(保存成库文件然后 #Include 也行)。 6、由于许多因素会影响屏幕图像,所以换一台电脑一般就要重新 抓字/抓图。设置一样的屏幕分辨率、浏览器放大倍数、(取消) 平滑屏幕字体边缘,可能通用性高一些。单色文字也通用一些。 =========== 找字函数 使用说明 =========== 是否成功 := 查找文字( 中心点X, 中心点Y, 左右偏移W, 上下偏移H , 文字, 颜色, 返回X, 返回Y, 返回OCR结果 , 0字符容许误差百分比, _字符容许误差百分比 ) 1、屏幕查找范围为(X-W, Y-H)—>(X+W, Y+H),返回找到文字的中心坐标。 2、颜色带*号的为灰度阀值(或灰差)模式,对于非单色的文字比较好用。 3、颜色不带*号为“RRGGBB-偏色RR偏色GG偏色BB”格式,同大漠一样。 4、末尾的容差参数允许有一些点不同,取值范围 0~1(即 0%~100%)。 5、如果颜色模式的偏色不为0,则末尾两个容差参数也最好大于0。 6、对于游戏中搜图常用的背景透明图,把“_字符”容差取1即可。 7、注意抓字时是鼠标移开后再抓的,如果查找文字时鼠标刚好在 目标位置并造成了变色、凹凸等影响,可能要移开后再查找。 =========================================== */ #NoEnv #SingleInstance Force SetBatchLines, -1 CoordMode, Mouse CoordMode, Pixel CoordMode, ToolTip SetTitleMatchMode, 2 SetWorkingDir, %A_ScriptDir% ;---------------------------- Menu, Tray, Icon, Shell32.dll, 23 Menu, Tray, Add Menu, Tray, Add, 显示主窗口 Menu, Tray, Default, 显示主窗口 Menu, Tray, Click, 1 ;-- 左右上下抓字抓图的范围 ww:=35, hh:=12 nW:=2*ww+1, nH:=2*hh+1 ;---------------------------- gosub, 生成抓字窗口 gosub, 生成主窗口 OnExit, savescr gosub, readscr return F12:: ; 按[F12]保存修改并重启脚本 SetTitleMatchMode, 2 SplitPath, A_ScriptName,,,, name IfWinExist, %name% { ControlSend, ahk_parent, {Ctrl Down}s{Ctrl Up} Sleep, 500 } Reload return readscr: f=%A_Temp%\~scr1.tmp FileRead, s, %f% GuiControl, Main:, scr, %s% s= return savescr: f=%A_Temp%\~scr1.tmp GuiControlGet, s, Main:, scr FileDelete, %f% FileAppend, %s%, %f% ExitApp 显示主窗口: Gui, Main:Show, CEnter return 生成主窗口: Gui, Main:Default Gui, +AlwaysOnTop +HwndMain_ID Gui, Margin, 15, 15 Gui, Color, DDEEFF Gui, Font, s6 bold, Verdana Gui, Add, Edit, xm w660 r25 vMyEdit -Wrap -VScroll Gui, Font, s12 norm, Verdana Gui, Add, Button, xm w220 gMainRun, 抓取文字图像 Gui, Add, Button, x+0 wp gMainRun, 全屏查找测试 Gui, Add, Button, x+0 wp gMainRun, 复制代码 Gui, Font, s12 cBlue, Verdana Gui, Add, Edit, xm w660 h350 vscr Hwndhscr -Wrap HScroll Gui, Show, NA, 文字/图像字库生成工具 ;--------------------------------------- OnMessage(0x100, "EditEvents1") ; WM_KEYDOWN OnMessage(0x201, "EditEvents2") ; WM_LButtonDOWN return EditEvents1() { ListLines, Off if (A_Gui="Main") and (A_GuiControl="scr") SetTimer, 显示文字, -100 } EditEvents2() { ListLines, Off if (A_Gui="catch") WM_LBUTTONDOWN() else EditEvents1() } 显示文字: ListLines, Off Critical ControlGet, i, CurrentLine,,, ahk_id %hscr% ControlGet, s, Line, %i%,, ahk_id %hscr% if RegExMatch(s,"(\d+)\.([\w+/]{3,})",r) { s:=RegExReplace(base64tobit(r2),".{" r1 "}","$0`n") s:=StrReplace(StrReplace(s,"0","_"),"1","0") } else s= GuiControl, Main:, MyEdit, % Trim(s,"`n") return MainRun: k:=A_GuiControl WinMinimize Gui, Hide DetectHiddenWindows, Off WinWaitClose, ahk_id %Main_ID% if IsLabel(k) gosub, %k% Gui, Main:Show GuiControl, Main:Focus, scr return 复制代码: GuiControlGet, s,, scr Clipboard:=StrReplace(s,"`n","`r`n") s= return 抓取文字图像: ;------------------------------ ; 先用一个微型GUI提示抓字范围 Gui, Mini:Default Gui, +LastFound +AlwaysOnTop -Caption +ToolWindow +E0x08000000 WinSet, Transparent, 100 Gui, Color, Red Gui, Show, Hide w%nW% h%nH% ;------------------------------ Hotkey, $*LButton, _LButton_Off, On ListLines, Off loop { MouseGetPos, px, py if GetKeyState("LButton","P") break Gui, Show, % "NA x" (px-ww) " y" (py-hh) ToolTip, % "当前鼠标位置:" px "," py . "`n请移到目标位置后点击左键" Sleep, 20 } KeyWait, LButton Gui, Color, White loop { MouseGetPos, x, y if Abs(px-x)+Abs(py-y)>100 break Gui, Show, % "NA x" (x-ww) " y" (y-hh) ToolTip, 请把鼠标移开100像素以上 Sleep, 20 } ToolTip ListLines, On Hotkey, $*LButton, Off Gui, Destroy WinWaitClose cors:=getc(px,py,ww,hh) Gui, catch:Default loop, 6 GuiControl,, Edit%A_Index% GuiControl,, huicha, 50 GuiControl,, xiugai, % xiugai:=0 gosub, 重读 Gui, Show, CEnter GuiControl, Focus, fazhi DetectHiddenWindows, Off WinWaitClose, ahk_id %catch_ID% _LButton_Off: return WM_LBUTTONDOWN() { global ListLines, Off MouseGetPos,,,, mclass if !InStr(mclass,"Progress") return MouseGetPos,,,, mid, 2 For k,v in C_ if (v=mid) { if (xiugai and bg!="") { c:=cc[k], cc[k]:=c="0" ? "_" : c="_" ? "0" : c c:=c="0" ? "White" : c="_" ? "Black" : WindowColor gosub, SetColor } else { c:=cors[k] GuiControl, catch:, yanse, % StrReplace(c,"0x") c:=((c>>16&0xFF)*38+(c>>8&0xFF)*75+(c&0xFF)*15)>>7 GuiControl, catch:, huidu, %c% } return } } getc(px,py,ww,hh) { xywh2xywh(px-ww,py-hh,2*ww+1,2*hh+1,x,y,w,h) if (w<1 or h<1) return, 0 bch:=A_BatchLines SetBatchLines, -1 ;-------------------------------------- GetBitsFromScreen(x,y,w,h,Scan0,Stride,bits) ;-------------------------------------- cors:=[], k:=0, nW:=2*ww+1, nH:=2*hh+1 ListLines, Off fmt:=A_FormatInteger SetFormat, IntegerFast, H loop, %nH% { j:=py-hh-y+A_Index-1 loop, %nW% { i:=px-ww-x+A_Index-1, k++ if (i>=0 and i<w and j>=0 and j<h) c:=NumGet(Scan0+0,i*4+j*Stride,"uint") , cors[k]:="0x" . SubStr(0x1000000|c,-5) else cors[k]:="0xFFFFFF" } } SetFormat, IntegerFast, %fmt% ListLines, On ; 左右上下超出屏幕边界的值 cors.left:=Abs(px-ww-x) cors.Right:=Abs(px+ww-(x+w-1)) cors.up:=Abs(py-hh-y) cors.down:=Abs(py+hh-(y+h-1)) SetBatchLines, %bch% return, cors } 全屏查找测试: GuiControlGet, s, Main:, scr wenzi= while RegExMatch(s,"文字[.:]=""([^""]+)""",r) wenzi.=r1, s:=StrReplace(s,r,"","",1) if !RegExMatch(s,"查找文字\(([^)]+)\)",r) return StringSplit, r, r1, `,, "" if r0<6 return t1:=A_TickCount ok:=查找文字(r1,r2,r3,r4,wenzi,r6,X,Y,OCR,r10,r11) t1:=A_TickCount-t1 MsgBox, 4096,, % "查找结果:" (ok ? "成功":"失败") . "`n`n文字识别结果:" OCR . "`n`n耗时:" t1 " 毫秒,找到的位置:" (ok ? X "," Y:"") if ok { MouseMove, X, Y Sleep, 1000 } return 生成抓字窗口: WindowColor:="0xCCDDEE" Gui, catch:Default Gui, +LastFound +AlwaysOnTop +ToolWindow +Hwndcatch_ID Gui, Margin, 15, 15 Gui, Color, %WindowColor% Gui, Font, s16, Verdana ListLines, Off w:=(2*35+1)*14//nW+1, h:=(2*12+1)*14//nH+1 loop, % nH*nW { j:=A_Index=1 ? "" : Mod(A_Index,nW)=1 ? "xm y+-1" : "x+-1" Gui, Add, Progress, w%w% h%h% %j% -Theme } ListLines, On Gui, Add, Button, xm+120 w70 gRun Section, 上删 Gui, Add, Button, x+0 wp gRun, 上3 Gui, Add, Button, xm y+15 wp gRun, 左删 Gui, Add, Button, x+0 wp gRun, 左3 Gui, Add, Button, x+15 wp gRun, 智删 Gui, Add, Button, x+15 wp gRun, 右删 Gui, Add, Button, x+0 wp gRun, 右3 Gui, Add, Button, xm+120 y+15 wp gRun, 下删 Gui, Add, Button, x+0 wp gRun, 下3 ;------------------------- Gui, Add, Text, xm+410 ys+10 Section w60 CEnter, 颜色 Gui, Add, Edit, x+2 w120 vyanse ReadOnly Gui, Add, Text, x+2 w60 CEnter, 偏色 Gui, Add, Edit, x+2 w120 vpianse Limit6 Gui, Add, Button, x+5 yp-6 w140 gRun, 颜色二值化 ;------------------------- Gui, Add, Text, xs w60 CEnter, 灰度 Gui, Add, Edit, x+2 w120 vhuidu ReadOnly Gui, Add, Text, x+2 w60 CEnter, 阀值 Gui, Add, Edit, x+2 w120 vfazhi Gui, Add, Button, x+5 yp-6 w140 gRun Default, 灰度二值化 ;------------------------- Gui, Add, Text, xs w244 CEnter, 灰差阀值(与四周比较) Gui, Add, Edit, xs+246 yp w120 vhuicha Gui, Add, Button, x+5 yp-6 w140 gRun, 灰差二值化 ;------------------------- Gui, Add, Button, xm gRun, 重读 Gui, Add, Checkbox, x+15 yp+6 vxiugai gRun, 修改黑白色 Gui, Add, Text, x+30, 字库识别结果 Gui, Add, Edit, x+5 w140 vziku Gui, Add, Button, x+5 yp-6 gRun, 分割添加 Gui, Add, Button, x+5 gRun, 整体添加 Gui, Add, Button, x+30 gRun, 确定 Gui, Add, Button, x+10 gCancel, 关闭 ;------------------------- Gui, Show, Hide, 抓字生成字库 WinGet, s, ControlListHwnd C_:=StrSplit(s,"`n"), s:="" return Run: Critical k:=A_GuiControl if IsLabel(k) goto, %k% return xiugai: GuiControlGet, xiugai return SetColor: c:=c="White" ? 0xFFFFFF : c="Black" ? 0x000000 : ((c&0xFF)<<16)|(c&0xFF00)|((c&0xFF0000)>>16) SendMessage, 0x2001, 0, c,, % "ahk_id " . C_[k] return 重读: if !IsObject(cc) cc:=[], gg:=[], pp:=[] left:=Right:=up:=down:=k:=0, bg:="" loop, % nH*nW { cc[++k]:=1, c:=cors[k] gg[k]:=((c>>16&0xFF)*38+(c>>8&0xFF)*75+(c&0xFF)*15)>>7 gosub, SetColor } ; 裁剪抓字范围超过屏幕边界的部分 loop, % cors.left gosub, 左删 loop, % cors.Right gosub, 右删 loop, % cors.up gosub, 上删 loop, % cors.down gosub, 下删 return 颜色二值化: GuiControlGet, c,, yanse GuiControlGet, dc,, pianse if c= { MsgBox, 4096,, `n 请先进行选色! `n, 1 return } dc:=dc="" ? "000000" : StrReplace(dc,"0x") color:=c "-" dc, k:=i:=0 c:=Round("0x" c), dc:=Round("0x" dc) R:=(c>>16)&0xFF, G:=(c>>8)&0xFF, B:=c&0xFF dR:=(dc>>16)&0xFF, dG:=(dc>>8)&0xFF, dB:=dc&0xFF R1:=R-dR, G1:=G-dG, B1:=B-dB R2:=R+dR, G2:=G+dG, B2:=B+dB loop, % nH*nW { if (cc[++k]="") continue c:=cors[k], R:=(c>>16)&0xFF, G:=(c>>8)&0xFF, B:=c&0xFF if (R>=R1 && R<=R2 && G>=G1 && G<=G2 && B>=B1 && B<=B2) cc[k]:="0", c:="Black", i++ else cc[k]:="_", c:="White", i-- gosub, SetColor } ; 背景色 bg:=i>0 ? "0":"_" return 灰度二值化: GuiControl, Focus, fazhi GuiControlGet, fazhi if fazhi= { ; 统计灰度直方图 loop, 256 pp[A_Index-1]:=0 loop, % nH*nW if (cc[A_Index]!="") pp[gg[A_Index]]++ ; 迭代法求二值化阈值 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,, fazhi, %fazhi% } color:="*" fazhi, k:=i:=0 loop, % nH*nW { if (cc[++k]="") continue if (gg[k]<fazhi+1) cc[k]:="0", c:="Black", i++ else cc[k]:="_", c:="White", i-- gosub, SetColor } ; 背景色 bg:=i>0 ? "0":"_" return 灰差二值化: GuiControlGet, huicha if huicha= { MsgBox, 4096,, `n 请先设置边缘灰度差(比如50)! `n, 1 return } huicha:=Round(huicha) if (left=cors.left) gosub, 左删 if (Right=cors.Right) gosub, 右删 if (up=cors.up) gosub, 上删 if (down=cors.down) gosub, 下删 color:="**" huicha, k:=i:=0 loop, % nH*nW { if (cc[++k]="") continue c:=gg[k]+huicha if (gg[k-1]>c or gg[k+1]>c or gg[k-nW]>c or gg[k+nW]>c) cc[k]:="0", c:="Black", i++ else cc[k]:="_", c:="White", i-- gosub, SetColor } ; 背景色 bg:=i>0 ? "0":"_" return gui_del: cc[k]:="", c:=WindowColor gosub, SetColor return 左3: loop, 3 gosub, 左删 return 左删: if (left+Right>=nW) return left++, k:=left loop, %nH% { gosub, gui_del k+=nW } return 右3: loop, 3 gosub, 右删 return 右删: if (left+Right>=nW) return Right++, k:=nW+1-Right loop, %nH% { gosub, gui_del k+=nW } return 上3: loop, 3 gosub, 上删 return 上删: if (up+down>=nH) return up++, k:=(up-1)*nW loop, %nW% { k++ gosub, gui_del } return 下3: loop, 3 gosub, 下删 return 下删: if (up+down>=nH) return down++, k:=(nH-down)*nW loop, %nW% { k++ gosub, gui_del } return getwz: wz= if bg= return ListLines, Off k:=0 loop, %nH% { v= loop, %nW% v.=cc[++k] wz.=v="" ? "" : v "`n" } ListLines, On return 智删: gosub, getwz if wz= { MsgBox, 4096, 提示, `n请先进行一种二值化!, 1 return } while InStr(wz,bg) { if (wz~="^" bg "+\n") { wz:=RegExReplace(wz,"^" bg "+\n") gosub, 上删 } else if !(wz~="m`n)[^\n" bg "]$") { wz:=RegExReplace(wz,"m`n)" bg "$") gosub, 右删 } else if (wz~="\n" bg "+\n$") { wz:=RegExReplace(wz,"\n\K" bg "+\n$") gosub, 下删 } else if !(wz~="m`n)^[^\n" bg "]") { wz:=RegExReplace(wz,"m`n)^" bg) gosub, 左删 } else break } wz= return 确定: 分割添加: 整体添加: gosub, getwz if wz= { MsgBox, 4096, 提示, `n请先进行一种二值化!, 1 return } Gui, Hide GuiControlGet, ziku ziku:=Trim(ziku) IfInString, A_ThisLabel, 分割 { ; 正则表达式中数字需要十进制 SetFormat, IntegerFast, d s:="", bg:=StrLen(StrReplace(wz,"_")) loop { while InStr(wz,bg) and !(wz~="m`n)^[^\n" bg "]") wz:=RegExReplace(wz,"m`n)^.") loop, % InStr(wz,"`n")-1 { i:=A_Index if !(wz~="m`n)^.{" i "}[^\n" bg "]") { ; 自动分割会裁边,小数点等的字库要手动制作 v:=RegExReplace(wz,"m`n)^(.{" i "}).*","$1") v:=RegExReplace(v,"^(" bg "+\n)+") v:=RegExReplace(v,"\n\K(" bg "+\n)+$") s.=towz(SubStr(ziku,1,1),v) ziku:=SubStr(ziku,2) wz:=RegExReplace(wz,"m`n)^.{" i "}") continue, 2 } } break } add(s) return } IfInString, A_ThisLabel, 整体 { add(towz(ziku,wz)) return } ; 生成代码中的坐标为裁剪后整体文字的中心位置 px1:=px-ww+left+(nW-left-Right)//2 py1:=py-hh+up+(nH-up-down)//2 s:= StrReplace(towz(ziku,wz),"文字.=","文字:=") . "`nif 查找文字(" px1 "," py1 ",150000,150000,文字,""" . color . """,X,Y,OCR,0,0)`n" . "{`n CoordMode, Mouse`n MouseMove, X, Y`n}`n" GuiControl, Main:, scr, %s% s:=wz:="" return towz(ziku,wz) { SetFormat, IntegerFast, d wz:=StrReplace(StrReplace(wz,"0","1"),"_","0") wz:=InStr(wz,"`n")-1 . "." . bit2base64(wz) return, "`n文字.=""|<" ziku ">" wz """`n" } add(s) { global hscr s:=RegExReplace("`n" s "`n","\R","`r`n") ControlGet, i, CurrentCol,,, ahk_id %hscr% if i>1 ControlSend,, {Home}{Down}, ahk_id %hscr% Control, EditPaste, %s%,, ahk_id %hscr% } ;---- 将后面的函数附加到自己的脚本中 ---- ;----------------------------------------- ; 查找屏幕文字/图像字库及OCR识别 ; 注意:参数中的x、y为中心点坐标,w、h为左右上下偏移 ; cha1、cha0分别为0、_字符的容许误差百分比 ;----------------------------------------- 查找文字(x,y,w,h,wz,c,ByRef rx="",ByRef ry="",ByRef ocr="" , cha1=0, cha0=0) { xywh2xywh(x-w,y-h,2*w+1,2*h+1,x,y,w,h) if (w<1 or h<1) return, 0 bch:=A_BatchLines SetBatchLines, -1 ;-------------------------------------- GetBitsFromScreen(x,y,w,h,Scan0,Stride,bits) ;-------------------------------------- ; 设定图内查找范围,注意不要越界 sx:=0, sy:=0, sw:=w, sh:=h loop, 2 { if PicOCR(Scan0,Stride,sx,sy,sw,sh,wz,c ,rx,ry,ocr,cha1,cha0) { rx+=x, ry+=y SetBatchLines, %bch% return, 1 } ; 容差为0的若失败则使用 5% 的容差再找一次 if (A_Index=1 and cha1=0 and cha0=0) cha1:=0.05, cha0:=0.05 else break } SetBatchLines, %bch% return, 0 } ;-- 规范输入范围在屏幕范围内 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,ByRef bits) { VarSetCapacity(bits,w*h*4,0), bpp:=32 Scan0:=&bits, Stride:=((w*bpp+31)//32)*4 Ptr:=A_PtrSize ? "UPtr" : "UInt", PtrP:=Ptr . "*" ; 桌面窗口对应包含所有显示器的虚拟屏幕 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, PtrP,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) } ;----------------------------------------- ; 图像内查找文字/图像字符串及OCR函数 ;----------------------------------------- PicOCR(Scan0, Stride, sx, sy, sw, sh, wenzi, c , ByRef rx, ByRef ry, ByRef ocr, cha1, cha0) { static MyFunc if !MyFunc { x32:="5589E55383C4808B452C0FAF45248B5528C1E20201D0894" . "5F08B5530B80000000029D0C1E00289C28B452401D08945ECC" . "745E800000000C745D800000000C745D4000000008B4530894" . "5D08B45348945CCC745C800000000837D08000F854D0100008" . "B450CC1E81025FF0000008945C48B450CC1E80825FF0000008" . "945C08B450C25FF0000008945BC8B4510C1E81025FF0000008" . "945B88B4510C1E80825FF0000008945B48B451025FF0000008" . "945B08B45C42B45B88945AC8B45C02B45B48945A88B45BC2B4" . "5B08945A48B55C48B45B801D08945A08B55C08B45B401D0894" . "59C8B55BC8B45B001D0894598C745F400000000E9A6000000C" . "745F800000000E9840000008B45F083C00289C28B452001D00" . "FB6000FB6C08945C48B45F083C00189C28B452001D00FB6000" . "FB6C08945C08B55F08B452001D00FB6000FB6C08945BC8B45C" . "43B45AC7C338B45C43B45A07F2B8B45C03B45A87C238B45C03" . "B459C7F1B8B45BC3B45A47C138B45BC3B45987F0B8B55E88B4" . "53C01D0C600318345F8018345F0048345E8018B45F83B45300" . "F8C70FFFFFF8345F4018B45EC0145F08B45F43B45340F8C4EF" . "FFFFFE917020000837D08010F85A30000008B450C83C001C1E" . "00789450CC745F400000000EB7DC745F800000000EB628B45F" . "083C00289C28B452001D00FB6000FB6C06BD0268B45F083C00" . "189C18B452001C80FB6000FB6C06BC04B8D0C028B55F08B452" . "001D00FB6000FB6D089D0C1E00429D001C83B450C730B8B55E" . "88B453C01D0C600318345F8018345F0048345E8018B45F83B4" . "5307C968345F4018B45EC0145F08B45F43B45340F8C77FFFFF" . "FE96A010000C745F400000000EB7BC745F800000000EB608B5" . "5E88B45388D0C028B45F083C00289C28B452001D00FB6000FB" . "6C06BD0268B45F083C00189C38B452001D80FB6000FB6C06BC" . "04B8D1C028B55F08B452001D00FB6000FB6D089D0C1E00429D" . "001D8C1F80788018345F8018345F0048345E8018B45F83B453" . "07C988345F4018B45EC0145F08B45F43B45340F8C79FFFFFF8" . "B453083E8018945948B453483E801894590C745F401000000E" . "9B0000000C745F801000000E9940000008B45F40FAF453089C" . "28B45F801D08945E88B55E88B453801D00FB6000FB6D08B450" . "C01D08945EC8B45E88D50FF8B453801D00FB6000FB6C03B45E" . "C7F488B45E88D50018B453801D00FB6000FB6C03B45EC7F328" . "B45E82B453089C28B453801D00FB6000FB6C03B45EC7F1A8B5" . "5E88B453001D089C28B453801D00FB6000FB6C03B45EC7E0B8" . "B55E88B453C01D0C600318345F8018B45F83B45940F8C60FFF" . "FFF8345F4018B45F43B45900F8C44FFFFFF8B45D40FAF45308" . "9C28B45D801D089458CC745F800000000E912030000C745F40" . "0000000E9F60200008B45F40FAF453089C28B45F801C28B458" . "C01D08945F0C745E800000000E9C40200008B45E883C0018D1" . "485000000008B454801D08B008945948B45E883C0028D14850" . "00000008B454801D08B008945908B55F88B459401D03B45D00" . "F8F800200008B55F48B459001D03B45CC0F8F6F0200008B45E" . "88D1485000000008B454801D08B008945888B45E883C0038D1" . "485000000008B454801D08B008945848B45E883C0048D14850" . "00000008B454801D08B008945808B45E883C0058D148500000" . "0008B454801D08B008945E48B45E883C0068D1485000000008" . "B454801D08B008945E08B45843945800F4D458089857CFFFFF" . "FC745EC00000000E9820000008B45EC3B45847D378B55888B4" . "5EC01D08D1485000000008B454001D08B108B45F001D089C28" . "B453C01D00FB6003C31740E836DE401837DE4000F889E01000" . "08B45EC3B45807D378B55888B45EC01D08D1485000000008B4" . "54401D08B108B45F001D089C28B453C01D00FB6003C30740E8" . "36DE001837DE0000F88620100008345EC018B45EC3B857CFFF" . "FFF0F8C6FFFFFFF837DC8000F858A0000008B55288B45F801C" . "28B454C89108B454C83C0048B4D2C8B55F401CA89108B454C8" . "D50088B459489028B454C8D500C8B45908902C745C80400000" . "0837D180175728B45F42B45908945D48B559089D001C001D08" . "945CC8B559089D0C1E00201D001C083C0648945D0837DD4007" . "907C745D4000000008B45342B45D43B45CC7D338B45342B45D" . "48945CCEB288B55DC8B451401D03B45F87F1B8B45C88D50018" . "955C88D1485000000008B454C01D0C700FFFFFFFF8B45C88D5" . "0018955C88D1485000000008B454C01D08B55E883C20789108" . "17DC8FD0300000F8FAA000000C745EC00000000EB298B55888" . "B45EC01D08D1485000000008B454001D08B108B45F001D089C" . "28B453C01D0C600308345EC018B45EC3B45847CCF8B45F883C" . "0010145D88B45948945DC8B45302B45D83B45D00F8D0AFDFFF" . "F8B45302B45D88945D0E9FCFCFFFF90EB0490EB01908345E80" . "78B45E83B451C0F8C30FDFFFF8345F4018B45F43B45CC0F8CF" . "EFCFFFF8345F8018B45F83B45D00F8CE2FCFFFF837DC800750" . "8B800000000EB0690B80100000083EC805B5DC24800" x64:="554889E54883C480894D108955184489452044894D288B4" . "5580FAF45488B5550C1E20201D08945F48B5560B8000000002" . "9D0C1E00289C28B454801D08945F0C745EC00000000C745DC0" . "0000000C745D8000000008B45608945D48B45688945D0C745C" . "C00000000837D10000F855D0100008B4518C1E81025FF00000" . "08945C88B4518C1E80825FF0000008945C48B451825FF00000" . "08945C08B4520C1E81025FF0000008945BC8B4520C1E80825F" . "F0000008945B88B452025FF0000008945B48B45C82B45BC894" . "5B08B45C42B45B88945AC8B45C02B45B48945A88B55C88B45B" . "C01D08945A48B55C48B45B801D08945A08B55C08B45B401D08" . "9459CC745F800000000E9B6000000C745FC00000000E994000" . "0008B45F483C0024863D0488B45404801D00FB6000FB6C0894" . "5C88B45F483C0014863D0488B45404801D00FB6000FB6C0894" . "5C48B45F44863D0488B45404801D00FB6000FB6C08945C08B4" . "5C83B45B07C388B45C83B45A47F308B45C43B45AC7C288B45C" . "43B45A07F208B45C03B45A87C188B45C03B459C7F108B45EC4" . "863D0488B45784801D0C600318345FC018345F4048345EC018" . "B45FC3B45600F8C60FFFFFF8345F8018B45F00145F48B45F83" . "B45680F8C3EFFFFFFE959020000837D10010F85B60000008B4" . "51883C001C1E007894518C745F800000000E98D000000C745F" . "C00000000EB728B45F483C0024863D0488B45404801D00FB60" . "00FB6C06BD0268B45F483C0014863C8488B45404801C80FB60" . "00FB6C06BC04B8D0C028B45F44863D0488B45404801D00FB60" . "00FB6D089D0C1E00429D001C83B451873108B45EC4863D0488" . "B45784801D0C600318345FC018345F4048345EC018B45FC3B4" . "5607C868345F8018B45F00145F48B45F83B45680F8C67FFFFF" . "FE999010000C745F800000000E98D000000C745FC00000000E" . "B728B45EC4863D0488B4570488D0C028B45F483C0024863D04" . "88B45404801D00FB6000FB6C06BD0268B45F483C0014C63C04" . "88B45404C01C00FB6000FB6C06BC04B448D04028B45F44863D" . "0488B45404801D00FB6000FB6D089D0C1E00429D04401C0C1F" . "80788018345FC018345F4048345EC018B45FC3B45607C86834" . "5F8018B45F00145F48B45F83B45680F8C67FFFFFF8B456083E" . "8018945988B456883E801894594C745F801000000E9CA00000" . "0C745FC01000000E9AE0000008B45F80FAF456089C28B45FC0" . "1D08945EC8B45EC4863D0488B45704801D00FB6000FB6D08B4" . "51801D08945F08B45EC4898488D50FF488B45704801D00FB60" . "00FB6C03B45F07F538B45EC4898488D5001488B45704801D00" . "FB6000FB6C03B45F07F388B45EC2B45604863D0488B4570480" . "1D00FB6000FB6C03B45F07F1D8B55EC8B456001D04863D0488" . "B45704801D00FB6000FB6C03B45F07E108B45EC4863D0488B4" . "5784801D0C600318345FC018B45FC3B45980F8C46FFFFFF834" . "5F8018B45F83B45940F8C2AFFFFFF8B45D80FAF456089C28B4" . "5DC01D0894590C745FC00000000E98E030000C745F80000000" . "0E9720300008B45F80FAF456089C28B45FC01C28B459001D08" . "945F4C745EC00000000E9400300008B45EC48984883C001488" . "D148500000000488B85900000004801D08B008945988B45EC4" . "8984883C002488D148500000000488B85900000004801D08B0" . "08945948B55FC8B459801D03B45D40F8FEA0200008B55F88B4" . "59401D03B45D00F8FD90200008B45EC4898488D14850000000" . "0488B85900000004801D08B0089458C8B45EC48984883C0034" . "88D148500000000488B85900000004801D08B008945888B45E" . "C48984883C004488D148500000000488B85900000004801D08" . "B008945848B45EC48984883C005488D148500000000488B859" . "00000004801D08B008945E88B45EC48984883C006488D14850" . "0000000488B85900000004801D08B008945E48B45883945840" . "F4D4584894580C745F000000000E9980000008B45F03B45887" . "D428B558C8B45F001D04898488D148500000000488B8580000" . "0004801D08B108B45F401D04863D0488B45784801D00FB6003" . "C31740E836DE801837DE8000F88D40100008B45F03B45847D4" . "28B558C8B45F001D04898488D148500000000488B858800000" . "04801D08B108B45F401D04863D0488B45784801D00FB6003C3" . "0740E836DE401837DE4000F888D0100008345F0018B45F03B4" . "5800F8C5CFFFFFF837DCC000F859D0000008B55508B45FC01C" . "2488B85980000008910488B85980000004883C0048B4D588B5" . "5F801CA8910488B8598000000488D50088B45988902488B859" . "8000000488D500C8B45948902C745CC04000000837D3001757" . "A8B45F82B45948945D88B559489D001C001D08945D08B55948" . "9D0C1E00201D001C083C0648945D4837DD8007907C745D8000" . "000008B45682B45D83B45D07D3B8B45682B45D88945D0EB308" . "B55E08B452801D03B45FC7F238B45CC8D50018955CC4898488" . "D148500000000488B85980000004801D0C700FFFFFFFF8B45C" . "C8D50018955CC4898488D148500000000488B8598000000480" . "1D08B55EC83C2078910817DCCFD0300000F8FB5000000C745F" . "000000000EB348B558C8B45F001D04898488D1485000000004" . "88B85800000004801D08B108B45F401D04863D0488B4578480" . "1D0C600308345F0018B45F03B45887CC48B45FC83C0010145D" . "C8B45988945E08B45602B45DC3B45D40F8D8EFCFFFF8B45602" . "B45DC8945D4E980FCFFFF90EB0490EB01908345EC078B45EC3" . "B45380F8CB4FCFFFF8345F8018B45F83B45D00F8C82FCFFFF8" . "345FC018B45FC3B45D40F8C66FCFFFF837DCC007508B800000" . "000EB0690B8010000004883EC805DC3909090909090909090" MCode(MyFunc, A_PtrSize=8 ? x64:x32) } ;-------------------------------------- ; 统计字库文字的个数和宽高,将解释文字存入数组并删除<> ;-------------------------------------- ocrtxt:=[], info:=[], t1:=[], t0:=[], p:=0 loop, Parse, wenzi, | { v:=A_LoopField, txt:="", e1:=cha1, e0:=cha0 ; 用角括号输入每个字库字符串的识别结果文字 if RegExMatch(v,"<([^>]*)>",r) v:=StrReplace(v,r), txt:=Trim(r1) ; 可以用中括号输入每个文字的两个容差,以逗号分隔 if RegExMatch(v,"\[([^\]]*)]",r) { v:=StrReplace(v,r), r2:="" StringSplit, r, r1, `, e1:=r1, e0:=r2 } ; 记录每个文字的起始位置、宽、高、01字符的数量和容差 StringSplit, r, v, . w:=r1, v:=base64tobit(r2), h:=StrLen(v)//w if (r0<2 or h<1 or w>sw or h>sh or StrLen(v)!=w*h) continue len1:=len0:=0, j:=sw-w+1, i:=-j ListLines, Off loop, Parse, v { i:=Mod(A_Index,w)=1 ? i+j : i+1 if A_LoopField t1[4*(p+len1++)]:=i else t0[4*(p+len0++)]:=i } ListLines, On e1:=Round(len1*e1), e0:=Round(len0*e0) info.Push(p,w,h,len1,len0,e1,e0) ocrtxt.Push(txt), p+=StrLen(v) } IfEqual, p, 0, return, 0 ;-------------------------------------- ; in 输入各文字的起始位置等信息,out 返回结果 ; interval 两字的间隔超过此值,识别结果就加入*号 ; limit 根据第一个字限制后续查找高度和右范围 ;-------------------------------------- mode:=InStr(c,"**") ? 2 : InStr(c,"*") ? 1 : 0 c:=StrReplace(c,"*"), interval:=5, limit:=1 if mode=0 { c:=StrReplace(c,"0x") . "-0" StringSplit, r, c, - c:=Round("0x" r1), dc:=Round("0x" r2) } num:=info.MaxIndex() , VarSetCapacity(gs, sw*sh) , VarSetCapacity(ss, sw*sh, Asc("0")) , VarSetCapacity(s1, p*4, 0) , VarSetCapacity(s0, p*4, 0) , VarSetCapacity(in, num*4) , VarSetCapacity(out, 1024*4, 0) ListLines, Off loop, % num NumPut(info[A_Index], in, (A_Index-1)*4, "int") For k,v in t1 NumPut(v, s1, k, "int") For k,v in t0 NumPut(v, s0, k, "int") ListLines, On if DllCall(&MyFunc, "int",mode , "uint",c, "uint",dc , "int",interval, "int",limit, "int",num , "ptr",Scan0, "int",Stride , "int",sx, "int",sy, "int",sw, "int",sh , "ptr",&gs, "ptr",&ss , "ptr",&s1, "ptr",&s0, "ptr",&in, "ptr",&out) { ; 返回第一个文字的中心位置 x:=NumGet(out,0,"int"), y:=NumGet(out,4,"int") w:=NumGet(out,8,"int"), h:=NumGet(out,12,"int") rx:=x+w//2, ry:=y+h//2, ocr:="", i:=12 while (k:=NumGet(out,i+=4,"int")) v:=ocrtxt[k//7], ocr.=v="" ? "*" : v return, 1 } return, 0 } MCode(ByRef code, hex) { ListLines, Off bch:=A_BatchLines SetBatchLines, -1 VarSetCapacity(code, StrLen(hex)//2) loop, % StrLen(hex)//2 NumPut("0x" . SubStr(hex,2*A_Index-1,2), code, A_Index-1, "char") Ptr:=A_PtrSize ? "UPtr" : "UInt" DllCall("VirtualProtect", Ptr,&code, Ptr ,VarSetCapacity(code), "uint",0x40, Ptr . "*",0) SetBatchLines, %bch% ListLines, On } base64tobit(s) { ListLines, Off Chars:="0123456789+/ABCDEFGHIJKLMNOPQRSTUVWXYZ" . "abcdefghijklmnopqrstuvwxyz" SetFormat, IntegerFast, d StringCaseSense, On 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) } StringCaseSense, Off s:=SubStr(s,1,InStr(s,"1",0,0)-1) s:=RegExReplace(s,"[^01]+") ListLines, On return, s } bit2base64(s) { ListLines, Off 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 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, On return, s } /************ 机器码的C源码 ************ int __attribute__((__stdcall__)) OCR( int mode , unsigned int c, unsigned int dc , int interval, int limit, int num , unsigned char * Bmp, int Stride , int sx, int sy, int sw, int sh , unsigned char * gs, char * ss , int * s1, int * s0, int * in, int * out ) { int x, y, o=sy*Stride+sx*4, j=Stride-4*sw, i=0; int o1, o2, w, h, max, len1, len0, e1, e0, lastw; int sx1=0, sy1=0, sw1=sw, sh1=sh, Ptr=0; //先将图像各点在ss中转化为01字符 if (mode==0) //颜色模式 { int R=(c>>16)&0xFF, G=(c>>8)&0xFF, B=c&0xFF; int dR=(dc>>16)&0xFF, dG=(dc>>8)&0xFF, dB=dc&0xFF; int R1=R-dR, G1=G-dG, B1=B-dB; int R2=R+dR, G2=G+dG, B2=B+dB; 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]; if (R>=R1 && R<=R2 && G>=G1 && G<=G2 && B>=B1 && B<=B2) ss[i]='1'; } } 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++) if (Bmp[2+o]*38+Bmp[1+o]*75+Bmp[o]*15<c) ss[i]='1'; } else //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; } w=sw-1; h=sh-1; for (y=1; y<h; y++) { for (x=1; x<w; 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) ss[i]='1'; } } } //ss中每一点都进行一次全字库匹配 NextWenzi: o1=sy1*sw+sx1; for (x=0; x<sw1; x++) { for (y=0; y<sh1; y++) { o=y*sw+x+o1; for (i=0; i<num; i+=7) { w=in[i+1]; h=in[i+2]; if (x+w>sw1 || y+h>sh1) continue; o2=in[i]; len1=in[i+3]; len0=in[i+4]; e1=in[i+5]; e0=in[i+6]; max=len1>len0 ? len1 : len0; for (j=0; j<max; j++) { if (j<len1 && ss[o+s1[o2+j]]!='1' && (--e1)<0) goto NoMatch; if (j<len0 && ss[o+s0[o2+j]]!='0' && (--e0)<0) goto NoMatch; } //成功找到文字或图像 if (Ptr==0) { out[0]=sx+x; out[1]=sy+y; out[2]=w; out[3]=h; Ptr=4; //找到第一个字就确定后续查找的上下范围和右边范围 if (limit==1) { sy1=y-h; sh1=h*3; sw1=h*10+100; if (sy1<0) sy1=0; if (sh1>sh-sy1) sh1=sh-sy1; } } //与前一字间隔较远就添加*号 else if (x>=lastw + interval) out[Ptr++]=-1; out[Ptr++]=i+7; //返回的int数组中元素个数不超过1024 if (Ptr>1021) goto returnOK; //清除找到的文字,后续查找范围从文字左侧X坐标+1开始 for (j=0; j<len1; j++) ss[o+s1[o2+j]]='0'; sx1+=x+1; lastw=w; if (sw1>sw-sx1) sw1=sw-sx1; goto NextWenzi; //------------ NoMatch: continue; } } } if (Ptr==0) return 0; returnOK: return 1; } */ ;============ 脚本结束 ================= ;
我想问一下,你这个跟大漠有啥关系?
🙄 河老师,你好,这个跟大漠毫无关系,但是这个要比大漠好,实现了纯ahk源码。由于是从别处抄来的搬运版,所以连标题也不修改了,错就错了,如果硬要说跟大漠的关系的话就是主要功能相同,都是全屏幕找字找图的坐标位置,这个功能很有用,甚至可以用于网页操作,当WEB操作无法实现或不稳定时(个别电脑由于系统文件不全在网页点对象操作方面会遇到问题,甚至无法连接或创建网页对象)此代码是个不错的选择,而且是非常爽的纯ahk源码实现,比大漠要好5倍。方便我也方便大家在写代码时复制利用,防止找不到源代码。
以前此文章的标题不太好所以重新修改标题后重新发布
期待作者能够开发出图形二值查找函数,从而兼容不同的屏幕分辨率和窗口缩放值
根据图形搜索,而不限制于图片的大小、像素和分辨率,从而到达完全自由的境界。
我个人感觉,通过取点附近的3个点来查找位置比较可靠,因为不同分辨率下或窗口缩放率下3个点的相对位置和颜色值一般不会改变。
根据搜索到的三个点的位置和所要搜索的点之间的位置比例关系换算出结果比较可靠和兼容,当搜索结果相差太大则丢弃此次查找的结果。
从而可以兼容不同的分辨率,窗口缩放和操作系统。
还有一个办法是为不同的情况分别找几次图,多找几次
。。。。。。。。好复杂