欢迎加入开源鸿蒙 PC社区https://harmonypc.csdn.net/效果截图第6篇百度OCR手写识别接入系列教程导航篇号标题状态01环境搭建与项目创建✅02数据模型与单词仓库✅03主入口页面与导航结构✅04极速划词页面实现✅05手写画布实现✅06百度OCR手写识别接入本篇07答案比对与反馈UI下一篇08单词切换与底部导航09词根分解与水印展示10项目总结与优化方向源码仓库https://atomgit.com/qq_33247427/englishProject一、为什么选择百度 OCR1.1 华为端侧 OCR 的问题HarmonyOS 提供了kit.CoreVisionKit的textRecognitionAPI理论上可以在设备端完成文字识别无需网络。但在实际开发中遇到了两个严重问题问题错误信息原因服务未初始化“The service is abnormal”需要先调用init()识别超时“Run timed out, please try again later”PixelMap 太大端侧推理超时即使加了init()和图片缩放在部分真机上仍然不稳定。1.2 百度手写 OCR 的优势对比项华为 CoreVisionKit百度手写 OCR网络依赖无端侧需要网络稳定性部分设备超时稳定可靠手写识别质量一般专门针对手写优化首次使用需下载模型即用免费额度无限每天 500 次足够开发测试响应速度不稳定通常 1-2 秒1.3 百度 OCR 申请步骤注册 百度智能云账号进入控制台 → 文字识别 → 创建应用勾选「手写文字识别」能力获取API Key和Secret Key二、网络权限配置百度 OCR 需要网络请求必须在module.json5中声明权限{ module: { requestPermissions: [ { name: ohos.permission.INTERNET } ] } }HarmonyOS 的INTERNET权限属于系统授权权限声明即可使用不需要动态申请。三、BaiduOCRService 完整实现3.1 文件结构创建electron/src/main/ets/services/BaiduOCRService.etsimport{image}fromkit.ImageKit;import{util}fromkit.ArkTS;import{http}fromkit.NetworkKit;constAPI_KEYyour_api_key_here;constSECRET_KEYyour_secret_key_here;letcachedToken:string;3.2 获取 Access Token百度 API 使用 OAuth 2.0 认证需要先用 API Key Secret Key 换取 Access TokenasyncfunctiongetAccessToken():Promisestring{// Token 缓存避免重复请求if(cachedToken){returncachedToken;}consturlhttps://aip.baidubce.com/oauth/2.0/token?grant_typeclient_credentialsclient_id${API_KEY}client_secret${SECRET_KEY};constreqhttp.createHttp();try{constrespawaitreq.request(url,{method:http.RequestMethod.POST});constdataJSON.parse(resp.resultasstring)asRecordstring,string;cachedTokendata[access_token];console.log(BaiduOCR token 获取成功);returncachedToken;}finally{req.destroy();// 必须销毁否则内存泄漏}}关键点Token 有效期 30 天缓存后不需要每次都请求http.createHttp()创建的实例用完必须destroy()生产环境应该把 Key 放在服务端不要硬编码在客户端3.3 PixelMap 转 Base64百度 OCR 接受 Base64 编码的图片asyncfunctionpixelMapToBase64(pixelMap:image.PixelMap):Promisestring{constpackerimage.createImagePacker();try{// 将 PixelMap 编码为 JPEG比 PNG 小很多constbufferawaitpacker.packing(pixelMap,{format:image/jpeg,quality:90// 90% 质量平衡大小和清晰度});// ArrayBuffer → Uint8Array → Base64 字符串consthelpernewutil.Base64Helper();constuint8newUint8Array(buffer);constb64helper.encodeToStringSync(uint8);returnb64;}finally{packer.release();// 释放 packer 资源}}为什么用 JPEG 而不是 PNG手写内容是黑白线条JPEG 90% 质量足够清晰JPEG 文件通常比 PNG 小 3-5 倍上传更快百度 API 有请求体大小限制4MB3.4 英文手写识别exportasyncfunctionbaiduOCRRecognize(pixelMap:image.PixelMap):Promisestring{try{constbase64awaitpixelMapToBase64(pixelMap);consttokenawaitgetAccessToken();// 百度手写文字识别接口consturlhttps://aip.baidubce.com/rest/2.0/ocr/v1/handwriting?access_token${token};constbodyimage${encodeURIComponent(base64)};constreqhttp.createHttp();try{constrespawaitreq.request(url,{method:http.RequestMethod.POST,header:{Content-Type:application/x-www-form-urlencoded},extraData:body});constresultJSON.parse(resp.resultasstring)asRecordstring,Object;constwordsResultresult[words_result]asArrayRecordstring,string;if(wordsResultwordsResult.length0){// 清洗结果只保留英文字母和空格consttokenswordsResult.map((w:Recordstring,string)w[words].replace(/[^a-zA-Z\s]/g,).trim().toLowerCase()).filter((s:string)s.length0);if(tokens.length0)return;// 去重水印和手写可能被重复识别constseennewSetstring();constunique:string[][];for(consttoftokens){if(!seen.has(t)){seen.add(t);unique.push(t);}}returnunique.join( ).trim();}return;}finally{req.destroy();}}catch(e){console.error(BaiduOCR 识别失败:,JSON.stringify(e));return;}}3.5 中文手写识别exportasyncfunctionbaiduOCRRecognizeChinese(pixelMap:image.PixelMap):Promisestring{try{constbase64awaitpixelMapToBase64(pixelMap);consttokenawaitgetAccessToken();consturlhttps://aip.baidubce.com/rest/2.0/ocr/v1/handwriting?access_token${token};constbodyimage${encodeURIComponent(base64)};constreqhttp.createHttp();try{constrespawaitreq.request(url,{method:http.RequestMethod.POST,header:{Content-Type:application/x-www-form-urlencoded},extraData:body});constresultJSON.parse(resp.resultasstring)asRecordstring,Object;constwordsResultresult[words_result]asArrayRecordstring,string;if(wordsResultwordsResult.length0){// 只保留中文字符returnwordsResult.map((w:Recordstring,string)w[words].replace(/[^\u4e00-\u9fa5]/g,).trim()).filter((s:string)s.length0).join();}return;}finally{req.destroy();}}catch(e){console.error(BaiduOCR 中文识别失败:,JSON.stringify(e));return;}}四、在页面中调用4.1 导入服务import{componentSnapshot}fromkit.ArkUI;import{image}fromkit.ImageKit;import{baiduOCRRecognize,baiduOCRRecognizeChinese}from../services/BaiduOCRService;4.2 doRecognize 方法asyncdoRecognize(){if(this.isRecognizing||this.currentWordnull){return;}this.isRecognizingtrue;this.feedbackText识别中…;this.feedbackColor#6B7280;try{// 1. 截取画布组件为 PixelMapconstpixelMap:image.PixelMapawaitcomponentSnapshot.get(speedDictCanvas);// 2. 调用百度 OCRconsttextawaitbaiduOCRRecognize(pixelMap);// 3. 比对答案this.recognizedTexttext;this.checkAnswer(text);}catch(e){consterreasRecordstring,string;this.feedbackText识别失败(err[message]??);this.feedbackColor#B5533C;}this.isRecognizingfalse;}4.3 Loading 状态识别过程需要 1-2 秒用State isRecognizing控制按钮状态Button(){Row({space:4}){if(this.isRecognizing){LoadingProgress().width(14).height(14).color(#FFFFFF)}Text(this.isRecognizing?识别中:识别).fontSize(13).fontColor(#FFFFFF)}}.enabled(!this.isRecognizing)// 识别中禁用按钮五、API 响应格式百度手写 OCR 返回的 JSON 格式{log_id:1234567890,words_result_num:2,words_result:[{words:apple},{words:Apple}]}words_result识别到的文字块数组每个块的words字段是识别出的文字手写体可能被分成多个块多行书写水印文字也可能被识别到需要去重六、结果清洗策略6.1 为什么需要清洗百度 OCR 会识别画布上所有可见文字包括用户手写的内容我们需要的水印文字需要过滤或去重误识别的噪点6.2 清洗流程原始结果 → 去除非字母字符 → 转小写 → 去空格 → 去重 → 拼接示例输入: [Apple, apple, app le] 处理: [apple, apple, app le] → 去非字母 → [apple, apple, apple] 去重: [apple] 输出: apple七、错误处理7.1 常见错误错误码含义处理方式110Access Token 无效清除缓存重新获取216201图片为空提示用户先书写17每日调用量超限提示明天再试网络错误无网络提示检查网络7.2 容错代码try{consttextawaitbaiduOCRRecognize(pixelMap);// ...}catch(e){consterreasRecordstring,string;this.feedbackText识别失败(err[message]??网络异常);this.feedbackColor#B5533C;}八、本篇小结通过本篇教程我们完成了理解了选择百度 OCR 的原因端侧 OCR 不稳定完成了百度 OCR 服务申请和权限配置实现了 BaiduOCRServiceToken 缓存 PixelMap 转 Base64 API 调用掌握了 componentSnapshot 截图 OCR 的完整链路实现了识别结果清洗和去重处理了 Loading 状态和错误情况下一篇预告第 7 篇答案比对与反馈 UI— 我们将实现识别结果与正确答案的比对逻辑以及画布上的大字体反馈浮层。