eas_passport_ocr 0.2.3
eas_passport_ocr: ^0.2.3 copied to clipboard
On-device passport MRZ recognition for Flutter Android and iOS.
eas_passport_ocr · Flutter SDK #
Android/iOS 设备本地识别 TD3 护照。不上传图片。返回核心字段、rawMrz、isExpired,与 JavaScript SDK 一致;没有中文版面识别,也不输出其他辅助字段。
当前版本 0.2.3,也提供源码交付包 eas_passport_ocr-flutter-0.2.3.tar.gz。
授权 #
本包采用专有的评估与商业许可,不是 MIT 或其他开源许可证。允许内部测试、评估及为评估修改;生产部署、商用、面向公众的应用或服务,以及源码或编译产物的再分发,需要事先取得 Easit 的单独书面授权。从 pub.dev 下载不等于取得商业授权。第三方依赖遵循各自条款。
接入 #
在 App 的 pubspec.yaml 中固定版本:
dependencies:
eas_passport_ocr: 0.2.3
执行 flutter pub get。如使用本地交付包,解压后改用路径依赖:
dependencies:
eas_passport_ocr:
path: ../eas_passport_ocr
需要 Flutter ≥ 3.44、Dart ≥ 3.12(锁定插件版本的实际最低要求)。运行 flutter pub get。本包封装社区的 google_mlkit_text_recognition: 0.17.1,原生模型必须随 App 打包。
import 'dart:convert';
import 'package:eas_passport_ocr/eas_passport_ocr.dart';
final sdk = EasPassportOcr(correctDistortion: true); // 默认开启机读码变形校正
try {
final result = await sdk.recognizeResult(localImagePath);
if (result.containsKey('code')) {
// 展示 result['msg'] 和 result['suggestion'],引导用户重试。
} else {
final passportNumber = result['passportNumber'];
// 将字段填入业务表单,并让用户核对。
}
final json = jsonEncode(result); // 用于复制或交给调用方
} finally {
await sdk.dispose();
}
recognize 接收本地文件路径,不接受 http/file URL。同一个实例可顺序扫描;扫描中再次调用或释放会返回 BUSY。待扫描结束后 dispose(),重复释放安全。相册/摄像头的选图、权限、裁剪由宿主 App 负责,建议平拍并保留完整底部两行机读码。
整页识别与结果确认 #
默认接收完整护照资料页,无需手动指定机读码区域。先调用本地 ML Kit,再对原图和对比度副本重复读取;必要时自动搜索两行字符,优先保留整行字符的自然比例,校正弯曲基线,再尝试逐字符校正。长行会整体缩放到输出画布内,避免尾部被裁掉。
0.2.3 同步了 JavaScript SDK 的重复确认与冲突检查:两行文字需要不同处理尝试的重复支持。接受整行校正结果前,还会用另一种几何采样重读第二行;出现不同但都通过校验的护照号或日期时返回失败。不会猜换 O/0、补字、截字或放宽校验。更严格的确认可能拒绝以前能返回的照片,重复一致也不能保证所有字段正确,仍需核对原件。
无法定位时,会有限地尝试小图放大、旋转和 ML Kit 检出的行框裁剪;每次最多调用 80 次原生识别,确认结果后提前结束。困难图片可能耗时更长。局部光照均衡和斜切补偿只改善仍有笔画的图片,不能恢复被反光抹掉或被截断的信息,也不代表支持任意扭曲、整页四角检测。
解码、缩放、几何处理和派生图片编码通过 compute 在后台 isolate 完成。ML Kit 使用本地文件路径:整页副本、裁剪和字符行图保存在系统临时目录,成功或异常结束都会删除,不修改用户原图。进程被系统强制终止时无法保证清理;不要备份或上传这些临时文件。
correctDistortion: false 关闭几何、小图放大、行框与方向重试,仍执行整页重复确认。注入自定义 PassportTextEngine 时,由自定义引擎负责图像处理及重复确认;SDK 继续做严格 MRZ 解析和返回值校验,不读取自定义引擎的虚拟路径。
平台配置 #
- Android:插件最低 minSdk 21,compileSdk 至少 36,targetSdk 使用当前 Flutter 模板值;如果你的 Flutter 或其他插件要求更高,取更高值。使用插件自带的
com.google.mlkit:text-recognition:16.0.1(模型打包版),不要切换为 Play Services 动态下载版。 - iOS:最低部署版本 15.5、Xcode 15.3+。在 Runner 及 Podfile 设置部署版本,按 ML Kit 文档排除不支持的 32 位架构。默认插件带拉丁字符模型,不需要额外中文 Pod。
- 不支持 Flutter Web、macOS/Windows/Linux 图片 OCR;这些平台调用默认引擎会返回
UNSUPPORTED_PLATFORM。纯parsePassportMrz不调用原生 OCR。 - 相册/拍照示例使用 image_picker;iOS Info.plist 需配置
NSCameraUsageDescription和NSPhotoLibraryUsageDescription。
API 与结果 #
EasPassportOcr(correctDistortion: false) 可关闭默认引擎的图像校正;注入自定义 engine 时,由该引擎自行负责预处理。
recognizeResult(path) 返回可直接 jsonEncode 的 Map(成功或失败);原有 recognize(path) 返回 PassportResult;toJson() 返回以下键:
documentType, issuingCountry, surname, givenNames, passportNumber, nationality, birthDate, sex, expiryDate, rawMrz, isExpired。
日期格式为 YYYY-MM-DD,性别 M/F/X。isExpired 按当前设备本地日期计算,到期当天未过期;toJson() 会重新计算,不保存过时的过期标志。两位年份的世纪仍需与护照原件核对。
// 已经有 OCR 文字时,无需调用模型:
final result = parsePassportMrz('$line1\n$line2');
final expired = result.isExpired;
final data = result.toJson();
旧接口 recognize 校验失败会抛异常,不返回未经校验的数据。错误码:INVALID_INPUT、UNSUPPORTED_PLATFORM、BUSY、DISPOSED、MRZ_NOT_FOUND、MRZ_INVALID、OCR_FAILED。错误对象不附带证件图片或原始识别文本。
需要接入其他本地原生 OCR 时,实现 PassportTextEngine 的 recognizeLines() 和 close(),传入 EasPassportOcr(engine: yourEngine)。返回按阅读顺序排列的文字行,SDK 负责 MRZ 定位、解析、校验和统一结果。
示例与验证 #
example/lib/main.dart 提供相册/拍照和复制 JSON 的完整 Dart 页面。当前交付没有生成 Android/iOS 工程壳:
cd example
flutter create --platforms=android,ios --project-name passport_ocr_example .
flutter pub get
# 完成上述平台和权限配置后
flutter run
库内检查:
flutter pub get
flutter analyze
flutter test
测试使用公开虚构样例、合成变形字符图和原生通道替身,覆盖结果契约、重复确认、校验碰撞、几何校正、旋转/行框回退、重试预算、实例复用、临时文件清理和资源释放。
尚未完成 Android/iOS 真机 OCR 验收。 单测中的 ML Kit 返回值是替身,不能证明实际照片识别率。网页 200 组结果也不能代表 Flutter;两端 OCR 引擎不同。集成后应使用目标设备断网验证原生模型、拍照权限及实际照片效果。源码包体积不含原生引擎和模型,不等于 App 安装包增量。
依赖来源 #
- Flutter ML Kit 插件及平台要求(社区维护,不是 Google 官方 Flutter SDK)
- Android ML Kit 本地模型
第三方依赖及原生 ML Kit 的使用遵循各自条款。本包没有包含网页使用的 Tesseract 或 OCR-B 模型。
失败 JSON(0.2.0) #
recognizeResult 失败时只返回三个字符串字段:code、msg、suggestion。成功仍为原有 11 个护照字段。
{
"code": "MRZ_INVALID",
"msg": "未能识别清楚,照片可能存在反光、扭曲、缺角或文字截断。",
"suggestion": "请避开反光、摊平护照,完整拍入资料页及四角,确保底部两行字母和数字清晰、未被截断。"
}
使用 result.containsKey('code') 判断失败。suggestion 为单个字符串,多条建议合并成文本。
内部仍保留图像诊断及字段校验:有证据时 msg 说明疑似反光、弯曲/尺寸变化、机读码贴边或字符像素不足;无法定位具体原因时,将反光、扭曲、缺角、截断作为可能原因一并提示。质量判断为保守规则,不是经真实数据集标定的分类模型;不包含整页四角检测或独立模糊分类器,贴边不能等同于物理缺角。只有默认图像引擎执行图片检测,自定义文字引擎仅有字段校验信息。
结果不再包含 success、error 包装、diagnosis、检测指标或原因列表,也不包含未经校验的身份数据、照片或堆栈。图片本地处理,无新模型下载。成功的 rawMrz 和 isExpired 保留。
从 0.1.x 升级: 将旧的 result.success === false / result.error.message 分支改为上述三字段结构。recognize() 抛异常的使用方式保留,JS PassportOcrError.toJSON() / Dart PassportOcrException.toJson() 返回相同三字段。