本地微信OCR的js版本来源
发现有 大神 逆向微信自带的OCR功能。最后看了半天用到了另一个 大神 帮你简化后的ddl,其实这位大佬用到了另一位 大佬 项目里src里面的c#编译出来的函数,里面的wechat_ocr函数可以用来控制微信自带的mmmojo.dll和wechatOrc.exe。
而mmmojo.dll和wechatOrc.exe是用来调用微信OCR最重要的两个文件,PS:微信自带的。
废话不多说,直接展示代码,不过在展示代码之前,我们需要配置一些基本的环境,特别是里面的node-gyp,它允许使用C++/C等底层语言编写的模块在Node.js环境中运行,但是安装它有点费劲,下面是我的配置 (可能是这个项目我做下来其中最麻烦的之一)
关键的一步就是可以安装好ffi-napi就好了,ffi-napi可以加载并使用本地的动态链接库或共享对象,实现与现有的C/C++代码的集成。
进入代码阶段
在上述环境搞好的情况下,本身其实js代码很简单的,就是加载好大佬给封装好的wcocr.ddl,确定自己mmmojo.ddl这个文件的所在路径和wechatOrc.exe的路径就好了。如下:
const wechatDir = "D:\\normalLife\\WeChat\\[3.9.12.29]";
const ocrExe = "C:\\Users\\98178\\AppData\\Roaming\\Tencent\\WeChat\\XPlugin\\Plugins\\WeChatOCR\\7079\\extracted\\WeChatOCR.exe";
完整代码如下:
const ffi = require('ffi-napi');
const ref = require('ref-napi');
const wchar = require('ref-wchar-napi');
const { promisify } = require('util');
const path = require('path');
// Define the DLL interface with absolute path
const WechatOCR = ffi.Library(path.join(__dirname, 'wcocr.dll'), {
'wechat_ocr': ['bool', [
wchar.string, // ocrExeWStr
wchar.string, // wechatDirWStr
'string', // imgFn
'pointer' // callback
]],
});
async function performOCR(ocrExePath, wechatDirPath, imagePath) {
console.log("Starting OCR process...");
return new Promise((resolve, reject) => {
try {
// 验证DLL是否正确加载
if (!WechatOCR || !WechatOCR.wechat_ocr) {
throw new Error("DLL not properly loaded");
}
// 检查文件路径是否都是字符串类型
console.log("Checking parameters types:", {
ocrExePath: typeof ocrExePath,
wechatDirPath: typeof wechatDirPath,
imagePath: typeof imagePath
});
const callback = ffi.Callback('void', ['string'], (result) => {
if (!result) {
reject(new Error("OCR result is empty"));
return;
}
resolve(result);
});
try {
console.log("Attempting to call DLL function...");
const success = WechatOCR.wechat_ocr(
ocrExePath,
wechatDirPath,
imagePath,
callback
);
console.log("OCR function call returned:", success);
if (!success) {
// 更详细的错误信息
const error = new Error("OCR initialization failed");
error.details = {
ocrExePath,
wechatDirPath,
imagePath
};
reject(error);
}
} catch (dllError) {
console.error("DLL call failed with error:", {
message: dllError.message,
code: dllError.code,
stack: dllError.stack
});
reject(dllError);
}
} catch (error) {
console.error("Error in performOCR:", error);
reject(error);
}
});
}
async function main() {
try {
console.log("OCR begin...");
// 替换成你自己本地的
const ocrExe = "C:\\Users\\98178\\AppData\\Roaming\\Tencent\\WeChat\\XPlugin\\Plugins\\WeChatOCR\\7079\\extracted\\WeChatOCR.exe";
const wechatDir = "D:\\normalLife\\WeChat\\[3.9.12.29]";
// 替换成你自己的图片路径或者直接用我的demo图片
const testImage = "C:\\Users\\98178\\Pictures\\Screenshots\\屏幕截图 2024-11-10 203019.png";
// Verify if files exist
const fs = require('fs');
[ocrExe, wechatDir, testImage].forEach(path => {
if (!fs.existsSync(path)) {
throw new Error(`Path does not exist: ${path}`);
}
});
const result = await performOCR(ocrExe, wechatDir, testImage);
// console.log("OCR result:", result);
const {ocr_response} = JSON.parse(result);
const combinedText = ocr_response
.sort((a, b) => a.top - b.top) // 按照 top 坐标排序,确保文本顺序从上到下
.map(item => item.text) // 提取所有的 text 字段
.join('\n'); // 用换行符连接所有文本
console.log("Combined text:");
console.log(combinedText);
console.log("OCR end...");
} catch (error) {
console.error("Error in main:", error);
}
}
// Run the main function
main().catch(console.error);
exports.performOCR = performOCR;
这里有一个点:
就是下面这段代码,我一开始ddl总是调用出现问题,说是初始化有问题,后来问了好久copilot才发现,是wcocr.dll里面的wechat_ocr的前两个入参是用unicode的格式,直接写string是不行的,后来搞了半天才发现,换了格式后,一下子就可以了。
const WechatOCR = ffi.Library(path.join(__dirname, 'wcocr.dll'), {
'wechat_ocr': ['bool', [
wchar.string, // ocrExeWStr
wchar.string, // wechatDirWStr
'string', // imgFn
'pointer' // callback
]],
});
最后就是直接运行这个js,就可以把你的图片中的文字提取出来了,效果图如下:
可以看到效果还是非常不错的。