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.
example/lib/main.dart
import 'dart:convert';
import 'dart:async';
import 'package:flutter/services.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:eas_passport_ocr/eas_passport_ocr.dart';
void main() => runApp(
MaterialApp(
title: '本地护照识别',
theme: ThemeData(
colorSchemeSeed: const Color(0xff173f32),
useMaterial3: true,
),
home: const PassportPage(),
),
);
class PassportPage extends StatefulWidget {
const PassportPage({super.key});
@override
State<PassportPage> createState() => _PassportPageState();
}
class _PassportPageState extends State<PassportPage> {
final _service = EasPassportOcr();
bool _busy = false;
String _status = '选择清晰的护照资料页。照片在设备内识别,不上传。';
Map<String, dynamic>? _result;
Future<void> _scan(ImageSource source) async {
setState(() {
_busy = true;
_result = null;
_status = '正在设备内识别…';
});
try {
final file = await ImagePicker().pickImage(
source: source,
maxWidth: 2600,
imageQuality: 95,
);
if (file == null) {
if (mounted) setState(() => _status = '已取消选择');
return;
}
final result = await _service.recognizeResult(file.path);
if (mounted)
setState(() {
_result = result;
_status = result.containsKey('code')
? result['msg'] as String
: '校验通过,请与原件核对姓名及日期。';
});
} on PassportOcrException catch (error) {
if (mounted) setState(() => _status = error.message);
} catch (_) {
if (mounted) setState(() => _status = '识别失败,请检查权限、原生模型配置或更换照片。');
} finally {
if (mounted) {
setState(() => _busy = false);
} else {
await _service.dispose();
}
}
}
@override
void dispose() {
if (!_busy) unawaited(_service.dispose());
super.dispose();
}
@override
Widget build(BuildContext context) => Scaffold(
appBar: AppBar(title: const Text('本地护照识别')),
body: ListView(
padding: const EdgeInsets.all(24),
children: [
Text(_status),
const SizedBox(height: 20),
if (_busy) const LinearProgressIndicator(),
FilledButton(
onPressed: _busy ? null : () => _scan(ImageSource.camera),
child: const Text('拍摄护照'),
),
OutlinedButton(
onPressed: _busy ? null : () => _scan(ImageSource.gallery),
child: const Text('从相册选择'),
),
if (_result != null) ...[
const SizedBox(height: 20),
if (_result!.containsKey('code')) ...[
Text(_result!['suggestion'] as String),
const SizedBox(height: 12),
],
SelectableText(const JsonEncoder.withIndent(' ').convert(_result)),
OutlinedButton(
onPressed: () async {
try {
if (!_result!.containsKey('code')) {
_result = parsePassportMrz(
(_result!['rawMrz'] as List).join('\n'),
).toJson();
}
await Clipboard.setData(
ClipboardData(
text: const JsonEncoder.withIndent(' ').convert(_result),
),
);
if (mounted) setState(() => _status = 'JSON 已复制');
} catch (_) {
if (mounted) setState(() => _status = '复制失败,请重试');
}
},
child: const Text('复制 JSON 结果'),
),
TextButton(
onPressed: _busy
? null
: () => setState(() {
_result = null;
_status = '已清空识别结果';
}),
child: const Text('清空结果'),
),
],
],
),
);
}