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 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; } }