import 'dart:async'; import 'dart:typed_data'; import 'package:camera/camera.dart'; import 'package:flutter/foundation.dart'; import 'package:image/image.dart' as img; import '../utils/app_config.dart'; class CameraService extends ChangeNotifier { CameraController? _controller; List _cameras = []; bool _isInitialized = false; bool _isStreaming = false; Timer? _captureTimer; CameraController? get controller => _controller; bool get isInitialized => _isInitialized; bool get isStreaming => _isStreaming; /// 初始化相机 Future initialize() async { try { _cameras = await availableCameras(); if (_cameras.isEmpty) { print('没有可用的相机'); return; } // 使用后置摄像头 final camera = _cameras.firstWhere( (camera) => camera.lensDirection == CameraLensDirection.back, orElse: () => _cameras.first, ); _controller = CameraController( camera, ResolutionPreset.medium, // 中等分辨率,平衡质量和性能 enableAudio: false, imageFormatGroup: ImageFormatGroup.jpeg, ); await _controller!.initialize(); _isInitialized = true; notifyListeners(); print('相机初始化成功'); } catch (e) { print('相机初始化失败: $e'); _isInitialized = false; } } /// 拍摄单张照片 Future takePicture() async { if (!_isInitialized || _controller == null) return null; try { final XFile image = await _controller!.takePicture(); final bytes = await image.readAsBytes(); // 压缩图像 final compressedBytes = await _compressImage(bytes); return compressedBytes; } catch (e) { print('拍照失败: $e'); return null; } } /// 开始实时捕获(定时拍照) void startStreaming(Function(Uint8List) onImageCaptured) { if (_isStreaming) return; _isStreaming = true; notifyListeners(); _captureTimer = Timer.periodic(AppConfig.captureInterval, (timer) async { if (!_isStreaming) { timer.cancel(); return; } final imageBytes = await takePicture(); if (imageBytes != null) { onImageCaptured(imageBytes); } }); print('开始实时捕获,间隔: ${AppConfig.captureInterval.inMilliseconds}ms'); } /// 停止实时捕获 void stopStreaming() { _isStreaming = false; _captureTimer?.cancel(); _captureTimer = null; notifyListeners(); print('停止实时捕获'); } /// 压缩图像 Future _compressImage(Uint8List bytes) async { return await compute(_compressImageIsolate, bytes); } /// 在独立 Isolate 中压缩图像(避免阻塞 UI) static Uint8List _compressImageIsolate(Uint8List bytes) { // 解码图像 img.Image? image = img.decodeImage(bytes); if (image == null) return bytes; // 调整大小 if (image.width > AppConfig.imageMaxWidth || image.height > AppConfig.imageMaxHeight) { image = img.copyResize( image, width: AppConfig.imageMaxWidth, height: AppConfig.imageMaxHeight, ); } // 压缩为 JPEG final compressed = img.encodeJpg(image, quality: AppConfig.imageQuality); print('图像压缩: ${bytes.length} bytes -> ${compressed.length} bytes'); return Uint8List.fromList(compressed); } /// 切换摄像头 Future switchCamera() async { if (_cameras.length < 2) return; final currentLens = _controller?.description.lensDirection; final newCamera = _cameras.firstWhere( (camera) => camera.lensDirection != currentLens, orElse: () => _cameras.first, ); await _controller?.dispose(); _controller = CameraController( newCamera, ResolutionPreset.medium, enableAudio: false, imageFormatGroup: ImageFormatGroup.jpeg, ); await _controller!.initialize(); notifyListeners(); } /// 释放资源 @override void dispose() { stopStreaming(); _controller?.dispose(); super.dispose(); } }