| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260 |
- import 'dart:async';
- import 'dart:convert';
- import 'dart:io';
- import 'dart:math' as math;
- import 'dart:ui' as ui;
- import 'package:crypto/crypto.dart';
- import 'package:flutter/material.dart';
- import 'package:flutter/services.dart';
- // import 'package:fluttertoast/fluttertoast.dart';
- import 'package:logging/logging.dart';
- import 'package:path_provider/path_provider.dart';
- import 'package:share_plus/share_plus.dart';
- T? tryCast<T>(dynamic object) => object is T ? object : null;
- final Logger _log = Logger('utils.dart');
- Future<ui.Image> loadUiImageFromFile(String filePath) async {
- final file = await localFile(filePath);
- final data = await file.readAsBytes();
- final Completer<ui.Image> completer = Completer();
- ui.decodeImageFromList(data, (ui.Image img) {
- return completer.complete(img);
- });
- return completer.future;
- }
- Future<ui.Image> loadUiImageFromXFile(XFile xfile) async {
- final file = File(xfile.path);
- final data = await file.readAsBytes();
- final Completer<ui.Image> completer = Completer();
- ui.decodeImageFromList(data, (ui.Image img) {
- return completer.complete(img);
- });
- return completer.future;
- }
- Future<ui.Image> loadUiImageFromAsset(String assetPath) async {
- final ByteData data = await rootBundle.load(assetPath);
- final Completer<ui.Image> completer = Completer();
- ui.decodeImageFromList(Uint8List.view(data.buffer), (ui.Image img) {
- return completer.complete(img);
- });
- return completer.future;
- }
- Future<ui.Image> loadUiImageFromNetwork(String url) async {
- final ByteData data = await NetworkAssetBundle(Uri.parse(url)).load('');
- final Completer<ui.Image> completer = Completer();
- ui.decodeImageFromList(Uint8List.view(data.buffer), (ui.Image img) {
- return completer.complete(img);
- });
- return completer.future;
- }
- Future<Map<String, dynamic>> loadJSONFromAsset(String assetPath) async {
- final jsonStr = await rootBundle.loadString(assetPath);
- final Map<String, dynamic> json = jsonDecode(jsonStr);
- return json;
- }
- Future<Uint8List> loadFileDataFromAsset(String assetPath) async {
- final ByteData data = await rootBundle.load(assetPath);
- return Uint8List.view(data.buffer);
- }
- Future<List<String>> listAssets(String path) async {
- final manifestContent = await rootBundle.loadString('AssetManifest.json');
- final Map<String, dynamic> manifestMap = jsonDecode(manifestContent);
- // _log.info('manifestMap: $manifestMap');
- final paths = manifestMap.keys.where((String key) => key.contains(path)).toList();
- return paths;
- }
- Future<String> localDir() async {
- final Directory dir = await getApplicationDocumentsDirectory();
- return dir.path;
- }
- Future<File> localFile(String filePath) async {
- final String path = await localDir();
- return File('$path/$filePath');
- }
- // Future<Map<String, dynamic>> loadJson(String filePath) async {
- Future<Object> loadJson(String filePath) async {
- File file = await localFile(filePath);
- final String str = await file.readAsString();
- final json = jsonDecode(str);
- _log.info('json: ${json.runtimeType}');
- return json;
- }
- Future<bool> ensureDirectory(File file) async {
- Directory directory = file.parent;
- if (!await directory.exists()) {
- await directory.create(recursive: true);
- return true;
- }
- return true;
- }
- Future<bool> saveBytes(String filePath, Uint8List data) async {
- File file = await localFile(filePath);
- _log.info('saveImage: file=$file');
- await ensureDirectory(file);
- await file.writeAsBytes(data);
- return true;
- }
- Future<bool> saveImage(String filePath, ui.Image image) async {
- final bytes = await image.toByteData(format: ui.ImageByteFormat.png);
- if (bytes == null) return false;
- return saveBytes(filePath, bytes.buffer.asUint8List());
- }
- Future<bool> saveJson(String filePath, dynamic data) async {
- File file = await localFile(filePath);
- await ensureDirectory(file);
- String str = jsonEncode(data);
- await file.writeAsString(str);
- return true;
- }
- Future<bool> saveString(String filePath, String data) async {
- File file = await localFile(filePath);
- await ensureDirectory(file);
- await file.writeAsString(data);
- return true;
- }
- Future<ui.Image> mosaicImage(ui.Image image) async {
- ui.PictureRecorder recorder = ui.PictureRecorder();
- ui.Canvas canvas = ui.Canvas(recorder);
- ui.Paint paint = ui.Paint();
- canvas.drawImageRect(image, Rect.fromLTWH(0, 0, image.width.toDouble(), image.height.toDouble()), const Rect.fromLTWH(0, 0, 8, 8), paint);
- ui.Image mosaicImage = await recorder.endRecording().toImage(8, 8);
- return mosaicImage;
- }
- Future<ui.Image> mosaicImage2(ui.Image image) async {
- const int piece = 8;
- final data = await image.toByteData();
- final pixels = data!.buffer.asUint32List();
- ui.PictureRecorder recorder = ui.PictureRecorder();
- ui.Canvas canvas = ui.Canvas(recorder);
- ui.Paint paint = ui.Paint();
- double width = image.width / piece;
- double height = image.height / piece;
- for (int i = 0; i < piece; i++) {
- for (int j = 0; j < piece; j++) {
- Rect rect = Rect.fromLTWH(i * width, j * height, width, height);
- int pixel32 = pixels[rect.center.dy.toInt() * image.width + rect.center.dx.toInt()];
- int hex = abgrToArgb(pixel32);
- Color color = Color(hex);
- canvas.drawRect(rect, paint..color = color);
- }
- }
- ui.Image mosaicImage = await recorder.endRecording().toImage(image.width, image.height);
- return mosaicImage;
- }
- int abgrToArgb(int argbColor) {
- int r = (argbColor >> 16) & 0xFF;
- int b = argbColor & 0xFF;
- return (argbColor & 0xFF00FF00) | (b << 16) | r;
- }
- class TimingLogSplit {
- String tag;
- Duration duration;
- TimingLogSplit(this.tag, this.duration);
- @override
- String toString() => '$tag: ${duration.inMilliseconds}';
- }
- class TimingLog {
- final String label;
- final DateTime _start = DateTime.now();
- DateTime? _lastSplit;
- final List<TimingLogSplit> splits = [];
- TimingLog(this.label);
- TimingLog addSplit(String tag) {
- _lastSplit ??= _start;
- final current = DateTime.now();
- splits.add(TimingLogSplit('$label.$tag', Duration(microseconds: (current.microsecondsSinceEpoch - _lastSplit!.microsecondsSinceEpoch))));
- _lastSplit = current;
- return this;
- }
- TimingLog stop() {
- final current = DateTime.now();
- splits.add(TimingLogSplit('$label.total', Duration(microseconds: (current.microsecondsSinceEpoch - _start.microsecondsSinceEpoch))));
- return this;
- }
- @override
- String toString() {
- return splits.join('\n');
- }
- }
- String md5Hash(String str) {
- return md5.convert(utf8.encode(str)).toString();
- }
- String niceBytes(bytes, {decimals = 2}) {
- if (!bytes) return '0 Bytes';
- const k = 1024;
- final dm = decimals < 0 ? 0 : decimals;
- final sizes = ['Bytes', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'];
- final i = (math.log(bytes) / math.log(k)).floor();
- return '${((bytes / math.pow(k, i)).toFixed(dm))} ${sizes[i]}';
- }
- String timeSpentFormat(int seconds) {
- int hour = seconds ~/ 3600;
- int minute = seconds % 3600 ~/ 60;
- int second = seconds % 60;
- if (hour > 0) {
- return "${formatNum(hour)}:${formatNum(minute)}:${formatNum(second)}";
- } else {
- return "${formatNum(minute)}:${formatNum(second)}";
- }
- }
- String formatNum(int num) {
- return num < 10 ? "0$num" : "$num";
- }
- void checkMemory() {
- ImageCache imageCache = PaintingBinding.instance.imageCache;
- debugPrint("liveImageCount = ${imageCache.liveImageCount}");
- if (imageCache.liveImageCount >= 100) {
- debugPrint("liveImageCount = ${imageCache.liveImageCount}, clear!");
- imageCache.clear();
- imageCache.clearLiveImages();
- }
- }
- // 辅助扩展:解决 Dart 缺少 firstWhereOrNull 的问题
- extension IterableExtension<T> on Iterable<T> {
- T? firstWhereOrNull(bool Function(T element) test) {
- for (final element in this) {
- if (test(element)) {
- return element;
- }
- }
- return null;
- }
- }
|