如何使用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默认行为一致,无交互裁剪默认采用居中裁剪规则,参数计算逻辑如下:
- 获取原图实际宽
originalWidth、高originalHeight - 计算目标宽高比
targetRatio = ratioX / ratioY,原图实际宽高比originalRatio = originalWidth / originalHeight - 对比两个比例确定裁剪区域尺寸:
- 原图比例大于目标比例:原图偏宽,裁剪高度等于原图高度,裁剪宽度 = 原图高度 * 目标比例,左右裁去多余部分
- 原图比例小于目标比例:原图偏高,裁剪宽度等于原图宽度,裁剪高度 = 原图宽度 / 目标比例,上下裁去多余部分
- 两者比例相等:无需裁剪直接返回原图
- 计算居中偏移量:
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
相关产品推荐
相关产品推荐

