Flutter如何按指定纹理坐标裁剪图像并仅显示目标区域内容
Flutter 精确裁剪图像指定区域实现方案
这里提供两种实现思路,均不需要用户交互裁剪弹窗,可满足固定坐标裁剪的需求:
方案1:运行时实时裁剪(无需预处理,优先推荐)
直接使用Flutter内置API在绘制阶段完成裁剪,逻辑完全基于原图像像素坐标,最终展示效果不受外层Widget尺寸影响,不需要额外引入第三方依赖。
核心通过CustomPaint + canvas.drawImageRect实现,示例代码如下:
1. 自定义裁剪绘制类
import 'dart:ui' as ui; import 'package:flutter/material.dart'; class FixedCropImagePainter extends CustomPainter { // 原图像实例 final ui.Image originImage; // 裁剪区域(对应原图像的像素坐标范围) final Rect cropArea; FixedCropImagePainter({required this.originImage, required this.cropArea}); @override void paint(Canvas canvas, Size size) { // 原图像裁剪范围 final srcRect = cropArea; // 目标绘制范围:占满当前CustomPaint的尺寸,可按需自定义缩放比例 final dstRect = Rect.fromLTWH(0, 0, size.width, size.height); canvas.drawImageRect(originImage, srcRect, dstRect, Paint()); } @override bool shouldRepaint(covariant FixedCropImagePainter oldDelegate) { return originImage != oldDelegate.originImage || cropArea != oldDelegate.cropArea; } }
2. 页面中使用
首先需要把原图像加载为ui.Image类型的对象,再传入自定义绘制类即可:
import 'package:flutter/services.dart'; // 加载资源目录下的图像为ui.Image对象 Future<ui.Image> loadAssetImage(String assetPath) async { final byteData = await rootBundle.load(assetPath); final codec = await ui.instantiateImageCodec(byteData.buffer.asUint8List()); final frameInfo = await codec.getNextFrame(); return frameInfo.image; } // 组件使用示例 class CropImageDemo extends StatelessWidget { const CropImageDemo({super.key}); @override Widget build(BuildContext context) { return FutureBuilder<ui.Image>( // 替换为你的图像资源路径 future: loadAssetImage("assets/test_image.png"), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.done && snapshot.hasData) { // 按照需求填写裁剪的坐标范围:左上角(125,47),右下角(746,693) final targetCropArea = Rect.fromLTRB(125, 47, 746, 693); // CustomPaint的尺寸可自定义,这里设置为裁剪区域的原始尺寸,也可填其他值做缩放 final paintSize = Size(targetCropArea.width, targetCropArea.height); return CustomPaint( size: paintSize, painter: FixedCropImagePainter( originImage: snapshot.data!, cropArea: targetCropArea, ), ); } return const CircularProgressIndicator(); }, ); } }
方案2:预处理裁剪后本地缓存
如果需要多次复用裁剪后的图像,可提前完成裁剪操作并缓存到本地,后续直接加载裁剪后的文件即可,需要用到第三方图像处理库image:
- 先在
pubspec.yaml中添加依赖:
dependencies: image: ^4.2.0 path_provider: ^2.1.0
- 裁剪并缓存的示例逻辑:
import 'package:image/image.dart' as img; import 'dart:io'; import 'package:path_provider/path_provider.dart'; Future<File> cropAndCacheImage(String originImagePath, Rect cropArea, String uniqueCacheKey) async { // 读取原图像 final originFile = File(originImagePath); final originBytes = await originFile.readAsBytes(); final originImage = img.decodeImage(originBytes)!; // 执行裁剪 final croppedImage = img.copyCrop( originImage, x: cropArea.left.toInt(), y: cropArea.top.toInt(), width: cropArea.width.toInt(), height: cropArea.height.toInt(), ); // 保存到本地临时缓存目录 final tempDir = await getTemporaryDirectory(); final croppedFile = File("${tempDir.path}/crop_$uniqueCacheKey.png"); await croppedFile.writeAsBytes(img.encodePng(croppedImage)); return croppedFile; }
后续直接使用Image.file加载返回的裁剪后文件即可。
内容的提问来源于stack exchange,提问作者Chen Li Yong
相关产品推荐
相关产品推荐

