This commit is contained in:
28
.gitea/workflows/build.yaml
Normal file
28
.gitea/workflows/build.yaml
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
name: Build Server
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
compile-dll:
|
||||||
|
name: Compile DLL
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- run: |
|
||||||
|
apt-get update && apt-get install -y build-essential cmake g++ python3-dev
|
||||||
|
- run: |
|
||||||
|
git clone https://github.com/swigger/wechat-ocr.git wcocr
|
||||||
|
- run: |
|
||||||
|
# fix: https://github.com/abseil/abseil-cpp/issues/1206
|
||||||
|
sed -i 's/v3.21.0/v3.21.2/g' wcocr/CMakeLists.txt
|
||||||
|
- run: |
|
||||||
|
mkdir -p wcocr/build && cd wcocr/build && cmake .. && make -j$(nproc)
|
||||||
|
- name: Upload artifacts
|
||||||
|
uses: christopherhx/gitea-upload-artifact@v4 # actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: libwcocr
|
||||||
|
path: wcocr/build/libwcocr.so
|
||||||
|
|
||||||
36
.gitignore
vendored
Normal file
36
.gitignore
vendored
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
# dependencies (bun install)
|
||||||
|
node_modules
|
||||||
|
|
||||||
|
# output
|
||||||
|
out
|
||||||
|
dist
|
||||||
|
*.tgz
|
||||||
|
|
||||||
|
# code coverage
|
||||||
|
coverage
|
||||||
|
*.lcov
|
||||||
|
|
||||||
|
# logs
|
||||||
|
logs
|
||||||
|
_.log
|
||||||
|
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
|
||||||
|
|
||||||
|
# dotenv environment variable files
|
||||||
|
.env
|
||||||
|
.env.development.local
|
||||||
|
.env.test.local
|
||||||
|
.env.production.local
|
||||||
|
.env.local
|
||||||
|
|
||||||
|
# caches
|
||||||
|
.eslintcache
|
||||||
|
.cache
|
||||||
|
*.tsbuildinfo
|
||||||
|
|
||||||
|
# IntelliJ based IDEs
|
||||||
|
.idea
|
||||||
|
|
||||||
|
# Finder (MacOS) folder config
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
libwcocr.so
|
||||||
15
README.md
Normal file
15
README.md
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# wxocr
|
||||||
|
|
||||||
|
To install dependencies:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bun install
|
||||||
|
```
|
||||||
|
|
||||||
|
To run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bun run index.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
This project was created using `bun init` in bun v1.2.18. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime.
|
||||||
29
bun.lock
Normal file
29
bun.lock
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"lockfileVersion": 1,
|
||||||
|
"workspaces": {
|
||||||
|
"": {
|
||||||
|
"name": "wxocr",
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/bun": "latest",
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"typescript": "^5",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"packages": {
|
||||||
|
"@types/bun": ["@types/bun@1.2.18", "", { "dependencies": { "bun-types": "1.2.18" } }, "sha512-Xf6RaWVheyemaThV0kUfaAUvCNokFr+bH8Jxp+tTZfx7dAPA8z9ePnP9S9+Vspzuxxx9JRAXhnyccRj3GyCMdQ=="],
|
||||||
|
|
||||||
|
"@types/node": ["@types/node@24.0.10", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ENHwaH+JIRTDIEEbDK6QSQntAYGtbvdDXnMXnZaZ6k13Du1dPMmprkEHIL7ok2Wl2aZevetwTAb5S+7yIF+enA=="],
|
||||||
|
|
||||||
|
"@types/react": ["@types/react@19.1.8", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-AwAfQ2Wa5bCx9WP8nZL2uMZWod7J7/JSplxbTmBQ5ms6QpqNYm672H0Vu9ZVKVngQ+ii4R/byguVEUZQyeg44g=="],
|
||||||
|
|
||||||
|
"bun-types": ["bun-types@1.2.18", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-04+Eha5NP7Z0A9YgDAzMk5PHR16ZuLVa83b26kH5+cp1qZW4F6FmAURngE7INf4tKOvCE69vYvDEwoNl1tGiWw=="],
|
||||||
|
|
||||||
|
"csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
|
||||||
|
|
||||||
|
"typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="],
|
||||||
|
|
||||||
|
"undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="],
|
||||||
|
}
|
||||||
|
}
|
||||||
14
package.json
Normal file
14
package.json
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"name": "wxocr",
|
||||||
|
"type": "module",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"start": "bun run src/index.ts"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/bun": "latest"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"typescript": "^5"
|
||||||
|
}
|
||||||
|
}
|
||||||
76
src/index.ts
Normal file
76
src/index.ts
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
import { CString, dlopen, FFIType, JSCallback, suffix, type Pointer } from "bun:ffi";
|
||||||
|
|
||||||
|
const libPath = `libwcocr.${suffix}`;
|
||||||
|
|
||||||
|
const WechatOCR = dlopen(libPath, {
|
||||||
|
wechat_ocr: {
|
||||||
|
args: [
|
||||||
|
FFIType.cstring, // ocr_exe路径
|
||||||
|
FFIType.cstring, // wechat_dir路径
|
||||||
|
FFIType.cstring, // imgfn路径
|
||||||
|
FFIType.function, // 回调函数指针
|
||||||
|
],
|
||||||
|
returns: FFIType.bool, // 返回布尔值
|
||||||
|
},
|
||||||
|
stop_ocr: {
|
||||||
|
args: [],
|
||||||
|
returns: FFIType.void, // 无返回值
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// 主函数
|
||||||
|
async function callWechatOcr(
|
||||||
|
ocrExe: string,
|
||||||
|
wechatDir: string,
|
||||||
|
imgfn: string
|
||||||
|
): Promise<string> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
// 创建回调函数
|
||||||
|
const callback = new JSCallback(
|
||||||
|
(argPtr: Pointer) => {
|
||||||
|
const arg = new CString(argPtr).toString();
|
||||||
|
resolve(arg);
|
||||||
|
callback.close(); // 释放回调
|
||||||
|
},
|
||||||
|
{
|
||||||
|
args: [FFIType.ptr],
|
||||||
|
returns: FFIType.void,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// 调用wechat_ocr函数
|
||||||
|
const result = WechatOCR.symbols.wechat_ocr(
|
||||||
|
Buffer.from(ocrExe + "\0"), // 转换为C字符串
|
||||||
|
Buffer.from(wechatDir + "\0"),
|
||||||
|
Buffer.from(imgfn + "\0"),
|
||||||
|
callback // 直接传递JSCallback实例
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
callback.close();
|
||||||
|
reject(new Error("OCR调用失败"));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
// 请在这里替换为你的实际路径
|
||||||
|
const ocrExe = "/opt/wechat/wxocr";
|
||||||
|
const wechatDir = "/opt/wechat";
|
||||||
|
const imgfn = "/home/imbytecat/Pictures/Screenshots/Screenshot_07-Jul_10-00-20_9907.png";
|
||||||
|
|
||||||
|
console.log("OCR开始...");
|
||||||
|
try {
|
||||||
|
const result = await callWechatOcr(ocrExe, wechatDir, imgfn);
|
||||||
|
console.log("OCR结果:", result);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("OCR错误:", error);
|
||||||
|
} finally {
|
||||||
|
// 清理资源
|
||||||
|
WechatOCR.symbols.stop_ocr();
|
||||||
|
console.log("OCR结束...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 运行主函数
|
||||||
|
main();
|
||||||
29
tsconfig.json
Normal file
29
tsconfig.json
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
// Environment setup & latest features
|
||||||
|
"lib": ["ESNext"],
|
||||||
|
"target": "ESNext",
|
||||||
|
"module": "Preserve",
|
||||||
|
"moduleDetection": "force",
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"allowJs": true,
|
||||||
|
|
||||||
|
// Bundler mode
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"allowImportingTsExtensions": true,
|
||||||
|
"verbatimModuleSyntax": true,
|
||||||
|
"noEmit": true,
|
||||||
|
|
||||||
|
// Best practices
|
||||||
|
"strict": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"noUncheckedIndexedAccess": true,
|
||||||
|
"noImplicitOverride": true,
|
||||||
|
|
||||||
|
// Some stricter flags (disabled by default)
|
||||||
|
"noUnusedLocals": false,
|
||||||
|
"noUnusedParameters": false,
|
||||||
|
"noPropertyAccessFromIndexSignature": false
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user