颤动& Firebase:上传图片前的压缩

时间:2017-10-01 18:44:54

标签: firebase dart firebase-storage flutter

我想将用户在我的应用中选择的照片发送到Firebase存储。我有一个带有属性_imageFile的简单类,其设置如下:

File _imageFile;

_getImage() async {
    var fileName = await ImagePicker.pickImage();
    setState(() {
        _imageFile = fileName;
    });
}

之后,我发送照片,如下代码:

final String rand1 = "${new Random().nextInt(10000)}";
final String rand2 = "${new Random().nextInt(10000)}";
final String rand3 = "${new Random().nextInt(10000)}";
final StorageReference ref = FirebaseStorage.instance.ref().child('${rand1}_${rand2}_${rand3}.jpg');
final StorageUploadTask uploadTask = ref.put(_imageFile);
final Uri downloadUrl = (await uploadTask.future).downloadUrl;
print(downloadUrl);

问题是照片通常非常大。在上传之前,Flutter / Dart中是否有任何压缩和调整照片大小的方法?我对质量的损失感到满意。

12 个答案:

答案 0 :(得分:17)

我遇到了这个并且能够使用Dart caches class definitionsimage package完成压缩/调整大小。您可以查看dart path providerimage api以获取其他方式和更多帮助。

这就是我的所作所为:

import 'package:image/image.dart' as Im;
import 'package:path_provider/path_provider.dart';
import 'dart:math' as Math;

void compressImage() async {
  File imageFile = await ImagePicker.pickImage();
  final tempDir = await getTemporaryDirectory();
  final path = tempDir.path;
  int rand = new Math.Random().nextInt(10000);

  Im.Image image = Im.decodeImage(imageFile.readAsBytesSync());
  Im.Image smallerImage = Im.copyResize(image, 500); // choose the size here, it will maintain aspect ratio

  var compressedImage = new File('$path/img_$rand.jpg')..writeAsBytesSync(Im.encodeJpg(image, quality: 85));
}

然后我将compressedImage上传到firebase存储。您可以使用quality属性调整jpg保存的质量,在我的情况下,我选择85(满分100)。

希望这有帮助!如果您有任何问题,请告诉我。

答案 1 :(得分:5)

image_picker插件目前非常简单。可以直接添加用于指定所选图像的所需大小/质量的选项。如果您这样做,请向我们发送拉取请求!

答案 2 :(得分:1)

下面的代码是我用相机拍摄然后压缩的代码:

import 'dart:async' show Future;
import 'dart:io' show File;
import 'package:flutter/foundation.dart' show compute;
import 'package:flutter/material.dart' show BuildContext;
import 'package:image/image.dart' as Im;
import 'dart:math' as Math;
import 'package:image_picker/image_picker.dart';
import 'package:path_provider/path_provider.dart' show getTemporaryDirectory;

Future<File> takeCompressedPicture(BuildContext context) async {
  var _imageFile = await ImagePicker.pickImage(source: ImageSource.camera);
  if (_imageFile == null) {
    return null;
  }

  // You can have a loading dialog here but don't forget to pop before return file;

  final tempDir = await getTemporaryDirectory();
  final rand = Math.Random().nextInt(10000);
  _CompressObject compressObject =
      _CompressObject(_imageFile, tempDir.path, rand);
  String filePath = await _compressImage(compressObject);
  print('new path: ' + filePath);
  File file = File(filePath);

  // Pop loading

  return file;
}

Future<String> _compressImage(_CompressObject object) async {
  return compute(_decodeImage, object);
}

String _decodeImage(_CompressObject object) {
  Im.Image image = Im.decodeImage(object.imageFile.readAsBytesSync());
  Im.Image smallerImage = Im.copyResize(
      image, 1024); // choose the size here, it will maintain aspect ratio
  var decodedImageFile = File(object.path + '/img_${object.rand}.jpg');
  decodedImageFile.writeAsBytesSync(Im.encodeJpg(smallerImage, quality: 85));
  return decodedImageFile.path;
}

class _CompressObject {
  File imageFile;
  String path;
  int rand;

  _CompressObject(this.imageFile, this.path, this.rand);
}

您可以通过以下方法非常简单地调用它:

import 'path/to/compress_image.dart' as CompressImage;
// ...
File file = await CompressImage.takeCompressedPicture(context);

答案 3 :(得分:1)

除了提及此本地库: https://pub.dartlang.org/packages/flutter_image_compress

这是一个完全基于 dart的带有隔离器的压缩器,它可能使压缩与多核CPU中的UI线程并行。

  

您可能想使用计算功能,该功能使使用隔离更简单:   https://docs.flutter.io/flutter/foundation/compute.html   https://flutter.io/cookbook/networking/background-parsing/

import 'package:image/image.dart' as ImageLib;
import 'package:path_provider/path_provider.dart';

Future<void> getCompressedImage(SendPort sendPort) async {
  ReceivePort receivePort = ReceivePort();

  sendPort.send(receivePort.sendPort);
  List msg = (await receivePort.first) as List;

  String srcPath = msg[0];
  String name = msg[1];
  String destDirPath = msg[2];
  SendPort replyPort = msg[3];

  ImageLib.Image image =
      ImageLib.decodeImage(await new File(srcPath).readAsBytes());

  if (image.width > 500 || image.height > 500) {
    image = ImageLib.copyResize(image, 500);
  }

  File destFile = new File(destDirPath + '/' + name);
  await destFile.writeAsBytes(ImageLib.encodeJpg(image, quality: 60));

  replyPort.send(destFile.path);
}

Future<File> compressImage(File f) async {
  ReceivePort receivePort = ReceivePort();

  await Isolate.spawn(getCompressedImage, receivePort.sendPort);
  SendPort sendPort = await receivePort.first;

  ReceivePort receivePort2 = ReceivePort();

  sendPort.send([
    f.path,
    f.uri.pathSegments.last,
    (await getTemporaryDirectory()).path,
    receivePort2.sendPort,
  ]);

  var msg = await receivePort2.first;

  return new File(msg);
}

if (false ==
    await SimplePermissions.checkPermission(
        Permission.ReadExternalStorage)) {
  await SimplePermissions.requestPermission(
    Permission.ReadExternalStorage);
}

File img = await ImagePicker.pickImage(
    source: ImageSource.gallery);
if (null != img) {
  img = await compressImage(img);
}

答案 4 :(得分:1)

使用image_picker插件并将调用图片功能用作

Future<File> imageFile = ImagePicker.pickImage(source: ImageSource.gallery , maxHeight: 200 , maxWidth: 200 );

将maxHeight和maxWidth更改为所需的图像大小。

答案 5 :(得分:1)

有很多解决方案:

使用image_picker包:

您可以使用 ImagePicker 的内置 imageQuality 属性来压缩图像。此属性采用介于 0100 之间的值,表示原始图像质量的百分比。

首先,在 pubspec.yaml 文件中添加 image_picker 作为依赖项。

使用

  File _image;

  Future getImage() async {
    var image = await ImagePicker.pickImage(
        source: ImageSource.gallery,  
                imageQuality: 25,
    );

    setState(() {
      _image = image;
    });
  }
<块引用>

这种方法的优点是它嵌入在 image_picker 包,因此非常易于使用。

您还可以通过图像小部件调整质量。

使用 filterQuality 设置图像的 FilterQuality

示例:

Image.asset('assets/kab1.png', filterQuality: FilterQuality.high,), 

这些属性存在于 AssetImageNetworkImageFileImageMemoryImage 中。

<块引用>

您也可以简单地调整图像大小(调整图像大小可以压缩它)。为此,请尝试使用 ResizeImage 小部件

另一种解决方案是使用 flutter_image_compress

答案 6 :(得分:0)

我正在使用

  

package:image / image.dart

面对下面的问题

  • 在转换图像时显示空白页(压缩图像时可能需要花费很多时间)
  • 压缩图像拉伸后看起来不太好

然后使用下面的插件,同样可以正常工作,没有任何问题,甚至更快,而且我期望的是

https://github.com/btastic/flutter_native_image.git

以上链接中提供的步骤和方法。

答案 7 :(得分:0)

您可以使用名为flutter_image_compress

的插件
// Active image file
File _imageFile;

// Select an image via gallery or camera
Future<void> _pickImage(ImageSource source) async {
  File selected = await ImagePicker.pickImage(source: source);

// Compress plugin
  File compressedImage = await FlutterImageCompress.compressAndGetFile(
    selected.path,
    selected.path,
    quality: 50,
  );

  setState(() {
    _imageFile = compressedImage;
    print('compressedimagesize: ${_imageFile.lengthSync()}');
  });
}

Voila!压缩文件图像

答案 8 :(得分:0)

由于您使用的是Firebase,因此一种选择是使用“扩展程序-调整图像大小”。它为您提供了保留或删除原始图像的选项,安装和使用非常简单。

答案 9 :(得分:0)

不建议使用2020更新'pickImage'。请改用imagePicker.getImage()方法 **

  ImagePicker picker = ImagePicker();
   PickedFile compressedImage = await imagePicker.getImage(
  source: ImageSource.camera,
  imageQuality: 80,
);

ImageQuality文档:

返回一个包装了所拾取图像的PickedFile对象。的 返回的PickedFile旨在在单个APP中使用 会议。不要保存文件路径并在会话之间使用它。的 源参数控制图像的来源。这可以是 ImageSource.camera或ImageSource.gallery。 iOS支持的地方 HEIC图片,Android 8及更低版本没有。仅适用于Android 9及更高版本 支持HEIC图像(如果除尺寸修改外使用) 用法说明如下。如果指定,图像将位于 最大maxWidth宽和maxHeight高。否则图像将是 返回其原始宽度和高度。 imageQuality参数 修改图像的质量,范围是0-100,其中100是 原始/最高质量。如果imageQuality为null,则带有 原始质量将被退回。仅支持压缩 某些图像类型(例如JPEG)以及Android PNG和WebP上的图像。如果 所选择的图像不支持压缩,警告 消息将被记录。使用preferredCameraDevice指定 源为ImageSource.camera时要使用的相机。的 当源为ImageSource.gallery时,preferredCameraDevice被忽略。 如果摄像机不支持所选摄像机,也会被忽略。 设备。默认为CameraDevice.rear。请注意,Android没有 文档化的参数,用于指定前面还是后面 应该打开相机,不能保证此功能在 Android设备。在Android中,MainActivity可以销毁 很多原因。如果发生这种情况,结果将在此丢失 呼叫。然后,当您的应用重新启动到时,您可以调用getLostData 检索丢失的数据。

答案 10 :(得分:0)

您可以按照以下操作,

//Compressing Image
    File compressedImg = await FlutterNativeImage.compressImage(
      _image.path,
      quality: 70,
    );
//Compressing Image

答案 11 :(得分:0)


<强>1.如果您使用的是移动设备,您可以使用flutter_image_compress: ^1.0.0 来完成这项工作

例如。 通过 Uint8List 和质量,您将立即获得压缩图像。

Future<Uint8List> testComporessList(Uint8List uint8List) async {
    var result = await FlutterImageCompress.compressWithList(
      uint8List,
      quality: 50,
    );
    return result;
}

2.但是,如果您使用的是 flutter web,那么除了图像选择器等之外,您将无法获得任何其他选项。
我最终使用了 javascript。你可以在这里找到答案。
Flutter Web: How Do You Compress an Image/File?