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 应用程序打开?

如何使用 Flutter 与 ERC721 智能合约交互?

如何将内存中的图像上传为 Flutter web 中 body 上的二进制图像?

Flutter 压缩相机图像

在 Flutter Web 中上传多个文件(图像)