本文最后更新于 798 天前
一、实现的效果
二、实现
2.1 首先需要拍照或从相册选取图片进行OCR识别
2.1.1 这里使用的是阿里云OCR识别 替换为你申请的AppID即可
// 将图册或拍照获取的图片 转为Base64 (注意图片压缩处理)
override suspend fun ocrImage(imgBase64: String): Flow<ApiResult<OcrBean>> {
return flow {
try{
val ocrBean = RetrofitClient.service.ocrImage("https://english.market.alicloudapi.com/ocrservice/english","APPCODE b8d5c0db45d44741bbdc9efec215d887", OcrParams(imgBase64,false,false,false))
emit(ApiResult.Success(ocrBean))
}catch (e:Exception){
emit(ApiResult.Failure(e.message))
}
}.flowOn(Dispatchers.IO)
}
2.2 获取OCR识别后的文本坐标进行边框绘制
2.2.1 OCR识别后的结果 (格式参考阿里云OCR)
// 将识别结果传给ImageRegion(自定义类)-底部源码查看
image.setWordPos(it.toMutableList())
fun setWordPos(wordsInfo:MutableList<PrismWordsInfo>){
this.wordsInfo = wordsInfo
// 遍历所有的文本项--文本内容、文本的坐标 单位:px像素
for(wordInfo in wordsInfo){
var mPath:Path = Path()
var region: Region = Region()
// 获取四个顶点坐标进行确认位置 设置Path路径
// 注意:图片最终显示 的宽是和屏幕宽一样,所以就需要对应的换算
Ext.ocrBitmap?.also{
mPath.run {
moveTo(wordInfo.pos[0].x * screenWidth / it.width * 1f,wordInfo.pos[0].y * height / it.height * 1f)
lineTo(wordInfo.pos[1].x * screenWidth / it.width * 1f,wordInfo.pos[1].y * height / it.height * 1f)
lineTo(wordInfo.pos[2].x * screenWidth / it.width * 1f,wordInfo.pos[2].y * height / it.height * 1f)
lineTo(wordInfo.pos[3].x * screenWidth / it.width * 1f,wordInfo.pos[3].y * height / it.height * 1f)
close()
}
// 通过Path路径获取对应的Region 用于点击位置判断
val bounds = RectF()
mPath.computeBounds(bounds,true)
region.setPath(mPath,Region(bounds.left.toInt
(),bounds.top.toInt(),bounds.right.toInt
(),bounds.bottom.toInt()))
}
// 将每个文本所在的路径以及区域存储到集合内
mPathList.add(mPath)
mRegionList.add(region)
}
postInvalidate()
}
2.3 判断点击位置是否在某一个文本边框内
@SuppressLint("ClickableViewAccessibility")
override fun onTouchEvent(event: MotionEvent?): Boolean {
when(event?.action){
MotionEvent.ACTION_DOWN->{
var contains = false
var index = 0
for (region in mRegionList){
if(region.contains(event.x.toInt(), event.y.toInt())){
contains = true
index = mRegionList.indexOf(region)
break
}else{
contains = false
}
}
if(contains){
this.listener?.run {
onWordClick(wordsInfo[index].word)
}
}
}
}
return super.onTouchEvent(event)
}
// 接口回调 点击
var listener:OnWordClickListener? = null
interface OnWordClickListener{
fun onWordClick(word:String)
}
fun setWordOnClickListener(listener: OnWordClickListener){
this.listener = listener
}
2.4 集成腾讯x5内核 WebView嵌入百度翻译(或使用API)
fun init() {
webview.webViewClient = object : WebViewClient() {
override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {
return false
}
override fun onPageFinished(view: WebView, url: String) {
super.onPageFinished(view, url)
// 页面加载完成后去除 顶部(就一些不想展示的内容 )
webview.loadUrl("javascript:(function(){ document.getElementById(\"new-header\").style.display=\"none\";})()")
if (Build.VERSION.SDK.toInt() >= 16) changGoForwardButton(view)
}
}
webview.loadUrl(mHomeUrl)
}
private val mHomeUrl = "https://fanyi.baidu.com/"
2.4.1 注入js自动填充点击的文本并自动点击翻译
// 上述的点击 接口回调
image.setWordOnClickListener(object : ImageRegion.OnWordClickListener{
override fun onWordClick(word: String) {
wordSearch.visibility = View.VISIBLE
// 自动填充翻译文本和自动点击进行翻译
webview.loadUrl("javascript:(function(){ document.getElementById(\"j-textarea\").value = \"${word}\"; document.getElementsByClassName(\"trans-btn\")[0].click();})()")
}
})