Here is my code:
Future getImage() async {
var image = await ImagePicker.pickImage(source: ImageSource.gallery);
setState(() {
_image = image;
print('Image Path $_image');
});
}
The image returned from ImagePicker.pickImage(...) is a File object that you can pass around to other widgets, just like you would with any other object. For example, consider this snippet, where NewPage takes a File image object as a parameter:
Future<void> navigateOnImage() async {
var image = await ImagePicker.pickImage(source: ImageSource.gallery);
Navigator.of(context)
.push(MaterialPageRoute(builder: (_) => NewPage(image)));
}
Another option may be to convert the File object to a more handy object for your use case, such as a UInt8List object, with the File.readAsBytes method. Then you can pass that around just like in the example above.
Check out this flutter.dev article for more info on passing data when navigating.
Related
i'm trying to upload an image to the cloud firestore and the firebase storage. I'm saving the image url in a variable called imgUrl, this variable is later on passed inside a function called addIntervention(). The problem is that the upload task takes few time so if I upload and click the save button directly, imgUrl will be having null value cus the image is still getting uploaded.
Here is my code:
IconButton(
icon: Icon(
Icons.image,
color: Palette.primaryColor,
),
onPressed: () async {
ImagePicker imagePicker = ImagePicker();
XFile? file = await imagePicker.pickImage(
source: ImageSource.gallery);
if (file == null) return;
Reference referenceRoot =
FirebaseStorage.instance.ref();
Reference dirImages =
referenceRoot.child("iv_images");
Reference imgToUpload = dirImages.child(file.name);
try {
await imgToUpload.putFile(File(file.path));
var x = imgUrl = await imgToUpload.getDownloadURL();
imgUrl = x;
} catch (e) {}
},
),
And for the button I took this snippet:
if (imgUrl.isEmpty) {
QuickAlert.show(
context: context,
type: QuickAlertType.error,
title: 'Error',
text:
'Please upload an image');
} else {
await addIntervention(
imgUrl,
etatLabel,
numIntv,
intervention,
myPrice!,
note,
dateTime);
Noting that i'm using async/await for the save button as well, is there any way I can solve this? thanks in advance.
You can try these tips:
First thing to make your upload time a lot less is to compress a picture, you don't have to compress the image till it gets blurry but a small amount of compression will significantly reduce your upload time. Also if a use selects an image then he/she may want to crop it too. So it will be better if you add that functionality too.
Luckily there's a package called image_cropper(link), which you can use to crop as well as for compressing your image.
If you don't want to show any loading indicator then you can directly pass the image to the next screen and run your processes in the background(which is called optimistic updating), but if you want to show a loading indicator then you can use this package called flutter_spinkit. It has a very large variety of loading indicators which you will love.
When a user clicks on a button, you can show a progress indicator on the button itself to indicate how much percent has been uploaded, has to be uploaded before the user can click on the button.
In the firebase, you can get percentage like this:
Future getImage(BuildContext context) async {
final picker = ImagePicker();
final pickedFile = await picker.getImage(source: ImageSource.gallery);
setState(() {
_image = File(pickedFile.path);
});
StorageReference firebaseStorageRef = FirebaseStorage.instance.ref().child('profile/${Path.basename(_image.path)}}');
StorageUploadTask uploadTask = firebaseStorageRef.putFile(_image);
var dowurl = await (await uploadTask.onComplete).ref.getDownloadURL();
setState(() {
_imageURL = dowurl.toString();
});
print(_imageURL);
}
uploadTask.events.listen((event) {
setState(() {
_progress = event.snapshot.bytesTransferred.toDouble() /
event.snapshot.totalByteCount.toDouble();
});
}).onError((error) {
// do something to handle error
});
Then you can display progress like this:
Text('Uploading ${(_progress * 100).toStringAsFixed(2)} %')
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.
in my flutter app, the user picture is loaded by Cached Network image command, which gets its url by stream builder from firestore.
I am trying to add the functionality to the user of changing his pic by pressing on the pic as following:
Selecting his pic with image picker.
upload it to firebase storage.
updating firestore usercollection document with new image url.
I created the below code.
The problem is getDownloadURL() is not returning actual string, but "Instance of 'Future'".
so the new link stored in firestore is not correct to be used by Cached Network Image.
how can I get the actual URl String?
My Future Function Code:
Future ChangeProfilePic() async {
String newimageurl = "";
FirebaseStorage storage = FirebaseStorage.instance;
Reference ref =
storage.ref().child("ProfileImages/$globaluserid".toString());
CollectionReference userscollectionref =
FirebaseFirestore.instance.collection('UsersCollection');
final ImagePicker _picker = ImagePicker();
final XFile? image = await _picker.pickImage(source: ImageSource.gallery);
File imagefile = File(image!.path);
UploadTask uploadTask = ref.putFile(imagefile);
uploadTask.whenComplete(() {
newimageurl = ref.getDownloadURL().toString();
print("Image Uploaded");
userscollectionref
.doc(globaluserid)
.update({'User_image_link': newimageurl});
print("Link is Updated");
}).catchError((onError) {
print("Error");
print(onError);
});
}
Like many calls in your code `` is an asynchronous call, whose result won't be available immediately, so it returns a Future that will at some point contain the value. You can use await to wait for such a Future to complete and get its value, similar to what you already do in await _picker.pickImage.
await ref.getDownloadURL().toString();
Another change to consider is that putFile returns a Task, but that is actually also a Future, which means that you can await that too.
Combining these two fact, you can simplify your code to:
final XFile? image = await _picker.pickImage(source: ImageSource.gallery);
File imagefile = File(image!.path);
await ref.putFile(imagefile);
newimageurl = (await ref.getDownloadURL()).toString();
print("Image Uploaded");
userscollectionref
.doc(globaluserid)
.update({'User_image_link': newimageurl});
print("Link is Updated");
I copied this from the official image web picker files but I get the message that getImage return an Object? instead of an Image. Where is the problem? And I importet the package if you think that is the problem.
class _LoadPhotoState extends State<LoadPhoto> {
late final Image _pickedImage;
Future<void> _pickImage() async {
Image fromPicker = await ImagePickerWeb.getImage(outputType: ImageType.widget);
setState(() {
_pickedImage = fromPicker;
});
}
}
It's not your fault, the README is wrong: the API reference of that package says the getImage method returns a Future<Object?>. However, the solution is easy:
Image fromPicker = (await ImagePickerWeb.getImage(outputType: ImageType.widget)) as Image;
I am getting the image by image picker and then adding the file to the list of file but it shows the error-The method 'add' was called on null..
My code:-
final picker=ImagePicker();
selectImageFromGallery() async
{
setState(() {
inProcess=true;
});
final imageFile= await picker.getImage(source: ImageSource.gallery);
if(imageFile!=null)
{
File _image=File(imageFile.path);
files.add(_image);
}
setState(() {
inProcess=false;
});
}
It seems like files is a List<File> but it's not properly initialized.
You need to initialize it as an empty list, such as:
final files = <File>[];
so you can add files to it.