import 'dart:io'; import 'package:sino_med_cloud/core/utils/logger.dart'; import 'picker_service.dart'; import 'image_processor.dart'; import 'media_exception.dart'; /// 统一媒体服务入口 /// /// 提供快捷的图片选择、拍照和处理功能 /// /// 使用示例: /// ```dart /// // 从相册选择并自动压缩 /// final file = await MediaService.pickFromGallery(); /// /// // 使用系统相机拍照并自动压缩 /// final photo = await MediaService.pickFromCamera(); /// /// // 使用专业相机拍照(需要手动管理生命周期) /// final cameraService = CameraService(); /// await cameraService.init(); /// final photo = await cameraService.takePicture(); /// final compressed = await MediaService.compressImage(photo!); /// cameraService.dispose(); /// ``` class MediaService { /// 使用系统相机拍照(快捷方式) /// /// 自动压缩图片,适合快速拍照场景 /// /// - [imageQuality] 图片质量(1-100),默认 90 /// - [maxWidth] 压缩后的最大宽度,默认 1080px /// - [maxHeight] 压缩后的最大高度,默认 1920px /// - [compressQuality] 压缩质量(1-100),默认 85 /// /// 返回压缩后的照片文件,如果用户取消或失败返回 null /// /// 抛出 [MediaException] 如果操作失败 static Future pickFromCamera({ int imageQuality = PickerService.defaultImageQuality, int maxWidth = ImageProcessor.defaultMaxWidth, int? maxHeight, int compressQuality = ImageProcessor.defaultQuality, }) async { try { AppLogger.d('开始使用系统相机拍照...'); final file = await PickerService.pickFromCamera( imageQuality: imageQuality, ); if (file == null) { return null; } AppLogger.d('开始压缩图片...'); final compressed = await ImageProcessor.compress( file, maxWidth: maxWidth, maxHeight: maxHeight, quality: compressQuality, ); AppLogger.d('拍照并压缩完成: ${compressed.path}'); return compressed; } on MediaException { rethrow; } catch (e) { AppLogger.e('拍照并压缩失败', e); throw MediaException( '拍照并压缩失败: ${e.toString()}', originalError: e, ); } } /// 从相册选择图片(快捷方式) /// /// 自动压缩图片,适合快速选择场景 /// /// - [imageQuality] 图片质量(1-100),默认 90 /// - [maxWidth] 压缩后的最大宽度,默认 1080px /// - [maxHeight] 压缩后的最大高度,默认 1920px /// - [compressQuality] 压缩质量(1-100),默认 85 /// /// 返回压缩后的图片文件,如果用户取消或失败返回 null /// /// 抛出 [MediaException] 如果操作失败 static Future pickFromGallery({ int imageQuality = PickerService.defaultImageQuality, int maxWidth = ImageProcessor.defaultMaxWidth, int? maxHeight, int compressQuality = ImageProcessor.defaultQuality, }) async { try { AppLogger.d('开始从相册选择图片...'); final file = await PickerService.pickFromGallery( imageQuality: imageQuality, ); if (file == null) { return null; } AppLogger.d('开始压缩图片...'); final compressed = await ImageProcessor.compress( file, maxWidth: maxWidth, maxHeight: maxHeight, quality: compressQuality, ); AppLogger.d('选择并压缩完成: ${compressed.path}'); return compressed; } on MediaException { rethrow; } catch (e) { AppLogger.e('选择并压缩失败', e); throw MediaException( '选择并压缩失败: ${e.toString()}', originalError: e, ); } } /// 压缩图片 /// /// - [file] 原始图片文件 /// - [maxWidth] 最大宽度,默认 1080px /// - [maxHeight] 最大高度,默认 1920px /// - [quality] 压缩质量(1-100),默认 85 /// /// 返回压缩后的文件(覆盖原文件) /// /// 抛出 [ImageProcessingException] 如果压缩失败 static Future compressImage( File file, { int maxWidth = ImageProcessor.defaultMaxWidth, int? maxHeight, int quality = ImageProcessor.defaultQuality, }) async { return await ImageProcessor.compress( file, maxWidth: maxWidth, maxHeight: maxHeight, quality: quality, ); } /// 获取图片信息 /// /// 返回图片的宽度、高度和文件大小 /// /// 抛出 [ImageProcessingException] 如果获取失败 static Future> getImageInfo(File file) async { return await ImageProcessor.getImageInfo(file); } /// 医疗脱敏处理(去除 EXIF 信息) /// /// 移除图片中的 EXIF 元数据,保护患者隐私 /// /// 返回脱敏后的文件(覆盖原文件) /// /// 抛出 [ImageProcessingException] 如果处理失败 static Future removeExif(File file) async { return await ImageProcessor.removeExif(file); } /// 从相册选择视频 /// /// 返回选择的视频文件,如果用户取消选择返回 null /// /// 抛出 [MediaException] 如果选择失败 static Future pickVideoFromGallery() async { return await PickerService.pickVideoFromGallery(); } }