Flutter中如何使用AI生成的二维数组蒙版实现图像指定区域模糊
嘿,我来帮你搞定Flutter里指定区域模糊的问题!你遇到的MaskFilter.blur只能用单个sigma参数的问题确实挺头疼的,不过有两种靠谱的方案能实现你要的效果,咱们一步步说~
方案一:自定义Painter结合ImageFilter.blur(适合实时渲染)
这个方法直接在Widget的绘制流程里处理,不需要提前修改图像文件,适合需要实时交互的场景。
实现步骤
- 准备基础资源:你需要加载好原始图像,以及后端返回的二维蒙版数组。
- 生成蒙版路径:把二维数组转换成Canvas能识别的
Path——遍历数组,把值为0(需要模糊的深粉色区域)的位置转换成对应的矩形,添加到Path中:Path generateMaskPathFromArray(List<List<int>> maskArray, Size imageSize) { final path = Path(); final tileWidth = imageSize.width / maskArray[0].length; final tileHeight = imageSize.height / maskArray.length; for (int y = 0; y < maskArray.length; y++) { for (int x = 0; x < maskArray[y].length; x++) { if (maskArray[y][x] == 0) { // 0对应需要模糊的区域 final rect = Rect.fromLTWH( x * tileWidth, y * tileHeight, tileWidth, tileHeight, ); path.addRect(rect); } } } return path; } - 自定义Painter绘制模糊区域:利用
Canvas.saveLayer配合ImageFilter.blur(这个支持单独设置sigmaX和sigmaY!),只在蒙版区域应用模糊效果:class MaskedBlurPainter extends CustomPainter { final Image originalImage; final List<List<int>> maskArray; MaskedBlurPainter({required this.originalImage, required this.maskArray}); @override void paint(Canvas canvas, Size size) { // 先绘制原始图像,保留非模糊区域 canvas.drawImage(originalImage, Offset.zero, Paint()); final maskPath = generateMaskPathFromArray(maskArray, size); // 保存当前图层,给后续内容应用模糊滤镜 canvas.saveLayer( Offset.zero & size, Paint()..imageFilter = ImageFilter.blur(sigmaX: 15, sigmaY: 10), ); // 用clear模式绘制蒙版路径,相当于把模糊效果"裁剪"到蒙版区域 canvas.drawPath( maskPath, Paint()..blendMode = BlendMode.clear, ); // 恢复图层,完成绘制 canvas.restore(); } @override bool shouldRepaint(covariant MaskedBlurPainter oldDelegate) { return originalImage != oldDelegate.originalImage || maskArray != oldDelegate.maskArray; } } - 在Widget中使用:把这个Painter放到
CustomPaint里就能显示了:CustomPaint( size: Size(originalImage.width.toDouble(), originalImage.height.toDouble()), painter: MaskedBlurPainter(originalImage: originalImage, maskArray: maskArray), )
方案二:用image库提前处理图像(适合保存或复用)
如果需要把处理后的图像保存到本地,或者多次复用,推荐用pub上的image库直接操作像素,精度更高。
实现步骤
- 添加依赖:在
pubspec.yaml里加上:dependencies: image: ^4.0.17 # 版本号以最新为准 - 编写处理函数:把原始图像转成
image库的对象,遍历蒙版数组对指定区域应用模糊,再转成Flutter的Image:import 'package:image/image.dart' as img; import 'dart:typed_data'; import 'dart:ui' as ui; Future<ui.Image> applyMaskedBlur(ui.Image originalImage, List<List<int>> maskArray) async { // 把Flutter Image转成image库的Image对象 final byteData = await originalImage.toByteData(format: ui.ImageByteFormat.png); final img.Image inputImage = img.decodeImage(byteData!.buffer.asUint8List())!; final width = inputImage.width; final height = inputImage.height; final tileWidth = width ~/ maskArray[0].length; final tileHeight = height ~/ maskArray.length; // 遍历蒙版,模糊指定区域 for (int y = 0; y < maskArray.length; y++) { for (int x = 0; x < maskArray[y].length; x++) { if (maskArray[y][x] == 0) { final startX = x * tileWidth; final startY = y * tileHeight; final endX = (x + 1) * tileWidth; final endY = (y + 1) * tileHeight; // 这里可以分别设置sigmaX和sigmaY,精准控制模糊方向和程度 img.blur( inputImage, sigmaX: 15, sigmaY: 10, x: startX, y: startY, width: endX - startX, height: endY - startY, ); } } } // 转成Flutter可用的Image final Uint8List outputBytes = img.encodePng(inputImage); final codec = await ui.instantiateImageCodec(outputBytes); final frame = await codec.getNextFrame(); return frame.image; } - 调用并显示:在FutureBuilder里处理异步操作,显示处理后的图像:
FutureBuilder<ui.Image>( future: applyMaskedBlur(originalImage, maskArray), builder: (context, snapshot) { if (snapshot.hasData) { final byteData = await snapshot.data!.toByteData(format: ui.ImageByteFormat.png); return Image(image: MemoryImage(byteData!.buffer.asUint8List())); } return const CircularProgressIndicator(); }, )
小提示
- 如果蒙版的精度很高(比如每个元素对应单个像素),方案二的像素操作性能会更好;如果是大块区域模糊,方案一更轻便。
ImageFilter.blur在不同平台的渲染效果可能略有差异,记得在目标平台上测试调整sigma值。
内容的提问来源于stack exchange,提问作者Salim Benabadji
相关产品推荐
相关产品推荐

