Flutter & Firebase: Compression avant le téléchargement de l'image
Je souhaite envoyer les photos sélectionnées par l'utilisateur dans mon application à Firebase Storage. J'ai une classe simple avec la propriété _imageFile
qui est définie comme ceci:
File _imageFile;
_getImage() async {
var fileName = await ImagePicker.pickImage();
setState(() {
_imageFile = fileName;
});
}
après cela j'envoie une photo comme avec ce code:
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);
Le problème est que les photos sont souvent très grandes. Existe-t-il une méthode dans Flutter/Dart pour compresser et redimensionner une photo avant de la télécharger? Je suis d'accord avec la perte de qualité.
Le image_picker plugin est actuellement très simple. Il serait simple d'ajouter une option permettant de spécifier la taille/qualité souhaitée de l'image sélectionnée. Si vous faites cela, s'il vous plaît envoyez-nous une demande de traction!
Je me suis heurté à cela et j'ai pu effectuer une compression/redimensionnement avec le package Dart image avec fournisseur de chemin . Vous pouvez consulter Dart image api et exemples pour d’autres moyens et obtenir de l’aide.
Voici ce que j'ai fait:
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));
}
Ensuite, j'ai téléchargé compressedImage
sur la base de stockage de base de feu. Vous pouvez ajuster la qualité avec laquelle le jpg est enregistré en utilisant la propriété quality. Dans mon cas, j’ai choisi 85 (sur 100).
J'espère que cela t'aides! Faites moi savoir si vous avez des questions.
Le code suivant correspond à ce que j'utilise pour prendre une image avec l'appareil photo, puis pour la compresser:
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);
}
Vous pouvez appeler cela très facilement avec ceci:
import 'path/to/compress_image.Dart' as CompressImage;
// ...
File file = await CompressImage.takeCompressedPicture(context);
En plus de mentionner cette bibliothèque native: https://pub.dartlang.org/packages/flutter_image_compress
Il s’agit d’un compresseur entièrement basé sur Dart avec isolates, ce qui pourrait rendre la compression parallèle au thread d’UI dans les CPU multi-cœur.
Vous voudrez peut-être utiliser la fonction de calcul qui simplifie l'utilisation des isolats: https://docs.flutter.io/flutter/foundation/compute.htmlhttps://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);
}