import 'dart:convert'; import 'dart:io'; import 'dart:math'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_cache_manager/flutter_cache_manager.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:http/http.dart' as http; import 'package:image_cropper/image_cropper.dart'; import 'package:image_gallery_saver/image_gallery_saver.dart'; import 'package:image_picker/image_picker.dart'; import 'package:mime/mime.dart'; import 'package:permission_handler/permission_handler.dart'; import '../network/NetworkConfig.dart'; class AppUtil { /// 默认为下载网络图片,如需下载资源图片,需要指定 [isAsset] 为 `true`。 static Future saveImage(String imageUrl, {bool isAsset = false}) async { try { if (imageUrl == null) throw '保存失败,图片不存在!'; print(NetworkConfig.systemVersion); /// 权限检测 PermissionStatus storageStatus; ///android13及以上版本 "storage" 已废除 图片 视频 音频权限需要分别申请 if (int.parse(NetworkConfig.systemVersion) >= 13) { storageStatus = await Permission.photos.status; } else { storageStatus = await Permission.storage.status; } if (storageStatus != PermissionStatus.granted) { if (int.parse(NetworkConfig.systemVersion) >= 13) { storageStatus = await Permission.photos.request(); } else { storageStatus = await Permission.storage.request(); } if (storageStatus != PermissionStatus.granted) { throw '无法存储图片,请先授权!'; } } /// 保存的图片数据 Uint8List imageBytes; if (isAsset == true) { /// 保存资源图片 ByteData bytes = await rootBundle.load(imageUrl); imageBytes = bytes.buffer.asUint8List(); } else { Map map = {}; /// 保存网络图片 CachedNetworkImage image = CachedNetworkImage(imageUrl: imageUrl); BaseCacheManager manager = image.cacheManager ?? DefaultCacheManager(); Map headers = image.httpHeaders != null ? image.httpHeaders! : map; File file = await manager.getSingleFile( image.imageUrl, headers: headers, ); imageBytes = await file.readAsBytes(); } /// 保存图片 final result = await ImageGallerySaver.saveImage(imageBytes, quality: 100); if (result == null || result == '') throw '图片保存失败'; EasyLoading.showToast("Successfully saved"); } catch (e) { print(e.toString()); } } ///保存Widget图片 static Future saveWidgetImage(ByteData bytes) async { try { if (bytes == null) throw '保存失败,图片不存在!'; /// 权限检测 PermissionStatus storageStatus; ///android13及以上版本 "storage" 已废除 图片 视频 音频权限需要分别申请 if (int.parse(NetworkConfig.systemVersion) >= 13) { storageStatus = await Permission.photos.status; } else { storageStatus = await Permission.storage.status; } if (storageStatus != PermissionStatus.granted) { if (int.parse(NetworkConfig.systemVersion) >= 13) { storageStatus = await Permission.photos.request(); } else { storageStatus = await Permission.storage.request(); } if (storageStatus != PermissionStatus.granted) { throw '无法存储图片,请先授权!'; } } Uint8List imageBytes = bytes.buffer.asUint8List(); /// 保存图片 final result = await ImageGallerySaver.saveImage(imageBytes, quality: 100); if (result == null || result == '') throw '图片保存失败'; EasyLoading.showToast("Successfully saved"); } catch (e) { print(e.toString()); } } //获取图片 static Future getImages() async { final pkImage = await ImagePicker().pickImage( source: ImageSource.gallery, ); return pkImage!; } //裁剪 static cropImage(BuildContext context, String path, int index) async { double x = 1.0; double y = 1.0; switch (index) { case 0: x = 1.0; y = 1.0; break; case 1: x = 3.0; y = 4.0; break; case 2: x = 4.0; y = 3.0; break; case 3: x = 9.0; y = 16.0; break; case 4: x = 16.0; y = 9.0; break; } CroppedFile? croppedFile = await ImageCropper().cropImage( maxHeight: 100, sourcePath: path, // aspectRatioPresets: [ // CropAspectRatioPreset.square, //1:1 // ], //aspectRatio: CropAspectRatio(ratioX: x, ratioY: y), uiSettings: [ IOSUiSettings( title: 'Cropper', aspectRatioLockEnabled: true, resetAspectRatioEnabled: false, ), AndroidUiSettings( toolbarTitle: 'Cropper', toolbarColor: Color(0xFFBE6FDF), toolbarWidgetColor: Colors.white, activeControlsWidgetColor: Color(0xFFBE6FDF), initAspectRatio: CropAspectRatioPreset.square, lockAspectRatio: true, ), WebUiSettings( context: context, viewwMode: WebViewMode.mode_1, cropBoxMovable: false /*customDialogBuilder: (cropper, initCropper, crop, rotate, scale) { return CropperDialog( cropper: cropper, initCropper: initCropper, crop: crop, rotate: rotate, scale: scale, ); },*/ ), ], ); return croppedFile; } //解析图片转base64 static uploadImage(XFile pickedFile) async { var file = File(pickedFile.path); String? type = lookupMimeType(pickedFile.path); //读取格式 Uint8List imageBytes = await file.readAsBytes(); String base64 = base64Encode(imageBytes); return "data:$type;base64,$base64"; } //解析图片转base64 static uploadImage2(File pickedFile) async { String? type = lookupMimeType(pickedFile.path); //读取格式 Uint8List imageBytes = await pickedFile.readAsBytes(); String base64 = base64Encode(imageBytes); return "data:$type;base64,$base64"; } // 获取文件大小 static String getFileSizeString({int? bytes, int decimals = 0}) { if (bytes! <= 0) return "0 Bytes"; const suffixes = [" Bytes", "KB", "MB", "GB", "TB"]; var i = (log(bytes) / log(1024)).floor(); return ((bytes / pow(1024, i)).toStringAsFixed(decimals)) + suffixes[i]; } // 获取文件大小(mb) static double getFileSizeDouble({int? bytes, int decimals = 0}) { final kb = bytes! / 1024; final mb = kb / 1024; print("object===$mb"); return mb; } ///网络图片转base64 static Future networkImageToBase64(String imageUrl) async { http.Response response = await http.get(Uri.parse(imageUrl)); final bytes = response.bodyBytes; print("bytes===$bytes"); return bytes != null ? base64Encode(bytes) : null; } }