这是【Flutter 问题系列第 74 篇】,如果觉得有用的话,欢迎关注专栏。
文章目录
- 一:问题描述
- 二:引入,获取依赖
- 三:根据数据类型指定压缩方式
- 3-1:Uint8List → Uint8List
- 3-2:File → File
- 3-3:File → Uint8List
- 3-4:Asset → Uint8List
- 解释说明
- 四:完整代码
一:问题描述
项目中用到了百度 OCR 图像识别的功能,如果上传的图片大于 4 兆的话,就会提示因图片过大识别失败。
所以需要对上传的图像进行压缩,在 Flutter 中如何对图像数据进行压缩呢?
二:引入,获取依赖
这里用到了 pub 上的第三方插件库 flutter_image_compress,同时支持在 Android 和 iOS 上运行。截止到发文最新版本是 1.1.0 。
在项目的配置文件 pubspec.yaml
中引入依赖,如下图所示
然后在终端执行 flutter pub get
命令获取依赖。
三:根据数据类型指定压缩方式
这里我根据官方文档指定的数据类型,封装了四种不同的图像数据转换的方法,
这里自定义一个压缩图片的工具类 CompressUtil
,并指定其最小分辨率的高度和宽度。
如下代码所示
class CompressUtil {static int minHeight = 1920; static int minWidth = 1080;
}
然后在当前工具类中,定义了如下四个压缩的方法,简单明了,不需要你对插件有了解,直接拿走使用就行。
3-1:Uint8List → Uint8List
第一种压缩方式的参数类型是 Uint8List ,返回值类型是 Future
,如下代码所示
static Future<Uint8List> u8ToU8(Uint8List list) async {int quality &#61; imageQuality(list.length);Uint8List result &#61; await FlutterImageCompress.compressWithList(list,minWidth: minWidth,minHeight: minHeight,quality: quality,);debugPrint("压缩后图片的大小&#xff1a;${size(result.length)}");return result;}
3-2&#xff1a;File → File
第二种压缩方式的参数类型是 File&#xff0c;返回值类型是 Future
&#xff0c;如下代码所示
static Future<File?> fileToFile(File file) async {int quality &#61; imageQuality(file.readAsBytesSync().length);Directory cache &#61; await getTemporaryDirectory();int time &#61; DateTime.now().millisecondsSinceEpoch;String savePath &#61; cache.path &#43; "/AllenSu_$time.jpg"; File? result &#61; await FlutterImageCompress.compressAndGetFile(file.path,savePath,minWidth: minWidth,minHeight: minHeight,quality: quality,);if (result !&#61; null) {debugPrint("压缩后图片的大小&#xff1a;${size(result.readAsBytesSync().length)}");}return result;}
获取文件路径这里用到了插件 path_provider&#xff0c;需要在 pubspec.yaml
文件中引入。
压缩后图片的路径你可以修改为自定义的路径。
3-3&#xff1a;File → Uint8List
第三种压缩方式的参数类型是 File&#xff0c;返回值类型是 Future
&#xff0c;如下代码所示
static Future<Uint8List?> fileToU8(File file) async {int quality &#61; imageQuality(file.readAsBytesSync().length);Uint8List? result &#61; await FlutterImageCompress.compressWithFile(file.path,minWidth: minWidth,minHeight: minHeight,quality: quality,);if (result !&#61; null) {debugPrint("压缩后图片的大小&#xff1a;${size(result.length)}");}return result;}
3-4&#xff1a;Asset → Uint8List
第三种压缩方式的参数类型是 String&#xff08;其实就是图片的路径 path&#xff09;&#xff0c;返回值类型是 Future
&#xff0c;如下代码所示
static Future<Uint8List?> assetToU8(String assetName) async {File file &#61; File(assetName);int quality &#61; imageQuality(file.readAsBytesSync().length);Uint8List? result &#61; await FlutterImageCompress.compressAssetImage(assetName,minWidth: minWidth,minHeight: minHeight,quality: quality,);if (result !&#61; null) {debugPrint("压缩后图片的大小&#xff1a;${size(result.length)}");}return result!;}
以上四种压缩图片的方式满足正常开发是没有问题的。
解释说明
代码中的方法 imageQuality(int length)
和 size((int length))
是我自己扩展的&#xff0c;原因如下
- 对于方法 imageQuality&#xff0c;是为了根据传入的图片字节长度&#xff0c;返回指定的图片质量。如果你想固定压缩图片的质量&#xff0c;可以不用在意这个方法。
- 对于方法 size&#xff0c;是为了方便查看图片的大小&#xff0c;因为图片的大小是字节数组的长度&#xff0c;看起来不太方便&#xff0c;所以进行了转换&#xff0c;如果图片小于 1 兆&#xff0c;则显示 KB&#xff0c;如果图片大于 1 兆&#xff0c;则显示 MB&#xff0c;并保留一位小数。
我并没有把代码中的注释去掉&#xff0c;因为我觉得你在调试的时候应该可以用得到。
四&#xff1a;完整代码
以上是对封装的工具类进行了拆分&#xff0c;对工具类的每个方法进行了解释说明。
但为方便大家复制&#xff0c;最后把完整的代码贴到这里&#xff0c;如下
import &#39;dart:io&#39;;
import &#39;dart:typed_data&#39;;
import &#39;package:flutter/widgets.dart&#39;;
import &#39;package:flutter_image_compress/flutter_image_compress.dart&#39;;
import &#39;package:path_provider/path_provider.dart&#39;;
class CompressUtil {static int minHeight &#61; 1920; static int minWidth &#61; 1080; static Future<Uint8List> u8ToU8(Uint8List list) async {int quality &#61; imageQuality(list.length);Uint8List result &#61; await FlutterImageCompress.compressWithList(list,minWidth: minWidth,minHeight: minHeight,quality: quality,);debugPrint("压缩后图片的大小&#xff1a;${size(result.length)}");return result;}static Future<File?> fileToFile(File file) async {int quality &#61; imageQuality(file.readAsBytesSync().length);Directory cache &#61; await getTemporaryDirectory();int time &#61; DateTime.now().millisecondsSinceEpoch;String savePath &#61; cache.path &#43; "/AllenSu_$time.jpg";File? result &#61; await FlutterImageCompress.compressAndGetFile(file.path,savePath,minWidth: minWidth,minHeight: minHeight,quality: quality,);if (result !&#61; null) {debugPrint("压缩后图片的大小&#xff1a;${size(result.readAsBytesSync().length)}");}return result;}static Future<Uint8List?> fileToU8(File file) async {int quality &#61; imageQuality(file.readAsBytesSync().length);Uint8List? result &#61; await FlutterImageCompress.compressWithFile(file.path,minWidth: minWidth,minHeight: minHeight,quality: quality,);if (result !&#61; null) {debugPrint("压缩后图片的大小&#xff1a;${size(result.length)}");}return result;}static Future<Uint8List?> assetToU8(String assetName) async {File file &#61; File(assetName);int quality &#61; imageQuality(file.readAsBytesSync().length);Uint8List? result &#61; await FlutterImageCompress.compressAssetImage(assetName,minWidth: minWidth,minHeight: minHeight,quality: quality,);if (result !&#61; null) {debugPrint("压缩后图片的大小&#xff1a;${size(result.length)}");}return result!;}static int imageQuality(int length) {debugPrint("压缩前图片的大小&#xff1a;${size(length)}");int quality &#61; 100; int m &#61; 1024 * 1024; if (length < 0.5 * m) {quality &#61; 70;debugPrint("图片小于 0.5 兆&#xff0c;质量设置为 70");} else if (length >&#61; 0.5 * m && length < 1 * m) {quality &#61; 60;debugPrint("图片大于 0.5 兆小于 1 兆&#xff0c;质量设置为 60");} else if (length >&#61; 1 * m && length < 2 * m) {quality &#61; 50;debugPrint("图片大于 1 兆小于 2 兆&#xff0c;质量设置为 50");} else if (length >&#61; 2 * m && length < 3 * m) {quality &#61; 40;debugPrint("图片大于 2 兆小于 3 兆&#xff0c;质量设置为 40");} else if (length >&#61; 3 * m && length < 4 * m) {quality &#61; 30;debugPrint("图片大于 3 兆小于 4 兆&#xff0c;质量设置为 30");} else {quality &#61; 20;debugPrint("图片大于 4 兆&#xff0c;质量设置为 20");}return quality;}static String size(int length) {String res &#61; "";final int unit &#61; 1024;final int m &#61; unit * unit; if (length < 1 * m) {res &#61; (length / unit).toStringAsFixed(0) &#43; " KB";}if (length >&#61; 1 * m) {res &#61; (length / m).toStringAsFixed(1) &#43; " MB";}return res;}
}
经测试&#xff0c;1 张 1.2 兆的图片&#xff0c;如果设置压缩质量为 50&#xff0c;压缩后大概在 50 - 100 kb 之间&#xff0c;图片虽然小了许多&#xff0c;但还是很清晰的&#xff0c;且 OCR 识别成功率几乎是 100 %。
至此&#xff0c;关于如何在 Flutter 中对图像数据进行压缩便介绍到这里。
你的问题得到解决了吗&#xff1f;欢迎在评论区留言。
赠人玫瑰&#xff0c;手有余香&#xff0c;如果觉得文章不错&#xff0c;希望可以给个一键三连&#xff0c;感谢。
结束语 Google 的 Flutter 越来越火&#xff0c;截止 2022年7月9日 GitHub 标星已达 142K&#xff0c;Flutter 毅然是一种趋势&#xff0c;所以作为前端开发者&#xff0c;没有理由不趁早去学习。
无论你是 Flutter 新手还是已经入门了&#xff0c;不妨先点个关注&#xff0c;后续我会将 Flutter 中的常用组件&#xff08;含有源码分析、组件的用法及注意事项&#xff09;以及可能遇到的问题写到 CSDN 博客中&#xff0c;希望自己学习的同时&#xff0c;也可以帮助更多的人。