
国庆节在家做一个文字识别网站
国庆节一直在下雨,我也没有办法出去愉快的玩耍,突然想到之前有在服务器上部署一个ocr文字识别接口,于是就想要做一个在线OCR识别工具,说干就干,但是打开了vs code却无从下手,页面应该怎么做呢?
想直接用识别接口的:https://zn.gg/tools/ocr
思路
- 首先需要上传图片
- 然后把图片转换成base64编码
- 之后通过ajax请求接口
- 展示返回识别到的内容
上传图片并获得base64编码
上传图片的话使用表单的input标签就可以,然后使用FileReader可以读取到图片内容,那么代码如下:
<input type="file" accept="image/jpeg,image/png,image/jpg,image/png" onchange="uploadImg(this)" multiple/>
<script>
function uploadImg(file) {
if (file && file.files[0]) {
var reader = new FileReader();
reader.onload = function(evt) {
var imageData = (evt.target.result.replace(/.*?base64,/, ""))
}
return reader.readAsDataURL(file.files[0])
}
}
</script>
imageData就是图片的base64编码,我使用正则表达式 /.?base64,/* 去掉了前缀,拿到了图片真正的base64编码。
ajax获取识别结果
那么之后就需要网络请求了,我使用ajax进行网络请求,所以首先需要导入jquery库,然后带入image参数进行请求,接口地址是:https://zn.gg/api/common/v1/ocr ,另外这个识别是需要一个过程的,所以设置了一下超时时间为60秒,为了方便解析返回的结果,所以设置了dataType为json,这样就可以直接获取结果了。在得到结果之后我们需要解析一下结果,这里使用eval来把字符串转换成了数组,通过循环遍历出结果,存放在变量msg中。
$.ajax({
type: 'POST',
url: 'https://zn.gg/api/common/v1/ocr',
timeout: '60000',
dataType: 'json',
data: {
image: imageData
},
success: function(data) {
let arr = eval('(' + data.value[0] + ')')
var msg = ""
arr.forEach(element => {
msg += element
});
//msg就是识别结果。
},
error: function(data) {
}
})
核心页面的设置
核心地方为使用了一个大的div里面包含两个小的div,设置大div的宽高,然后使用margin的auto让其居中,两个小的div设置为浮动,这样就可以左右各有一个div了。这两个div分别为source和result,source有input标签,用于上传图片,还有img标签用于展示;result里面有一个textarea文本域用来显示识别结果。这个代码由于涉及到style和html所以就不展示了,可以直接看最下面的完整代码。
美化
这个还是比较好玩的,一共有两个部分:
- 上传按钮
- 识别过程中的图片扫描效果
上传按钮美化
首先来说这个这个上传按钮,一个input标签,类型为file,我刚开始使用css增加背景颜色等试图让它变得好看一些,可是根本没有效果。于是换了一种思路:使用绝对位置,让input覆盖在另外一个元素上面,让input的宽高和被覆盖的元素相同,设置input透明,这样只需要没话被覆盖的元素就可以了。代码如下:
.core .source .button-upload {
position: relative;
}
.core .source .button-upload .button-upload-show {
position: absolute;
width: 120px;
height: 45px;
background: cornflowerblue;
}
.core .source .button-upload .button-upload-show p {
line-height: 45px;
text-align: center;
color: white;
}
.core .source .button-upload #button-upload-hidden {
position: absolute;
opacity: 0;
width: 120px;
height: 45px;
}
<div class="core">
<div class="source">
<div class="button-upload">
<div class="button-upload-show">
<p>上传图片</p>
</div>
<input id="button-upload-hidden" type="file" accept="image/png,image/jpg,image/jpeg" onchange="uploadImg(this)">
</div>
</div>
</div>
图片扫描效果
这个看起来很炫酷,实际上就是一个很简单的动画,放一个div覆盖在图片上,然后使用动画设置div的高度和透明度,这个div的背景是一个渐变色的蓝色背景,这样就实现了上下扫描的效果。上传图片后设置展示效果的div的display为block,接收到返回后设置为none,这样就实现了扫描效果。
完整代码
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>OCR 文字识别</title>
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
</head>
<style>
@keyframes scan {
0% {
height: 0;
}
to {
opacity: 0;
height: 298px;
}
}
* {
margin: 0;
padding: 0;
}
header {
height: 180px;
width: 100vw;
background: #f1f1f1;
}
header p {
text-align: center;
line-height: 180px;
font-size: 40px;
}
.core {
height: 540px;
width: 1000px;
margin: 20px auto;
}
.core .source {
float: left;
width: 480px;
margin: 0 10px;
}
.core .source .imageScan {
display: none;
position: absolute;
width: 480px;
height: 298px;
animation: scan 1.2s infinite;
background: linear-gradient(180deg, transparent, rgb(60, 166, 228));
}
.core .source #imgPreview {
width: 480px;
height: 298px;
}
.core .source .button-upload {
position: relative;
}
.core .source .button-upload .button-upload-show {
position: absolute;
width: 120px;
height: 45px;
background: cornflowerblue;
}
.core .source .button-upload .button-upload-show p {
line-height: 45px;
text-align: center;
color: white;
}
.core .source .button-upload #button-upload-hidden {
position: absolute;
opacity: 0;
width: 120px;
height: 45px;
}
.core .result {
float: left;
width: 480px;
margin: 0 10px;
}
.core .result #resultMsg {
width: 480px;
height: 298px;
}
</style>
<body>
<header>
<p>OCR 文字识别</p>
</header>
<div class="core">
<div class="source">
<div id="imageScan" class="imageScan"></div>
<img id="imgPreview" src="" alt="">
<div class="button-upload">
<div class="button-upload-show">
<p>上传图片</p>
</div>
<input id="button-upload-hidden" type="file" accept="image/png,image/jpg,image/jpeg" onchange="uploadImg(this)">
</div>
</div>
<div class="result">
<textarea name="" id="resultMsg" cols="30" rows="10"></textarea>
</div>
</div>
<script>
let imageScan = document.getElementById("imageScan")
let imgPreview = document.getElementById("imgPreview")
let resultMsg = document.getElementById("resultMsg")
function uploadImg(file) {
if (file && file.files[0]) {
imageScan.style.display = "block"
let reader = new FileReader()
reader.onload = function(evt) {
imgPreview.src = evt.target.result
let imageData = evt.target.result.replace(/.*?base64,/, "")
$.ajax({
type: 'POST',
url: 'https://zn.gg/api/common/v1/ocr',
timeout: '60000',
dataType: 'json',
data: {
image: imageData
},
success: function(data) {
let arr = eval('(' + data.value[0] + ')')
var msg = ""
arr.forEach(element => {
msg += element
});
resultMsg.innerText = msg
imageScan.style.display = "none"
},
error: function(data) {
imageScan.style.display = "none"
}
})
}
return reader.readAsDataURL(file.files[0])
}
}
</script>
</body>
</html>