This is my method for taking a picture:
handleTakePhoto() async {
Navigator.pop(context);
XFile? file = await ImagePicker()
.pickImage(source: ImageSource.camera, maxWidth: 960, maxHeight: 675);
setState(() {
this.file = file;
bytes = File(file!.path).readAsBytesSync();
});
}
while this is the one for taking a video:
handleTakeVideo() async {
Navigator.pop(context);
XFile? file = await ImagePicker()
.pickVideo(source: ImageSource.camera, maxDuration: const Duration(seconds: 10));
setState(() {
this.file = file;
bytes = File(file!.path).readAsBytesSync();
});
}
As you can see they are pratically identical, but later on my program I need to know if file is an image or a video. How can I do?
They method for taking pictures and video might be identical but the image file and video file are not identical, the contain different file extensions. an image file will either be .jpg, .jpeg or .png. you can print the file path to see these yourself. print(file.path).
check out this Flutter: Is the file an image or not? to help differentiate them.
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)} %')
I am trying to save an image to my local mobile device when I use this code from the pub.dev example page of the camera package. However I am not finding the file saved on the device. Can anyone please help me with how to save the image taken to a given path
void onTakePictureButtonPressed() {
takePicture().then((XFile? file) {
if (mounted) {
setState(() {
imageFile = file;
videoController?.dispose();
videoController = null;
});
if (file != null) {
showInSnackBar('Picture saved to ${file.path}');
}
}
});
}
Using await ImagePicker.pickImage(...), you are already on the right track because the function returns a File.
The File class has a copy method, which you can use to copy the file (which is already saved on disk by either the camera or by lying in gallery) and put it into your application documents directory:
// using your method of getting an image
final File image = await ImagePicker.pickImage(source: imageSource);
// getting a directory path for saving
final String path = await getApplicationDocumentsDirectory().path;
// copy the file to a new path
final File newImage = await image.copy('$path/image1.png');
setState(() {
_image = newImage;
});
You should also note that you can get the path of the image file from ImagePicker using image.path, which will also contain the file ending that you might want to extract and you can save your image path by using newImage.path.
You can use path provider and save the images like this
https://pub.dev/packages/path_provider
final XFile? image = await ImagePicker().pickImage(source: ImageSource.gallery);
if (image == null) return;
final String newFile = await getApplicationDocumentsDirectory().path;
final var fileName = basename(file.path);
final File localImage = await image.saveTo('$newFile/$fileName');
Trying to generate an Thumbnail image from video , the file is created but , errors as Invalid image on load .Using this package video_thumbnail
Creating thumbnail ,
Future<File> genThumbnail(url) async {
//WidgetsFlutterBinding.ensureInitialized();
Uint8List bytes;
final Completer<ThumbnailResult> completer = Completer();
bytes = await VideoThumbnail.thumbnailData(
video: url,
imageFormat: ImageFormat.JPEG,
maxHeight: 250,
maxWidth: 300,
timeMs: 0,
quality: 0);
int _imageDataSize = bytes.length;
print("image size: $_imageDataSize");
//final _image = Image.memory(bytes);
//var _file =File.fromRawPath(bytes);
Directory tempDir = await getTemporaryDirectory();
var uint8list = bytes;
var buffer = uint8list.buffer;
ByteData byteData = ByteData.view(buffer);
File file = await File('${tempDir.path}/img/THUMBNAIL${DateTime.now().toIso8601String()}.JPEG').writeAsBytes(
buffer.asUint8List(byteData.offsetInBytes, byteData.lengthInBytes));
return file;
}
Saving to firestore
await genThumbnail(fileurl).then((_thumbFIle) async{
String Thumbfileurl = await uploadFile(_thumbFIle, 'thumbnailOf${filenamewithoutExtension}.JPEG', 'videothumbnail');
await sendFileToFirestoreChat(fileType, fileurl, filenamewithoutExtension,Thumbfileurl);
return fileurl;
});
The Saved Image ,
https://firebasestorage.googleapis.com/v0/b/proj-inhouse.appspot.com/o/videos%2Fvideothumbnails%2FthumbnailOfVID-20210301-WA0006.JPEG?alt=media&token=fa4f23c1-601f-486b-97d1-c63e221166af
Posting this as a Community Wiki as it's based on #pskink comments.
To resolve, add the writeAsBytes(bytes) instead of writeAsBytes(buffer.asUint8List()). There is no need for any buffer.
I want to convert image captured with camera to base64 but it seems am converting the image path and not the image itself, please help me.
File file;
final picker = ImagePicker();
void _choose() async {
final pickedFile = await picker.getImage(source: ImageSource.camera);
file = File(pickedFile.path);
if (file != null) {
setState(() {
base64Encode(file.readAsBytesSync());
print(base64Encode(Image.file(file));
});
}
}
Wrong:
print(base64Encode(Image.file(file));
Right:
print(base64Encode(file.readAsBytesSync()));
I am using the following code to pick an image with maxHeight/width to save space.
void openGallery()async {
var gallery = await ImagePicker.pickImage(
source: ImageSource.gallery,
maxHeight: maxImageSize,
maxWidth: maxImageSize,
);
if (gallery!=null) {
var bytes = await gallery.readAsBytes();
if (DEBUG) print('Image bytes: ${bytes.length / 1024} KB');
if (DEBUG) print('Image path: ${gallery.path}');
setState(() {
List<int> imageBytes = gallery.readAsBytesSync();
_imageB64 = base64Encode(imageBytes);
// decoded = base64Decode(_imageB64);
if (DEBUG) print('Base64 String length: ${_imageB64.length / 1024} KB');
});
}
}
I am getting this following warning in my console:
image_picker: compressing is not supported for type (null). Returning the image with original quality
flutter: Image bytes: 153.583984375 KB
flutter: Image path: ...myimagpath.jpg
flutter: Base64 String length: 204.78125 KB
1) On one side I can see that my image is reduced in size as it is only 200kB but on the other hand the first line is confusing me.
2) Also, I was under the impression that BASE64 encoded images get smaller in size, As I want to save them to Firebase, will there be a problem saving them as just 'bytes' (as it is 153kb)?
Try this, It's working fine with my code.
var selectedProfileImage;
Future _getImage(bool fromCamera) async {
File image;
if (fromCamera) {
image = await ImagePicker.pickImage(source: ImageSource.camera, maxWidth: 150.0, maxHeight: 150.0);
} else {
image = await ImagePicker.pickImage(source: ImageSource.gallery, maxWidth: 150.0, maxHeight: 150.0);
}
if (image != null) {
// Initiate the ProgessBar
selectedProfileImage = image;
}
}