error when using File with ImagePicker Flutter - flutter

The error is with this line: File selectedImage
I only have dart.io imported, not even dart.html so I'm not sure why I'm getting this error.
here is the longer piece of code
import 'dart:io';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:random_string/random_string.dart';
import 'package:tennis_event_app/services/crud.dart';
class CreateBlog extends StatefulWidget {
#override
_CreateBlogState createState() => _CreateBlogState();
}
class _CreateBlogState extends State<CreateBlog> {
late String pass, authorName, title, desc;
File selectedImage;
final picker = ImagePicker();
bool _isLoading = false;
CrudMethods crudMethods = new CrudMethods();
Future getImage() async {
final pickedFile = await picker.getImage(source: ImageSource.gallery);
setState(() {
if (pickedFile != null) {
selectedImage = File(pickedFile.path);
} else {
print('No image selected.');
}
});
}
(this is not the entire code but just a larger piece)

What exact error are you getting?
Suggestion
Please do well to put setState((){...}); in the if-statement like this:
if(pickedFile != null){
setState((){
selectedImage = File(pickedFile.path);
});
}else{
print('No image selected');
}
and Hot Reload.
SEE COMPLETE SOLUTION THAT WORKED FOR ME
class _ImageSelectorState extends State<ImageSelector> {
var imageFile;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
width: 200.0,
height: 200.0,
color: Colors.grey.shade300,
child: imageFile != null
? Image.file(imageFile)
: Icon(
Icons.image,
),
),
SizedBox(height: 20.0),
//Button
Center(
child: ElevatedButton(
onPressed: _pickImage,
child: Text('Upload Image'),
),
),
],
),
);
}
_pickImage() async {
try {
final picker = await ImagePicker().getImage(
source: ImageSource.gallery,
);
if (picker != null) {
setState(() {
imageFile = File(picker.path);
});
}
} catch (e) {
print(e);
}
}
}
Result

Solution I Used:
I ended up changing File selectedImage; to File ? selectedImage;

Related

PickedImage getting null

I want to save an image locally on Device after Picking the Image From Gallery By using Path provider package . but _image file variable gets null after Selecting an Image From Gallery . Thats Why the Screen keeps Stuck on CircularProgressIndicator Screen . Can You Please Help me out of this null _image file variable.
import 'dart:io';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:image_picker/image_picker.dart';
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';
class SaveImage extends StatefulWidget {
const SaveImage({ Key? key }) : super(key: key);
#override
_SaveImageState createState() => _SaveImageState();
}
File? _image;
Future<File?> getImage() async{
var image = File(await ImagePicker.platform
.pickImage(source: ImageSource.gallery)
.then((value) => value.path));
final Directory directory = await getApplicationDocumentsDirectory();
final path=directory.toString();
final String fileName = basename(image.path);
// final String fileExtension = extension(image.path);
File newImage = await image.copy('$path/$fileName.jpg');
setState(() {
_image = newImage;
});
}
void setState(Null Function() param0) {
}
class _SaveImageState extends State<SaveImage> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Center(
child: Column(
children: [
Text('Pick Image From'),
SizedBox(height: 30,),
ElevatedButton(onPressed: (){
getImage();
}, child: Text('From Gallery')),
ElevatedButton(onPressed: (){
}, child: Text('From Camera')),
SizedBox(height: 50),
Container(
child: _image!=null?ClipRRect(
borderRadius: BorderRadius.circular(6),
child: Image.file(
_image!,
fit: BoxFit.cover,
)):Center(child: CircularProgressIndicator(),)
),
],
),
),
),
);
}
}
Some things are wrong in your code:
The getImage() function is not inside your class, so the setState won't work.
You're not checking the return value of ImagePicker.platform.pickImage(), as it can be null. You have to check it before initialising a File with it.
directory.toString() does not return the path of the directory, but it returns "Directory: '/something'". It is meant to be printed. If you want the actual directory path, you need directory.path
If it's still not working, make sure you have done the right setup, as asked by image_picker (setting up your Info.plist for IOS...)
Here is your code, working as expected:
class SaveImage extends StatefulWidget {
const SaveImage({Key? key}) : super(key: key);
#override
_SaveImageState createState() => _SaveImageState();
}
class _SaveImageState extends State<SaveImage> {
File? _image;
Future<File?> getImage() async {
PickedFile? pickedFile =
await ImagePicker.platform.pickImage(source: ImageSource.gallery);
if (pickedFile == null) {
return null;
}
final File file = File(pickedFile.path);
final Directory directory = await getApplicationDocumentsDirectory();
final path = directory.path;
final String fileName = basename(pickedFile.path);
// final String fileExtension = extension(image.path);
File newImage = await file.copy('$path/$fileName');
setState(() {
_image = newImage;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Center(
child: Column(
children: [
Text('Pick Image From'),
SizedBox(
height: 30,
),
ElevatedButton(
onPressed: () {
getImage();
},
child: Text('From Gallery')),
ElevatedButton(onPressed: () {}, child: Text('From Camera')),
SizedBox(height: 50),
Container(
child: _image != null
? ClipRRect(
borderRadius: BorderRadius.circular(6),
child: Image.file(
_image!,
fit: BoxFit.cover,
))
: Center(
child: CircularProgressIndicator(),
)),
],
),
),
),
);
}
}
If you want to store the image in the cache, you can use flutter_cache_manager library. It allows you to store and retrieve a file in cache.
Here is the code, updated to store the file in cache.
Notice that we use a key to identify our file in cache (I set it to the path of the file but you can set it to basically any String as long as it's unique to this file). If you want to use the file app-wide, you would probably need to store the key somewhere that can be accessed there.
class SaveImage extends StatefulWidget {
const SaveImage({Key? key}) : super(key: key);
#override
_SaveImageState createState() => _SaveImageState();
}
class _SaveImageState extends State<SaveImage> {
File? _image;
String? cachedFileKey;
Future<File?> getImage() async {
PickedFile? pickedFile =
await ImagePicker.platform.pickImage(source: ImageSource.gallery);
if (pickedFile == null) {
return null;
}
final File file = File(pickedFile.path);
final Uint8List fileBytes = await file.readAsBytes();
final cachedFile = await DefaultCacheManager()
.putFile(pickedFile.path, fileBytes, key: pickedFile.path);
setState(() {
cachedFileKey = pickedFile.path;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Center(
child: Column(
children: [
Text('Pick Image From'),
SizedBox(
height: 30,
),
ElevatedButton(
onPressed: () {
getImage();
},
child: Text('From Gallery')),
ElevatedButton(onPressed: () {}, child: Text('From Camera')),
const SizedBox(height: 50),
Container(
child: cachedFileKey != null
?
FutureBuilder<FileInfo?>(future: DefaultCacheManager().getFileFromCache(cachedFileKey!), builder: (context, snapShot) {
if (snapShot.hasData && snapShot.data != null) {
return ClipRRect(
borderRadius: BorderRadius.circular(6),
child: Image.file(snapShot.data!.file,
fit: BoxFit.cover,
));
} else {
return const Center(
child: CircularProgressIndicator(),
);
}
})
: const Center(
child: CircularProgressIndicator(),
)),
],
),
),
),
);
}
}
use image type PickedFile type. Ex:
PickedFile _image;
Future pickImageFromGallery(ImageSource source, BuildContext context) async {
var _image = await ImagePicker.platform.pickImage(source: source);
image = _image;
_uploadImage(image, context);
}
**for taking image path:
imageFile.path

flutter) There's a problem with using imagePicker

I'm using sdk 2.12.0 and image_picker 0.8.4 version.
I'm going to link my gallery to get an image.
However, when I press the Add Image button on my app, the app turns off immediately.
This is the code for the image_picker I used.
class CreatePage extends StatefulWidget {
const CreatePage({Key? key, required this.user}) : super(key: key);
final User user;
#override
_CreatePageState createState() => _CreatePageState();
}
class _CreatePageState extends State<CreatePage> {
//ImagePicker
final ImagePicker _picker = ImagePicker();
File? _imageFile;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: _buildAppbar(),
body: _buildBody(),
floatingActionButton: FloatingActionButton(
onPressed: _getImage,
backgroundColor: Colors.blue,
child: Icon(Icons.add_a_photo),
),
);
}
Future<void> _getImage() async {
//ImagePiker
var image = await _picker.pickImage(source: ImageSource.gallery);
setState(() {
_imageFile = File(image!.path);
});
}
And this is my full code about this page. (Firebase code is included)
import 'dart:io';
import 'dart:async';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
class CreatePage extends StatefulWidget {
//user info
const CreatePage({Key? key, required this.user}) : super(key: key);
final User user;
#override
_CreatePageState createState() => _CreatePageState();
}
class _CreatePageState extends State<CreatePage> {
//input text
final TextEditingController createText = TextEditingController();
//ImagePicker
final ImagePicker _picker = ImagePicker();
File? _imageFile;
//_createPageState가 제거될 때 호출됨
#override
void dispose() {
// TODO: implement dispose
createText.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: _buildAppbar(),
body: _buildBody(),
floatingActionButton: FloatingActionButton(
onPressed: _getImage,
backgroundColor: Colors.blue,
child: Icon(Icons.add_a_photo),
),
);
}
_buildAppbar() {
return AppBar(
actions: [
IconButton(
icon: Icon(Icons.send),
onPressed: () {
_uploadPost(context);
},
),
],
);
}
_buildBody() {
return SingleChildScrollView(
child: Column(
children: [
_imageFile == null ? Text("No Image") : Image.file(_imageFile!),
TextField(
controller: createText,
decoration: InputDecoration(
hintText: "내용을 입력하세요",
),
)
],
),
);
}
//gallery image
Future<void> _getImage() async {
var image = await _picker.pickImage(source: ImageSource.gallery);
setState(() {
_imageFile = File(image!.path);
});
}
Future _uploadPost(BuildContext context) async {
final firebaseStorageRef = FirebaseStorage.instance
.ref()
.child('post')
.child('${DateTime.now().microsecondsSinceEpoch}.png');
final task = await firebaseStorageRef.putFile(
_imageFile!, SettableMetadata(contentType: "image/png")
);
final uri = await task.ref.getDownloadURL();
//database document
final doc = FirebaseFirestore.instance.collection('post').doc();
//json type
await doc.set({
'id': doc.id,
'photoUrl': uri.toString(), //storage file url
'contents': createText, //user input text
'email': widget.user.email, //user email
'displayName': widget.user.displayName, //user name
'userPhotoUrl': widget.user.photoURL, //user profile image
});
//return page
Navigator.pop(context);
}
}
Pressing the floatingActionButton turns off the app and outputs the following error.
Lost connection to device.
May I know the cause of this?
Thank you in advance.
try adding dependency
image_picker: ^0.8.3+2
import 'package:image_picker/image_picker.dart';
then add this code
String url = "";
ImagePicker image = ImagePicker();
File ? file;
getImage() async {
var img = await image.pickImage(source: ImageSource.gallery);
setState(() {
file = File(img!.path);
});
}
And add:
onTap: () {
getImage();
},
add code:
child: file != null ?
Column(
children: [
Padding(
padding: const EdgeInsets.all(20.0),
child: Container(
color: Colors.black,
margin: EdgeInsets.only(top: 80),
width: double.infinity,
height: 250,
child: Image.file(
file!,
fit: BoxFit.contain,
),
),
),
My guess is that you don't have permission to access the Media on the device, thus aborting the app the moment you try to do so. Check out the permission handler package.

Flutter Camera recorded Video are incompatible with browsers - how to convert to .mp4?

I'm trying to capture a video and upload it to firebase storage.
The problem is, the recorded video format is .mov and this format seems to be incompatible with browsers.
How could I convert the recorded file to .mp4?
Below is the code I use to record and upload my videos.
import 'dart:io';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:flutter/material.dart';
import 'package:camera/camera.dart';
import 'package:video_player/video_player.dart';
import 'package:flutter/services.dart' show rootBundle;
import 'package:path_provider/path_provider.dart';
class CameraTestPage extends StatefulWidget {
const CameraTestPage({Key? key}) : super(key: key);
#override
_CameraTestPageState createState() => _CameraTestPageState();
}
class _CameraTestPageState extends State<CameraTestPage> {
List<CameraDescription>? cameras;
CameraController? controller;
bool frontCamera = false;
XFile? videoFile;
VideoPlayerController? videoController;
VoidCallback? videoPlayerListener;
#override
void initState() {
initCamera();
super.initState();
}
initCamera() async {
if (cameras == null) {
cameras = await availableCameras();
}
if (controller?.value.isInitialized ?? false) {
controller!.dispose();
}
controller = CameraController(
cameras!.firstWhere(
(element) => element.lensDirection == (frontCamera ? CameraLensDirection.front : CameraLensDirection.back),
),
ResolutionPreset.medium,
enableAudio: false,
);
controller!.initialize().then((value) {
setState(() {});
});
}
void onVideoRecordButtonPressed() {
startVideoRecording().then((_) {
if (mounted) setState(() {});
});
}
void onStopButtonPressed() {
stopVideoRecording().then((file) {
if (mounted) setState(() {});
if (file != null) {
print('Video recorded to ${file.path}');
videoFile = file;
_startVideoPlayer();
}
});
}
Future<void> _startVideoPlayer() async {
if (videoFile == null) {
return;
}
final VideoPlayerController vController = VideoPlayerController.file(File(videoFile!.path));
videoPlayerListener = () {
if (videoController != null && videoController!.value.size != null) {
// Refreshing the state to update video player with the correct ratio.
if (mounted) setState(() {});
videoController!.removeListener(videoPlayerListener!);
}
};
vController.addListener(videoPlayerListener!);
await vController.setLooping(true);
await vController.initialize();
await videoController?.dispose();
if (mounted) {
setState(() {
videoController = vController;
});
}
await vController.play();
}
Future<void> startVideoRecording() async {
final CameraController? cameraController = controller;
if (cameraController == null || !cameraController.value.isInitialized) {
print('Error: select a camera first.');
return;
}
if (cameraController.value.isRecordingVideo) {
// A recording is already started, do nothing.
return;
}
try {
await cameraController.startVideoRecording();
} on CameraException catch (e) {
_showCameraException(e);
return;
}
}
Future<XFile?> stopVideoRecording() async {
final CameraController? cameraController = controller;
if (cameraController == null || !cameraController.value.isRecordingVideo) {
return null;
}
try {
return cameraController.stopVideoRecording();
} on CameraException catch (e) {
_showCameraException(e);
return null;
}
}
void _showCameraException(CameraException e) {
print('Error: ${e.code}\n${e.description}');
}
_uploadVideo() async {
Reference ref = FirebaseStorage.instance.ref("test/test.mov");
UploadTask uploadTask = ref.putFile(File(videoFile!.path), SettableMetadata(contentType: 'video/mov'));
print("uploading");
uploadTask.whenComplete(() async {
String downloadUrl = await ref.getDownloadURL();
print("download url: $downloadUrl");
});
}
Widget _thumbnailWidget() {
final VideoPlayerController? localVideoController = videoController;
return Expanded(
child: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
SizedBox(
child: (localVideoController == null)
? Center(
child: Container(
child: Text("none"),
),
)
: Container(
child: AspectRatio(
aspectRatio: localVideoController.value.aspectRatio,
child: VideoPlayer(localVideoController),
),
decoration: BoxDecoration(
border: Border.all(color: Colors.pink),
),
),
),
],
),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Camera Test")),
body: Column(
children: [
if (controller != null)
Container(
child: CameraPreview(controller!),
height: 400,
),
Row(
children: [
ElevatedButton(
onPressed: () {
frontCamera = !frontCamera;
initCamera();
},
child: Text("Switch"),
),
ElevatedButton(
onPressed: () {
controller?.value.isRecordingVideo ?? false ? onStopButtonPressed() : onVideoRecordButtonPressed();
},
child: Text(controller?.value.isRecordingVideo ?? false ? "Stop" : "Record"),
),
ElevatedButton(
onPressed: videoFile != null ? _uploadVideo : null,
child: Text("Upload video"),
),
],
),
_thumbnailWidget(),
],
),
);
}
}
You can use the video_compress package to convert the video to mp4.
Here is your _uploadVideo() method updated to include this:
_uploadVideo() async {
Reference ref = FirebaseStorage.instance.ref("test/test.mp4");
MediaInfo? mediaInfo = await VideoCompress.compressVideo(
videoFile!.path,
quality: VideoQuality.DefaultQuality,
deleteOrigin: false, // It's false by default
);
UploadTask uploadTask = ref.putFile(
File(mediaInfo!.path!), SettableMetadata(contentType: 'video/mp4'));
print("uploading");
uploadTask.whenComplete(() async {
String downloadUrl = await ref.getDownloadURL();
print("download url: $downloadUrl");
});
}
Ensure you import the package by including this line:
import 'package:video_compress/video_compress.dart';

Flutter tflite image classification how to not show wrong results

Im trying to understand tensorflow and I wanted to create a flutter app with Image Classification for cat or dog.
I used https://teachablemachine.withgoogle.com/ to train my model with 100 epoches and 128 batches. The ouput of my model is 97% accuracy for both the cat and dog. I used a dataset from kaggle with 4000 images for each cat and dog.
My Code:
import 'dart:io';
import 'package:tflite/tflite.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
File? _image;
bool _loading = false;
List<dynamic>? _output;
final _picker = ImagePicker();
pickImage() async {
var image = await _picker.getImage(source: ImageSource.camera);
if (image == null) {
return null;
}
setState(() {
_image = File(image.path);
});
classifyImage(_image);
}
pickGalleryImage() async {
var image = await _picker.getImage(source: ImageSource.gallery);
if (image == null) {
return null;
}
setState(() {
_image = File(image.path);
});
classifyImage(_image);
}
#override
void initState() {
super.initState();
_loading = true;
loadModel().then((value) {
// setState(() {});
});
}
#override
void dispose() {
Tflite.close();
super.dispose();
}
classifyImage(File? image) async {
var output = await Tflite.runModelOnImage(
path: image!.path,
numResults: 2,
threshold: 0.5,
imageMean: 127.5,
imageStd: 127.5,
);
setState(() {
_loading = false;
_output = output;
});
}
loadModel() async {
await Tflite.loadModel(
model: 'assets/model_unquant.tflite',
labels: 'assets/labels.txt',
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Cat vs Dog Classifier'),
),
body: Center(
child: Column(
children: [
SizedBox(height: 160.0),
_image == null
? Text('No image selected')
: Container(
child: Image.file(_image!),
height: 250.0, // Fixed height for image
),
SizedBox(height: 20.0),
_output != null ? Text('${_output![0]['label']}') : Container(),
SizedBox(height: 50.0),
ElevatedButton(
onPressed: pickImage,
child: Text('Take Picture'),
),
ElevatedButton(
onPressed: pickGalleryImage,
child: Text('Camera Roll'),
),
],
),
),
);
}
}
My question:
If im picking a different image which isn't cat or dog, im still getting a 100% cat or dog feedback most of the time. How to not show these wrong results? What can we actually do?
You have to train Your original model on 3 classes:
cat
dog
other
then convert to tflite model and use it in your flutter project

Display Image from preferences in Flutter App

I am having a problem. I have a Drawer in Flutter App and I want to implement a feature where you can pick a photo from gallery. Thats the easy part. But i want to save this photo in the preferences and load it when the App starts again. The imageFromPreferences variable have to be an Future to use it in the preferenceImage() Future builder. I got not idea how to it after hours of research. Maybe its the total wrong approach and you got a different idea.
import 'dart:io';
import 'dart:ui';
import 'package:firstapp/database/database.dart';
import 'package:firstapp/views/note.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/painting.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
import 'package:image_picker/image_picker.dart';
import 'package:firstapp/Utility/Utility.dart';
class NoteList extends StatefulWidget {
#override
NoteListState createState() {
return new NoteListState();
}
}
class NoteListState extends State<NoteList> {
Future<File> imageFile;
Image imageFromPreferences;
pickImageFromGallery(ImageSource source) {
setState(() {
imageFile = ImagePicker.pickImage(source: source);
});
}
loadImageFromPreferences() {
Utility.getImageFromPreferences().then((img) {
setState(() {
imageFromPreferences = Utility.imageFromBase64String(img);
});
});
}
Widget preferenceImage() {
return FutureBuilder<Image>(
future: loadImageFromPreferences(),
builder: (BuildContext context, AsyncSnapshot<Image> image) {
print(image);
if (image.connectionState == ConnectionState.done && image.hasData) {
return image.data;
} else {
return Text("error");
}
},
);
}
Widget imageFromGallery() {
return FutureBuilder<File>(
future: imageFile,
builder: (BuildContext context, AsyncSnapshot<File> snapshot) {
if (snapshot.connectionState == ConnectionState.done &&
snapshot.hasData) {
Utility.saveImageToPreferences(
Utility.base64String(snapshot.data.readAsBytesSync()));
return Image.file(
snapshot.data,
);
}
return null;
},
);
}
finalPicker() {
if (imageFromGallery() == null) {
return preferenceImage();
} else if (imageFromGallery() != null) {
return imageFromGallery();
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Taking Notes')),
drawer: Drawer(
child: ListView(
children: <Widget>[
UserAccountsDrawerHeader(
accountEmail: Text('lala#web.de'),
accountName: Text('Max'),
decoration: BoxDecoration(
color: Theme.of(context).primaryColor,
),
currentAccountPicture: GestureDetector(
onTap: () {
pickImageFromGallery(ImageSource.gallery);
},
child: Column(
children: <Widget>[finalPicker()],
),
),
),
Container(
padding: EdgeInsets.all(20.0),
child: Text("Locked files"),
color: Theme.of(context).primaryColor,
),
],
),
),
This is how I save the Image as a String in the preferences. Maybe I could instead save it in a file?
import 'dart:async';
import 'dart:convert';
class Utility{
static const String IMG_KEY = "IMAGE_KEY";
static Future<bool> saveImageToPreferences(String value) async {
final SharedPreferences preferences = await SharedPreferences.getInstance();
return preferences.setString(IMG_KEY, value);
}
static Future<String> getImageFromPreferences() async{
final SharedPreferences preferences = await SharedPreferences.getInstance();
return preferences.getString(IMG_KEY);
}
static String base64String(Uint8List data) {
return base64Encode(data);
}
static Image imageFromBase64String(String base64String){
return Image.memory(base64Decode(base64String), fit: BoxFit.fill);
}
}
// 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 can store this path in your shared preference.
here you make copy in root directory and then store path of that image.
also you can used this plugin
https://pub.dev/packages/image_picker_saver
[image_picker_saver][1]