'Flutter Web: How Do You Compress an Image/File?
Flutter Web is currently in beta, so there's a lack of available info/resources on how to do this.
I could not find any flutter packages compatible with web to do this. Any tips?
Here's my code:
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");
}
});
});
}
Solution 1:[1]
Well I have spend days trying to figure it out. Here is what you need to understand. There is no proper library/package which can compress image in flutter web at the time I am writing this.So I end up using javascript code in my project.
Don't worry it is not too much of work.You can also read my blog for complete example.
Here is what you need to do.
1. Add browser image compresser(to compress image) cdn,filesaver(save image) cdn in your flutter web index.html file
also create new js file name app.js and import it too.
<script type="text/javascript"
src="https://cdn.jsdelivr.net/npm/[email protected]/dist/browser-image-compression.js"></script>
<script src="http://cdn.jsdelivr.net/g/filesaver.js"></script>
<script src="app.js" defer></script>
2. Now that import is done update app.js as below
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. Okay now you are ready to call this function whereever you need to compress image call this dart function from anywhere
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']);
UPDATE
If you wish to upload file to server via dart. then send the file to dart and send to server/firebase from there.
To send the compress file to flutter add this line of code.
window.parent.postMessage(compressedFile, "*");
And also to receive in flutter make sure you have this listener function.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
});
Note
This will work only in flutter web. if you run in mobile you will get 'dart:js' or 'dart:html' compile error. You can fix this by import base on platform.
Hope it help someone, Thanks
Solution 2:[2]
Since a pure Flutter solution to solve this problem still remains, I'll post an Flutter solution. Mind you though, that this solution is not the best performance wize. Personally, if I had to make a PWA, I would do it in HTML/javascript and ditch Flutter entirely.
The problem with web solution is that we can't really create a file, so we'll have to do it all in memory using Uint8List. For this purpose file_picker and image_compression_flutter packages meets out requirements. The big hurdle at first glance, is that image_compression_flutter requires both the raw bytes and the path (filename) to the file, but diving deeper it seems that the path is only used as an fallback to determine the mime type, so we don't really need it, or at least not a full path. This means we can do the following with file_picker (without any null concerns):
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;
}
You'll have to import foundation to access kIsWeb: import 'package:flutter/foundation.dart';
and with image_compression_flutter, something like:
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;
}
To upload to Firebase storage one could do something like this:
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'
},
),
);
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | cigien |
