| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209 |
- import 'dart:io';
- import 'dart:typed_data';
- import 'package:clean/model/asset_info.dart';
- import 'package:clean/module/image_picker/image_picker_util.dart';
- import 'package:clean/utils/toast_util.dart';
- import 'package:intl/intl.dart';
- import 'package:wechat_assets_picker/wechat_assets_picker.dart';
- import 'file_utils.dart';
- import 'package:exif/exif.dart';
- class ImageUtil {
- // 生成月份 key (用于内部存储)
- static String getMonthKey(DateTime date) {
- return '${date.year}-${date.month.toString().padLeft(2, '0')}';
- }
- // 格式化月份显示 (例如: Jan 2025)
- static String formatMonthKey(String monthKey) {
- final parts = monthKey.split('-');
- if (parts.length == 2) {
- final date = DateTime(int.parse(parts[0]), int.parse(parts[1]));
- return DateFormat('MMM yyyy').format(date);
- }
- return monthKey;
- }
- // 获取指定索引的月份显示文本
- static String getMonthText(Map<String, List<AssetInfo>> assets, int index) {
- final monthKeys = assets.keys.toList()
- ..sort((a, b) => b.compareTo(a)); // 最新的月份在前
- if (index < monthKeys.length) {
- return formatMonthKey(monthKeys[index]);
- }
- return '';
- }
- // 获取指定月份的图片
- static List<AssetInfo> getMonthAssets(
- Map<String, List<AssetInfo>> assets, int index) {
- final monthKeys = assets.keys.toList()
- ..sort((a, b) => b.compareTo(a)); // 最新的月份在前
- if (index < monthKeys.length) {
- return assets[monthKeys[index]] ?? [];
- }
- return [];
- }
- // 获取缩略图数据
- static Future<Uint8List?> getImageThumbnail(
- FileType type, AssetInfo asset) async {
- try {
- // 先尝试从本地读取缩略图
- final localThumb = await FileUtils.getThumbData(
- type, Platform.isIOS ? asset.id.substring(0, 36) : asset.id);
- if (localThumb != null) {
- return localThumb;
- }
- // 如果本地没有,则从 AssetEntity 获取
- return await asset.thumbnailData;
- } catch (e) {
- print('获取缩略图失败: $e');
- return null;
- }
- }
- // 获取原始图片文件
- static Future<File?> getImageFile(FileType type, AssetInfo asset) async {
- try {
- // 先尝试从本地读取
- final assetPath = await FileUtils.getAssetPath(type);
- final localFile = File(
- '$assetPath/${Platform.isIOS ? asset.id.substring(0, 36) : asset.id}.PNG');
- if (await localFile.exists()) {
- return localFile;
- }
- // 如果本地没有,则从 AssetEntity 获取
- return asset.file;
- } catch (e) {
- print('获取图片文件失败: $e');
- return null;
- }
- }
- static Future<Map<String, dynamic>> getPhotoDetails(AssetInfo asset) async {
- try {
- final Map<String, dynamic> details = {};
- var title = "";
- if (asset.originalPath != null) {
- // 查找 "o_" 的位置
- final int index = asset.originalPath!.lastIndexOf('_o_');
- if (index != -1) {
- // 截取 "o_" 后面的字符串
- title = asset.originalPath!.substring(index + 3);
- } else {
- // 如果没有找到 "o_",返回原始文件名
- title = asset.originalPath!.split('/').last;
- }
- }
- // 基本信息
- details['fileName'] = title;
- // 创建格式化器
- final formatter = DateFormat('yyyy-MM-dd EEE HH:mm');
- details['createDate'] = formatter.format(asset.createDateTime);
- details['width'] = asset.width;
- details['height'] = asset.height;
- details['size'] = asset.size;
- // 获取文件
- final path = asset.originalPath;
- // final file = await asset.file;
- if (path != null && path.isNotEmpty) {
- try {
- final file = File(path);
- // 读取 EXIF 数据
- final bytes = await file.readAsBytes();
- final exifData = await readExifFromBytes(bytes);
- if (exifData.isNotEmpty) {
- // 相机信息
- details['make'] = exifData['Image Make']?.printable;
- details['model'] = exifData['Image Model']?.printable;
- // 拍摄参数
- // 光圈值
- details['aperture'] = exifData['EXIF FNumber']?.printable;
- // 快门速度/曝光时间
- details['exposureTime'] = exifData['EXIF ExposureTime']?.printable;
- // ISO感光度
- details['iso'] = exifData['EXIF ISOSpeedRatings']?.printable;
- // 焦距
- details['focalLength'] =
- exifData['EXIF FocalLengthIn35mmFilm']?.printable;
- // GPS 信息
- if (exifData.containsKey('GPS GPSLatitude') &&
- exifData.containsKey('GPS GPSLongitude')) {
- details['latitude'] = exifData['GPS GPSLatitude']?.printable;
- details['longitude'] = exifData['GPS GPSLongitude']?.printable;
- }
- }
- } catch (e) {
- print('读取 EXIF 数据失败: $e');
- ToastUtil.show('Failed to get photo details');
- }
- }
- print(details);
- return details;
- } catch (e) {
- print('Failed to get photo details: $e');
- return {};
- }
- }
- /// 格式化图片尺寸
- static String formatResolution(int width, int height) {
- final megapixels = (width * height) / 1000000.0;
- if (megapixels >= 1) {
- return '${megapixels.toStringAsFixed(1)} MP ($width × $height)';
- } else {
- return '$width × $height';
- }
- }
- /// 格式化文件大小
- static String formatFileSize(int bytes) {
- if (bytes < 1024) return '$bytes B';
- if (bytes < 1024 * 1024) return '${(bytes / 1024).toStringAsFixed(1)} KB';
- if (bytes < 1024 * 1024 * 1024) {
- return '${(bytes / (1024 * 1024)).toStringAsFixed(1)} MB';
- }
- return '${(bytes / (1024 * 1024 * 1024)).toStringAsFixed(1)} GB';
- }
- /// 格式化光圈值
- static String formatAperture(String? value) {
- if (value == null) return 'Unknown';
- return 'f/$value';
- }
- /// 格式化曝光时间
- static String formatExposureTime(String? value) {
- if (value == null) return 'Unknown';
- // 将分数转换为更易读的格式
- if (value.contains('/')) {
- final parts = value.split('/');
- if (parts.length == 2) {
- final numerator = int.parse(parts[0]);
- final denominator = int.parse(parts[1]);
- if (numerator == 1) {
- return '1/${denominator}s';
- }
- }
- }
- return '${value}s';
- }
- }
|