Flutter腹板:如何压缩图像/文件?

4xrmg8kj  于 2023-01-14  发布在  Flutter
关注(0)|答案(4)|浏览(205)

Flutter Web目前处于测试阶段,因此缺乏如何做到这一点的可用信息/资源。
我找不到任何与网页兼容的flutter软件包来做这件事。有什么提示吗?
下面是我的代码:

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");
    }
  });
});
}
um6iljoc

um6iljoc1#

我已经花了几天的时间试图弄明白它。这里是你需要了解的。在我写这篇文章的时候,没有合适的库/包可以压缩flutter web中的图像。所以我最终在我的项目中使用javascript代码。
不要担心,这不是太多的工作。你也可以阅读我的博客完整的例子。
这是你需要做的。

    • 1.在flutter web index.html文件中添加浏览器图像压缩器(压缩图像)cdn、文件保存器(保存图像)cdn

同时创建名为app.js的新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函数**

一个二个一个一个

    • 更新**

如果您希望通过dart.将文件上传到服务器,则将文件发送到dart,然后再从dart发送到server/firebase。
要将压缩文件发送给flutter,请添加以下代码行。

window.parent.postMessage(compressedFile, "*");

同时要在Flutter中接收,请确保您有此侦听器函数。
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'编译错误。你可以通过导入基于平台修复这个问题。*

希望能帮到什么人,谢谢

wlp8pajw

wlp8pajw2#

因为一个纯粹的Flutter解决方案仍然存在,我将发布一个Flutter解决方案。但请注意,这个解决方案不是最好的性能wize。个人而言,如果我必须做一个PWA,我会在HTML/javascript中做,并完全抛弃Flutter。
Web解决方案的问题是我们不能真正创建一个文件,所以我们必须使用Uint 8List在内存中完成所有操作。为此,file_picker和image_compression_flutter包满足我们的要求。乍一看,最大的障碍是image_compression_flutter需要原始字节和路径(文件名),但深入研究后发现,该路径似乎仅用作确定mime类型的备用路径,因此我们实际上并不需要它,或者至少不是完整路径,这意味着我们可以使用file_picker执行以下操作(没有任何空值问题):

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;
  }

您必须导入foundation才能访问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'
            },
          ),
        );
0yg35tkg

0yg35tkg3#

感谢@Kunchok Tashi使用pica js包想出了一个非常快速的解决方案。
安装https://pub.dev/packages/js包之前,请按以下步骤操作:
首先,将pica和您自己的js文件(本例中为app.js)添加到index.html中:

<script
  src="https://cdnjs.cloudflare.com/ajax/libs/pica/9.0.1/pica.min.js"
  integrity="sha512-FH8Ofw1HLbwK/UTvlNBxsfICDXYZBr9dPuTh3j17E5n1QZjaucKikW6UwMREFo7Z42AlIigHha3UVwWepr0Ujw=="
  crossorigin="anonymous"
  referrerpolicy="no-referrer"
></script>
<script src="app.js" defer></script>

其次,app.js应该在web文件夹中,其内容如下:

async function fetchAndResizeImage(url) {
  const response = await fetch(url);
  var blob = await response.blob();
  const bitmap = await createImageBitmap(blob);

  const maxWidth = 1920.0; // set max sizes
  const maxHeight = 1080.0;

  console.log(`Width: ${bitmap.width}; Height: ${bitmap.height}`);

  // this simple routine makes sure that the resized image fully fits inside the box specified by max sizes while maintaining proportions
  var targetWidth = null;
  var targetHeight = null;
  if (bitmap.width > maxWidth) {
    targetWidth = maxWidth;
    const calcHeight = (targetHeight = Math.floor(
      bitmap.height * (targetWidth / bitmap.width)
    ));
    if (calcHeight > maxHeight) {
      targetHeight = maxHeight;
      targetWidth = Math.floor(targetWidth * (targetHeight / calcHeight));
    }
  } else if (bitmap.height > maxHeight) {
    targetHeight = maxHeight;
    const calcWidth = (targetWidth = Math.floor(
      bitmap.width * (targetHeight / bitmap.height)
    ));
    if (calcWidth > maxWidth) {
      targetWidth = maxWidth;
      targetHeight = Math.floor(targetHeight * (targetWidth / calcWidth));
    }
  }

  console.log(`Target width: ${targetWidth}; Target height: ${targetHeight}`);

  if (targetWidth != null && targetHeight != null) {
    const canvas = document.createElement("canvas");
    canvas.width = targetWidth;
    canvas.height = targetHeight;

    const _pica = pica();
    blob = await _pica.toBlob(await _pica.resize(bitmap, canvas), "image/jpeg");
  }

  const buffer = await blob.arrayBuffer();

  return { buffer: buffer, mimeType: blob.type };
}

第三,在lib中的任意位置添加dart文件,其内容如下:

@JS()
library app;

import 'dart:typed_data';

import 'package:js/js.dart';

external dynamic fetchAndResizeImage(String url);

@JS()
@anonymous
class ImageResult {
  external ByteBuffer get buffer;
  external String get mimeType;
}

最后,要调整图像大小,只需导入上述文件并调用:

var result = await promiseToFuture<ImageResult>(
  fetchAndResizeImage(url),
);
var imageBytes = result.buffer.asUint8List();
var mimeType = result.mimeType;
sh7euo9m

sh7euo9m4#

目前,我将创建一个云函数,在文件上传到后端的firebase存储时调整/压缩文件。
下面的链接介绍了在问题解决之前,如何为需要解决方法的用户执行此操作:https://www.youtube.com/watch?v=OKW8x8-qYs0
编辑
image picker library已更新。可以在here中找到解决方案

相关问题