Flutter 裁剪图片

在ble传入数据的时候对图片要一定的要求,比如:尺寸、文件大小等。 1、输入图片形状:长方形、正方形 2、目标大小 3、输入裁剪和压缩后的图片 4、代码如下

ini 复制代码
/// 将图片裁剪为正方形并缩放到 [squareSize] x [squareSize],
/// 然后通过调整 JPEG 质量压缩至 [targetSize] 字节以内。
/// [imageBytes]  : 原始图像字节数据
/// [squareSize]  : 最终正方形的边长(像素),例如 360
/// [targetSize]  : 目标文件大小(字节)
/// [minQuality]  : 允许的最低 JPEG 质量(1-100),防止过度压缩
/// 返回压缩后的 JPEG 字节数据,如果解码失败则返回原图。
static Future<Uint8List> compressToSize(
  Uint8List imageBytes,
  int squareSize,
  int targetSize, {
  int minQuality = 85,
}) async {
  final original = img.decodeImage(imageBytes);
  if (original == null) return imageBytes; // 解码失败,返回原图

  // 1. 裁剪为正方形(基于最小边居中裁剪)
  img.Image squareImage;
  final int srcWidth = original.width;
  final int srcHeight = original.height;

  if (srcWidth > srcHeight) {
    // 宽度大于高度:以高度为边长,裁剪左右
    final int cropX = (srcWidth - srcHeight) ~/ 2;
    squareImage = img.copyCrop(
      original,
      x: cropX,
      y: 0,
      width: srcHeight,
      height: srcHeight,
    );
  } else if (srcHeight > srcWidth) {
    // 高度大于宽度:以宽度为边长,裁剪上下
    final int cropY = (srcHeight - srcWidth) ~/ 2;
    squareImage = img.copyCrop(
      original,
      x: 0,
      y: cropY,
      width: srcWidth,
      height: srcWidth,
    );
  } else {
    // 已是正方形,无需裁剪
    squareImage = original;
  }

  // 2. 缩放到目标正方形尺寸
  final resizedImage = img.copyResize(
    squareImage,
    width: squareSize,
    height: squareSize,
  );

  // 3. 二分法调整 JPEG 质量
  int low = 1;
  int high = 100;
  int bestQuality = 100;
  Uint8List bestBytes = img.encodeJpg(resizedImage, quality: bestQuality);

  // 如果最高质量已经小于目标,直接返回
  if (bestBytes.length <= targetSize) {
    return bestBytes;
  }

  const int maxIterations = 10;
  for (int i = 0; i < maxIterations; i++) {
    int mid = (low + high) ~/ 2;
    if (mid < minQuality) break;

    final compressedBytes = img.encodeJpg(resizedImage, quality: mid);
    if (compressedBytes.length <= targetSize) {
      // 满足要求,尝试更高质量
      bestQuality = mid;
      bestBytes = compressedBytes;
      low = mid + 1;
    } else {
      high = mid - 1;
    }

    if (low > high) break;
  }

  return bestBytes;
}
相关推荐
MyBili3 分钟前
【安卓开发/搞机】快图浏览(QuickPic)技术解析:为何这款3MB应用仍是本地图库的性能天花板?
android·app·安卓·文件管理·相册·看图软件·手机相册
Rain5098 分钟前
谁动了我的 URL?——记一次微前端“灵异 Bug“的排查实录
前端·vue.js·人工智能·前端框架·bug·ai编程
bjzhang7531 分钟前
使用HTML+CSS美化上传进度条展示
前端·css·html
何以解忧,唯有..37 分钟前
Vue 3 响应式核心:ref() 与 reactive() 的深入解析与实战
前端·javascript·vue.js
晴天1642 分钟前
Chrome DevTools Protocol(CDP)分享-Day36
前端·chrome·chrome devtools
风骏时光牛马42 分钟前
程序员的职场成长:技术之外,更要修炼底层思考力
前端
YWL44 分钟前
CSS变量与预处理器
前端·css
朱 欢 庆4 小时前
云服务器附件备份到本机内网服务器
运维·服务器·前端·经验分享
支支დ9 小时前
VO by Vercel 前端特定优势:为什么它是构建 AI 应用的新范式
前端·人工智能
香芋芋圆10 小时前
AI 冲击内卷之下,普通前端如何破局?WebGIS—— 低门槛突围赛道
前端·javascript·人工智能·学习·职场发展