读光 手写体OCR 免费调用
读光ocr在线体验
打开控制台
打开js文件美化观看
大概在如图所示行,有一个变量计算d,这个就是签名
获取签名的js方法
并赋给一个js变量,这里我把这个存成文件方便java读取
dgSign.js
var getSign = function i(e) {
function t(e, t) {
return e << t | e >>> 32 - t
}
function n(e, t) {
var n = 2147483648 & e
, r = 2147483648 & t
, o = 1073741824 & e
, a = 1073741824 & t
, i = (1073741823 & e) + (1073741823 & t);
return o & a ? 2147483648 ^ i ^ n ^ r : o | a ? 1073741824 & i ? 3221225472 ^ i ^ n ^ r : 1073741824 ^ i ^ n ^ r : i ^ n ^ r
}
function r(e, t, n) {
return e & t | ~e & n
}
function o(e, t, n) {
return e & n | t & ~n
}
function a(e, t, n) {
return e ^ t ^ n
}
function i(e, t, n) {
return t ^ (e | ~n)
}
function c(e, o, a, i, c, s, l) {
return e = n(e, n(n(r(o, a, i), c), l)),
n(t(e, s), o)
}
function s(e, r, a, i, c, s, l) {
return e = n(e, n(n(o(r, a, i), c), l)),
n(t(e, s), r)
}
function l(e, r, o, i, c, s, l) {
return e = n(e, n(n(a(r, o, i), c), l)),
n(t(e, s), r)
}
function u(e, r, o, a, c, s, l) {
return e = n(e, n(n(i(r, o, a), c), l)),
n(t(e, s), r)
}
function f(e) {
var t = ""
, n = ""
, r = void 0
, o = void 0;
for (o = 0; o <= 3; o++)
r = e >>> 8 * o & 255,
n = "0" + r.toString(16),
t += n.substr(n.length - 2, 2);
return t
}
var d = []
, p = void 0
, h = void 0
, m = void 0
, v = void 0
, y = void 0
, g = void 0
, b = void 0
, w = void 0
, x = void 0;
for (e = function (e) {
e = e.replace(/\r\n/g, "\n");
for (var t = "", n = 0; n < e.length; n++) {
var r = e.charCodeAt(n);
r < 128 ? t += String.fromCharCode(r) : r > 127 && r < 2048 ? (t += String.fromCharCode(r >> 6 | 192),
t += String.fromCharCode(63 & r | 128)) : (t += String.fromCharCode(r >> 12 | 224),
t += String.fromCharCode(r >> 6 & 63 | 128),
t += String.fromCharCode(63 & r | 128))
}
return t
}(e),
d = function (e) {
for (var t = void 0, n = e.length, r = n + 8, o = (r - r % 64) / 64, a = 16 * (o + 1), i = new Array(a - 1), c = 0, s = 0; s < n;)
t = (s - s % 4) / 4,
c = s % 4 * 8,
i[t] |= e.charCodeAt(s) << c,
s += 1;
return t = (s - s % 4) / 4,
c = s % 4 * 8,
i[t] |= 128 << c,
i[a - 2] = n << 3,
i[a - 1] = n >>> 29,
i
}(e),
g = 1732584193,
b = 4023233417,
w = 2562383102,
x = 271733878,
p = 0; p < d.length; p += 16)
h = g,
m = b,
v = w,
y = x,
g = c(g, b, w, x, d[p + 0], 7, 3614090360),
x = c(x, g, b, w, d[p + 1], 12, 3905402710),
w = c(w, x, g, b, d[p + 2], 17, 606105819),
b = c(b, w, x, g, d[p + 3], 22, 3250441966),
g = c(g, b, w, x, d[p + 4], 7, 4118548399),
x = c(x, g, b, w, d[p + 5], 12, 1200080426),
w = c(w, x, g, b, d[p + 6], 17, 2821735955),
b = c(b, w, x, g, d[p + 7], 22, 4249261313),
g = c(g, b, w, x, d[p + 8], 7, 1770035416),
x = c(x, g, b, w, d[p + 9], 12, 2336552879),
w = c(w, x, g, b, d[p + 10], 17, 4294925233),
b = c(b, w, x, g, d[p + 11], 22, 2304563134),
g = c(g, b, w, x, d[p + 12], 7, 1804603682),
x = c(x, g, b, w, d[p + 13], 12, 4254626195),
w = c(w, x, g, b, d[p + 14], 17, 2792965006),
b = c(b, w, x, g, d[p + 15], 22, 1236535329),
g = s(g, b, w, x, d[p + 1], 5, 4129170786),
x = s(x, g, b, w, d[p + 6], 9, 3225465664),
w = s(w, x, g, b, d[p + 11], 14, 643717713),
b = s(b, w, x, g, d[p + 0], 20, 3921069994),
g = s(g, b, w, x, d[p + 5], 5, 3593408605),
x = s(x, g, b, w, d[p + 10], 9, 38016083),
w = s(w, x, g, b, d[p + 15], 14, 3634488961),
b = s(b, w, x, g, d[p + 4], 20, 3889429448),
g = s(g, b, w, x, d[p + 9], 5, 568446438),
x = s(x, g, b, w, d[p + 14], 9, 3275163606),
w = s(w, x, g, b, d[p + 3], 14, 4107603335),
b = s(b, w, x, g, d[p + 8], 20, 1163531501),
g = s(g, b, w, x, d[p + 13], 5, 2850285829),
x = s(x, g, b, w, d[p + 2], 9, 4243563512),
w = s(w, x, g, b, d[p + 7], 14, 1735328473),
b = s(b, w, x, g, d[p + 12], 20, 2368359562),
g = l(g, b, w, x, d[p + 5], 4, 4294588738),
x = l(x, g, b, w, d[p + 8], 11, 2272392833),
w = l(w, x, g, b, d[p + 11], 16, 1839030562),
b = l(b, w, x, g, d[p + 14], 23, 4259657740),
g = l(g, b, w, x, d[p + 1], 4, 2763975236),
x = l(x, g, b, w, d[p + 4], 11, 1272893353),
w = l(w, x, g, b, d[p + 7], 16, 4139469664),
b = l(b, w, x, g, d[p + 10], 23, 3200236656),
g = l(g, b, w, x, d[p + 13], 4, 681279174),
x = l(x, g, b, w, d[p + 0], 11, 3936430074),
w = l(w, x, g, b, d[p + 3], 16, 3572445317),
b = l(b, w, x, g, d[p + 6], 23, 76029189),
g = l(g, b, w, x, d[p + 9], 4, 3654602809),
x = l(x, g, b, w, d[p + 12], 11, 3873151461),
w = l(w, x, g, b, d[p + 15], 16, 530742520),
b = l(b, w, x, g, d[p + 2], 23, 3299628645),
g = u(g, b, w, x, d[p + 0], 6, 4096336452),
x = u(x, g, b, w, d[p + 7], 10, 1126891415),
w = u(w, x, g, b, d[p + 14], 15, 2878612391),
b = u(b, w, x, g, d[p + 5], 21, 4237533241),
g = u(g, b, w, x, d[p + 12], 6, 1700485571),
x = u(x, g, b, w, d[p + 3], 10, 2399980690),
w = u(w, x, g, b, d[p + 10], 15, 4293915773),
b = u(b, w, x, g, d[p + 1], 21, 2240044497),
g = u(g, b, w, x, d[p + 8], 6, 1873313359),
x = u(x, g, b, w, d[p + 15], 10, 4264355552),
w = u(w, x, g, b, d[p + 6], 15, 2734768916),
b = u(b, w, x, g, d[p + 13], 21, 1309151649),
g = u(g, b, w, x, d[p + 4], 6, 4149444226),
x = u(x, g, b, w, d[p + 11], 10, 3174756917),
w = u(w, x, g, b, d[p + 2], 15, 718787259),
b = u(b, w, x, g, d[p + 9], 21, 3951481745),
g = n(g, h),
b = n(b, m),
w = n(w, v),
x = n(x, y);
return (f(g) + f(b) + f(w) + f(x)).toLowerCase()
}
getSign("%s");
手写题接口调用
POST https://duguang.aliyun.com/ocrdemo/ocrDemoSecondService.json
Content-Type: application/x-www-form-urlencoded
表单方式提交 这里我选的是本地图片,如果选择网络路径的话,则把img缓存url:图片地址
body参数 | 描述 |
---|---|
img | 图片base64码,与url选择其中一个即可 |
url | 网络图片地址,与img选择其中一个即可 |
type | ocr识别类型 注意当前网页链接,后面就跟着 https://duguang.aliyun.com/experience?type=universal&subtype=shouxie#intro 该属性值为 "demo_"+subtype
|
sign | 调用加密算法**getSign()**生成, img类型入参为 图片base64码.length()+"duguang.aliyun.com"+type url类型入参为 网络图片地址+"duguang.aliyun.com"+type
|
到这就能*使用了,下面是通过spring restTemplate调用
package test;
import io.cqxa.util.Base64Utils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpHost;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
/**
* @author 任勇
* @date 2021-10-25 18:45:13
* @description ocr文字识别 工具类
*/
@Slf4j
public class OcrServiceImpl {
/**
* js引擎
*/
private static ScriptEngine se = (new ScriptEngineManager()).getEngineByName("js");
/**
* 获取restTemplate,https跳过ssl校验
* @param
* @return
* @author 任勇 on 2021/10/23 15:08
*/
public RestTemplate restTemplate(){
// 长连接保持时长5分钟
PoolingHttpClientConnectionManager pollingConnectionManager = new PoolingHttpClientConnectionManager(200, TimeUnit.SECONDS);
// 最大连接数
pollingConnectionManager.setMaxTotal(3000);
// 单路由的并发数
pollingConnectionManager.setDefaultMaxPerRoute(100);
HttpClientBuilder httpClientBuilder = HttpClients.custom();
httpClientBuilder.setConnectionManager(pollingConnectionManager);
// 重试次数2次,并开启
httpClientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(2,true));
// 保持长连接配置,需要在头添加Keep-Alive
httpClientBuilder.setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy());
HttpClient httpClient = httpClientBuilder.
//由于我是内网开发需要配置代理,如不需要可以不设置
setProxy(new HttpHost("保密", 保密, "http"))
.build();
// httpClient连接底层配置clientHttpRequestFactory
HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
clientHttpRequestFactory.setReadTimeout(120*1000);
clientHttpRequestFactory.setConnectTimeout(120*1000);
RestTemplate restTemplate = new RestTemplate(clientHttpRequestFactory);
return restTemplate;
}
/**
* 读光ocr手写体识别
* @param imgFilePath
* @return
* @author 任勇 on 2021/10/25 8:51
*/
public String handwritingRecognition(String imgFilePath){
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.MULTIPART_FORM_DATA);
MultiValueMap<String, String> body = new LinkedMultiValueMap<>(3);
String base64 = Base64Utils.imageToBase64(imgFilePath);
body.add("type","demo_shouxie");
body.add("img",base64);
body.add("sign",getSign(base64));
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(body, httpHeaders);
//手写体识别
String url = "http://duguang.aliyun.com/ocrdemo/ocrDemoSecondService.json";
try {
RestTemplate restTemplate = restTemplate();
ResponseEntity<com.alibaba.fastjson.JSONObject> jsonObjectResponseEntity = restTemplate.postForEntity(url, request, com.alibaba.fastjson.JSONObject.class);
com.alibaba.fastjson.JSONObject jsonObject = jsonObjectResponseEntity.getBody();
return Optional.ofNullable(jsonObject.getJSONObject("data"))
.map(jsonObjectTemp -> jsonObjectTemp.getString("content"))
.orElse(null);
}catch (Exception e){
e.printStackTrace();
log.error(e.getMessage());
}
return null;
}
/**
* 根据base64计算签名
* 加载js文件,替换要加密的串,执行获取结果
* @param baseCode64
* @return
* @author 任勇 on 2021/10/24 16:31
*/
public static String getSign(String baseCode64){
//这段可替换为其他工具类方法读取文本里全部内容,因为我这用的springboot,所以资源放在了static/下
String signStr = null;
try (InputStream is = OcrServiceImpl.class.getClassLoader().getResourceAsStream("static/dgSign.js")){
byte[] filecontent = new byte[is.available()];
is.read(filecontent);
signStr = new String(filecontent, StandardCharsets.UTF_8);
}catch (Exception e){
e.printStackTrace();
log.error(e.getMessage());
}
if(StringUtils.isEmpty(signStr)){
return null;
}
signStr = signStr.replace("%s",baseCode64.length()+"duguang.aliyun.comdemo_shouxie");
Object obj = null;
try {
obj = se.eval(signStr);
} catch (Exception e) {
e.printStackTrace();
}
if (obj == null) {
return null;
}
return String.valueOf(obj);
}
public static void main(String[] args) {
OcrServiceImpl ocrService = new OcrServiceImpl();
String recognition = ocrService.handwritingRecognition("D:\\deskTop\\11111.png");
System.out.println(recognition);
}
}
Base64Utils.java
package io.cqxa.util;
import org.apache.commons.io.IOUtils;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Base64;
import java.util.Optional;
/**
* @author 任勇
* @date 2021/10/21 14:42
* @description base64工具类
* 参考文档 https://blog.csdn.net/qq_39098813/article/details/81270164
*/
public class Base64Utils {
/**
* 将图片文件转换成base64字符串,参数为该图片的路径
*
* @param imageFilePath
* @return java.lang.String
*/
public static String imageToBase64(String imageFilePath) {
// 对字节数组Base64编码
return Optional.ofNullable(imageFilePath)
.map(Base64Utils::imageToBase64NoPrefix)
// 返回Base64编码过的字节数组字符串
.map(dataTemp -> "data:image/jpeg;base64," + dataTemp)
.orElse("");
}
/**
* 将图片文件转换成base64字符串,参数为该图片的路径
*
* @param imageFilePath
* @return java.lang.String
*/
public static String imageToBase64NoPrefix(String imageFilePath) {
byte[] data = null;
// 读取图片字节数组
try (InputStream in = new FileInputStream(imageFilePath)){
data = IOUtils.toByteArray(in);
} catch (IOException e) {
e.printStackTrace();
}
return new String(Base64.getEncoder().encode(data));
}
}
识别图片
js文件所在地址