【HarmonyOS AI】 通用文字识别详解
一、通用文字识别是什么?
通用文字识别,也就是 OCR(Optical Character Recognition,光学字符识别),用来把图片中的文字转换成应用可以处理的文本。例如,一张书页照片经过识别后,里面的内容就能被复制到笔记里;一张包含快递单号的截图,也可以提取出单号,用于查询物流。
在 HarmonyOS 中,Core Vision Kit(基础视觉服务)提供了端侧通用文字识别能力。开发者把图片交给系统服务,就可以获取识别到的文字及其位置,无需自行训练和部署 OCR 模型。识别过程在设备本地执行,图片不必为了这一步处理上传到云端。
文字识别,处理的是移动应用里另一个常见需求:把拍下来、存下来的文字,变成可以继续使用的内容。
二、它能做什么?
1、 提取图片里的文字
输入可以来自相机、图库,也可以是应用拿到的截图或扫描图片。识别后得到的字符,可以直接展示在文本框里,供用户修改、复制或保存。
比如,用户收到一张会议通知截图,应用可以提取其中的时间、地址等文字,再让用户选择需要的部分。OCR 负责把图片读成文字,具体哪些内容要填进日历或表单,由应用继续处理。
2、返回文字位置,用于选取和高亮
除了文字内容,识别结果还包含文字区域的位置和外框信息。开发者可以据此在原图上标出文字,做出"点击某一行""选择某一段"的交互。
如果页面上的图片经过缩放或旋转,绘制文字框时也需要做相应的坐标换算。后面的 Demo 先实现整张图片的文字提取,不涉及框选交互。
3、处理多种语言的印刷体文字
能力覆盖简体中文、繁体中文、英文、日文和韩文,适用于书籍、报刊、文档等印刷体文字,也支持一定范围内的文本倾斜、拍摄倾斜及复杂光照和背景场景。
本期介绍的主要规格如下,选取测试图片时可以先按这张表检查。
| 项目 | 支持范围或要求 |
|---|---|
| 图片格式 | JPEG、JPG、PNG |
| 语言 | 简体中文、繁体中文、英文、日文、韩文 |
| 字体 | 文档印刷体 |
| 文本长度 | 不超过 10000 字符 |
| 分辨率 | 720p 以上 |
| 图片高度 | 100 像素 < 高度 < 15210 像素 |
| 图片宽度 | 100 像素 < 宽度 < 10000 像素 |
| 图片比例 | 高宽比建议在 10:1 以下,接近手机屏幕比例为宜 |
| 角度 | 文本与拍摄角度夹角在 ±30° 范围内 |
规格依据华为开发者联盟本期能力介绍。印刷体支持不能直接推及任意手写字;拍摄时也应尽量保持清晰,避免反光遮挡文字。
端侧处理给这类功能带来的直接好处,是省去 OCR 请求中的图片上传和结果回传。应用也可以让原图留在本地。实际识别耗时仍与图片大小和设备有关;如果后续接入在线翻译、搜索或同步,相关数据传输需要由应用另行安排。
三、实际移动开发中,哪些场景需要它?
1、表单录入:从图片中取出需要填写的内容
报销、物流、客户资料登记等应用,经常需要用户对着图片填写一串信息。比如,物流查询页要求输入运单号,而用户手里只有一张快递单照片;报销页面需要填写票据上的日期和金额。
可以在输入框旁边增加"从图片提取"入口:选择图片,识别文字,再由用户选取或确认要填入的内容。这类功能尤其适合减少长编号的手动录入。
开发时要留意,通用 OCR 返回的是文字,金额、日期、单号的筛选和校验仍需业务代码处理。识别出票据文字,并不代表已经完成了票据字段结构化。
2、笔记与阅读:把纸面内容摘录到应用里
读书笔记、学习工具和知识管理应用,可以把 OCR 放在"新增笔记"或"导入内容"的流程中。
用户拍下一页书,提取文字,删掉不需要的段落,再保存到笔记。原本需要逐字输入的内容,变成了核对和编辑。对于学习外语的应用,也可以先提取句子,再接到查词或翻译功能。
这个场景适合先做一个很小的版本:一张图、一个结果编辑框、一个保存入口。本文的 Demo 就从这一流程的前半段开始。
3、 图片搜索:按图片里的文字查找资料
截图收藏、资料归档和企业文档应用里,文件名经常不能反映图片内容。用户记得截图里有一个项目名称,却不记得图片存在哪里。
一种接入方式是在用户导入图片时执行 OCR,将文字结果与图片标识一起保存,再用这些文字建立搜索索引。用户输入关键词后,应用查找索引并返回对应图片。
这里的检索和索引由应用实现,OCR 提供可供搜索的文本。若要批量处理相册,还需要单独设计授权、任务调度和资源管理,不能把单图 Demo 直接放进无限循环。
4、拍照翻译:先识别,再把文字交给翻译服务
旅行、语言学习和跨境购物应用,常会遇到菜单、招牌、商品说明等图片。用户想知道其中某段外文的意思,通常不方便手动输入。
应用可以先识别原文,让用户确认或选择目标段落,再调用翻译服务。图片上的文字位置还可以用于标记原文,帮助用户对照。
这时 OCR 负责读取文字,翻译由后续能力完成。把两步拆开后,原文也能单独复制、编辑,识别错字时不必重新走完整流程。
四、Demo:从图库选一张图片,提取并编辑文字
下面做一个单页面示例,完成这些操作:
- 点击按钮,打开系统图片选择器。
- 选择一张图片,在页面上预览。
- 自动调用通用文字识别,展示识别结果。
- 用户可以直接修改文本,也可以长按选择、复制。
示例代码单独保存为同目录下的 Index.ets,也完整列在下面。
1、准备工程
在 DevEco Studio 中创建 Stage 模型的 Empty Ability 工程,使用支持 Core Vision Kit 的 HarmonyOS SDK,将页面代码放到 entry/src/main/ets/pages/Index.ets。
准备一张符合前面规格的 JPG 或 PNG 图片,放入测试设备图库;先用一张清晰的印刷体文档图片跑通流程。目标系统版本和设备支持范围按 textRecognition API 参考核对,并在支持该能力的真机上验证。
选图使用系统 PhotoViewPicker,应用只读取用户本次选中的图片。本示例的处理过程是选图、解码和本地识别,没有服务端接口配置。
2、完整页面代码
typescript
import { textRecognition } from '@kit.CoreVisionKit';
import { image } from '@kit.ImageKit';
import { fileIo } from '@kit.CoreFileKit';
import { photoAccessHelper } from '@kit.MediaLibraryKit';
import { BusinessError } from '@kit.BasicServicesKit';
@Entry
@Component
struct Index {
@State private previewUri: string = '';
@State private resultText: string = '';
@State private statusText: string = '请选择一张包含印刷体文字的图片';
@State private busy: boolean = false;
private pageActive: boolean = true;
aboutToAppear(): void {
this.pageActive = true;
}
aboutToDisappear(): void {
// 已经开始的任务继续执行清理,但不再更新已退出的页面。
this.pageActive = false;
}
private async loadPixelMap(uri: string): Promise<image.PixelMap> {
const file = await fileIo.open(uri, fileIo.OpenMode.READ_ONLY);
try {
const source = image.createImageSource(file.fd);
try {
const info = await source.getImageInfo();
const width = info.size.width;
const height = info.size.height;
if (width <= 100 || width >= 10000 ||
height <= 100 || height >= 15210) {
throw new Error('图片尺寸超出识别范围,请裁剪或缩放后重试');
}
return await source.createPixelMap();
} finally {
await source.release();
}
} finally {
await fileIo.close(file);
}
}
private async recognize(pixelMap: image.PixelMap): Promise<string> {
await textRecognition.init();
try {
const visionInfo: textRecognition.VisionInfo = {
pixelMap: pixelMap
};
const configuration: textRecognition.TextRecognitionConfiguration = {
isDirectionDetectionSupported: false
};
const result = await textRecognition.recognizeText(
visionInfo, configuration
);
return result.value;
} finally {
await textRecognition.release();
}
}
private async selectAndRecognize(): Promise<void> {
if (this.busy) {
return;
}
this.busy = true;
try {
const picker = new photoAccessHelper.PhotoViewPicker();
const selection = await picker.select({
MIMEType: photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE,
maxSelectNumber: 1
});
if (!this.pageActive || selection.photoUris.length === 0) {
return;
}
const uri = selection.photoUris[0];
this.previewUri = uri;
this.resultText = '';
this.statusText = '正在识别,请稍候...';
const pixelMap = await this.loadPixelMap(uri);
try {
if (!this.pageActive) {
return;
}
const text = await this.recognize(pixelMap);
if (this.pageActive) {
this.resultText = text;
this.statusText = text.trim().length > 0
? '识别完成,可以编辑结果或长按复制'
: '未识别到文字,请换一张更清晰的图片';
}
} finally {
await pixelMap.release();
}
} catch (error) {
if (this.pageActive) {
const err = error as BusinessError;
this.statusText = `处理失败:${err.message}`;
}
} finally {
if (this.pageActive) {
this.busy = false;
}
}
}
build() {
Scroll() {
Column({ space: 16 }) {
Text('图片文字提取')
.fontSize(24)
.fontWeight(FontWeight.Bold)
if (this.previewUri.length > 0) {
Image(this.previewUri)
.width('100%')
.height(220)
.objectFit(ImageFit.Contain)
.backgroundColor('#F3F4F6')
}
Button(this.busy ? '处理中...' : '从图库选图并识别')
.width('100%')
.enabled(!this.busy)
.onClick(() => {
this.selectAndRecognize();
})
Text(this.statusText)
.width('100%')
.fontSize(14)
.fontColor('#666666')
TextArea({
text: this.resultText,
placeholder: '识别结果会显示在这里'
})
.width('100%')
.height(260)
.fontSize(16)
.copyOption(CopyOptions.LocalDevice)
.onChange((value: string) => {
this.resultText = value;
})
}
.width('100%')
.padding(20)
}
.width('100%')
.height('100%')
}
}
3、代码里的几个关键点
图片 URI 要先转换为 PixelMap。 图片选择器返回的是 URI;代码通过 fileIo.open() 打开文件,再用 image.createImageSource() 解码。传给识别接口的是 PixelMap,不是文件路径字符串。
真正发起识别的是 recognizeText()。 输入放在 VisionInfo.pixelMap 中,识别后的完整文本通过 result.value 获取。isDirectionDetectionSupported 用于配置朝向检测,示例沿用官方指南的 false 设置。接口调用方式可对照官方开发指南。
这个 Demo 按单次任务管理资源。 每次识别前初始化服务,识别结束后释放;文件、图片源和 PixelMap 也分别在使用结束后清理。这样的写法便于看清完整流程。如果业务需要连续识别多张图片,可以在一个识别会话中复用服务,并在全部任务结束后释放。
选图和识别期间禁止重复点击。 busy 控制按钮状态;取消选图、未识别到文字和调用失败分别处理。页面退出后,任务会继续走资源清理,但不再更新页面上的结果。
4、怎么验证这个 Demo?
运行后先选择一张清晰的文字图片。正常流程中,页面会显示原图和"正在识别"的提示,随后把识别内容填入文本框。可以手动修改一处文字,并长按选中内容进行复制。
再试三种情况:打开图库后取消选择;选择一张没有文字的图片;开始识别后退出页面。分别检查按钮能否恢复、空结果是否有提示,以及退出过程中是否出现异常。
这里提供的是完整页面示例,识别调用流程依据官方开发指南整理,未在本次整理中进行 DevEco Studio 编译和真机运行,识别效果及耗时需要在目标设备上验证。
跑通这个页面后,接到笔记应用时,可以把文本框内容保存为笔记;接到表单页面时,可以把用户确认的文字填入对应字段。先把一个具体录入流程做顺,再扩展拍照、文字框选或批量处理。
5、参考资料
6、AI提示词,用于开发HarmonyOS通用文字识别
bash
你是一名熟悉 HarmonyOS、ArkTS 和 ArkUI 的移动应用开发工程师。请基于 Core Vision Kit 的通用文字识别能力,开发一个"图片文字提取"页面。
功能要求:
1. 点击"选择图片",通过系统 PhotoViewPicker 从图库选择一张图片,并在页面预览。
2. 将图片解码为 PixelMap,调用 textRecognition 完成端侧文字识别。
3. 将识别结果展示在可编辑文本框中,支持选择、复制,方便用户提取截图、书页和文档中的文字。
4. 识别期间显示处理状态并禁止重复提交;正确处理取消选图、图片读取失败、未识别到文字和识别异常。
5. 正确管理识别服务、文件句柄、ImageSource 和 PixelMap 的生命周期,避免内存泄漏及页面退出后的无效更新。
技术要求:
使用 ArkTS、ArkUI 和 Stage 模型,优先适配当前工程的 SDK。识别调用使用 @kit.CoreVisionKit 的 textRecognition,选图使用系统图片选择器。OCR 在设备本地执行,不接入云端识别接口。界面简洁,包含图片预览、操作按钮、状态提示和结果编辑区。
请先检查现有工程结构,并根据华为官方文档核对当前 SDK 的接口、设备支持范围及权限要求,不要编造 API。随后直接完成代码和必要配置,提供完整 Index.ets 及涉及的其他文件,不要只给伪代码或零散片段。最后说明运行步骤,并验证正常识别、取消选图、空结果、连续操作和退出页面等情况;无法实际编译或真机验证的部分请明确标注。