From 9ba62443b52d2baf99f9f9cee59651604199896d Mon Sep 17 00:00:00 2001 From: rochy_he Date: Sun, 30 Jun 2019 03:31:28 +0800 Subject: [PATCH] add BaiDu OCR interface --- readme.md | 4 +- src/main/java/com/luooqi/ocr/MainFm.java | 2 +- .../java/com/luooqi/ocr/utils/OcrUtils.java | 76 ++++++++++++++++++- 3 files changed, 78 insertions(+), 4 deletions(-) diff --git a/readme.md b/readme.md index 646e3c4..b2c88eb 100644 --- a/readme.md +++ b/readme.md @@ -1,8 +1,7 @@ ## 树洞 OCR 文字识别 一款跨平台的 OCR 小工具 -百度网盘:[https://pan.baidu.com/s/1gVVQ58fZ8ori-O7rWKpRPQ](https://pan.baidu.com/s/1gVVQ58fZ8ori-O7rWKpRPQ) -提取码:m6d8 +下载地址:[百度网盘](https://pan.baidu.com/s/1gVVQ58fZ8ori-O7rWKpRPQ) 提取码:`m6d8` > - `xxx-with-jre.xx` 是完整版,带运行环境;如果精简版不能正常工作,请下载完整版使用; > - 文字识别使用了各云平台开发的识别接口,因此需要联网才能正常使用; @@ -38,6 +37,7 @@ - [x] 识别结果文本对齐(暂未实现多分栏) - [x] 全屏模式下截图 - [x] 添加正在识别动画 + - [x] 多屏支持 - [ ] 文本翻译 - [ ] 公式识别 - [ ] 表格识别 diff --git a/src/main/java/com/luooqi/ocr/MainFm.java b/src/main/java/com/luooqi/ocr/MainFm.java index 26fe0cb..3882e50 100644 --- a/src/main/java/com/luooqi/ocr/MainFm.java +++ b/src/main/java/com/luooqi/ocr/MainFm.java @@ -182,7 +182,7 @@ public static void doOcr(BufferedImage image){ processController.show(); Thread ocrThread = new Thread(()->{ byte[] bytes = CommUtils.imageToBytes(image); - String text = OcrUtils.sogouWebOcr(bytes); + String text = OcrUtils.ocrImg(bytes); Platform.runLater(()-> { processController.close(); textArea.setText(text); diff --git a/src/main/java/com/luooqi/ocr/utils/OcrUtils.java b/src/main/java/com/luooqi/ocr/utils/OcrUtils.java index 8dfbdc7..31e3991 100644 --- a/src/main/java/com/luooqi/ocr/utils/OcrUtils.java +++ b/src/main/java/com/luooqi/ocr/utils/OcrUtils.java @@ -1,8 +1,10 @@ package com.luooqi.ocr.utils; import cn.hutool.core.codec.Base64; +import cn.hutool.core.lang.UUID; import cn.hutool.core.util.CharsetUtil; import cn.hutool.core.util.StrUtil; +import cn.hutool.core.util.URLUtil; import cn.hutool.crypto.SecureUtil; import cn.hutool.http.HttpRequest; import cn.hutool.http.HttpResponse; @@ -12,7 +14,9 @@ import cn.hutool.json.JSONUtil; import com.luooqi.ocr.model.TextBlock; +import java.awt.*; import java.util.*; +import java.util.List; /** * tools-ocr @@ -20,6 +24,46 @@ */ public class OcrUtils { + public static String ocrImg(byte[] imgData) { + int i = Math.abs(UUID.randomUUID().hashCode()) % 4; + switch (i){ + case 0: + return bdGeneralOcr(imgData); + case 1: + return bdAccurateOcr(imgData); + case 2: + return sogouMobileOcr(imgData); + default: + return sogouWebOcr(imgData); + } + } + + private static String bdGeneralOcr(byte[] imgData){ + return bdBaseOcr(imgData, "general_location"); + } + + private static String bdAccurateOcr(byte[] imgData){ + return bdBaseOcr(imgData, "https://aip.baidubce.com/rest/2.0/ocr/v1/accurate"); + } + + private static String bdBaseOcr(byte[] imgData, String type){ + String[] urlArr = new String[]{"http://ai.baidu.com/tech/ocr/general", "http://ai.baidu.com/index/seccode?action=show"}; + StringBuilder cookie = new StringBuilder(); + for (String url : urlArr) { + HttpResponse cookieResp = WebUtils.get(url); + List ckList = cookieResp.headerList("Set-Cookie"); + for (String s : ckList) { + cookie.append(s.replaceAll("expires[\\S\\s]+", "")); + } + } + HashMap header = new HashMap<>(); + header.put("Referer", "http://ai.baidu.com/tech/ocr/general"); + header.put("Cookie", cookie.toString()); + String data = "type="+URLUtil.encodeQuery(type)+"&detect_direction=false&image_url&image=" + URLUtil.encodeQuery("data:image/jpeg;base64," + Base64.encode(imgData)) + "&language_type=CHN_ENG"; + HttpResponse response = WebUtils.postRaw("http://ai.baidu.com/aidemo", data, 0, header); + return extractBdResult(WebUtils.getSafeHtml(response)); + } + public static String sogouMobileOcr(byte[] imgData) { String boundary = "------WebKitFormBoundary8orYTmcj8BHvQpVU"; String url = "http://ocr.shouji.sogou.com/v2/ocr/json"; @@ -59,7 +103,7 @@ private static String extractSogouResult(String html) { } JSONArray jsonArray = jsonObject.getJSONArray("result"); List textBlocks = new ArrayList<>(); - boolean isEng = false; + boolean isEng; for (int i = 0; i < jsonArray.size(); i++) { JSONObject jObj = jsonArray.getJSONObject(i); TextBlock textBlock = new TextBlock(); @@ -76,4 +120,34 @@ private static String extractSogouResult(String html) { return CommUtils.combineTextBlocks(textBlocks, isEng); } + private static String extractBdResult(String html) { + if (StrUtil.isBlank(html)) { + return ""; + } + JSONObject jsonObject = JSONUtil.parseObj(html); + if (jsonObject.getInt("errno", 0) != 0) { + return ""; + } + JSONArray jsonArray = jsonObject.getJSONObject("data").getJSONArray("words_result"); + List textBlocks = new ArrayList<>(); + boolean isEng = false; + for (int i = 0; i < jsonArray.size(); i++) { + JSONObject jObj = jsonArray.getJSONObject(i); + TextBlock textBlock = new TextBlock(); + textBlock.setText(jObj.getStr("words").trim()); + //noinspection SuspiciousToArrayCall + JSONObject location = jObj.getJSONObject("location"); + int top = location.getInt("top"); + int left = location.getInt("left"); + int width = location.getInt("width"); + int height = location.getInt("height"); + textBlock.setTopLeft(new Point(top, left)); + textBlock.setTopRight(new Point(top, left + width)); + textBlock.setBottomLeft(new Point(top + height, left)); + textBlock.setBottomRight(new Point(top + height, left + width)); + textBlocks.add(textBlock); + } + return CommUtils.combineTextBlocks(textBlocks, isEng); + } + }