You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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:

  1. 先在pubspec.yaml中添加依赖:
dependencies:
  image: ^4.2.0
  path_provider: ^2.1.0
  1. 裁剪并缓存的示例逻辑:
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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 07:06:05