在大佬Thinkai的指导下,解决了关键的urlencode问题。。。与其说指导不如说直接帮我解决了= =
首先感谢Thinkai大佬,然后在本站也学到不少知识,感谢河许人(偷偷的说,我在B站给你投硬币了哟~)
原理是调用windows自带的certutil.exe将图片编码保存在txt文件中,然后从txt文件里读取再post给百度API获取识别结果
基于上述原理,系统要求WinXP以上。。。certutil.exe听说2003自带,XP可以尝试下载一个2003的版本放到脚本目录下供脚本调用(理论可以,没试过,本人测试环境为32位Win10 = =)
接下来是代码:
#Include, %A_WorkingDir%\lib\JSON.ahk global Cfgfile := A_WorkingDir "\Cfg.dat" global P_id := "" global P_secret := "" global P_token := "" global C_n := 0 global C_finsh := 0 global C_txtC := 0 global C_txtNo := 0 global C_imgC := 0 global C_imgNo := 0 global C_basexe := "certutil.exe" global C_basexeTmp := "" Begin1(Cfgfile) if StrLen(P_id) < 18 or StrLen(P_secret) < 24 { msgbox % "参数错误,请在Cfg.dat中填写正确的id与secret" ExitApp } global P_image := "" P_Url := "https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials" P_Url := P_Url "&client_id=" P_id "&client_secret=" P_secret P_Json := JSON.Load(URLDownloadToVar(P_Url)) P_access_token := P_Json.access_token P_access_token := FixToken(P_Json.access_token) MsgBox, 0, 批量图片识别 - By 0772Boy, 按Ctrl+F9开始\暂停识别`n按Ctrl+F10编辑配置文件(修改文件后请重启本程序)`n按Ctrl+F11查看帮助文档`n按Ctrl+F12直接结束程序。, 99 global Goon := 0 return ^F9:: if Goon = 0 Goon := 1 else Goon := 0 Loop 999 { if Goon := 0 { TrayTip, 程序已暂停, 按Ctrl+F9重新开始转换。,3 Break } ;图片转换为Base64并保存为txt if Get_Base64(A_Index) = A_Index { C_txtNo := A_Index } Else { C_imgC := A_Index Writedat(Cfgfile) if C_imgC > 1 { C_imgC := C_imgC - 1 TrayTip, 停止, 已完成%C_imgC%张图片转换。,10 } else TrayTip, 停止, 图片转换出现错误。,10 Break } sleep, 500 ;txt读取 if Get_Txt(C_txtNo) != C_txtNo { C_txtC := A_Index Writedat(Cfgfile) if C_txtC > 1 { C_txtC := C_txtC - 1 TrayTip, 停止, 已完成%C_txtC%张图片转换。,10 } else TrayTip, 停止, Base64读取出现错误。,10 Break } Del_Txt(C_txtNo) ;调用百度Orc识别后再保存到text文件夹中 Txtmp := Get_Url(P_image,P_access_token) FileTmp := A_WorkingDir "\text\" C_txtNo ".txt" FileAppend , %Txtmp%, %FileTmp%, UTF-8 C_finsh := C_txtNo Writedat(Cfgfile) TrayTip, 批量图片识别 - By 0772Boy, 第%C_txtNo%张图片已经完成,请查看text\%C_txtNo%.txt中内容。,3 } return ^F12:: MsgBox, 0, 批量图片识别 - By 0772Boy, 程序退出。, 9 ExitApp Return ^F10:: runtmp := "notepad.exe " Get_space( A_WorkingDir "\Cfg.dat") run, %runtmp% Return ^F11:: Helptext := "注意事项:所有图片必须使用jpg格式,并且按1~999的顺序存放在img目录下,程序路径请勿包含中文,识别结果按1~999保存在程序目录下Text文件夹中,在识别过程中再按一次Ctrl+F9也需要等到当前这一张图片识别结束才会停止,暂停之后重新开始识别仍然是从1开始。" Helptext := "按Ctrl+F9开始\暂停识别`n按Ctrl+F10编辑配置文件(修改文件后请重启本程序)`n按Ctrl+F11查看帮助文档`n按Ctrl+F12直接结束程序。`n" Helptext MsgBox, 0, 批量图片识别 - By 0772Boy, %Helptext%, 999 Return Get_Url(imgBase64,access_token) { P_Url := "https://aip.baidubce.com/rest/2.0/ocr/v1/general_basic?access_token=" access_token postdata := "image=" urlencode(imgBase64) P_ReturnTxt := URLDownloadToVar(P_Url, "UTF-8", "POST", postdata, {"Content-Type":"application/x-www-form-urlencoded"}) P_Json := JSON.Load(P_ReturnTxt) if P_Json.error_msg != "" return P_Json.error_msg wordsC := P_Json.words_result_num if wordsC > 1 { Loop % wordsC { txtmp := txtmp P_Json.words_result[A_Index].words if C_n { txtmp := txtmp "`n" } } return txtmp } else { Return P_Json.words_result[1].words } Return 0 } Del_Txt(txtNumber) { txtPath := A_WorkingDir "\img\" txtNumber ".txt" if FileExist(txtPath) { FileDelete % txtPath } } Get_Txt(txtNumber) { txtPath := A_WorkingDir "\img\" txtNumber ".txt" if FileExist(txtPath) { P_image := "" Loop, Read, %txtPath% { if InStr(A_LoopReadLine, "-----") = 0 and StrLen(A_LoopReadLine) > 0 { P_image := P_image A_LoopReadLine ;MsgBox % Base64Text } } return txtNumber } Else { Return txtPath "`n文件不存在,请检查。" } } Get_Base64(imgNumber) { imgPath := A_WorkingDir "\img\" imgNumber if FileExist(imgPath ".jpg") { ;如果路径中有空格就用双引号括起来 imgPath := Get_space(imgPath ".jpg") ;base64编码保存成txt文件放在图片同一个目录下 TargetTmp := Get_space(C_basexeTmp) " -encode " imgPath " " Get_space(A_WorkingDir "\img\" imgNumber ".txt") ;msgbox % TargetTmp RunWait, %TargetTmp% Return imgNumber } Else { Return imgPath ".jpg`n文件不存在,请检查。" } } FixToken(str) { TokenTmp := str if InStr(str, ".") = 0 TokenTmp := P_token return TokenTmp } Get_space(FilePath1) { if InStr(FilePath1, " ") { return """" FilePath1 """" } return FilePath1 } Begin1(Cfgpath) { Begin11: if FileExist(Cfgpath) { IniRead, P_id, %Cfgpath%, Config, id IniRead, P_secret, %Cfgpath%, Config, secret IniRead, P_token, %Cfgpath%, Config, token IniRead, C_n, %Cfgpath%, Config, 保留换行 IniRead, C_finsh, %Cfgpath%, Config, finsh IniRead, C_txtC, %Cfgpath%, Config, txtC IniRead, C_txtNo, %Cfgpath%, Config, txtNo IniRead, C_imgC, %Cfgpath%, Config, imgC IniRead, C_imgNo, %Cfgpath%, Config, imgNo IniRead, C_basexe, %Cfgpath%, Config, basexe } Else { MsgBox % Cfgpath "`n文件不存在,将使用默认配置创建该文件。" ; C_n := 0 ; C_finsh := ; C_txtC := 0 ; C_txtNo := 0 ; C_imgC := 0 ; C_imgNo := 0 ; C_basexe := "certutil.exe" Writedat(Cfgpath) Goto, Begin11 } if FileExist("C:\Windows\System32\" C_basexe) or FileExist(A_WorkingDir "\" C_basexe) { if FileExist("C:\Windows\System32\" C_basexe) C_basexeTmp := "C:\Windows\System32\" C_basexe else C_basexeTmp := A_WorkingDir "\" C_basexe } Else { msgbox, 0, 系统文件缺失, 请自行下载对应系统版本的certutil.exe到程序目录中。,10 ExitApp } return } Writedat(Cfgpath) { IniWrite, %C_n%, %Cfgpath%, Config, 保留换行 IniWrite, %C_finsh%, %Cfgpath%, Config, finsh IniWrite, %C_txtC%, %Cfgpath%, Config, txtC IniWrite, %C_txtNo%, %Cfgpath%, Config, txtNo IniWrite, %C_imgC%, %Cfgpath%, Config, imgC IniWrite, %C_imgNo%, %Cfgpath%, Config, imgNo IniWrite, %C_basexe%, %Cfgpath%, Config, basexe } URLDownloadToVar(url, Encoding = "",Method="GET",postData="",headers:=""){ ;网址,编码,请求方式,post数据 hObject:=ComObjCreate("WinHttp.WinHttpRequest.5.1") hObject.SetTimeouts(30000,30000,1200000,1200000) ;设置超时 try hObject.Open(Method,url,(Method="POST" ? True : False)) ;打开连接 ;设置header if IsObject(headers) { for k,v in headers { if v hObject.SetRequestHeader(k, v) } } if postData { try hObject.Send(postData) hObject.WaitForResponse(-1) } else { try hObject.Send() } if (Encoding && hObject.ResponseBody) { oADO := ComObjCreate("adodb.stream") oADO.Type := 1 oADO.Mode := 3 oADO.Open() oADO.Write(hObject.ResponseBody) oADO.Position := 0 oADO.Type := 2 oADO.Charset := Encoding return oADO.ReadText(), oADO.Close() } return hObject.ResponseText } urlencode(string){ nstring := Ansi2UTF8(string) Loop % StrLen(nstring) { hex := format("{1:02x}", hex2 := NumGet(&nstring,A_index-1,"Uchar")) if (hex2==33 || (hex2>=39 && hex2 <=42) || hex2==45 || hex2 ==46 || (hex2>=48 && hex2<=57) || (hex2>=65 && hex2<=90) || hex2==95 || (hex2>=97 && hex2<=122) || hex2==126) content .= Chr(hex2) else content .= "`%" hex } return content } Ansi2UTF8(sString) { Ansi2Unicode(sString, wString, 0) Unicode2Ansi(wString, zString, 65001) return zString } Ansi2Unicode(ByRef sString, ByRef wString, CP = 0) { nSize := DllCall("MultiByteToWideChar" , "Uint", CP , "Uint", 0 , "Uint", &sString , "int", -1 , "Uint", 0 , "int", 0) VarSetCapacity(wString, nSize * 2) DllCall("MultiByteToWideChar" , "Uint", CP , "Uint", 0 , "Uint", &sString , "int", -1 , "Uint", &wString , "int", nSize) } Unicode2Ansi(ByRef wString, ByRef sString, CP = 0) { nSize := DllCall("WideCharToMultiByte" , "Uint", CP , "Uint", 0 , "Uint", &wString , "int", -1 , "Uint", 0 , "int", 0 , "Uint", 0 , "Uint", 0) VarSetCapacity(sString, nSize) DllCall("WideCharToMultiByte" , "Uint", CP , "Uint", 0 , "Uint", &wString , "int", -1 , "str", sString , "int", nSize , "Uint", 0 , "Uint", 0) }
Cfg.dat 是用来保存配置的文件,看代码就知道它的格式,就不贴内容上来了
JSON部分的代码没贴上来,我是直接include它整个文件的,可以在这里找到:
提取码: j83j
多谢您的长久支持
我在52上看到了你的帖子,并且下载了exe文件试了一下,挺好的。点赞。
不用certutil.exe怎么进行base64编码,还有可以通过vbs脚本执行certutil.exe隐藏cmd界面
这个不错的