ver1.00.00
update2
This commit is contained in:
@@ -2,8 +2,10 @@ import 'dart:io';
|
||||
import 'dart:typed_data';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:google_mlkit_barcode_scanning/google_mlkit_barcode_scanning.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
// 新增导入
|
||||
import 'package:zxing2/qrcode.dart';
|
||||
import 'package:image/image.dart' as img;
|
||||
|
||||
import '../../providers/user_provider.dart';
|
||||
|
||||
@@ -22,19 +24,13 @@ class _BindAccountPageState extends State<BindAccountPage> {
|
||||
String? _statusMessage;
|
||||
File? _selectedImageFile; // 用户选择的原始二维码截图
|
||||
|
||||
// 条码扫描器
|
||||
final BarcodeScanner _barcodeScanner = BarcodeScanner(
|
||||
formats: [BarcodeFormat.qrCode],
|
||||
);
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_qrContentController.dispose();
|
||||
_barcodeScanner.close();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
// 1. 选择图片并识别二维码
|
||||
// 1. 选择图片并识别二维码 (使用 zxing2替代 ML Kit)
|
||||
Future<void> _pickImageAndScan() async {
|
||||
try {
|
||||
final XFile? pickedFile = await _picker.pickImage(source: ImageSource.gallery);
|
||||
@@ -42,33 +38,79 @@ class _BindAccountPageState extends State<BindAccountPage> {
|
||||
|
||||
setState(() {
|
||||
_isProcessing = true;
|
||||
_statusMessage = "正在识别二维码...";
|
||||
_statusMessage = "正在加载图片...";
|
||||
_selectedImageFile = File(pickedFile.path);
|
||||
});
|
||||
|
||||
final inputImage = InputImage.fromFilePath(pickedFile.path);
|
||||
final List<Barcode> barcodes = await _barcodeScanner.processImage(inputImage);
|
||||
// 读取图片字节
|
||||
final bytes = await pickedFile.readAsBytes();
|
||||
|
||||
// 使用 image 库解码图片为 RGB 数据
|
||||
final img.Image? decodedImage = img.decodeImage(bytes);
|
||||
|
||||
if (decodedImage == null) {
|
||||
throw Exception("无法解析图片格式");
|
||||
}
|
||||
|
||||
setState(() {
|
||||
_isProcessing = false;
|
||||
_statusMessage = "正在解析二维码...";
|
||||
});
|
||||
|
||||
if (barcodes.isNotEmpty && barcodes.first.rawValue != null) {
|
||||
final String code = barcodes.first.rawValue!;
|
||||
final reader = QRCodeReader();
|
||||
|
||||
try {
|
||||
// 【修复点开始】
|
||||
// 1. 获取 Uint8List (RGBA 格式)
|
||||
final Uint8List rgbaBytes = decodedImage.getBytes(order: img.ChannelOrder.rgba);
|
||||
|
||||
// 2. 将 Uint8List 转换为 Int32List
|
||||
// 注意:这需要底层字节序匹配。大多数现代移动设备是 Little Endian。
|
||||
// Uint8List 的长度必须是 4 的倍数(RGBA 每个像素4字节),这通常成立。
|
||||
final Int32List pixels = Int32List.view(rgbaBytes.buffer);
|
||||
|
||||
// 3. 创建 LuminanceSource
|
||||
// ZXing 的 RGBLuminanceSource 期望 Int32List,其中每个 int 代表一个像素 (0xAARRGGBB 或类似格式)
|
||||
// 由于 image 库给出的是 RGBA (0xRR, 0xGG, 0xBB, 0xAA),直接转换可能导致颜色通道错位,
|
||||
// 但 ZXing 主要关注亮度(灰度),通常 RGBA 直接转 Int32 也能被正确二值化识别,
|
||||
// 如果识别失败,可能需要手动重排字节为 ARGB。
|
||||
|
||||
final source = RGBLuminanceSource(
|
||||
decodedImage.width,
|
||||
decodedImage.height,
|
||||
pixels
|
||||
);
|
||||
// 【修复点结束】
|
||||
|
||||
final binarizer = HybridBinarizer(source);
|
||||
final bitmap = BinaryBitmap(binarizer);
|
||||
|
||||
final result = reader.decode(bitmap);
|
||||
|
||||
if (result != null && result.text != null) {
|
||||
setState(() {
|
||||
_qrContentController.text = result.text!;
|
||||
_statusMessage = "识别成功";
|
||||
});
|
||||
} else {
|
||||
setState(() {
|
||||
_statusMessage = "未识别到二维码,请手动输入";
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
// 捕获 zxing 内部的 NotFoundException 等
|
||||
print("ZXing Error: $e"); // 调试用
|
||||
setState(() {
|
||||
_qrContentController.text = code;
|
||||
_statusMessage = "识别成功";
|
||||
});
|
||||
} else {
|
||||
setState(() {
|
||||
_statusMessage = "未识别到二维码,请手动输入";
|
||||
_statusMessage = "未在图中找到有效二维码";
|
||||
});
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
setState(() {
|
||||
_statusMessage = "识别出错: $e";
|
||||
});
|
||||
} finally {
|
||||
setState(() {
|
||||
_isProcessing = false;
|
||||
_statusMessage = "识别失败: $e";
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -92,7 +134,9 @@ class _BindAccountPageState extends State<BindAccountPage> {
|
||||
});
|
||||
|
||||
try {
|
||||
// 下载背景图用于隐写
|
||||
final httpClient = HttpClient();
|
||||
// 建议在实际生产环境中添加 timeout
|
||||
final request = await httpClient.getUrl(Uri.parse('https://union.godserver.cn/assets/jpeg/20180621142015_5FmGZ-wYXkyL4y.jpeg'));
|
||||
final response = await request.close();
|
||||
final bytes = <int>[];
|
||||
@@ -101,6 +145,9 @@ class _BindAccountPageState extends State<BindAccountPage> {
|
||||
}
|
||||
imageBytes = Uint8List.fromList(bytes);
|
||||
|
||||
// 关闭 client 以释放资源
|
||||
httpClient.close();
|
||||
|
||||
if (imageBytes == null || imageBytes.isEmpty) throw Exception("图片数据无效");
|
||||
|
||||
setState(() {
|
||||
@@ -108,7 +155,6 @@ class _BindAccountPageState extends State<BindAccountPage> {
|
||||
});
|
||||
|
||||
// 调用 Provider
|
||||
// 注意:这里 segaId 参数其实传的是 QR Code 的内容
|
||||
final userProvider = context.read<UserProvider>();
|
||||
final result = await userProvider.uploadStegImage(imageBytes, segaId: qrContent);
|
||||
|
||||
@@ -122,10 +168,13 @@ class _BindAccountPageState extends State<BindAccountPage> {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text("✅ ${result['msg']}"), backgroundColor: Colors.green, duration: const Duration(seconds: 5)),
|
||||
);
|
||||
// 绑定成功后,通常建议刷新用户信息
|
||||
// 绑定成功后,刷新用户信息
|
||||
await userProvider.initUser();
|
||||
|
||||
// 可选:清空输入或跳转
|
||||
// _qrContentController.clear();
|
||||
// Navigator.of(context).pop();
|
||||
} else {
|
||||
// 后端返回 500 或其他错误
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text("❌ ${result['msg']}"), backgroundColor: Colors.red, duration: const Duration(seconds: 5)),
|
||||
);
|
||||
@@ -276,7 +325,7 @@ class _BindAccountPageState extends State<BindAccountPage> {
|
||||
child: Text(
|
||||
_statusMessage!,
|
||||
style: TextStyle(
|
||||
color: _statusMessage!.contains("失败") || _statusMessage!.contains("错误") ? Colors.redAccent : Colors.white70,
|
||||
color: _statusMessage!.contains("失败") || _statusMessage!.contains("错误") || _statusMessage!.contains("未识别") ? Colors.redAccent : Colors.white70,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user