package com.ruoyi.system.utils; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.baidu.aip.ocr.AipOcr; import com.ruoyi.system.config.BaiduOCRConfig; import lombok.extern.slf4j.Slf4j; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.io.File; import java.util.HashMap; import java.util.Map; /** * 百度OCR工具类 * 使用百度AI开放平台的OCR服务进行文字识别 * 支持通用文字识别、手写体识别等多种识别类型 * * 使用示例: * // 通用文字识别 * JSONObject result = BaiduOCRUtil.generalRecognize("path/to/image.jpg"); * * // 手写体识别 * JSONObject result = BaiduOCRUtil.handwritingRecognize("path/to/image.jpg"); */ @Component @Slf4j public class BaiduOCRUtil { private static BaiduOCRConfig staticBaiduOcrConfig; @Autowired public void setBaiduOcrConfig(BaiduOCRConfig baiduOcrConfig) { BaiduOCRUtil.staticBaiduOcrConfig = baiduOcrConfig; } /** * 获取百度OCR客户端实例 * @return AipOcr客户端实例 */ private static AipOcr getClient() { AipOcr client = new AipOcr(staticBaiduOcrConfig.getAppId(), staticBaiduOcrConfig.getApiKey(), staticBaiduOcrConfig.getSecretKey()); // 设置连接超时时间和socket超时时间 client.setConnectionTimeoutInMillis(2000); client.setSocketTimeoutInMillis(60000); return client; } /** * 通用文字识别(图片路径) * @param imagePath 图片路径 * @return 识别结果 */ public static JSONObject generalRecognize(String imagePath) { try { AipOcr client = getClient(); // 参数为图片路径 HashMap options = new HashMap(); options.put("language_type", "CHN_ENG"); // 识别语言类型 options.put("detect_direction", "true"); // 是否检测图像朝向 options.put("detect_language", "true"); // 是否检测语言 options.put("probability", "true"); // 是否返回识别结果中每一行的置信度 org.json.JSONObject res = client.basicGeneral(imagePath, options); log.info("百度OCR通用文字识别成功,图片路径: {}", imagePath); JSONObject result = new JSONObject(); result.put("success", true); result.put("data", JSON.parseObject(res.toString())); result.put("content", extractContentFromBaiduResult(JSON.parseObject(res.toString()))); return result; } catch (Exception e) { log.error("百度OCR通用文字识别失败: {}", e.getMessage(), e); JSONObject errorResult = new JSONObject(); errorResult.put("success", false); errorResult.put("error", e.getMessage()); return errorResult; } } /** * 通用文字识别(文件对象) * @param imageFile 图片文件对象 * @return 识别结果 */ public static JSONObject generalRecognize(File imageFile) { try { AipOcr client = getClient(); // 参数为图片文件 HashMap options = new HashMap(); options.put("language_type", "CHN_ENG"); options.put("detect_direction", "true"); options.put("detect_language", "true"); options.put("probability", "true"); // 读取文件字节数组或使用文件路径 org.json.JSONObject res = client.basicGeneral(imageFile.getAbsolutePath(), options); log.info("百度OCR通用文字识别成功,文件名: {}", imageFile.getName()); JSONObject result = new JSONObject(); result.put("success", true); result.put("data", JSON.parseObject(res.toString())); result.put("content", extractContentFromBaiduResult(JSON.parseObject(res.toString()))); return result; } catch (Exception e) { log.error("百度OCR通用文字识别失败: {}", e.getMessage(), e); JSONObject errorResult = new JSONObject(); errorResult.put("success", false); errorResult.put("error", e.getMessage()); return errorResult; } } /** * 通用文字识别(图片字节数组) * @param imageBytes 图片字节数组 * @return 识别结果 */ public static JSONObject generalRecognize(byte[] imageBytes) { try { AipOcr client = getClient(); HashMap options = new HashMap(); options.put("language_type", "CHN_ENG"); options.put("detect_direction", "true"); options.put("detect_language", "true"); options.put("probability", "true"); org.json.JSONObject res = client.basicGeneral(imageBytes, options); log.info("百度OCR通用文字识别成功,字节数组长度: {}", imageBytes.length); JSONObject result = new JSONObject(); result.put("success", true); result.put("data", JSON.parseObject(res.toString())); result.put("content", extractContentFromBaiduResult(JSON.parseObject(res.toString()))); return result; } catch (Exception e) { log.error("百度OCR通用文字识别失败: {}", e.getMessage(), e); JSONObject errorResult = new JSONObject(); errorResult.put("success", false); errorResult.put("error", e.getMessage()); return errorResult; } } /** * 高精度文字识别 * @param imagePath 图片路径 * @return 识别结果 */ public static JSONObject accurateRecognize(String imagePath) { try { AipOcr client = getClient(); HashMap options = new HashMap(); options.put("recognize_granularity", "big"); // 是否定位单字符位置 options.put("language_type", "CHN_ENG"); options.put("detect_direction", "true"); options.put("detect_language", "true"); options.put("vertexes_location", "true"); // 是否返回文字外接多边形顶点位置 options.put("probability", "true"); org.json.JSONObject res = client.accurateGeneral(imagePath, options); log.info("百度OCR高精度文字识别成功,图片路径: {}", imagePath); JSONObject result = new JSONObject(); result.put("success", true); result.put("data", JSON.parseObject(res.toString())); result.put("content", extractContentFromBaiduResult(JSON.parseObject(res.toString()))); return result; } catch (Exception e) { log.error("百度OCR高精度文字识别失败: {}", e.getMessage(), e); JSONObject errorResult = new JSONObject(); errorResult.put("success", false); errorResult.put("error", e.getMessage()); return errorResult; } } /** * 手写体识别 * @param imagePath 图片路径 * @return 识别结果 */ public static JSONObject handwritingRecognize(String imagePath) { try { AipOcr client = getClient(); // 手写体识别参数 HashMap options = new HashMap(); options.put("language_type", "CHN_ENG"); org.json.JSONObject res = client.handwriting(imagePath, options); log.info("百度OCR手写体识别成功,图片路径: {}", imagePath); JSONObject result = new JSONObject(); result.put("success", true); result.put("data", JSON.parseObject(res.toString())); result.put("content", extractContentFromBaiduResult(JSON.parseObject(res.toString()))); return result; } catch (Exception e) { log.error("百度OCR手写体识别失败: {}", e.getMessage(), e); JSONObject errorResult = new JSONObject(); errorResult.put("success", false); errorResult.put("error", e.getMessage()); return errorResult; } } /** * 手写体识别(文件对象) * @param imageFile 图片文件对象 * @return 识别结果 */ public static JSONObject handwritingRecognize(File imageFile) { try { AipOcr client = getClient(); HashMap options = new HashMap(); options.put("language_type", "CHN_ENG"); org.json.JSONObject res = client.handwriting(imageFile.getAbsolutePath(), options); log.info("百度OCR手写体识别成功,文件名: {}", imageFile.getName()); JSONObject result = new JSONObject(); result.put("success", true); result.put("data", JSON.parseObject(res.toString())); result.put("content", extractContentFromBaiduResult(JSON.parseObject(res.toString()))); return result; } catch (Exception e) { log.error("百度OCR手写体识别失败: {}", e.getMessage(), e); JSONObject errorResult = new JSONObject(); errorResult.put("success", false); errorResult.put("error", e.getMessage()); return errorResult; } } /** * 身份证识别 * @param imagePath 图片路径 * @param isFront true为正面,false为反面 * @return 识别结果 */ public static JSONObject idCardRecognize(String imagePath, boolean isFront) { try { AipOcr client = getClient(); HashMap options = new HashMap(); String idCardSide = isFront ? "front" : "back"; org.json.JSONObject res = client.idcard(imagePath, idCardSide, options); log.info("百度OCR身份证识别成功,图片路径: {},方向: {}", imagePath, idCardSide); JSONObject result = new JSONObject(); result.put("success", true); result.put("data", JSON.parseObject(res.toString())); return result; } catch (Exception e) { log.error("百度OCR身份证识别失败: {}", e.getMessage(), e); JSONObject errorResult = new JSONObject(); errorResult.put("success", false); errorResult.put("error", e.getMessage()); return errorResult; } } /** * 银行卡识别 * @param imagePath 图片路径 * @return 识别结果 */ public static JSONObject bankCardRecognize(String imagePath) { try { AipOcr client = getClient(); org.json.JSONObject res = client.bankcard(imagePath, new HashMap()); log.info("百度OCR银行卡识别成功,图片路径: {}", imagePath); JSONObject result = new JSONObject(); result.put("success", true); result.put("data", JSON.parseObject(res.toString())); return result; } catch (Exception e) { log.error("百度OCR银行卡识别失败: {}", e.getMessage(), e); JSONObject errorResult = new JSONObject(); errorResult.put("success", false); errorResult.put("error", e.getMessage()); return errorResult; } } /** * 营业执照识别 * @param imagePath 图片路径 * @return 识别结果 */ public static JSONObject businessLicenseRecognize(String imagePath) { try { AipOcr client = getClient(); HashMap options = new HashMap(); org.json.JSONObject res = client.businessLicense(imagePath, options); log.info("百度OCR营业执照识别成功,图片路径: {}", imagePath); JSONObject result = new JSONObject(); result.put("success", true); result.put("data", JSON.parseObject(res.toString())); return result; } catch (Exception e) { log.error("百度OCR营业执照识别失败: {}", e.getMessage(), e); JSONObject errorResult = new JSONObject(); errorResult.put("success", false); errorResult.put("error", e.getMessage()); return errorResult; } } /** * 从百度OCR结果中提取文本内容 * @param result 百度OCR返回的结果(fastjson格式) * @return 提取的文本内容 */ private static String extractContentFromBaiduResult(JSONObject result) { StringBuilder content = new StringBuilder(); if (result.containsKey("words_result") && result.getJSONArray("words_result") != null) { JSONArray wordsResult = result.getJSONArray("words_result"); for (int i = 0; i < wordsResult.size(); i++) { JSONObject wordResult = wordsResult.getJSONObject(i); if (wordResult.containsKey("words")) { content.append(wordResult.getString("words")).append("\n"); } } } return content.toString().trim(); } /** * 从识别结果中提取目标字段(金额、日期、备注等) * @param ocrResult OCR识别的原始结果 * @return 提取后的目标字段 */ public static java.util.Map extractTargetFields(JSONObject ocrResult) { java.util.Map extracted = new java.util.HashMap<>(); // 校验OCR结果是否有效 if (!ocrResult.containsKey("success") || !ocrResult.getBooleanValue("success")) { extracted.put("error", ocrResult.getString("error")); return extracted; } // 获取识别的文字内容 String content = ocrResult.getString("content"); if (content == null || content.isEmpty()) { extracted.put("error", "OCR识别结果为空"); return extracted; } // 在内容中查找特定关键词 String[] lines = content.split("\n"); for (String line : lines) { line = line.trim(); // 查找金额相关信息 if (line.contains("金额") || line.contains("合计") || line.contains("总计") || line.matches(".*\\d+\\.\\d{2}.*")) { if (!extracted.containsKey("totalAmount")) { extracted.put("totalAmount", line); } } // 查找日期相关信息 if (line.contains("日期") || line.matches(".*\\d{4}[-/年]\\d{1,2}[-/月]\\d{1,2}.*")) { if (!extracted.containsKey("date")) { extracted.put("date", line); } } // 查找备注相关信息 if (line.contains("备注") || line.contains("说明")) { if (!extracted.containsKey("remark")) { extracted.put("remark", line); } } } // 如果没有找到特定字段,返回全文 if (extracted.isEmpty()) { extracted.put("fullText", content); } return extracted; } }