flutter/lib/utils/image_utils.dart
2025-09-17 15:32:18 +08:00

73 lines
2.1 KiB
Dart

import 'dart:io';
import 'dart:math' as math;
import 'dart:typed_data';
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
class ImageUtils {
/// 将图片裁剪成圆形,返回 PNG 文件路径
/// [imageFile] 或 [imageData] 二选一
static Future<String> toCircleImageFile({
Uint8List? imageData,
File? imageFile,
}) async {
if (imageData == null && imageFile == null) {
throw ArgumentError('必须提供 imageData 或 imageFile');
}
// 读取原始字节
final bytes = imageData ?? await imageFile!.readAsBytes();
// 1. 解码图片
final codec = await ui.instantiateImageCodec(bytes);
final frame = await codec.getNextFrame();
final original = frame.image;
final width = original.width;
final height = original.height;
final size = math.min(width, height);
// 2. 画布
final recorder = ui.PictureRecorder();
final canvas = Canvas(recorder);
final paint = Paint()..isAntiAlias = true;
// 3. 圆形遮罩
final center = Offset(size / 2, size / 2);
canvas.drawCircle(center, size / 2, paint..color = Colors.white);
// 4. 设置混合模式为 srcIn
paint.blendMode = BlendMode.srcIn;
// 5. 绘制原图(取正方形区域,保证圆形不变形)
final srcRect = Rect.fromLTWH(
(width - size) / 2,
(height - size) / 2,
size.toDouble(),
size.toDouble(),
);
final dstRect = Rect.fromLTWH(0, 0, size.toDouble(), size.toDouble());
canvas.drawImageRect(original, srcRect, dstRect, paint);
// 6. 导出为 Image
final picture = recorder.endRecording();
final imgFinal = await picture.toImage(size, size);
// 7. 转 PNG 字节
final byteData = await imgFinal.toByteData(format: ui.ImageByteFormat.png);
final pngBytes = byteData!.buffer.asUint8List();
// 8. 存临时文件
final tempDir = await getTemporaryDirectory();
final file = File(
'${tempDir.path}/circle_${DateTime.now().millisecondsSinceEpoch}.png',
);
await file.writeAsBytes(pngBytes);
return file.path;
}
}