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

Flutter/Dart中如何读取本地图片、获取尺寸并内存缩放?

嘿,这事儿我熟!在Flutter/Dart里完全能在内存里完成「读图→取尺寸→缩放」的全流程,不用把处理后的图片存回磁盘,直接就能用Image组件显示。下面给你一步步拆解实现:

步骤1:从磁盘读取图片字节

首先我们用dart:io里的File类读取图片文件,把它转换成内存中的字节数组(Uint8List)——这是后续所有操作的基础:

import 'dart:io';

// 替换成你的图片实际路径
final imageFile = File('/storage/emulated/0/Download/test.jpg');
if (!await imageFile.exists()) {
  throw Exception('图片文件不存在');
}
final originalBytes = await imageFile.readAsBytes();
步骤2:获取图片原始宽高

要拿到原始尺寸,我们需要用dart:ui里的图片解码能力(不能直接用Flutter的Image组件,因为它是UI层的,没法直接拿尺寸数据):

import 'dart:ui' as ui;

// 解码字节得到原始图片对象
final codec = await ui.instantiateImageCodec(originalBytes);
final frame = await codec.getNextFrame();
final originalImage = frame.image;

// 现在就能拿到原始宽高了
final originalWidth = originalImage.width;
final originalHeight = originalImage.height;
print('原始尺寸:$originalWidth x $originalHeight');
步骤3:内存中缩放图片

接下来我们用Canvas绘制缩放后的图片,再把绘制结果转换成字节数组——全程都在内存里完成,不用碰磁盘:

// 定义目标缩放尺寸(这里按比例缩放到宽度300,你可以按需调整)
final targetWidth = 300;
final targetHeight = (originalHeight * targetWidth / originalWidth).round();

// 创建绘图记录器和画布
final recorder = ui.PictureRecorder();
final canvas = Canvas(recorder);
// 用高质量滤镜提升缩放后的图片清晰度
final paint = Paint()..filterQuality = FilterQuality.high;

// 把原始图片绘制到目标尺寸的画布上
canvas.drawImageRect(
  originalImage,
  Rect.fromLTWH(0, 0, originalWidth.toDouble(), originalHeight.toDouble()),
  Rect.fromLTWH(0, 0, targetWidth.toDouble(), targetHeight.toDouble()),
  paint,
);

// 结束绘图,生成缩放后的图片对象
final picture = recorder.endRecording();
final scaledImage = await picture.toImage(targetWidth, targetHeight);
// 把图片转换成PNG字节(也可以选JPEG,不过PNG无损)
final byteData = await scaledImage.toByteData(format: ui.ImageByteFormat.png);
final scaledBytes = byteData!.buffer.asUint8List();

// 重要:记得释放图片资源,避免内存泄漏
originalImage.dispose();
scaledImage.dispose();
最终显示缩放后的图片

现在scaledBytes就是内存里的缩放后图片字节,直接用Image.memory就能显示:

Image.memory(scaledBytes)
完整封装函数

为了方便复用,你可以把这些逻辑封装成一个异步函数:

import 'dart:io';
import 'dart:ui' as ui;
import 'dart:typed_data';

Future<Uint8List> scaleImageFromDisk(String imagePath, int targetWidth) async {
  final imageFile = File(imagePath);
  if (!await imageFile.exists()) {
    throw Exception('图片文件不存在');
  }

  // 读取原始字节
  final originalBytes = await imageFile.readAsBytes();

  // 获取原始尺寸
  final codec = await ui.instantiateImageCodec(originalBytes);
  final frame = await codec.getNextFrame();
  final originalImage = frame.image;
  final originalWidth = originalImage.width;
  final originalHeight = originalImage.height;

  // 计算目标高度(按比例缩放)
  final targetHeight = (originalHeight * targetWidth / originalWidth).round();

  // 绘制缩放后的图片
  final recorder = ui.PictureRecorder();
  final canvas = Canvas(recorder);
  final paint = Paint()..filterQuality = FilterQuality.high;

  canvas.drawImageRect(
    originalImage,
    Rect.fromLTWH(0, 0, originalWidth.toDouble(), originalHeight.toDouble()),
    Rect.fromLTWH(0, 0, targetWidth.toDouble(), targetHeight.toDouble()),
    paint,
  );

  final picture = recorder.endRecording();
  final scaledImage = await picture.toImage(targetWidth, targetHeight);
  final byteData = await scaledImage.toByteData(format: ui.ImageByteFormat.png);
  final scaledBytes = byteData!.buffer.asUint8List();

  // 释放资源
  originalImage.dispose();
  scaledImage.dispose();

  return scaledBytes;
}

调用的时候就这么用:

final scaledBytes = await scaleImageFromDisk('/path/to/your/image.jpg', 300);
// 在UI里显示
Image.memory(scaledBytes)
注意事项
  • 别忘了处理异常:比如文件不存在、解码失败、内存不足等情况,建议用try-catch包裹调用逻辑
  • 如果需要按高度缩放,或者固定尺寸(不按比例),只需要调整targetWidth和targetHeight的计算逻辑就行
  • 缩放后的图片格式可以选ui.ImageByteFormat.jpeg,这样字节数组会更小,但会损失一点画质

内容的提问来源于stack exchange,提问作者Marcelo Glasberg

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 08:39:08