Preview Picked Image in Flutter - flutter

Hi I am using the image_picker package in flutter to pick images and store them to firestore.
I want to preview the image in a circle avatar before I actually upload it so how would I go about doing that?
This is the code I have to pick the image:
String imageUrl = '';
Future pickImage(ImageSource imageSource) async {
ImagePicker imagePicker = ImagePicker();
XFile? file = await imagePicker.pickImage(
source: imageSource);
if (file == null) return;
String uniqueFileName = DateTime
.now()
.millisecondsSinceEpoch
.toString();
//Getting a reference to storage root
Reference referenceRoot = FirebaseStorage.instance.ref();
Reference referenceDirImages = referenceRoot.child(
'images');
//Create a reference for the image to be stored
Reference referenceImageToUpload = referenceDirImages
.child(uniqueFileName);
try {
//Store the file
await referenceImageToUpload.putFile(File(file.path));
// Success: get download URL
imageUrl =
await referenceImageToUpload.getDownloadURL();
} catch (error) {
// Some error occurred
}
}
This is where I ask the user to pick the image either from the gallery or camera and then in the circle avatar I want them to preview the image before actually uploading it:
InkWell(
child: CircleAvatar(
backgroundColor: Colors.blue[900],
radius: 100,
),
onTap: () async {
return showDialog(context: context, builder: (context) {
return Center(
child: SizedBox(
height: 200,
child: AlertDialog(
backgroundColor: Colors.blue[900],
actionsPadding: const EdgeInsets.all(10.0),
content: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
ElevatedButton(onPressed: () {
pickImage(ImageSource.gallery);
},
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.white)
),
child: const Text("Gallery",
style: TextStyle(
color: Colors.black
),)),
const SizedBox(
height: 10,
),
ElevatedButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.white)
),
onPressed: () {
pickImage(ImageSource.camera);
},
child: const Text("Camera", style: TextStyle(
color: Colors.black
),),
)
],
),
),
),
),
);
}
);
}
),
Thanks!

Well you need to separate your functions into sub-functions, but first I will create this variable:
File? imageFile;
then it should be a function that picks that image from the device and update the state of the imageFile variable we made.
Future pickImage(ImageSource imageSource) async {
ImagePicker imagePicker = ImagePicker();
XFile? file = await imagePicker.pickImage(source: imageSource);
if (file == null) return;
setState(() {
imageFile = File(file.path);
});
}
and a method that returns the widget which will show the actual image we pick:
Image genratePreviowWidget(File file) {
return Image.file(file);
}
and in your UI, you should show it under an if condition like this:
Column(
children: [
if(imageFile != null) genratePreviowWidget(imageFile ),
],
),
now you have a method that pick the image and show it directly in your UI after it's done.
forwe still have that imageFile, so you can simply upload it ( confirm uploading it) from a separate method:
Future confirmUpload(File file) async {
String uniqueFileName = DateTime.now().millisecondsSinceEpoch.toString();
//Getting a reference to storage root
Reference referenceRoot = FirebaseStorage.instance.ref();
Reference referenceDirImages = referenceRoot.child('images');
//Create a reference for the image to be stored
Reference referenceImageToUpload = referenceDirImages.child(uniqueFileName);
try {
//Store the file
await referenceImageToUpload.putFile(file);
// Success: get download URL
imageUrl = await referenceImageToUpload.getDownloadURL();
} catch (error) {}
}
and you will need to call it when you want to upload it like this:
confirmUpload(imageFile);

Related

How to display future image with image provider in flutter

I'm building edit Screen where user can change Image. I would like user to display one of three images: - image from server - temporary image if previously not uploaded - new image to upload.
Problem appear when I'm going to display image from server. With use of future builder it's possible to display image but new image cannot be uploaded. If I'm not using future builder I get error
future is not subtype of type ImageProvider
My avatar for displaying images
CircleAvatar(
radius: MediaQuery.of(context).size.width / 6,
backgroundColor: Colors.grey,
backgroundImage: getImage(),
),
getImage()
getImage() {
if (_image != null) {
if (uploadCounter == 0) {
uploadImage();
AlertDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(20.0))),
backgroundColor: Colors.lightBlue[900],
content: Container(
child: Text('Uploading...'),
),
);
}
return FileImage(_image);
} else {
return _emptyImage;
}
}
and my upload image
uploadImage() async {
if (_image == null) {
showAlertDialog(
context: context,
title: "Error Uploading!",
content: "No Image was selected.");
return;
} else {
setState(() {
uploadStatus = true;
});
final preffs = await SharedPreferences.getInstance();
final token = preffs.getString('token');
final id = preffs.getString('id');
var uri = Uri.parse('http://10.0.2.2:8000/profiles/update/');
var request = http.MultipartRequest('PUT', uri)
..fields['id'] = id
..headers.addAll({"Authorization": token})
..files.add(await http.MultipartFile.fromPath('image_1', _image.path));
var response = await request.send();
if (response.statusCode == 200) {
print('Uploaded!');
print(response);
}
setState(
() {
uploadStatus = false;
uploadCounter = 1;
},
);
}
}
I was trying to get image from server trough future builder or to save image before entering this screen then reload it from file, but saving files in flutter is not best solution I think
The only solution works at the moment looks like this.
FutureBuilder<Profile>(
future: profileService.getProfile(),
builder: (context, snapshot) {
if (snapshot.hasData) {
profile = snapshot.data;
return CircleAvatar(
radius: MediaQuery.of(context).size.width / 6,
backgroundColor: Colors.grey,
backgroundImage: Image.network(
"http://10.0.2.2:8000/" +
profile.image_1.toString())
.image,
);
} else {
return Container();
}
}),
CircleAvatar(
radius: 0.1,
backgroundColor: Colors.grey,
backgroundImage: getImage(),
),
If I put second CircleAvatar in return of if-else I get some problems Like no photo just gray Image etc, problem with upload photo.

How to take screenshot of entire screen outside of your FLUTTER DESKTOP app(mostly for Windows OS)?

I'm new to flutter. Now I am able to take screenshot for my entire desktop app screen using Screenshot package & storing that image to local storage.
But my requirement is to capture the screenshot of entire screen of the window, like if 2 applications are opened(1 Flutter + 1 any other app e.g. browser) in 1 screen, then we can able to take whole screen's screenshot not only flutter app.
Please help me on how to take entire window's screenshot in Windows OS desktop app?
If it's not possible directly from Flutter, then how to achieve this by implementing some native code with Flutter?
check this completely working as expected
bool _isAccessAllowed = false;
CapturedData? _lastCapturedData;
#override
void initState() {
super.initState();
_init();
}
void _init() async {
_isAccessAllowed = await ScreenCapturer.instance.isAccessAllowed();
}
void _handleClickCapture(CaptureMode mode) async {
Directory directory = await getApplicationDocumentsDirectory();
String imageName =
'Screenshot-${DateTime.now().millisecondsSinceEpoch}.png';
String imagePath =
'${directory.path}/screen_capturer_example/Screenshots/$imageName';
_lastCapturedData = await ScreenCapturer.instance.capture(
mode: mode,
imagePath: imagePath,
silent: true,
);
if (_lastCapturedData != null) {
// ignore: avoid_print
// print(_lastCapturedData!.toJson());
} else {
// ignore: avoid_print
print('User canceled capture');
}
setState(() {});
}
Widget _buildBody(BuildContext context) {
return PreferenceList(
children: <Widget>[
if (Platform.isMacOS)
PreferenceListSection(
children: [
PreferenceListItem(
title: const Text('isAccessAllowed'),
accessoryView: Text('$_isAccessAllowed'),
onTap: () async {
bool allowed =
await ScreenCapturer.instance.isAccessAllowed();
BotToast.showText(text: 'allowed: $allowed');
setState(() {
_isAccessAllowed = allowed;
});
},
),
PreferenceListItem(
title: const Text('requestAccess'),
onTap: () async {
await ScreenCapturer.instance.requestAccess();
},
),
],
),
PreferenceListSection(
title: const Text('METHODS'),
children: [
PreferenceListItem(
title: const Text('capture'),
accessoryView: Row(children: [
CupertinoButton(
child: const Text('region'),
onPressed: () {
_handleClickCapture(CaptureMode.region);
},
),
CupertinoButton(
child: const Text('screen'),
onPressed: () {
_handleClickCapture(CaptureMode.screen);
},
),
CupertinoButton(
child: const Text('window'),
onPressed: () {
_handleClickCapture(CaptureMode.window);
},
),
]),
),
],
),
if (_lastCapturedData != null && _lastCapturedData?.imagePath != null)
Container(
margin: const EdgeInsets.only(top: 20),
width: 400,
height: 400,
child: Image.file(
File(_lastCapturedData!.imagePath!),
),
),
],
);
}
// screen shot taken by the App.
You might try using this package: screen_capturer. It works on Windows, Linux and MacOS.
From the docs:
Example of usage:
import 'package:screen_capturer/screen_capturer.dart';
CapturedData? capturedData = await screenCapturer.capture(
mode: CaptureMode.screen, // screen, window
imagePath: '<path>',
);
CaptureMode.screen is to capture the entire screen.
The screenshot package which you mention is only for taking screenshots for widgets of your app not of whole screen.

I tried to upload multi images, but it wasn't display preview photos

I tried to upload multi images, but it wasn't display preview photos.
Original code is can display only photo, but I modified the code then tried to upload multi images. Still cannot show to me.
Original Code, working well, but just show one image
SizedBox(
height: 250,
child: AspectRatio(
aspectRatio: 487 / 451,
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: MemoryImage(_file!),
fit: BoxFit.fill,
alignment: FractionalOffset.topCenter,
),
),
),
),
),
Then I tried to modified to this one
Expanded(
child: GridView.builder(
itemCount: selectedFiles.length,
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3),
itemBuilder: (BuildContext context, int index) {
return Image.file(File(selectedFiles[index].path));
},
),
),
It wasn't show to me.
I can got the image list
Future<void> selectImage() async {
if (selectedFiles != null) {
selectedFiles.clear();
}
try {
final List<XFile>? imgs = await _picker.pickMultiImage();
if (imgs!.isNotEmpty) {
selectedFiles.addAll(imgs);
}
print("image list : " + imgs.length.toString());
} catch (e) {
print(e.toString());
}
setState(() {});
}
Or I need to modify this code??
SimpleDialogOption(
padding: const EdgeInsets.all(20),
child: const Text('Choose from gallery'),
onPressed: () async {
Navigator.of(context).pop();
Uint8List file = await pickImage(ImageSource.gallery);
// final List<XFile>? imgs = await _picker.pickMultiImage();
// if (imgs!.isNotEmpty) {
// selectedFiles.addAll(imgs);
// }
setState(() {
_file = file;
});
},
),
For the GridView to display images the Ui has to rebuild
So when you add images to your list
if (imgs!.isNotEmpty) {
selectedFiles.addAll(imgs);
}
you dont notify the UI to rebuild.
you can call an empty setstate below the selectedFiles to force UI to rebuild.
if (imgs!.isNotEmpty) {
selectedFiles.addAll(imgs);
setState((){
})
}
For example when picking a single file
File? myfile;
pickFile()async{
FilePickerResult? result = await FilePicker.platform.pickFiles();
if (result != null) {
File file = File(result.files.single.path);
setState((){
myFile=file;
})
} else {
// User canceled the picker
}}

How to render image from Firebase without rebuilding?

I'm trying to implement profile image picking in my flutter app using Firebase Storage. I use image_picker to get the image and upload it to Firebase, get the download link and add the download link to the imgsrc field in the cloud firestore, from where I can render the NetworkImage.
Center(
child: Stack(
children: [
buildImage(),
Positioned(
bottom: 5,
right: 5,
child: GestureDetector(
onTap: showPhotoAlertDialog,
child: buildEditIcon(Color(0xff407bff))),
),
],
),
),
How can I get the default Icons.person kind image for when the user has no profile image, and get the image from the database otherwise?
The code I'm using right now is as follows:
Widget buildImage() {
return CircleAvatar(
backgroundImage: NetworkImage(loggedInUser.imgsrc ??
'https://th.bing.com/th/id/R.945f33b643f2ceffcdae90fb57c61854?rik=XcI0SYBgSefoCA&riu=http%3a%2f%2fgetdrawings.com%2ffree-icon-bw%2fanonymous-avatar-icon-19.png&ehk=5n%2buJG66CeLQZsmhaMt8gag5rXuM3TdebAL6W35K1E4%3d&risl=&pid=ImgRaw&r=0'),
backgroundColor: Colors.grey[350],
radius: 100,
);
}
I created an Alert Dialog widget to choose whether to choose the image from camera or from the gallery.
showPhotoAlertDialog() {
AlertDialog alert = AlertDialog(
title: Text("Upload from"),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextButton(
onPressed: () {
imageFromCamera()
.then((value) => uploadFile())
.whenComplete(() => postSource());
setState(() {}); ----->
},
child: Text("Upload from camera"),
),
TextButton(
onPressed: () {
imageFromGallery().then((value) => uploadFile());
postSource();
setState(() {});
},
child: Text("Upload from gallery"),
)
],
),
);
showDialog(
context: context,
builder: (BuildContext context) {
return alert;
},
);
}
To upload the image to storage and post the source to cloud firestore, I use the following methods:
Future uploadFile() async {
if (file == null) return;
final fileName = path.basename(file!.path);
final destination = 'files/$fileName';
task = FirebaseApi.uploadFile(destination, file!);
setState(() {});
if (task == null) return;
final snapshot = await task!.whenComplete(() {});
urlDownload = await snapshot.ref.getDownloadURL();
print('Download-Link: $urlDownload');
}
postSource() async {
FirebaseFirestore firebaseFirestore = FirebaseFirestore.instance;
await firebaseFirestore
.collection("users")
.doc(user?.uid)
.update({'imgsrc': urlDownload});
}
The link gets uploaded properly and I'm able to get the link in my NetworkImage, but it doesn't get rendered immediately. I have to close the parent drawer and open it again to get it. I call setState(){} as well after posting the source, but it doesn't make any difference. How can I get the image without having to close and open the drawer?
Any help would be appreciated!
Thanks
You also have to update image in model class or in this imgsrc also just add this line above setState in onPressed of TextButton.
loggedInUser.imgsrc = urlDownload;

flutter, trying to update a picture from Storage

I'm trying to upload, and update a picture from firebase storage. But for some reason this is not working properly.
This would be the scenario; A user take a picture from his camera, so this picture is uploaded to my storage, so after that I get the url picture, so I can use this like NetworkImage(url) to update the picture.
This is what's happening currently:
Let's say I don't have any picture.
I update my profile with a new picture. (This works perfectly).
Now let's say I want to update my profile picture, so I take another picture, let's call it A so I upload this one.
Nothing happens, picture doesn't change.
But If I try again with a B picture, for some reason the picture is updated with the A picture.
This would be my code and how I'm facing this feature.
I have the next method which is invoked when a user click over his picture. I wait for the result (value) so when I got the result I upload the picture. Then, when the picture is uploaded, I just call to setState and save the url into the _imageUrl variable.
After that, I change the "profilePic" attribute from my data base to true.
String _imageUrl = 'assets/profileDefault.jpg';
bool profilePicture = false;
io.File profilePic;
Future getFromCamara() async {
await ImagePicker().getImage(source: ImageSource.camera).then((value) {
profilePic = io.File(value.path);
FirebaseStorage.instance.ref().child('picture').putFile(profilePic);
}).then((result) {
var ref = FirebaseStorage.instance.ref().child('picture');
ref.getDownloadURL().then((loc) => setState(() => _imageUrl = loc));
});
try {
FirebaseFirestore.instance
.collection('Usuarios')
.doc(uid)
.update({'profilePic': true});
} catch (e) {
print(e.toString());
}
So now, using a StreamBuilder, I get the result of profilePic from my DataBase, if is True, I download the URL, and if don't, I just use the Asset default's pic.
body: StreamBuilder(
stream: FirebaseFirestore.instance.collection('Usuarios').snapshots(),
builder: (context, AsyncSnapshot<QuerySnapshot> snapshot1) {
if (!snapshot1.hasData) {
return Center(
child: CircularProgressIndicator(),
);
}
List<DocumentSnapshot> users = snapshot1.data.docs;
for (DocumentSnapshot user in users) {
if (user.id == userID) {
profilePicture = user['profilePic'];
}
}
if (profilePicture) {
FirebaseStorage.instance
.ref()
.child('picture')
.getDownloadURL()
.then((loc) => _imageUrl = loc);
} else {
_imageUrl = 'assets/profileDefault.jpg';
}
return Stack(
alignment: Alignment.center,
children: <Widget>[
Positioned(
top: 0,
child: Container(
color: Color.fromRGBO(255, 0, 0, 70),
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height * .55,
),
),
Positioned(
top: MediaQuery.of(context).size.height * .015,
left: 15,
right: 15,
child: Container(
width: MediaQuery.of(context).size.height * .90,
height: 300,
padding: EdgeInsets.only(bottom: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
GestureDetector(
onTap: () => _setPic(context),
child: CircleAvatar(
radius: 79,
backgroundColor: Color(0xFFFFFFFFF),
child: CircleAvatar(
radius: 75,
backgroundImage: profilePicture
? NetworkImage(_imageUrl)
: AssetImage(_imageUrl),
),
),
),
// More code...
What I'm doing wrong? Why my picture isn't getting updated?
Updated:
I tried this, so I can save in pictureTemp the picture's bytes, calling to setState to rebuild the widget and put the picture with Image.memory(pictureTemp). But it doesn't seem to work.
Uint8List pictureTemp;
io.File profilePic;
Future getFromCamara() async {
var pickedFile = await ImagePicker().getImage(source: ImageSource.camera);
var image = await pickedFile.readAsBytes();
FirebaseStorage.instance
.ref()
.child('picture')
.putFile(io.File(pickedFile.path));
setState(() {
pictureTemp = image;
});
child: CircleAvatar(
radius: 75,
backgroundImage: profilePicture
? pictureTemp == null
? AssetImage(_imageUrl)
: Image.memory(pictureTemp)
: AssetImage(_imageUrl),
),
Here when the image is picked you should directly set it or you can set it after the firebase upload is finished successfully.
But rather than loading an image from Firebase URL after the upload, you can directly load from the picked file as follows;
image = Image.memory(await pickedFile.readAsBytes())
This will instantly set the image and will save you a read call to Firebase. You should always try to minimize the Firebase Reads whenever possible.