I am working on uploading the uint8List type image to Firestore and get it again.
I have converted to String to upload to Firestore.
Future _pageDrawScreen() async {
// screenshot pakage
Uint8List? _previewImage = await _testController.capture(); // get uint8List image data
if (_previewImage == null) {
logger.d("_previewImage null");
}
// convert to String
_pageModel!.previewImage = _previewImage.toString();
// Firestore update
}
Then, I take the image data again, convert it, and output it as a memory image.
Widget _pageContainer(int index, PageModel pageModel) {
// get image and convert
Uint8List? previewImage;
if (pageModel.previewImage != null) {
List<int> list = pageModel.previewImage!.codeUnits;
previewImage = Uint8List.fromList(list);
// logger.d(previewImage);
}
return ListTile(
title: pageModel.previewImage != null
? ExtendedImage.memory(
previewImage!,// error!
width: 125,
height: 125,
fit: BoxFit.cover,
// check image state
loadStateChanged: (state) {
switch (state.extendedImageLoadState) {
case LoadState.loading:
return const SizedBox(
width: 50,
height: 50,
child: CircularProgressIndicator(
color: Colors.red,
),
);
case LoadState.completed:
return null;
// Failed error!!
case LoadState.failed:
return const Material(
color: Colors.white,
child: Icon(
Icons.cancel,
color: Colors.red,
size: 50,
),
);
}
},
)
: Container(
width: 125,
height: 125,
color: Colors.white,
child: const Center(
child: CircularProgressIndicator(),
),
),
);
}
However, this image is checked as an error state. Is the conversion of Uint8List wrong?
Expected Results (When using the uint8list image as it is,
):
Actual Results:
import
import 'dart:convert';
for uploading
Uint8List? _previewImage = await _testController.capture();
if(_previewImage != null){
String previewImage = base64.encode(_previewImage);
}
after fetching the image data
Uint8List previewImage = base64.decode(previewImage);
Related
I am using image picker to get image from user then displayed in "CreateCard" UI.
The issue occur when i try using condition in my UI file, i need the condition so i can check if the file image is null before i can display it.
I am working with flutter GetX..
"CreateCard "UI Code:
GetBuilder<CreateCardContollerImp>(builder: (controller) =>UploadImage(
ontap: () {
showModalBottomSheet(
context: context,
builder: (context) {
return CreateCardBottomSheet(
uploadImageGallery: () {
controller.uploadImageGallery();
});
});
},
image: controller.image == null // Error occur here !
? AssetImage(AppImageAsset.profileimage)
: FileImage(controller.image),
),),
"UploadImage" Deifiniton:
class UploadImage extends StatelessWidget {
final void Function() ontap;
final ImageProvider<Object> image;
const UploadImage({super.key, required this.ontap, required this.image});
#override
Widget build(BuildContext context) {
return InkWell(
onTap: ontap,
child: Stack(children: [
Container(
width: 170,
height: 170,
decoration: BoxDecoration(
boxShadow: const [
BoxShadow(
offset: Offset(0, 0),
color: AppColor.primaryColor,
blurRadius: 0,
),
],
borderRadius: BorderRadius.circular(100),
),
padding: const EdgeInsets.symmetric(vertical: 5),
child: CircleAvatar(
backgroundImage: image,
radius: MediaQuery.of(context).size.width - 310,
),
),
]),
);
}
}
"CreateCard" Controller:
class CreateCardContollerImp extends CreateCardContoller {
GlobalKey<FormState> formstate = GlobalKey<FormState>();
final imagepicker = ImagePicker();
late String imagePath;
late File image;
#override
uploadImageGallery() async {
final pickedimage = await imagepicker.getImage(source: ImageSource.gallery);
if (pickedimage != null) {
image = File(pickedimage.path);
imagePath = pickedimage.path;
update();
} else {
printError(info: "No image selected");
}
}
I was expecting this method will work fine.
you're logic looks fine, try casting the as ImageProvider:
controller.image == null
? AssetImage(AppImageAsset.profileimage) as ImageProvider
: FileImage(controller.image) as ImageProvider,
Another alternative is to try just using ImageProvider directly without unnecessary casting.
controller.image == null
? AssetImage(AppImageAsset.profileimage)
: NetworkImage(controller.image),
TheAssetImage is used in getting the avatar profile image from the app's asset.
The NetworkImage is used in getting the avatar profile image from the online DB or API.
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);
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
}}
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.
I'm new to flutter and in an app I'm building I use ImagePicker plugin.
with that the file path image is viewed in my app after I get it from camera/gallery.
the image.path is like this
/storage/emulated/0/Android/data/.../files/Pictures/234d9437-8652-48de-a2b6-711b5f8b702d3492716976084944343.jpg
I need to get the image "234d9437-8652-48de-a2b6-711b5f8b702d3492716976084944343.jpg" part from that and send it to a backend db. I need to convert this before sending. Backend only accept Images in FileFormat.
How can get the image from the file path. in this case it's the variable _imageURI. Then from that retrieve the image and convert it into a FileFormat. After that I need to pass it to a Backend using a json POST request.
In my json request I have a field for 'image': that I need to set the value got from image selected in file format and set to there. how can do this?
can someone explain me with a code ?
much appreciated.
My Code
File _imageURI;
Future _getImageFromCamera() async {
var petImage = await ImagePicker.pickImage(source: ImageSource.camera); //or gallery
setState(() {
_imageURI = petImage;
print(_imageURI.path);
}
}
Image Viewed as
Container(
width: 120.0,
height: 120.0,
decoration: new BoxDecoration(
shape: BoxShape.circle,
image: new DecorationImage(
fit: BoxFit.cover,
image: new FileImage(
_imageURI,
scale: 1.0,
),
),
),
),
Json Request
dogData = {
{
"user_email": "email#m.com,
"user_token": "thisistoken",
"pet": {
"age": "integer",
"birth_date": "%d %b %Y (01 JAN 1996)",
"image": "!Swagger doesn't allow to put file upload. Use formdata instead of base64 in frontend module.",
"name": "string",
"sex": "string",
"user_id": "id"
}
}
My API call
final pet = await CallApi().createThePet(dogData, 'pets/create');
////
Future<dynamic> createThePet(data, apiUrl) async{
var fullUrl = _baseUrl + apiUrl; // + await _getToken();
final response = await http.post(fullUrl, body: jsonEncode(data), headers: _setHeaders());
....
The term you are looking for is called Multi-Part.
There isn't any definite piece of code for that in flutter so i am posting an example snippet.
Future<void> _uploadImage(File image) async {
String tempURL = https://YOUR_WEBSITE/upload";
var request = new http.MultipartRequest("POST", Uri.parse(tempURL));
request.headers["authorization"] = YOUR_TOKEN_HERE;
// prepare file to send.
var profilePhoto = http.MultipartFile(
'upload', image.readAsBytes().asStream(), image.lengthSync(),
filename: image.path);
request.files.add(profilePhoto);
try {
// send files to server.
var response = await request.send();
if (response.statusCode == 200) {
// now we will update the data with the
response.stream.bytesToString().asStream().listen((data) {
_updatePhoto(data);
});
} else {
print("res status code in upload func : ${response.statusCode}");
}
} catch (error) {
print("Error : $error");
}
}
Hope this helps,it is working fine with my project
Install imagepicker,mime,http and import it
import 'package:mime/mime.dart';
import 'package:http/http.dart' as http;
import 'package:http/http.dart';
import 'package:http_parser/http_parser.dart';
import 'package:image_picker/image_picker.dart';
Initialize variable
File _image;
final Imagepicker = ImagePicker();
View for showing image after selecting
Container(
width: 350,
height: 250,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15.0),
border: Border.all(
color: Colors.deepOrangeAccent[400], width: 1.0)),
child: GestureDetector(
child: ClipRRect(
borderRadius: BorderRadius.circular(15.0),
child: Container(
width: 350,
height: 250,
child: _image == null
? Text('No image selected.')
: Image.file(
_image,
fit: BoxFit.cover,
),
decoration: new BoxDecoration(
borderRadius: BorderRadius.circular(10.0),
color: Colors.white,
),
),
),
onTap: () {
getImage();
},
),
),
ImagePicker from camera
Future getImage() async {
PickedFile image =
await Imagepicker.getImage(source: ImageSource.camera, maxHeight: 1000);
setState(() {
_image = File(image.path);
});
}
Submit Function
void submit(File image, String descrption) async {
try {
///Spilits the path and returns only the filename and type
final mimeTypeData =lookupMimeType(image.path, headerBytes: [0xFF, 0xD8]).split('/');
///Url of your api
final request =new http.MultipartRequest("POST", Uri.parse(Urls.ImageInsert));
///replace AreaImage with your database value
final file = await http.MultipartFile.fromPath('AreaImage',
image.path,contentType: MediaType(mimeTypeData[0], mimeTypeData[1]));
///In case there is text fields or other details use like this
request.fields['user_email'] = "Email";
request.fields['user_token'] = "thisistoken";
request.files.add(file);
StreamedResponse response = await request.send();
//waiting for response
response.stream.transform(utf8.decoder).listen((value) {
//Response can be pass with map object to alertbox
Map<String, dynamic> map = jsonDecode(value);
try {
// hide progrssbar
pr.hide();
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text("Alert"),
//here we show response message from api/or you can show your own message
here
content: Text(map['message']),
actions: [
FlatButton(
child: Text("Close"),
onPressed: () {
//Do Something here
},
)
],
);
},
);
} catch (e) {
e.toString();
}
});
}
}
}
You can checkout my github for image upload with either gallery or cameragithub