wx-ocr 0.1.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Binary file
Binary file
Binary file
@@ -0,0 +1 @@
1
+ x64
wx_ocr/winapi.py ADDED
@@ -0,0 +1,195 @@
1
+ from ctypes import *
2
+ from ctypes.wintypes import *
3
+
4
+ user32 = WinDLL('user32', use_last_error=True)
5
+ kernel32 = WinDLL('kernel32', use_last_error=True)
6
+
7
+ class _SECURITY_ATTRIBUTES(Structure):
8
+ _fields_ = [('nLength', DWORD),
9
+ ('lpSecurityDescriptor', LPVOID),
10
+ ('bInheritHandle', BOOL),]
11
+
12
+ ULONG_PTR = c_ulong
13
+ INFINITE = 0xFFFFFFFF
14
+ PROCESS_ALL_ACCESS = 0x1FFFFF
15
+ MEM_COMMIT = 0x00001000
16
+ PAGE_EXECUTE_READWRITE = 0x40
17
+ MEM_RELEASE = 0x00008000
18
+ TH32CS_SNAPMODULE = 0x00000008
19
+ TH32CS_SNAPMODULE32 = 0x00000010
20
+ TH32CS_SNAPPROCESS = 0x00000002
21
+ PAGE_EXECUTE_READWRITE = 0x40
22
+ CS_HREDRAW = 2
23
+ CS_VREDRAW = 1
24
+ COLOR_WINDOW = 5
25
+ WS_OVERLAPPEDWINDOW = 13565952
26
+ CW_USEDEFAULT = -2147483648
27
+ SW_HIDE = 0
28
+ WM_COPYDATA = 0x004A
29
+
30
+
31
+ void = None
32
+ LPSECURITY_ATTRIBUTES = POINTER(_SECURITY_ATTRIBUTES)
33
+ LPTHREAD_START_ROUTINE = LPVOID
34
+ FARPROC = SIZE_T = c_ulong
35
+ HCURSOR = c_void_p
36
+ LRESULT = c_int64
37
+ WNDPROC = WINFUNCTYPE(LRESULT, HWND, UINT, WPARAM, LPARAM)
38
+
39
+ class COPYDATASTRUCT(Structure):
40
+ _fields_ = [
41
+ ('dwData', LPARAM),
42
+ ('cbData', DWORD),
43
+ ('lpData', c_void_p)
44
+ ]
45
+
46
+ class MODULEENTRY32(Structure):
47
+ _fields_ = [
48
+ ("dwSize", DWORD), # 结构的大小,以字节为单位,必须先初始化
49
+ ("th32ModuleID", DWORD), # 该成员不再使用,并且始终设置为 1
50
+ ("th32ProcessID", DWORD), # 进程pid
51
+ ("GlblcntUsage", DWORD), # 无意义, 一般等于0xFFFF
52
+ ("ProccntUsage", DWORD), # 无意义, 一般等于0xFFFF
53
+ ("modBaseAddr", POINTER(BYTE)), # 拥有进程上下文中模块的基地址
54
+ ("modBaseSize", DWORD), # 模块的大小,以字节为单位
55
+ ("hModule", HMODULE), # 拥有进程上下文中的模块句柄
56
+ ("szModule", c_char*256), # 模块名称
57
+ ("szExePath", c_char*260), # 模块路径
58
+ ]
59
+
60
+ class PROCESSENTRY32(Structure):
61
+ _fields_ = [
62
+ ("dwSize", DWORD), # 结构的大小,以字节为单位,必须先初始化
63
+ ("cntUsage", DWORD), # 该成员不再使用,并且始终设置为 1
64
+ ("th32ProcessID", DWORD), # 进程pid
65
+ ("th32DefaultHeapID", ULONG_PTR), # 无意义, 一般等于0xFFFF
66
+ ("th32ModuleID", DWORD), # 无意义, 一般等于0xFFFF
67
+ ("cntThreads", DWORD), # 拥有进程上下文中模块的基地址
68
+ ("th32ParentProcessID", DWORD), # 模块的大小,以字节为单位
69
+ ("pcPriClassBase", LONG), # 拥有进程上下文中的模块句柄
70
+ ("dwFlags", DWORD), # 模块名称
71
+ ("szExeFile", c_char*260), # 模块路径
72
+ ]
73
+
74
+ class WNDCLASS(Structure):
75
+ _fields_ = [('style', UINT),
76
+ ('lpfnWndProc', WNDPROC),
77
+ ('cbClsExtra', c_int),
78
+ ('cbWndExtra', c_int),
79
+ ('hInstance', HINSTANCE),
80
+ ('hIcon', HICON),
81
+ ('hCursor', HCURSOR),
82
+ ('hbrBackground', HBRUSH),
83
+ ('lpszMenuName', LPCWSTR),
84
+ ('lpszClassName', LPCWSTR)]
85
+
86
+ def func_def(name, restype, *argtypes, dll=kernel32):
87
+ def errcheck(result, func, args):
88
+ if not result:
89
+ raise WinError(get_last_error())
90
+ return result
91
+ cfunc = getattr(dll, name)
92
+ cfunc.argtypes = argtypes
93
+ cfunc.restype = restype
94
+ #cfunc.errcheck = errcheck
95
+ return cfunc
96
+
97
+ OpenProcess = func_def("OpenProcess", HANDLE, *(DWORD, BOOL, DWORD))
98
+ VirtualAllocEx = func_def("VirtualAllocEx", LPVOID, *(HANDLE, LPVOID, SIZE_T, DWORD, DWORD))
99
+ VirtualFreeEx = func_def("VirtualFreeEx", BOOL, *(HANDLE, LPVOID, SIZE_T, DWORD))
100
+ WriteProcessMemory = func_def("WriteProcessMemory", BOOL, *(HANDLE, LPVOID, LPCVOID, SIZE_T, POINTER(SIZE_T)))
101
+ GetModuleHandleA = func_def("GetModuleHandleA", HMODULE, *(LPCSTR,))
102
+ GetModuleHandleW = func_def("GetModuleHandleW", HMODULE, *(LPCWSTR, ))
103
+ GetProcAddress = func_def("GetProcAddress", c_void_p, *(HMODULE, LPCSTR))
104
+ CreateRemoteThread = func_def("CreateRemoteThread", HANDLE, *(HANDLE, LPSECURITY_ATTRIBUTES, DWORD, LPTHREAD_START_ROUTINE, LPVOID, DWORD, LPDWORD))
105
+ CloseHandle = func_def("CloseHandle", BOOL, *(HANDLE,))
106
+ CreateToolhelp32Snapshot = func_def("CreateToolhelp32Snapshot", HANDLE, *(DWORD, DWORD))
107
+ Module32First = func_def("Module32First", BOOL, *(HANDLE, POINTER(MODULEENTRY32)))
108
+ Module32Next = func_def("Module32Next", BOOL, *(HANDLE, POINTER(MODULEENTRY32)))
109
+ Process32First = func_def("Process32First", BOOL, *(HANDLE, POINTER(PROCESSENTRY32)))
110
+ Process32Next = func_def("Process32Next", BOOL, *(HANDLE, POINTER(PROCESSENTRY32)))
111
+ ReadProcessMemory = func_def("ReadProcessMemory", BOOL, *(HANDLE, LPCVOID, LPVOID, c_size_t, POINTER(c_size_t)))
112
+ FindWindowW = func_def("FindWindowW", HWND, *(LPCWSTR, LPCWSTR), dll=user32)
113
+ GetWindowThreadProcessId = func_def("GetWindowThreadProcessId", DWORD, *(HWND, LPDWORD), dll=user32)
114
+ LoadLibraryW = func_def("LoadLibraryW", HMODULE, *(LPCWSTR,))
115
+ FreeLibrary = func_def("FreeLibrary", BOOL, *(HMODULE, ))
116
+ VirtualProtect = func_def("VirtualProtect", BOOL, *(LPVOID, SIZE_T, DWORD, PDWORD))
117
+ VirtualProtectEx = func_def("VirtualProtectEx", BOOL, *(HANDLE, LPVOID, SIZE_T, DWORD, PDWORD))
118
+ DefWindowProcW = func_def("DefWindowProcW", LRESULT, *(HWND, UINT, WPARAM, LPARAM), dll=user32)
119
+ RegisterClassW = func_def("RegisterClassW", ATOM, *(POINTER(WNDCLASS), ), dll=user32)
120
+ CreateWindowExW = func_def("CreateWindowExW", HWND, *(DWORD, LPCWSTR, LPCWSTR, DWORD, c_int, c_int, c_int, c_int, HWND, HMENU, HINSTANCE, LPVOID), dll=user32)
121
+ ShowWindow = func_def('ShowWindow', BOOL, *(HWND, c_int), dll=user32)
122
+ UpdateWindow = func_def("UpdateWindow", BOOL, *(HWND, ), dll=user32)
123
+ GetMessageW = func_def("GetMessageW", BOOL, *(POINTER(MSG), HWND, UINT, UINT), dll=user32)
124
+ TranslateMessage = func_def('TranslateMessage', BOOL, *(POINTER(MSG), ), dll=user32)
125
+ DispatchMessageW = func_def('DispatchMessageW', LRESULT, *(POINTER(MSG),), dll=user32)
126
+ WaitForSingleObject = func_def('WaitForSingleObject', DWORD, *(HANDLE, DWORD))
127
+ GetExitCodeThread = func_def('GetExitCodeThread', BOOL, *(HANDLE, LPDWORD))
128
+
129
+ def CloseSomeHandle(*args):
130
+ '''关闭多个句柄'''
131
+ for arg in args:
132
+ if arg:
133
+ CloseHandle(arg)
134
+
135
+ def getPidByName(name=None, cls=None):
136
+ '''根据给定的name(进程名)和cls(类名)查找进程,返回进程pid'''
137
+ hwnd = FindWindowW(cls, name)
138
+ cpid = c_ulong()
139
+ if GetWindowThreadProcessId(hwnd, byref(cpid)):
140
+ return cpid.value
141
+ return 0
142
+
143
+ def getModuleInfo(moduleName, pid):
144
+ '''获取模块信息,返回模块信息的字典'''
145
+ hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE|TH32CS_SNAPMODULE32, pid)
146
+
147
+ me32 = MODULEENTRY32()
148
+ me32.dwSize = sizeof(MODULEENTRY32)
149
+
150
+ bRet = Module32First(hModuleSnap, pointer(me32))
151
+ while bRet:
152
+ szModule = me32.szModule.decode()
153
+ if szModule.upper() == moduleName.upper():
154
+ addr = cast(me32.modBaseAddr, c_void_p).value # hex(addressof(modBaseAddr.contents))
155
+ CloseHandle(hModuleSnap)
156
+ try:
157
+ me32.szExePath.decode("gbk")
158
+ except UnicodeDecodeError:
159
+ print(me32.szExePath)
160
+ module = {
161
+ 'modBaseSize': me32.modBaseSize, # 模块字节大小
162
+ 'th32ProcessID': me32.th32ProcessID, # 进程pid
163
+ 'modBaseAddr': addr, # 模块基址
164
+ "hModule": me32.hModule, # 模块句柄
165
+ 'szModule': me32.szModule.decode("ansi"), # 模块名称
166
+ 'szExePath': me32.szExePath.decode("ansi") # 模块路径
167
+ }
168
+ return module
169
+ bRet = Module32Next(hModuleSnap, pointer(me32) )
170
+ CloseHandle(hModuleSnap)
171
+
172
+ def getModuleBaseAddress(moduleName, pid):
173
+ '''获取模块基址'''
174
+ module = getModuleInfo(moduleName, pid)
175
+ if module:
176
+ return module["modBaseAddr"]
177
+
178
+ def enumProcess(procName):
179
+ '''枚举进程'''
180
+ hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)
181
+
182
+ pe32 = PROCESSENTRY32()
183
+ pe32.dwSize = sizeof(PROCESSENTRY32)
184
+ pids = []
185
+ bRet = Process32First(hModuleSnap, pointer(pe32))
186
+ while bRet:
187
+ szExeFile = pe32.szExeFile.decode()
188
+ if szExeFile.upper() == procName.upper():
189
+ pid = pe32.th32ProcessID # hex(addressof(modBaseAddr.contents))
190
+ pids.append(pid)
191
+ bRet = Process32Next(hModuleSnap, pointer(pe32) )
192
+ CloseHandle(hModuleSnap)
193
+ return pids
194
+
195
+
@@ -0,0 +1,194 @@
1
+ import os
2
+ import time
3
+ import platform
4
+ from typing import Callable, Dict, List
5
+ from enum import Enum
6
+ from .winapi import *
7
+ from . import default_callback
8
+ from .mmmojo_dll import MmmojoDll, MMMojoEnvironmentCallbackType, MMMojoEnvironmentInitParamType
9
+
10
+
11
+ class RequestIdUtility(Enum):
12
+ '''
13
+ enum RequestIdUtility
14
+ {
15
+ UtilityHiPush = 10001, //是Utility启动发送的
16
+ UtilityInitPullReq = 10002, //初始化请求
17
+ UtilityInitPullResp = 10003, //回复创建的都是Shared类型的info, 但是调用了SwapMMMojoWriteInfoCallback, 所以回调的还是Pull
18
+ UtilityResampleImagePullReq = 10010,
19
+ UtilityResampleImagePullResp = 10011,
20
+ UtilityDecodeImagePullReq = 10020,
21
+ UtilityDecodeImagePullResp = 10021,
22
+ UtilityPicQRScanPullReq = 10030, //10030是点击OCR时(也是打开图片时)发送的请求, 参数是图片路径
23
+ UtilityQRScanPullReq = 10031, //10031是截图框选时发送的请求, 参数应该是某种编码后的图片数据
24
+ UtilityQRScanPullResp = 10032, //这两种请求的返回ID都是10032
25
+ UtilityTextScanPushResp = 10040 //TextScan具体在扫什么不是很清楚 可能是用来判断图片上是否有文字
26
+ };
27
+ '''
28
+ UtilityHiPush = 10001
29
+ UtilityInitPullReq = 10002
30
+ UtilityInitPullResp = 10003
31
+ UtilityResampleImagePullReq = 10010
32
+ UtilityResampleImagePullResp = 10011
33
+ UtilityDecodeImagePullReq = 10020
34
+ UtilityDecodeImagePullResp = 10021
35
+ UtilityPicQRScanPullReq = 10030
36
+ UtilityQRScanPullReq = 10031
37
+ UtilityQRScanPullResp = 10032
38
+ UtilityTextScanPushResp = 10040
39
+
40
+ class RequestIdPlayer(Enum):
41
+ PlayerHiPush = 10001
42
+ PlayerInitPullReq = 10002
43
+ PlayerInitPullResp = 10003
44
+ PlayerInitPlayerCorePush = 10010
45
+ PlayerCreatePlayerCorePullReq = 10011
46
+ PlayerCreatePlayerCorePullResp = 10012
47
+ PlayerDestroyPlayerCorePush = 10013
48
+ PlayerPrepareAsyncPush = 10014
49
+ PlayerStartPush = 10015
50
+ PlayerStopPush = 10016
51
+ PlayerPausePush = 10017
52
+ PlayerResumePush = 10018
53
+ PlayerSetAudioMutePush = 10019
54
+ PlayerSeekToAsyncPush = 10020
55
+ PlayerGetCurrentPositionMsPullReq = 10021
56
+ PlayerGetCurrentPositionMsPullResp = 10022
57
+ PlayerSetVideoSurfacePush = 10023
58
+ PlayerSetAudioVolumePush = 10024
59
+ PlayerSetDataSourcePush = 10025
60
+ PlayerSetLoaderSourcePush = 10026
61
+ PlayerSetRepeatPush = 10027
62
+ PlayerResizePush = 10028
63
+ PlayerSetPlaySpeedRatio = 10029
64
+ PlayerInfoPush = 10030
65
+ PlayerErrorPlayerPush = 10031
66
+ PlayerVideoSizeChangedPush = 10032
67
+ PlayerUnknown0Push = 10033
68
+ PlayerStatePush = 10034
69
+ PlayerUnknonw1Push = 10035
70
+ PlayerUnknown2Push = 10036
71
+ PlayerStartTaskProxyPush = 10050
72
+ PlayerStartRequestProxyPush = 10051
73
+ PlayerCloseRequestProxyPush = 10052
74
+ PlayerPollingDatProxyPullReq = 10054
75
+
76
+
77
+
78
+ class XPluginManager(object):
79
+ m_cb_usrdata:py_object
80
+ m_exe_path:c_wchar_p
81
+ m_switch_native: Dict[str, str] = {}
82
+ m_cmdline: List[str] = []
83
+ m_mmmojo_env_ptr: c_void_p = c_void_p(None)
84
+ m_init_mmmojo_env = False
85
+ m_callbacks: Dict[str, Callable] = {}
86
+
87
+ def __init__(self, wechat_path) -> None:
88
+ python_bit = platform.architecture()[0]
89
+ if python_bit == "64bit":
90
+ dll_name = "mmmojo_64.dll"
91
+ else:
92
+ dll_name = "mmmojo.dll"
93
+ mmmojo_dllpath = os.path.join(wechat_path, dll_name)
94
+ if not os.path.exists(mmmojo_dllpath):
95
+ raise Exception("给定的微信路径不存在mmmojo.dll")
96
+ self._dll = MmmojoDll(mmmojo_dllpath)
97
+ self.m_cb_usrdata = self
98
+ # 增加callback的引用计数,防止被垃圾回收机制处理
99
+ self._callbacks_refer = {}
100
+
101
+ def __del__(self):
102
+ if self.m_init_mmmojo_env:
103
+ self.StopMMMojoEnv()
104
+
105
+ def SetExePath(self, exe_path:str) -> None:
106
+ ocr_exe_name = "WeChatOCR.exe"
107
+ if not exe_path.endswith(ocr_exe_name) and os.path.isdir(exe_path):
108
+ exe_path = os.path.join(exe_path, ocr_exe_name)
109
+ if not os.path.exists(exe_path):
110
+ raise Exception(f"指定的{ocr_exe_name}路径不存在!")
111
+ self.m_exe_path = c_wchar_p(exe_path)
112
+
113
+ def AppendSwitchNativeCmdLine(self, arg:str, value:str) -> None:
114
+ self.m_switch_native[arg] = value
115
+
116
+ def SetCommandLine(self, cmdline:List[str]) -> None:
117
+ self.m_cmdline = cmdline
118
+
119
+ def SetOneCallback(self, name:str, func:Callable) -> None:
120
+ self.m_callbacks[name] = func
121
+
122
+ def SetCallbacks(self, callbacks:Dict[str, Callable]) -> None:
123
+ self.m_callbacks.update(callbacks)
124
+
125
+ def SetCallbackUsrData(self, cb_usrdata:py_object):
126
+ self.m_cb_usrdata = cb_usrdata
127
+
128
+ def InitMMMojoEnv(self):
129
+ if not self.m_exe_path or not os.path.exists(self.m_exe_path.value):
130
+ raise Exception(f"给定的WeChatOcr.exe路径错误(m_exe_path): {self.m_exe_path}")
131
+ if self.m_init_mmmojo_env and self.m_mmmojo_env_ptr:
132
+ return
133
+ # 初始化环境
134
+ self._dll.InitializeMMMojo(0, None)
135
+ self.m_mmmojo_env_ptr = c_void_p(self._dll.CreateMMMojoEnvironment())
136
+ if not self.m_mmmojo_env_ptr:
137
+ raise Exception("CreateMMMojoEnvironment失败!")
138
+ # 设置回调函数的最后一个参数user_data的值
139
+ self._dll.SetMMMojoEnvironmentCallbacks(self.m_mmmojo_env_ptr, MMMojoEnvironmentCallbackType.kMMUserData.value, py_object(self.m_cb_usrdata))
140
+ self.SetDefaultCallbaks()
141
+ # 设置启动所需参数
142
+ SetMMMojoEnvironmentInitParams = self._dll.func_def("SetMMMojoEnvironmentInitParams", void, *(c_void_p, c_int, c_int))
143
+ SetMMMojoEnvironmentInitParams(self.m_mmmojo_env_ptr, MMMojoEnvironmentInitParamType.kMMHostProcess.value, 1)
144
+ SetMMMojoEnvironmentInitParams = self._dll.func_def("SetMMMojoEnvironmentInitParams", void, *(c_void_p, c_int, c_wchar_p))
145
+ SetMMMojoEnvironmentInitParams(self.m_mmmojo_env_ptr, MMMojoEnvironmentInitParamType.kMMExePath.value, self.m_exe_path)
146
+ # 设置SwitchNative命令行参数
147
+ for k,v in self.m_switch_native.items():
148
+ ck = c_char_p(k.encode())
149
+ cv = c_wchar_p(v)
150
+ self._dll.AppendMMSubProcessSwitchNative(self.m_mmmojo_env_ptr, ck, cv)
151
+ # 启动
152
+ self._dll.StartMMMojoEnvironment(self.m_mmmojo_env_ptr)
153
+ self.m_init_mmmojo_env = True
154
+
155
+ def SetDefaultCallbaks(self):
156
+ for i in MMMojoEnvironmentCallbackType:
157
+ fname = i.name
158
+ if fname == "kMMUserData":
159
+ continue
160
+ callback = self.m_callbacks.get(fname, None) or getattr(default_callback, f"Default{fname[3:]}")
161
+ callback_def = default_callback.callbacks_def[fname]
162
+ SetMMMojoEnvironmentCallbacks = self._dll.func_def("SetMMMojoEnvironmentCallbacks", void, *(c_void_p, c_int, callback_def))
163
+ self._callbacks_refer[fname] = callback_def(callback)
164
+ SetMMMojoEnvironmentCallbacks(self.m_mmmojo_env_ptr, i.value, self._callbacks_refer[fname])
165
+
166
+ def StopMMMojoEnv(self):
167
+ if self.m_init_mmmojo_env and self.m_mmmojo_env_ptr:
168
+ self._dll.StopMMMojoEnvironment(self.m_mmmojo_env_ptr)
169
+ self._dll.RemoveMMMojoEnvironment(self.m_mmmojo_env_ptr)
170
+ self.m_mmmojo_env_ptr = c_void_p(None)
171
+ self.m_init_mmmojo_env = False
172
+
173
+ def SendPbSerializedData(self, pb_data:bytes, pb_size:int, method:int, sync:int, request_id:int) -> None:
174
+ write_info:c_void_p = self._dll.CreateMMMojoWriteInfo(c_int(method), c_int(sync), c_uint32(request_id))
175
+ request:c_void_p = self._dll.GetMMMojoWriteInfoRequest(write_info, c_uint32(pb_size))
176
+ memmove(request, c_char_p(pb_data), pb_size)
177
+ self._dll.SendMMMojoWriteInfo(self.m_mmmojo_env_ptr, write_info)
178
+
179
+ def GetPbSerializedData(self, request_info:c_void_p, data_size:c_uint32) -> c_void_p:
180
+ pb_data = self._dll.GetMMMojoReadInfoRequest(request_info, byref(data_size))
181
+ return pb_data
182
+
183
+ def GetReadInfoAttachData(self, request_info:c_void_p, data_size:c_uint32) -> c_void_p:
184
+ attach_data = self._dll.GetMMMojoReadInfoAttach(request_info, byref(data_size))
185
+ return attach_data
186
+
187
+ def RemoveReadInfo(self, request_info:c_void_p) -> void:
188
+ return self._dll.RemoveMMMojoReadInfo(request_info)
189
+
190
+
191
+
192
+
193
+
194
+
@@ -0,0 +1,84 @@
1
+ Metadata-Version: 2.4
2
+ Name: wx-ocr
3
+ Version: 0.1.3
4
+ Summary: 超级简单的微信 OCR - 一行代码识别图片文字 | Super simple WeChat OCR
5
+ Author: wx-ocr contributors
6
+ License: MIT
7
+ Project-URL: Original Project, https://github.com/kanadeblisst00/wechat_ocr
8
+ Keywords: wechat,ocr,text-recognition,image-processing,微信,文字识别,wx
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Operating System :: Microsoft :: Windows
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.8
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Topic :: Multimedia :: Graphics :: Capture :: Screen Capture
21
+ Classifier: Topic :: Scientific/Engineering :: Image Recognition
22
+ Requires-Python: >=3.8
23
+ Description-Content-Type: text/markdown
24
+ License-File: LICENSE
25
+ Requires-Dist: protobuf>=3.20.0
26
+ Dynamic: license-file
27
+
28
+ # wx-ocr
29
+
30
+ 一行代码识别图片文字,无需安装微信
31
+
32
+ ## 安装
33
+
34
+ ```bash
35
+ pip install wx-ocr
36
+ ```
37
+
38
+ ## 使用
39
+
40
+ ### Python API
41
+
42
+ ```python
43
+ from wx_ocr import ocr
44
+
45
+ # 识别图片
46
+ texts = ocr("image.png", return_text_only=True)
47
+ print(texts) # ['文字1', '文字2', ...]
48
+
49
+ # 获取完整结果(包含位置信息)
50
+ result = ocr("image.png")
51
+ for item in result['ocrResult']:
52
+ print(item['text'], item['location'])
53
+
54
+ # 批量识别
55
+ from wx_ocr import ocr_batch
56
+ results = ocr_batch(["1.png", "2.png", "3.png"], return_text_only=True)
57
+ ```
58
+
59
+ ### 命令行
60
+
61
+ ```bash
62
+ # 识别图片
63
+ wx-ocr image.png
64
+
65
+ # JSON 格式输出
66
+ wx-ocr --format json image.png
67
+
68
+ # 批量处理
69
+ wx-ocr *.png
70
+
71
+ # 保存结果
72
+ wx-ocr --save --output results/ image.png
73
+ ```
74
+
75
+ ## 说明
76
+
77
+ - 仅支持 Windows
78
+ - 需要 Python 3.8+
79
+ - 无需安装微信(项目自带 OCR 文件)
80
+ - 基于 [wechat_ocr](https://github.com/kanadeblisst00/wechat_ocr) 开发
81
+
82
+ ## License
83
+
84
+ MIT
@@ -0,0 +1,27 @@
1
+ wx_ocr/__init__.py,sha256=MvD1EOE2ietqkQizcifkHyi0ZE7jTDb7S3VF0ioRLuw,4250
2
+ wx_ocr/cli.py,sha256=9gNR4TYCeEdfQE9oAeGNXtCICZtnSya2P3w7ggwLg_o,9513
3
+ wx_ocr/default_callback.py,sha256=ACiaTs7_TsRgHXLDMGwwSAivNAUdQ4FLEdVBjMOc7Ps,1973
4
+ wx_ocr/mmmojo_dll.py,sha256=9Wnv8-HqNnFMQxSLRWzeLwULiraTgBnLj66VENRTL9k,6655
5
+ wx_ocr/ocr_manager.py,sha256=AzoM7B6wtRMyE9Fiixq-ktOCdCXF_5SaXCTD_biCwCc,5868
6
+ wx_ocr/ocr_protobuf_pb2.py,sha256=S7g4JWkl_TxPjxO506gekneI0w35lK2g5gFBMIAU4fI,3249
7
+ wx_ocr/simple_api.py,sha256=6HA7G_7VvajBvNWk-StlhNBT1ykHEHLWDfkhr81vi3k,9983
8
+ wx_ocr/utility_protobuf_pb2.py,sha256=76Fy777BK_-B5ZXhOwKD_SsR8P1B6lDPysiAv2PtAHg,3064
9
+ wx_ocr/utils.py,sha256=tML-ajGRk-RT72_A2YsYuisd8kwQgcQtDGYvJb0tPRo,4492
10
+ wx_ocr/winapi.py,sha256=yrPqgcrLZSGPkRPpwJUl2_WYiR9aPGZdbtf66ewt_Ec,8559
11
+ wx_ocr/xplugin_manager.py,sha256=5QtTSfN5XUBVrBPg2a-OSK5DZKsL5Sj1xsbcwuYMNNE,8573
12
+ wx_ocr/wco_data/WeChatOCR.exe,sha256=mJ5cLQ5RwbK3XoMTrHtoYv6bZ94lkZVaO-EUnIf_NaE,36592232
13
+ wx_ocr/wco_data/mmmojo.dll,sha256=nxZMcAU1bTG9FKpH8kmo_FXbky31AwrKAn2jy2ftOqg,2077064
14
+ wx_ocr/wco_data/mmmojo_64.dll,sha256=1RM90skodkbNw0Zhy1pcSy5HpyzWC_COQAJTMhqMuJQ,2495368
15
+ wx_ocr/wco_data/x64.config,sha256=Vgn3KEA-GXuyVe9Qxirqux-TsJ97fDeZA0QLZc1DGcs,3
16
+ wx_ocr/wco_data/Model/FPOCRRecog.xnet,sha256=HPs6fXm5naksbYpZr9tvxEF0C8b1oW39xAtoEKTMH08,9578175
17
+ wx_ocr/wco_data/Model/OCRDetFP32.xnet.nas,sha256=qempkMpohyurp6N6m_HK2rucVLhMnLQ84ZY0YZ90Rng,1604697
18
+ wx_ocr/wco_data/Model/OCRParaDetV1.1.0.26.xnet,sha256=rZKTtdZHpXM36uh3ND6t81r4CmmbLaR2di-Bskt0Om4,2834840
19
+ wx_ocr/wco_data/Model/OCRRecogFP32V1.1.0.26.xnet,sha256=BhyDtbP8p9ehBjzTSSQq3ryTvmTNmwe1-BobyxqHV6A,7642697
20
+ wx_ocr/wco_data/Model/RecDict,sha256=1yWlaEHaBi25CIWLvXKZNsg1i5orbNVEQ2OzsIzm2vk,59801
21
+ wx_ocr/wco_data/Model/sohu_simp.txt,sha256=HNB23VmdGxZoVWK8SqC0f448w2tkQOYcEmTo-vv-iMk,24950
22
+ wx_ocr-0.1.3.dist-info/licenses/LICENSE,sha256=BAqHW4gQ1q31CJhJfP7FAwcYaUI1jUPnWvmf52dP_JM,1101
23
+ wx_ocr-0.1.3.dist-info/METADATA,sha256=iEBg4hpxTiE8BE5IFlxQCgBqkJl-3LrkoB3AXSgje20,2180
24
+ wx_ocr-0.1.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
25
+ wx_ocr-0.1.3.dist-info/entry_points.txt,sha256=RmsGyMOv-Efc-_kSfHFF9KzQX13c6Gd7APExrKsiJGA,43
26
+ wx_ocr-0.1.3.dist-info/top_level.txt,sha256=mJ57_4n8IkcgYcyOV6Z3ZMacnFhy73XDGRUfo9feH2c,7
27
+ wx_ocr-0.1.3.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.9.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ wx-ocr = wx_ocr.cli:main
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 wechat-ocr contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ wx_ocr