Flutter Web:如何压缩图像/文件?
Posted
技术标签:
【中文标题】Flutter Web:如何压缩图像/文件?【英文标题】:Flutter Web: How Do You Compress an Image/File? 【发布时间】:2020-06-28 22:00:55 【问题描述】:Flutter Web 目前处于测试阶段,因此缺乏有关如何执行此操作的可用信息/资源。
我找不到任何与 web 兼容的颤振包来执行此操作。 有什么建议吗?
这是我的代码:
uploadImage() async
File file;
FileReader fileReader = FileReader();
InputElement uploadInput = FileUploadInputElement();
uploadInput.click();
uploadInput.onChange.listen((event)
file = uploadInput.files.first;
fileReader.readAsDataUrl(file);
fileReader.onLoadEnd.listen((event)
if (file.type == "image/jpg" || file.type == "image/jpeg" || file.type == "image/png")
String base64FileString = fileReader.result.toString().split(',')[1];
//COMPRESS FILE HERE
setState(()
userImgFile = file;
userImageByteMemory = base64Decode(base64FileString);
);
else
CustomAlerts().showErrorAlert(context, "Image Upload Error", "Please Upload a Valid Image");
);
);
【问题讨论】:
如果您可以在 dartpad 中设置 MRE,我可以根据 post 为您提供帮助 您找到解决方案了吗?我需要知道如何在网络上执行此操作... @AxesGrinds 这个答案应该可以帮助你***.com/questions/46515679/… 【参考方案1】:由于仍然存在解决此问题的纯 Flutter 解决方案,因此我将发布 Flutter 解决方案。但请注意,此解决方案并不是最佳性能。就个人而言,如果我必须制作 PWA,我会在 html/javascript 中完成并完全放弃 Flutter。
Web 解决方案的问题是我们无法真正创建文件,因此我们必须使用 Uint8List 在内存中完成所有操作。为此,file_picker 和 image_compression_flutter 包满足了要求。 乍一看,最大的障碍是 image_compression_flutter 需要原始字节和文件的路径(文件名),但深入研究似乎该路径仅用作确定 mime 类型的后备,所以我们不真的需要它,或者至少不是完整的路径。 这意味着我们可以使用 file_picker 执行以下操作(没有任何 null 问题):
FilePickerResult? result = await FilePicker.platform.pickFiles();
var imageBytes;
var filename;
if (kIsWeb)
imageBytes = result!.files.first.bytes;
filename = result!.files.first.name;
else
var file = File(result!.files.first.path!);
imageBytes = await file.readAsBytes();
filename = result!.files.first.path;
您必须导入基础才能访问 kIsWeb: 导入'package:flutter/foundation.dart';
以及使用 image_compression_flutter,类似于:
Future<Uint8List?> compressImage(Uint8List imgBytes,
required String path, int quality = 70) async
final input = ImageFile(
rawBytes: imgBytes,
filePath: path,
);
Configuration config = Configuration(
outputType: ImageOutputType.jpg,
// can only be true for android and ios while using ImageOutputType.jpg or ImageOutputType.pngÏ
useJpgPngNativeCompressor: false,
// set quality between 0-100
quality: quality,
);
final param = ImageFileConfiguration(input: input, config: config);
final output = await compressor.compress(param);
return output.rawBytes;
要上传到 Firebase 存储,可以执行以下操作:
var filenameRef = DateTime.now().millisecondsSinceEpoch.toString();
var snapshot = await storage.ref(filenameRef).putData(
rawBytes, //the Uint8List
SettableMetadata(
contentType: 'image/jpeg',
customMetadata:
'myprop1': 'myprop1value'
'myprop2': 'myprop2value'
,
),
);
【讨论】:
此方法 compressImage 是否适用于网络?配置器方法至少会使用质量参数来压缩图像?【参考方案2】:好吧,我花了几天时间试图弄清楚。这是您需要了解的内容。在我写这篇文章的时候,没有合适的库/包可以压缩 Flutter Web 中的图像。所以我最终在我的项目中使用了 javascript 代码。 不用担心工作量不大。您也可以阅读我的博客了解完整示例。
这是您需要做的。1.在你的flutter web index.html文件中添加浏览器图像压缩器(压缩图像)cdn,filesaver(保存图像)cdn 同时创建新的 js 文件名 app.js 并导入它。
<script type="text/javascript"
src="https://cdn.jsdelivr.net/npm/browser-image-compression@1.0.13/dist/browser-image-compression.js"></script>
<script src="http://cdn.jsdelivr.net/g/filesaver.js"></script>
<script src="app.js" defer></script>
2。现在导入完成更新 app.js 如下
function compressAndDownloadImage(base64)
var url = base64;
fetch(url)
.then(res => res.blob())
.then(blob =>
var imageFile = blob;
console.log('originalFile instanceof Blob', imageFile instanceof Blob); // true
console.log(`originalFile size $imageFile.size / 1024 / 1024 MB`);
var options =
maxSizeMB: 0.2,//right now max size is 200kb you can change
maxWidthOrHeight: 1920,
useWebWorker: true
imageCompression(imageFile, options)
.then(function (compressedFile)
console.log('compressedFile instanceof Blob', compressedFile instanceof Blob); // true
console.log(`compressedFile size $compressedFile.size / 1024 / 1024 MB`); // smaller than maxSizeMB
console.log(compressedFile);
saveAs(new Blob([compressedFile], type: "image/jpeg" ), Math.floor(Date.now() / 1000) + '.jpeg');
return uploadToServer(compressedFile); // write your own logic
)
.catch(function (error)
console.log(error.message);
);
)
3.好的,现在你可以在任何需要压缩图像的地方调用这个函数了,从任何地方调用这个 dart 函数
import 'dart:js' as js; //import first
//call compressAndDownloadImage with base64 image you want to compress
var base64data="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="
js.context.callMethod(
'compressAndDownloadImage', ['$base64data']);
更新 如果您希望通过 dart 将文件上传到服务器。然后将文件发送到 dart 并从那里发送到服务器/firebase。 要将压缩文件发送到颤振添加这行代码。
window.parent.postMessage(compressedFile, "*");
还要确保你有这个监听器功能。import 'dart:html' as html;
window.addEventListener("message", (event)
html.MessageEvent event2 = event;
html.Blob blob = event2.data;
print(blob.type); // you can do whatever you want in dart
);
注意这只适用于flutter web。如果你在移动设备上运行,你会得到 'dart:js' 或 'dart:html' 编译错误。您可以通过基于平台的导入来解决此问题。 希望对大家有帮助,谢谢
【讨论】:
你能解释一下如何在这一行编写或通信 return uploadToServer(compressedFile); // 直接通过 dart 代码编写您自己的逻辑,因为我试图将我的图像上传到 firebase 服务器上,我需要使用图像路径调用我的函数 @ferox147 帖子更新了,你可以去看看。现在我们正在发送 blob 类型,如果您愿意,您可以发送 base64。谢谢 我收到空响应和错误,因为事件不是 MessageEvent 的类型。我们是否必须添加任何等待或异步函数,因为压缩可能需要时间并且在压缩完成后需要数据? 不是必需的,当你调用 postMessage 时,它会开始压缩,一旦完成,addEventListener 就会调用。只要确保你的监听器在监听。你可以在flutter中加入你的构建函数 @codingwithtashi 如何将 blob 发送到我的 API,此 blob 仅提供两种方法的大小和类型。但我想发送一个文件或字节类型【参考方案3】:目前,我将创建一个云函数来在文件上传到后端的 firebase 存储时调整文件大小/压缩文件作为解决方法。
这里有一个链接,说明如何为那些在解决此问题之前需要解决方法的人执行此操作:https://www.youtube.com/watch?v=OKW8x8-qYs0
编辑
image picker library 已更新。 可以找到解决办法here
【讨论】:
这并不能解决手头的问题,这不是颤振/飞镖解决方案。 此外,此评论中的 image_picker 库链接不支持 web 的大小调整/压缩。 OP要求网络。以上是关于Flutter Web:如何压缩图像/文件?的主要内容,如果未能解决你的问题,请参考以下文章
将 Flutter 应用迁移到 Flutter Web 时如何显示图像资产?
Flutter Web - 如何在桌面上的 Chrome 中测试 Flutter Web 应用程序打开?