crop_image_handler.dart
3.48 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
import 'dart:io';
import 'dart:typed_data';
import 'package:appframe/config/constant.dart';
import 'package:appframe/services/dispatcher.dart';
import 'package:dio/dio.dart';
import 'package:image/image.dart' as img;
import 'package:path/path.dart' as path;
import 'package:path_provider/path_provider.dart';
import 'package:uuid/uuid.dart';
class CropImageHandler extends MessageHandler {
@override
Future<dynamic> handleMessage(params) async {
if (params is! Map<String, dynamic>) {
throw Exception('参数错误');
}
var url = params['url'] as String?;
if (url == null || url.isEmpty) {
throw Exception('参数错误');
}
var cropScale = params['cropScale'] as String?;
if (cropScale == null || cropScale.isEmpty) {
throw Exception('参数错误');
}
var scaleArray = ['16:9', '9:16', '4:3', '3:4', '5:4', '4:5', '1:1'];
if (!scaleArray.contains(cropScale)) {
throw Exception('参数错误');
}
try {
String outputPath = await _cropImageByRatio(url, cropScale);
return {'tempFilePath': '${Constant.localServerTempFileUrl}$outputPath'};
} catch (e) {
throw Exception('裁剪出错');
}
}
Future<String> _cropImageByRatio(String url, String cropScale) async {
if (url.startsWith(Constant.localServerUrl)) {
url = url.replaceFirst(Constant.localServerUrl, '');
}
if (url.startsWith(Constant.localServerTemp)) {
url = url.replaceFirst(Constant.localServerTemp, '');
}
String extension = path.extension(url);
Directory cacheDirectory = await getApplicationCacheDirectory();
File imageFile;
// 对于远程图片,先下载到应用缓存目录,然后生成File
if (url.startsWith('https://') || url.startsWith('http://')) {
String tempFilePath = '${cacheDirectory.path}/${Uuid().v4()}$extension';
Dio dio = Dio();
Response resp = await dio.download(url, tempFilePath);
if (resp.statusCode != 200) {
throw Exception('下载图片失败');
}
dio.close(force: true);
imageFile = File(tempFilePath);
}
// 对于本地路径,直接生成File
else {
imageFile = File(url);
}
// 1. 读取图片文件并解码
Uint8List bytes = await imageFile.readAsBytes();
img.Image originalImage = img.decodeImage(bytes)!;
int originalWidth = originalImage.width;
int originalHeight = originalImage.height;
// 2. 计算目标裁剪区域
var targetRatio = cropScale.split(":");
double targetAspect = int.parse(targetRatio[0]) / int.parse(targetRatio[1]); // 例如 16/9
double currentAspect = originalWidth / originalHeight;
int cropWidth, cropHeight;
if (currentAspect > targetAspect) {
// 原图更宽,以高度为基准裁剪宽度
cropHeight = originalHeight;
cropWidth = (originalHeight * targetAspect).round();
} else {
// 原图更高,以宽度为基准裁剪高度
cropWidth = originalWidth;
cropHeight = (originalWidth / targetAspect).round();
}
// 3. 计算居中裁剪的起始点
int startX = (originalWidth - cropWidth) ~/ 2;
int startY = (originalHeight - cropHeight) ~/ 2;
// 4. 执行裁剪
img.Image croppedImage = img.copyCrop(originalImage, x: startX, y: startY, width: cropWidth, height: cropHeight);
// 5. 保存裁剪后的图片
String outputPath = '${cacheDirectory.path}/${Uuid().v4()}$extension';
await File(outputPath).writeAsBytes(img.encodeJpg(croppedImage));
return outputPath;
}
}