This question already has answers here:
What is a Future and how do I use it?
(6 answers)
Closed 3 months ago.
I'm making a watermark image using flutter and I need to convert Future to Uint8List.
This is the code where the problem happens.
child: Image.memory(putWatermarkOnImage(asset))
The child is in the Container widget and the result of the putWatermarkOnImage function has to be Uint8List type not a future type.
Future<Uint8List> putWatermarkOnImage(asset) async {
final assetFile = await asset.file;
var imageBytes = await assetFile!.readAsBytes();
ByteData watermarkImgByteData = await rootBundle.load('assets/images/ournow_logo.png');
Uint8List watermarkImgBytes = watermarkImgByteData.buffer.asUint8List();
Uint8List imageUint8List = Uint8List.fromList(imageBytes);
Uint8List watermarkedImg = await ImageWatermark.addImageWatermark(
originalImageBytes: imageUint8List,
waterkmarkImageBytes: watermarkImgBytes,
imgHeight: 200,
imgWidth: 200,
dstY: 400,
dstX: 400);
return watermarkedImg;
}
How can I solve this problem?
I have taken your code and wrote it the way I do to avoid confusions, so I created a class for you on the side to collect all bytes transformation related methods and called them "BytesHandlers"
then I re-organized the code as follows,,, I believe it will work
please test it and tell me if something is going wrong
import 'dart:io';
import 'dart:typed_data';
import 'package:flutter/services.dart';
import 'package:wechat_camera_picker/wechat_camera_picker.dart';
Future<Uint8List> putWatermarkOnImage(AssetEntity asset) async {
Uint8List _output;
if (asset != null){
final File assetFile = await asset.file;
final ByteData watermarkImgByteData = await BytesHandlers.getByteDataFromPath('assets/images/ournow_logo.png');
_output = await BytesHandlers.getUint8ListFromFile(assetFile);
_output = await ImageWatermark.addImageWatermark(
originalImageBytes: _output,
waterkmarkImageBytes: watermarkImgByteData,
imgHeight: 200,
imgWidth: 200,
dstY: 400,
dstX: 400
);
}
return _output;
}
class BytesHandlers {
// --------------------
BytesHandlers();
// --------------------
static Future<ByteData> getByteDataFromPath(String assetPath) async {
/// NOTE : Asset path can be local path or url
ByteData _byteData;
if (assetPath != null){
_byteData = await rootBundle.load(assetPath);
}
return _byteData;
}
// --------------------
static Future<Uint8List> getUint8ListFromFile(File file) async {
Uint8List _uInt;
if (file != null){
_uInt = await file.readAsBytes();
}
return _uInt;
}
// --------------------
}
then you get to call it like this
final Uint8List _ImageWithWatermark = await putWatermarkOnImage(_inputFile);
Related
I'm using image_picker & ImageCropper packages. I want to save a user-given picture in firestore database. So, I use functions like this.
First, set File? _image;
Functions for cropping & picking
Future _pickImage(ImageSource source) async {
Navigator.of(context).pop();
try {
final image = await ImagePicker().pickImage(source: source);
if (image == null) return;
File? img = File(image.path);
img = await _cropImage(imageFile: img);
setState(() {
_image = img;
});
} on PlatformException catch (e) {
print(e);
Navigator.of(context).pop();
}
}
Future<File?> _cropImage({required File imageFile}) async {
CroppedFile? croppedImage =
await ImageCropper().cropImage(sourcePath: imageFile.path);
if (CroppedFile == null) return null;
return File(croppedImage!.path);
}
and use this to save data in firestore
Future<String> uploadImageToStorage(
File file,
) async {
file
Reference ref =
_storage.ref().child("profilePics").child(_auth.currentUser!.uid);
UploadTask uploadTask = ref.putData(file);
TaskSnapshot snap = await uploadTask;
String downloadUrl = await snap.ref.getDownloadURL();
return downloadUrl;
}
Above function not work for File type data, It support for Uint8List. So, What can I do for this?
Next problem is, I'm getting File type data with ImagePicker for profile picture. Is it not problem?
Try changing your _cropImage-Method to return XFile? like this:
Future<XFile?> _cropImage({required File imageFile}) async {
CroppedFile? croppedImage =
await ImageCropper().cropImage(sourcePath: imageFile.path);
if (CroppedFile == null) return null;
return XFile(croppedImage!.path);
}
You also have to change the paramter of uploadImageToStorage to XFile file. Then you can use file!.readAsBytes(); to get a Uint8List.
Future<String> uploadImageToStorage(
XFile file,
) async {
Reference ref =
_storage.ref().child("profilePics").child(_auth.currentUser!.uid);
final fileBytes = await file.readAsBytes();
UploadTask uploadTask = ref.putData(fileBytes);
TaskSnapshot snap = await uploadTask;
String downloadUrl = await snap.ref.getDownloadURL();
return downloadUrl;
}
Following a tutorial for adding and saving images and getting errors for the below code, under ImagePicker, ImageSource and SelectedImage.
Future getImage() async {
var image = await ImagePicker.PickImage(source: ImageSource.camera);
setState(() {
selectedimage = image;
});
}
You need to create an instance first, then you will be able to use pickImage method.
Future getImage() async {
XFile? image = await ImagePicker().pickImage(source: ImageSource.camera);
if (image != null) {
setState(() {
selectedimage = image;
});
}
}
Fine more about image_picker
You have to be careful whenever playing with the setState() functions. This combined with how you pick the image and how you store it in the 'var' in your case could cause further trouble. To generally ease things up for further use I recommend creating a utils class, in which you would have an image picker method, just like this one:
import 'package:image_picker/image_picker.dart';
pickImage(ImageSource source) async {
final ImagePicker _imagePicker = ImagePicker();
XFile? _file = await _imagePicker.pickImage(source: source);
if (_file != null) {
return await _file.readAsBytes();
}
print('No Image Selected');
}
Afterwards, if you would like to call that in any other instance you would need something like this, though this is for a url image(I had it in hand), such as:
void selectImage() async {
Uint8List? im = await pickImage(ImageSource.gallery);
final ByteData imageData = await NetworkAssetBundle(Uri.parse(
"url for template image"))
.load("");
final Uint8List bytes = imageData.buffer.asUint8List();
// if null - use the template image
im ??= bytes;
// update state
setState(() {
_image = im!;
});
}
Hope it helped in a way.
I have a project with encrypt an audio for secure my data audio and when the user purchase they can play the audio, but until now didn't find how to do that. I found another way by converting the audio data into a string and then encrypting it, I found a code but it's incomplete so I'm still confused about using it.
import 'dart:io';
import 'dart:typed_data';
import 'package:file_picker/file_picker.dart';
import 'package:path_provider/path_provider.dart';
class MediaFile {
Future<String> get docPath async {
Directory appDocDir = await getApplicationDocumentsDirectory();
return appDocDir.path;
}
Future<Uint8List> get audioFileData async {
final String path = await docPath;
final String theFilePath = '$path/test.mp3';
final File theFile = new File(theFilePath);
if (await theFile.exists()) {
return await theFile.readAsBytes();
} else {
File file = await FilePicker.getFile();
return await file.readAsBytes();
}
}
Future<String> dataToString() async {
Uint8List data = await audioFileData;
return new String.fromCharCodes(data);
}
Future<File> saveMediaAsString(String fileName, String fileContent) async {
String path = await docPath;
Directory dataDir = new Directory('$path/data');
if (await dataDir.exists()) {
File file = new File('$path/data/$fileName');
return file.writeAsString(fileContent);
}
await dataDir.create();
File file = new File('$path/data/$fileName');
return file.writeAsString(fileContent);
}
Future<String> readFromStringMediaFile(String fileName) async {
String path = await docPath;
File file = new File('$path/data/$fileName');
return file.readAsString();
}
Uint8List stringToData(dataStr) {
List<int> list = dataStr.codeUnits;
return new Uint8List.fromList(list);
}
Future<File> createAudioFile(String fileName, Uint8List bytes) async {
String path = await docPath;
File file = new File('$path/$fileName');
return await file.writeAsBytes(bytes);
}
//here you can see how to use them
Future<File> testFile() async {
String dataStr = await dataToString();
File savedFile = await saveMediaAsString('codedFile', dataStr);
String contentSavedFile = await readFromStringMediaFile('codedFile');
Uint8List bytes = stringToData(contentSavedFile);
return await createAudioFile('test.mp3', bytes);
}
}
Is there any better way to convert network image to byteData? I am trying to convert network image from firebase url to byteData and here is my code:
Future<Uint8List> _loadNetworkImage() async {
try {
final response = await http.get(imageUrl);
return response.bodyBytes;
} catch (_) {
throw "Couldn't resolve network Image.";
}
}
Currently it takes almost 20+ seconds for a 7mb photo to be converted.
Here is how I ended up doing it.
Future<Uint8List?> _loadNetworkImage(String path) async {
final completer = Completer<ImageInfo>();
var img = NetworkImage(path);
img.resolve(const ImageConfiguration()).addListener(
ImageStreamListener((info, _) => completer.complete(info)));
final imageInfo = await completer.future;
final byteData =
await imageInfo.image.toByteData(format: ui.ImageByteFormat.png);
return byteData?.buffer.asUint8List();
}
I have the network url of image and I need to get Uint8List. How can I convert it?
I check answers in like question, but those ways don't work.
How to get a Flutter Uint8List from a Network Image?
Try this:
Uint8List bytes = (await NetworkAssetBundle(Uri.parse(url)).load(url))
.buffer
.asUint8List();
Uint8List yourVar;
final DecoderCallback callback = (Uint8List bytes, {int cacheWidth, int cacheHeight}) {
yourVar = bytes.buffer.asUint8List();
return instantiateImageCodec(bytes, targetWidth: cacheWidth, targetHeight: cacheHeight);
};
ImageProvider provider = NetworkImage(yourImageUrl);
provider.obtainKey(createLocalImageConfiguration(context)).then((key) {
provider.load(key, callback);
});
this did the trick for me:
import 'dart:typed_data';
import 'package:flutter/services.dart';
//Get the image from the URL and then convert it to Uint8List
Uint8List bytes = (await NetworkAssetBundle(Uri.parse('https://some_image_url.png'))
.load('https://some_image_url.png'))
.buffer
.asUint8List();
This works on me (using flutter web) with a library file_saver.
Uri uri = Uri.parse(url);
Uint8List bytes = await readBytes(uri);
await FileSaver.instance.saveFile(filename, bytes, 'jpg',
mimeType: MimeType.JPEG); // specify your vars
I'm having the same problem in Flutter web, I had to use the extended_image library, and I found inside your example that has a method that allows you to convert an ImageProvider to Bytes.
https://github.com/fluttercandies/extended_image/blob/master/example/lib/pages/simple/image_editor_demo.dart.
/// it may be failed, due to Cross-domain
Future<Uint8List> _loadNetwork(ExtendedNetworkImageProvider key) async {
try {
final Response response = await HttpClientHelper.get(Uri.parse(key.url),
headers: key.headers,
timeLimit: key.timeLimit,
timeRetry: key.timeRetry,
retries: key.retries,
cancelToken: key.cancelToken);
return response.bodyBytes;
} on OperationCanceledError catch (_) {
print('User cancel request ${key.url}.');
return Future<Uint8List>.error(
StateError('User cancel request ${key.url}.'));
} catch (e) {
return Future<Uint8List>.error(StateError('failed load ${key.url}. \n $e'));
}
}