调用Win自带的API来实现离线OCR,但是自带的API识别效果很拉胯。示例仅供参考
附带截图放大的示例整合包:【放大截图后,识别率稍微好点】
蓝奏云:https://wwp.lanzouj.com/iHlaO1v9asmh 提取码:ahk6
123网盘:https://www.123pan.com/s/ufi3Td-W8O53.html 提取码:ahk6
免类库的调用示例:
; 来源出处:https://www.autohotkey.com/boards/viewtopic.php?f=6&t=72674 #NoEnv SetBatchLines, -1 Return Esc:: ExitApp F1:: hBitmap := HBitmapFromScreen(GetArea()*) pIRandomAccessStream := HBitmapToRandomAccessStream(hBitmap) DllCall("DeleteObject", "Ptr", hBitmap) text := ocr(pIRandomAccessStream, "zh-Hans-CN") MsgBox % text Return GetArea() { area := [] StartSelection(area) while !area.w Sleep, 100 Return area } StartSelection(area) { handler := Func("Select").Bind(area) Hotkey, LButton, % handler, On ReplaceSystemCursors("IDC_CROSS") } Select(area) { static hGui := CreateSelectionGui() Hook := new WindowsHook(WH_MOUSE_LL := 14, "LowLevelMouseProc", hGui) Loop { KeyWait, LButton WinGetPos, X, Y, W, H, ahk_id %hGui% } until w > 0 ReplaceSystemCursors("") Hotkey, LButton, Off Hook := "" Gui, %hGui%:Show, Hide for k, v in ["x", "y", "w", "h"] area[v] := %v% } ReplaceSystemCursors(IDC = "") { static IMAGE_CURSOR := 2, SPI_SETCURSORS := 0x57 , exitFunc := Func("ReplaceSystemCursors").Bind("") , SysCursors := { IDC_APPSTARTING: 32650 , IDC_ARROW : 32512 , IDC_CROSS : 32515 , IDC_HAND : 32649 , IDC_HELP : 32651 , IDC_IBEAM : 32513 , IDC_NO : 32648 , IDC_SIZEALL : 32646 , IDC_SIZENESW : 32643 , IDC_SIZENWSE : 32642 , IDC_SIZEWE : 32644 , IDC_SIZENS : 32645 , IDC_UPARROW : 32516 , IDC_WAIT : 32514 } if !IDC { DllCall("SystemParametersInfo", UInt, SPI_SETCURSORS, UInt, 0, UInt, 0, UInt, 0) OnExit(exitFunc, 0) } else { hCursor := DllCall("LoadCursor", Ptr, 0, UInt, SysCursors[IDC], Ptr) for k, v in SysCursors { hCopy := DllCall("CopyImage", Ptr, hCursor, UInt, IMAGE_CURSOR, Int, 0, Int, 0, UInt, 0, Ptr) DllCall("SetSystemCursor", Ptr, hCopy, UInt, v) } OnExit(exitFunc) } } CreateSelectionGui() { Gui, New, +hwndhGui +Alwaysontop -Caption +LastFound +ToolWindow +E0x20 -DPIScale WinSet, Transparent, 130 Gui, Color, FFC800 Return hGui } LowLevelMouseProc(nCode, wParam, lParam) { static WM_MOUSEMOVE := 0x200, WM_LBUTTONUP := 0x202 , coords := [], startMouseX, startMouseY, hGui , timer := Func("LowLevelMouseProc").Bind("timer", "", "") if (nCode = "timer") { while coords[1] { point := coords.RemoveAt(1) mouseX := point[1], mouseY := point[2] x := startMouseX < mouseX ? startMouseX : mouseX y := startMouseY < mouseY ? startMouseY : mouseY w := Abs(mouseX - startMouseX) h := Abs(mouseY - startMouseY) try Gui, %hGUi%: Show, x%x% y%y% w%w% h%h% NA } } else { (!hGui && hGui := A_EventInfo) if (wParam = WM_LBUTTONUP) startMouseX := startMouseY := "" if (wParam = WM_MOUSEMOVE) { mouseX := NumGet(lParam + 0, "Int") mouseY := NumGet(lParam + 4, "Int") if (startMouseX = "") { startMouseX := mouseX startMouseY := mouseY } coords.Push([mouseX, mouseY]) SetTimer, % timer, -10 } Return DllCall("CallNextHookEx", Ptr, 0, Int, nCode, UInt, wParam, Ptr, lParam) } } class WindowsHook { __New(type, callback, eventInfo := "", isGlobal := true) { this.callbackPtr := RegisterCallback(callback, "Fast", 3, eventInfo) this.hHook := DllCall("SetWindowsHookEx", "Int", type, "Ptr", this.callbackPtr , "Ptr", !isGlobal ? 0 : DllCall("GetModuleHandle", "UInt", 0, "Ptr") , "UInt", isGlobal ? 0 : DllCall("GetCurrentThreadId"), "Ptr") } __Delete() { DllCall("UnhookWindowsHookEx", "Ptr", this.hHook) DllCall("GlobalFree", "Ptr", this.callBackPtr, "Ptr") } } HBitmapFromScreen(X, Y, W, H) { HDC := DllCall("GetDC", "Ptr", 0, "UPtr") HBM := DllCall("CreateCompatibleBitmap", "Ptr", HDC, "Int", W, "Int", H, "UPtr") PDC := DllCall("CreateCompatibleDC", "Ptr", HDC, "UPtr") DllCall("SelectObject", "Ptr", PDC, "Ptr", HBM) DllCall("BitBlt", "Ptr", PDC, "Int", 0, "Int", 0, "Int", W, "Int", H , "Ptr", HDC, "Int", X, "Int", Y, "UInt", 0x00CC0020) DllCall("DeleteDC", "Ptr", PDC) DllCall("ReleaseDC", "Ptr", 0, "Ptr", HDC) Return HBM } HBitmapToRandomAccessStream(hBitmap) { static IID_IRandomAccessStream := "{905A0FE1-BC53-11DF-8C49-001E4FC686DA}" , IID_IPicture := "{7BF80980-BF32-101A-8BBB-00AA00300CAB}" , PICTYPE_BITMAP := 1 , BSOS_DEFAULT := 0 DllCall("Ole32\CreateStreamOnHGlobal", "Ptr", 0, "UInt", true, "PtrP", pIStream, "UInt") VarSetCapacity(PICTDESC, sz := 8 + A_PtrSize*2, 0) NumPut(sz, PICTDESC) NumPut(PICTYPE_BITMAP, PICTDESC, 4) NumPut(hBitmap, PICTDESC, 8) riid := CLSIDFromString(IID_IPicture, GUID1) DllCall("OleAut32\OleCreatePictureIndirect", "Ptr", &PICTDESC, "Ptr", riid, "UInt", false, "PtrP", pIPicture, "UInt") ; IPicture::SaveAsFile DllCall(NumGet(NumGet(pIPicture+0) + A_PtrSize*15), "Ptr", pIPicture, "Ptr", pIStream, "UInt", true, "UIntP", size, "UInt") riid := CLSIDFromString(IID_IRandomAccessStream, GUID2) DllCall("ShCore\CreateRandomAccessStreamOverStream", "Ptr", pIStream, "UInt", BSOS_DEFAULT, "Ptr", riid, "PtrP", pIRandomAccessStream, "UInt") ObjRelease(pIPicture) ObjRelease(pIStream) Return pIRandomAccessStream } CLSIDFromString(IID, ByRef CLSID) { VarSetCapacity(CLSID, 16, 0) if res := DllCall("ole32\CLSIDFromString", "WStr", IID, "Ptr", &CLSID, "UInt") throw Exception("CLSIDFromString failed. Error: " . Format("{:#x}", res)) Return &CLSID } ; =================== 使用 UWP API 的光学字符识别 (OCR) =================== ocr(file, lang := "FirstFromAvailableLanguages") { static OcrEngineStatics, OcrEngine, MaxDimension, LanguageFactory, Language, CurrentLanguage, BitmapDecoderStatics, GlobalizationPreferencesStatics if (OcrEngineStatics = "") { CreateClass("Windows.Globalization.Language", ILanguageFactory := "{9B0252AC-0C27-44F8-B792-9793FB66C63E}", LanguageFactory) CreateClass("Windows.Graphics.Imaging.BitmapDecoder", IBitmapDecoderStatics := "{438CCB26-BCEF-4E95-BAD6-23A822E58D01}", BitmapDecoderStatics) CreateClass("Windows.Media.Ocr.OcrEngine", IOcrEngineStatics := "{5BFFA85A-3384-3540-9940-699120D428A8}", OcrEngineStatics) DllCall(NumGet(NumGet(OcrEngineStatics+0)+6*A_PtrSize), "ptr", OcrEngineStatics, "uint*", MaxDimension) ; MaxImageDimension } if (file = "ShowAvailableLanguages") { if (GlobalizationPreferencesStatics = "") CreateClass("Windows.System.UserProfile.GlobalizationPreferences", IGlobalizationPreferencesStatics := "{01BF4326-ED37-4E96-B0E9-C1340D1EA158}", GlobalizationPreferencesStatics) DllCall(NumGet(NumGet(GlobalizationPreferencesStatics+0)+9*A_PtrSize), "ptr", GlobalizationPreferencesStatics, "ptr*", LanguageList) ; get_Languages DllCall(NumGet(NumGet(LanguageList+0)+7*A_PtrSize), "ptr", LanguageList, "int*", count) ; count loop % count { DllCall(NumGet(NumGet(LanguageList+0)+6*A_PtrSize), "ptr", LanguageList, "int", A_Index-1, "ptr*", hString) ; get_Item DllCall(NumGet(NumGet(LanguageFactory+0)+6*A_PtrSize), "ptr", LanguageFactory, "ptr", hString, "ptr*", LanguageTest) ; CreateLanguage DllCall(NumGet(NumGet(OcrEngineStatics+0)+8*A_PtrSize), "ptr", OcrEngineStatics, "ptr", LanguageTest, "int*", bool) ; IsLanguageSupported if (bool = 1) { DllCall(NumGet(NumGet(LanguageTest+0)+6*A_PtrSize), "ptr", LanguageTest, "ptr*", hText) buffer := DllCall("Combase.dll\WindowsGetStringRawBuffer", "ptr", hText, "uint*", length, "ptr") text .= StrGet(buffer, "UTF-16") "`n" } ObjRelease(LanguageTest) } ObjRelease(LanguageList) return text } if (lang != CurrentLanguage) or (lang = "FirstFromAvailableLanguages") { if (OcrEngine != "") { ObjRelease(OcrEngine) if (CurrentLanguage != "FirstFromAvailableLanguages") ObjRelease(Language) } if (lang = "FirstFromAvailableLanguages") DllCall(NumGet(NumGet(OcrEngineStatics+0)+10*A_PtrSize), "ptr", OcrEngineStatics, "ptr*", OcrEngine) ; TryCreateFromUserProfileLanguages else { CreateHString(lang, hString) DllCall(NumGet(NumGet(LanguageFactory+0)+6*A_PtrSize), "ptr", LanguageFactory, "ptr", hString, "ptr*", Language) ; CreateLanguage DeleteHString(hString) DllCall(NumGet(NumGet(OcrEngineStatics+0)+9*A_PtrSize), "ptr", OcrEngineStatics, ptr, Language, "ptr*", OcrEngine) ; TryCreateFromLanguage } if (OcrEngine = 0) { msgbox Can not use language "%lang%" for OCR, please install language pack. ExitApp } CurrentLanguage := lang } IRandomAccessStream := file DllCall(NumGet(NumGet(BitmapDecoderStatics+0)+14*A_PtrSize), "ptr", BitmapDecoderStatics, "ptr", IRandomAccessStream, "ptr*", BitmapDecoder) ; CreateAsync WaitForAsync(BitmapDecoder) BitmapFrame := ComObjQuery(BitmapDecoder, IBitmapFrame := "{72A49A1C-8081-438D-91BC-94ECFC8185C6}") DllCall(NumGet(NumGet(BitmapFrame+0)+12*A_PtrSize), "ptr", BitmapFrame, "uint*", width) ; get_PixelWidth DllCall(NumGet(NumGet(BitmapFrame+0)+13*A_PtrSize), "ptr", BitmapFrame, "uint*", height) ; get_PixelHeight if (width > MaxDimension) or (height > MaxDimension) { msgbox Image is to big - %width%x%height%.`nIt should be maximum - %MaxDimension% pixels ExitApp } BitmapFrameWithSoftwareBitmap := ComObjQuery(BitmapDecoder, IBitmapFrameWithSoftwareBitmap := "{FE287C9A-420C-4963-87AD-691436E08383}") DllCall(NumGet(NumGet(BitmapFrameWithSoftwareBitmap+0)+6*A_PtrSize), "ptr", BitmapFrameWithSoftwareBitmap, "ptr*", SoftwareBitmap) ; GetSoftwareBitmapAsync WaitForAsync(SoftwareBitmap) DllCall(NumGet(NumGet(OcrEngine+0)+6*A_PtrSize), "ptr", OcrEngine, ptr, SoftwareBitmap, "ptr*", OcrResult) ; RecognizeAsync WaitForAsync(OcrResult) DllCall(NumGet(NumGet(OcrResult+0)+6*A_PtrSize), "ptr", OcrResult, "ptr*", LinesList) ; get_Lines DllCall(NumGet(NumGet(LinesList+0)+7*A_PtrSize), "ptr", LinesList, "int*", count) ; count loop % count { DllCall(NumGet(NumGet(LinesList+0)+6*A_PtrSize), "ptr", LinesList, "int", A_Index-1, "ptr*", OcrLine) DllCall(NumGet(NumGet(OcrLine+0)+7*A_PtrSize), "ptr", OcrLine, "ptr*", hText) buffer := DllCall("Combase.dll\WindowsGetStringRawBuffer", "ptr", hText, "uint*", length, "ptr") text .= StrGet(buffer, "UTF-16") "`n" ObjRelease(OcrLine) } Close := ComObjQuery(IRandomAccessStream, IClosable := "{30D5A829-7FA4-4026-83BB-D75BAE4EA99E}") DllCall(NumGet(NumGet(Close+0)+6*A_PtrSize), "ptr", Close) ; Close ObjRelease(Close) Close := ComObjQuery(SoftwareBitmap, IClosable := "{30D5A829-7FA4-4026-83BB-D75BAE4EA99E}") DllCall(NumGet(NumGet(Close+0)+6*A_PtrSize), "ptr", Close) ; Close ObjRelease(Close) ObjRelease(IRandomAccessStream) ObjRelease(BitmapDecoder) ObjRelease(BitmapFrame) ObjRelease(BitmapFrameWithSoftwareBitmap) ObjRelease(SoftwareBitmap) ObjRelease(OcrResult) ObjRelease(LinesList) return text } CreateClass(string, interface, ByRef Class) { CreateHString(string, hString) VarSetCapacity(GUID, 16) DllCall("ole32\CLSIDFromString", "wstr", interface, "ptr", &GUID) result := DllCall("Combase.dll\RoGetActivationFactory", "ptr", hString, "ptr", &GUID, "ptr*", Class) if (result != 0) { if (result = 0x80004002) msgbox No such interface supported else if (result = 0x80040154) msgbox Class not registered else msgbox error: %result% ExitApp } DeleteHString(hString) } CreateHString(string, ByRef hString) { DllCall("Combase.dll\WindowsCreateString", "wstr", string, "uint", StrLen(string), "ptr*", hString) } DeleteHString(hString) { DllCall("Combase.dll\WindowsDeleteString", "ptr", hString) } WaitForAsync(ByRef Object) { AsyncInfo := ComObjQuery(Object, IAsyncInfo := "{00000036-0000-0000-C000-000000000046}") loop { DllCall(NumGet(NumGet(AsyncInfo+0)+7*A_PtrSize), "ptr", AsyncInfo, "uint*", status) ; IAsyncInfo.Status if (status != 0) { if (status != 1) { DllCall(NumGet(NumGet(AsyncInfo+0)+8*A_PtrSize), "ptr", AsyncInfo, "uint*", ErrorCode) ; IAsyncInfo.ErrorCode msgbox AsyncInfo status error: %ErrorCode% ExitApp } ObjRelease(AsyncInfo) break } sleep 10 } DllCall(NumGet(NumGet(Object+0)+8*A_PtrSize), "ptr", Object, "ptr*", ObjectResult) ; GetResults ObjRelease(Object) Object := ObjectResult }
声明:站内资源为整理优化好的代码上传分享与学习研究,如果是开源代码基本都会标明出处,方便大家扩展学习路径。请不要恶意搬运,破坏站长辛苦整理维护的劳动成果。本站为爱好者分享站点,所有内容不作为商业行为。如若本站上传内容侵犯了原著者的合法权益,请联系我们进行删除下架。
评论(0)