import 'dart:io'; import 'package:camera/camera.dart' as camera_pkg; import 'package:sino_med_cloud/core/utils/logger.dart'; import 'media_exception.dart'; // 使用别名避免命名冲突 typedef CameraController = camera_pkg.CameraController; typedef ResolutionPreset = camera_pkg.ResolutionPreset; typedef CameraLensDirection = camera_pkg.CameraLensDirection; typedef XFile = camera_pkg.XFile; /// 专业相机服务 /// /// 适合医疗影像、证件采集、高质量拍照、连拍/自定义UI /// /// 使用示例: /// ```dart /// final cameraService = CameraService(); /// await cameraService.init(); /// final photo = await cameraService.takePicture(); /// cameraService.dispose(); /// ``` class CameraService { CameraController? _controller; bool _isInitialized = false; bool _isDisposed = false; /// 初始化相机 /// /// - [resolutionPreset] 分辨率预设,默认 veryHigh /// - [enableAudio] 是否启用音频,默认 false /// - [lensDirection] 镜头方向,默认后置摄像头 /// /// 抛出 [MediaCameraException] 如果初始化失败 Future init({ ResolutionPreset resolutionPreset = camera_pkg.ResolutionPreset.veryHigh, bool enableAudio = false, CameraLensDirection lensDirection = camera_pkg.CameraLensDirection.back, }) async { try { if (_isDisposed) { throw MediaCameraException('相机服务已释放,无法初始化'); } if (_isInitialized) { AppLogger.d('相机已初始化,跳过重复初始化'); return; } AppLogger.d('开始初始化相机...'); final cameras = await camera_pkg.availableCameras(); if (cameras.isEmpty) { throw MediaCameraException('未找到可用相机'); } final camera = cameras.firstWhere( (c) => c.lensDirection == lensDirection, orElse: () => cameras.first, ); _controller = camera_pkg.CameraController( camera, resolutionPreset, enableAudio: enableAudio, ); await _controller!.initialize(); _isInitialized = true; AppLogger.d('相机初始化成功: ${camera.name}'); } catch (e) { _isInitialized = false; if (e is camera_pkg.CameraException) { AppLogger.e('相机初始化失败(原生异常)', e); throw MediaCameraException( '相机初始化失败: ${e.toString()}', originalError: e, ); } if (e is MediaCameraException) { rethrow; } AppLogger.e('相机初始化失败', e); throw MediaCameraException( '相机初始化失败: ${e.toString()}', originalError: e, ); } } /// 获取相机控制器 /// /// 抛出 [MediaCameraException] 如果相机未初始化 CameraController get controller { if (!_isInitialized || _controller == null) { throw MediaCameraException('相机未初始化,请先调用 init()'); } return _controller!; } /// 检查相机是否已初始化 bool get isInitialized => _isInitialized && _controller?.value.isInitialized == true; /// 拍照 /// /// 返回拍摄的照片文件,如果失败返回 null /// /// 抛出 [MediaCameraException] 如果拍照失败 Future takePicture() async { try { if (!isInitialized) { throw MediaCameraException('相机未初始化,无法拍照'); } AppLogger.d('开始拍照...'); final camera_pkg.XFile file = await _controller!.takePicture(); final photoFile = File(file.path); if (!await photoFile.exists()) { throw MediaCameraException('拍照失败:文件不存在'); } AppLogger.d('拍照成功: ${photoFile.path}'); return photoFile; } catch (e) { if (e is camera_pkg.CameraException) { AppLogger.e('拍照失败(原生异常)', e); throw MediaCameraException( '拍照失败: ${e.toString()}', originalError: e, ); } if (e is MediaCameraException) { rethrow; } AppLogger.e('拍照失败', e); throw MediaCameraException( '拍照失败: ${e.toString()}', originalError: e, ); } } /// 释放相机资源 /// /// 必须在不再使用相机时调用,否则可能导致资源泄漏 Future dispose() async { if (_isDisposed) { return; } try { if (_controller != null) { await _controller!.dispose(); _controller = null; } _isInitialized = false; _isDisposed = true; AppLogger.d('相机资源已释放'); } catch (e) { AppLogger.e('释放相机资源失败', e); } } }