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

如何使用image包copyCrop方法实现1:1等比例图片自动裁剪

问题说明

之前的实现逻辑是调用图片裁剪器,引导用户从相册选择图片后按指定宽高比完成裁剪,后续发现image包无需唤起用户交互即可直接完成裁剪操作,但不知道如何计算指定宽高比(如1:1、0.8:1)对应的裁剪参数,也不清楚如何将这些参数传入image.copyCrop(int x, int y, int height,int width)方法。

原有交互裁剪代码

final croppedImage = await ImageCropper().cropImage(
  sourcePath: images!.path,
  cropStyle: CropStyle.rectangle,
  compressQuality: 100,
  compressFormat: ImageCompressFormat.jpg,
  aspectRatio: const CropAspectRatio(ratioX: 0.8, ratioY: 1.0),
);

测试中的无交互裁剪代码

var decodedImage = await decodeImageFromList(File(images!.path).readAsBytesSync());
print(decodedImage.width);
print(decodedImage.height);

final imageBytes = decodeImage(File(images!.path).readAsBytesSync())!;

img.Image cropOne = img.copyCrop(
  imageBytes,
  100,
  100,
  decodedImage.width,
  decodedImage.height,
);
File(images!.path).writeAsBytes(encodePng(cropOne));
实现方案

copyCrop方法的四个核心参数定义:

  • x:裁剪区域左上角距离原图左边缘的水平偏移量
  • y:裁剪区域左上角距离原图上边缘的垂直偏移量
  • width:裁剪区域的宽度
  • height:裁剪区域的高度

和ImageCropper默认行为一致,无交互裁剪默认采用居中裁剪规则,参数计算逻辑如下:

  1. 获取原图实际宽originalWidth、高originalHeight
  2. 计算目标宽高比targetRatio = ratioX / ratioY,原图实际宽高比originalRatio = originalWidth / originalHeight
  3. 对比两个比例确定裁剪区域尺寸:
    • 原图比例大于目标比例:原图偏宽,裁剪高度等于原图高度,裁剪宽度 = 原图高度 * 目标比例,左右裁去多余部分
    • 原图比例小于目标比例:原图偏高,裁剪宽度等于原图宽度,裁剪高度 = 原图宽度 / 目标比例,上下裁去多余部分
    • 两者比例相等:无需裁剪直接返回原图
  4. 计算居中偏移量:x = (原图宽度 - 裁剪宽度) ~/ 2,y = (原图高度 - 裁剪高度) ~/ 2

可直接复用的封装方法:

import 'dart:io';
import 'package:image/image.dart' as img;

/// 按指定宽高比居中裁剪图片
/// ratioX、ratioY对应CropAspectRatio的ratioX、ratioY参数
Future<File> autoCropImage({
  required File sourceFile,
  required double ratioX,
  required double ratioY,
}) async {
  // 解码原图
  final rawBytes = await sourceFile.readAsBytes();
  final originalImg = img.decodeImage(rawBytes)!;
  final originalW = originalImg.width;
  final originalH = originalImg.height;

  final targetRatio = ratioX / ratioY;
  final sourceRatio = originalW / originalH;

  int cropW, cropH;
  // 计算裁剪区域宽高
  if (sourceRatio > targetRatio) {
    cropH = originalH;
    cropW = (cropH * targetRatio).round();
  } else if (sourceRatio < targetRatio) {
    cropW = originalW;
    cropH = (cropW / targetRatio).round();
  } else {
    return sourceFile;
  }

  // 计算居中偏移
  final offsetX = (originalW - cropW) ~/ 2;
  final offsetY = (originalH - cropH) ~/ 2;

  // 执行裁剪,老版本image包用位置参数按offsetX、offsetY、cropW、cropH顺序传入即可
  final croppedImg = img.copyCrop(
    originalImg,
    x: offsetX,
    y: offsetY,
    width: cropW,
    height: cropH,
  );

  // 写入文件,可按需调整输出格式、压缩质量
  await sourceFile.writeAsBytes(img.encodeJpg(croppedImg, quality: 100));
  return sourceFile;
}

调用方式和原有ImageCropper传参逻辑一致:

// 0.8:1比例裁剪
await autoCropImage(
  sourceFile: File(images!.path),
  ratioX: 0.8,
  ratioY: 1.0,
);

// 1:1正方形裁剪
await autoCropImage(
  sourceFile: File(images!.path),
  ratioX: 1,
  ratioY: 1,
);

如果需要非居中的裁剪效果(比如顶部对齐、左对齐),只需要修改offsetX、offsetY的计算逻辑即可。


内容的提问来源于stack exchange,提问作者Flutter Dev

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 04:06:20