Saving ImagePicker image from gallery in Flutter - flutter

As always these simplest solutions are the hardest for me to solve. I have the ImagePicker function to get image from gallery and set it as a background. The code below works perfectly, but the image doesn't save, so after each restart, it isn't there. Here's the code:
Future _getImage() async {
final picker = ImagePicker();
final pickedFile = await picker.getImage(source: ImageSource.gallery);
setState(() {
if (pickedFile != null) {
_image = File(pickedFile.path);
print('_image: $_image');
} else {
print('No image selected');
}
});
}
So my question is how to save the image for it to be permanent and persist after restarts, I have tried everything (setting and saving paths etc) and for some reason can't get it to work. Hopefully the solution is simple. My understanding is it should be saved to local storage of the device, in this case the emulator, but it should work on every device of course.

You can save the image that is picked from the gallery by the user to the application directory. Then, use this image to show from the local storage.
Get the directory path using path_provider
Directory appDocDir = await getApplicationDocumentsDirectory();
String appDocPath = appDocDir.path;
Save image to your directory
final picker = ImagePicker();
final pickedFile = await picker.getImage(source: ImageSource.gallery);
if (pickedFile == null) return;
_image = File(pickedFile.path);
final fileName = 'background_image';
final File localImage = await _image.copy('${widget.appDocPath}/$fileName');
Use the image in your widget tree
Image image;
var hasLocalImage =
File('${widget.appDocPath}/background_image').existsSync();
if (hasLocalImage) {
var bytes =
File('${widget.appDocPath}/background_image').readAsBytesSync();
image = Image.memory(bytes);
}
Full working example:
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:path_provider/path_provider.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
// This makes the visual density adapt to the platform that you run
// the app on. For desktop platforms, the controls will be smaller and
// closer together (more dense) than on mobile platforms.
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: SplashScreen(),
);
}
}
class SplashScreen extends StatefulWidget {
#override
_SplashScreenState createState() => _SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen> {
String appDocPath;
Future<void> getApplicationDirectoryPath() async {
Directory appDocDir = await getApplicationDocumentsDirectory();
appDocPath = appDocDir.path;
}
#override
initState() {
getApplicationDirectoryPath().then((_) {
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (BuildContext context) => Home(
appDocPath,
)));
});
super.initState();
}
#override
Widget build(BuildContext context) {
return Container();
}
}
class Home extends StatefulWidget {
final String appDocPath;
Home(this.appDocPath);
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
File _image;
#override
initState() {
super.initState();
}
Future _getImage() async {
final picker = ImagePicker();
final pickedFile = await picker.getImage(source: ImageSource.gallery);
if (pickedFile == null) return;
_image = File(pickedFile.path);
final fileName = 'background_image';
final File localImage = await _image.copy('${widget.appDocPath}/$fileName');
setState(() {
});
}
#override
Widget build(BuildContext context) {
Image image;
var hasLocalImage =
File('${widget.appDocPath}/background_image').existsSync();
if (hasLocalImage) {
var bytes =
File('${widget.appDocPath}/background_image').readAsBytesSync();
image = Image.memory(bytes);
}
return new Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: () {
_getImage();
},
),
body: (File('${widget.appDocPath}/background_image').existsSync())
? Center(
child: image,
)
: Text('NO PICTURE HAS BEEN SELECTED NOW OR IN THE PAST'));
}
}

There's probably a better way to do this, but here's a working example using shared preferences :
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:shared_preferences/shared_preferences.dart';
void main() async {
runApp(MaterialApp(debugShowCheckedModeBanner: false, home: MyApp()));
}
class MyApp extends StatefulWidget {
#override
State<StatefulWidget> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String filePath = '';
getImage() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
bool check = prefs.containsKey('image');
if (check) {
setState(() {
filePath = prefs.getString('image');
});
return;
}
ImagePicker imagePicker = new ImagePicker();
PickedFile image = await imagePicker.getImage(source: ImageSource.gallery);
String imagePath = image.path;
await prefs.setString('image', imagePath);
setState(() {
filePath = prefs.getString('image');
});
}
#override
void initState() {
super.initState();
getImage();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Container(
child: filePath == '' ? FlatButton(
onPressed: getImage,
child: Text('get image'),
) : Image.file(File(filePath)),
)
);
}
}

Related

I wrote code in Flutter. But Shape plus not working but Image Picker working

I use Flutter and added Image Picker and Share Plus.
Image Picker working but doesnt work Share Plus?
I dont understand why doesnt working share plus.
Can you looking?
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:image_picker/image_picker.dart';
import 'package:share_plus/share_plus.dart';
void main() {
runApp(share1());
}
class share1 extends StatelessWidget {
const share1({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: "Image Share",
home: share2(),
);
}
}
class share2 extends StatefulWidget {
const share2({Key? key}) : super(key: key);
#override
State<share2> createState() => _share2State();
}
class _share2State extends State<share2> {
#override
void initState() {
// TODO: implement initState
super.initState();
}
File? _image;
Future getImage(ImageSource source) async {
try {
final image=await ImagePicker().pickImage(source: source);
if(image==null) return;
final imageTemporary = File(image.path);
setState(() {
this._image=imageTemporary;
Share.share(_image);
});
} on PlatformException catch (e) {
print('Failed to pick image : $e');
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(centerTitle:true,title: Text("Image Share"),),
body: Center(child: Column(children: [
SizedBox(height: 40,),
_image != null ? Image.file(_image!,width: 250,height: 250,fit: BoxFit.cover,)
: Image.network('https://picsum.photos/250?image=9'),
SizedBox(height: 40,),
ElevatedButton(onPressed: ()=> getImage(ImageSource.gallery), child: Text("Resim Seç")),
Text("Image Share"),
],),),
);
}
}
Purpose of the project : Adding and sharing pictures from the gallery. However, I couldn't get it to run.Any idea where is wrong with my code and what should I do?
File? _image;
Future getImage(ImageSource source) async {
try {
final image = await ImagePicker().pickImage(source: source);
if (image == null) return;
final imageTemporary = File(image.path);
setState(() {
this._image = imageTemporary;
});
final imagePath = _image!.path;
Share.shareFiles([imagePath], text: 'Sharing image');
} on PlatformException catch (e) {
print('Failed to pick image : $e');
}
}

Flutter: How to store the location data?

Errors:
The named parameter 'locationData' is required, but there's no
corresponding argument. Try adding the required argument.
Undefined name 'locationData'. Try correcting the name to one that is defined, or defining the name.
The location data in the main.dart file bring an error please help me solve it.
My code:
Below is the main.dart code that caused the error:
import 'package:firebase_core/firebase_core.dart';
import 'package:firstapp/screens/Login_screen.dart';
import 'package:firstapp/screens/authunication/phone_auth_screen.dart';
import 'package:firstapp/screens/home_screen.dart';
import 'package:firstapp/screens/location_screen.dart';
import 'package:firstapp/screens/splash_screen.dart';
import 'package:flutter/material.dart';
import 'package:location/location.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
// ignore: use_key_in_widget_constructors
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
primaryColor: Colors.cyan.shade900,
),
initialRoute: SplashScreen.id,
routes: {
SplashScreen.id: (context) => SplashScreen(),
LoginScreen.id: (context) => LoginScreen(),
PhoneAuthScreen.id: (context) => PhoneAuthScreen(),
LocationScreen.id: (context) => LocationScreen(),
HomeScreen.id: (context) => HomeScreen(locationData),
},
);`
Below is the code for the HomeScreen widget where I want location data:
import 'package:flutter/material.dart';
import 'package:location/location.dart';
class HomeScreen extends StatelessWidget {
static const String id = 'home-screen';
final LocationData locationData;
HomeScreen({
required this.locationData,
});
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(locationData.latitude.toString()),
),
body: Center(
child: Text('Home screen'),
),
);
}
}
Here is the code for the LocationScreen widget in the app:
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firstapp/screens/login_screen.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:location/location.dart';
class LocationScreen extends StatefulWidget {
static const String id = 'location-screen';
#override
State<LocationScreen> createState() => _LocationScreenState();
}
class _LocationScreenState extends State<LocationScreen> {
Location location = new Location();
late bool _serviceEnabled;
late PermissionStatus _permissionGranted;
late LocationData _locationData;
Future<LocationData?>getLocation() async {
_serviceEnabled = await location.serviceEnabled();
if (!_serviceEnabled) {
_serviceEnabled = await location.requestService();
if (!_serviceEnabled) {
return null;
}
}
_permissionGranted = await location.hasPermission();
if (_permissionGranted == PermissionStatus.denied) {
_permissionGranted = await location.requestPermission();
if (_permissionGranted != PermissionStatus.granted) {
return null;
}
}
_locationData = await location.getLocation();
return _locationData;
}
So,
The first error says that when you try to implement a HomeScreen widget, withoug giving the required parameter named locationData,to give the required parameted follow this code example:
HomeScreen(locationData: locationData)
The second error says that you are trying to use a variable that is not defined yet. In the page that you try to implement the HomeScreen widget, you should define a variable named locationData, to give it a value and then to try to use the HomeScreen widget. For instance:
class LocationScreen extends StatefulWidget {
const LocationScreen({Key? key}) : super(key: key);
#override
State<LocationScreen> createState() => _LocationScreenState();
}
class _LocationScreenState extends State<LocationScreen> {
LocationData locationData;
#override
Widget build(BuildContext context) {
//in case that you use the HomeScreen as a widget
return locationData == null ? Container() : HomeScreen(locationData: locationData);
//in case that you use the HomeScreen as Screen
return Container();
}
void getLocationData() async{
//in case that you use the HomeScreen as a widget
//this function will change the state after the locationData have been filled
locationData = await getLocation();
setState(() {
});
}
void navigateToHomeScreen() async{
//in case that you use the HomeScreen as a widget
//this function will change the state after the locationData have been filled
locationData = await getLocation();
Navigator.push(context, MaterialPageRoute(
builder: (context) => HomeScreen(locationData: locationData);
));
}
Future<LocationData?> getLocation() async {
_serviceEnabled = await location.serviceEnabled();
if (!_serviceEnabled) {
_serviceEnabled = await location.requestService();
if (!_serviceEnabled) {
return null;
}
}
_permissionGranted = await location.hasPermission();
if (_permissionGranted == PermissionStatus.denied) {
_permissionGranted = await location.requestPermission();
if (_permissionGranted != PermissionStatus.granted) {
return null;
}
}
_locationData = await location.getLocation();
return _locationData;
}
}
The third error says that don't use any Positional parameters in your HomeScreen class because you use named parameters, If you follow my code, it will be fixed as well
Hope I helped,
Enjoy flutter
On the HomeScreen, replace this line of code:
HomeScreen({required this.locationData,});
with
HomeScreen(this.locationData);
This should clear the error on main.dart

FlutterNativeSplash.removeAfter(initialisation) renders next screen before initialisation completes

I am using flutter_native_splash package and shared_preferneces to store my app data. I have the following code in my main.dart file.
import 'package:flutter/material.dart';
import 'package:flutter_native_splash/flutter_native_splash.dart';
import 'package:location/location.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'home_management.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
FlutterNativeSplash.removeAfter(initialization);
runApp(const MyApp());
}
void initialization(BuildContext context) async {
// Initialise shared preferences
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
// Initialise user location and store it in shared preferences
Location _location = Location();
bool? _serviceEnabled;
PermissionStatus? _permissionGranted;
LocationData? _locationData;
_serviceEnabled = await _location.serviceEnabled();
if (!_serviceEnabled) {
_serviceEnabled = await _location.requestService();
}
_permissionGranted = await _location.hasPermission();
if (_permissionGranted == PermissionStatus.denied) {
_permissionGranted = await _location.requestPermission();
}
_locationData = await _location.getLocation();
sharedPreferences.setDouble('latitude', _locationData.latitude!);
sharedPreferences.setDouble('longitude', _locationData.longitude!);
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(brightness: Brightness.light),
darkTheme: ThemeData(brightness: Brightness.dark),
themeMode: ThemeMode.dark,
home: const HomeManagement(),
);
}
}
I am using HomeManagement to manage my Pages with a bottom navigation bar, and the first page to load is RestaurantsMap() which looks as below.
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
class RestaurantsMap extends StatefulWidget {
const RestaurantsMap({Key? key}) : super(key: key);
#override
State<RestaurantsMap> createState() => _RestaurantsMapState();
}
class _RestaurantsMapState extends State<RestaurantsMap> {
late Future<SharedPreferences> sharedPreferences;
#override
void initState() {
sharedPreferences = SharedPreferences.getInstance();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Restaurants Map'),
),
body: FutureBuilder(
future: sharedPreferences,
builder: (BuildContext context,
AsyncSnapshot<SharedPreferences> snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
print(snapshot.data!.getDouble('latitude'));
return const Center(
child: Text('Start building something awesome! 💪🏻'),
);
} else {
return Container();
}
}),
);
}
}
Whenever I am accessing the latitude in RestaurantsMap inside the FutureBuilder, I am getting a null printed by the following line of code:
print(snapshot.data!.getDouble('latitude'));
Using print statements inside the initialization() function after sharedPreferences.setDouble returns the data, so the only logical explanation is that I am accessing the getDouble('latitude') before it is getting set.
Any observations/solutions would be helpful.
For future viewers, if anyone faces the same issue, just update to the latest version for flutter_native_splash. An update has been released that gives more flexibility to make a call to remove the splash screen.
Here is the new readme - https://pub.dev/packages/flutter_native_splash#3-set-up-app-initialization-optional

I am building a Photo editing app in flutter which can apply built in photo filters on an image picked from gallery

I have written the code by taking help from official documentation of each plugin. Inspite of that I am getting errors mentioned below. Can anyone help what is the issue ?
import 'dart:html';
import 'package:flutter/material.dart';
import 'package:flutter/semantics.dart';
import 'package:path/path.dart';
import 'package:photofilters/photofilters.dart';
import 'package:image_picker/image_picker.dart';
import 'package:image/image.dart' as imageLib;
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
File _image;
String fileName;
Filter _filter;
List<Filter> filters = presetFiltersList;
final picker = ImagePicker();
Future getImage() async {
final pickedFile = await picker.getImage(source: ImageSource.gallery);
fileName = basename(pickedFile.path);
var image = imageLib.decodeImage(pickedFile.readAsBytesSync());
setState(() {
if (pickedFile != null) {
_image = File(pickedFile.path);
} else {
print('No image selected.');
}
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton.extended(
onPressed: () {
getImage();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => PhotoFilterSelector(
image: _image,
filters: filters,
filename: fileName,
loader: Center(child: CircularProgressIndicator()),
),
));
},
label: Text("+"),
icon: Icon(
Icons.print,
color: Colors.black,
),
),
);
}
}
ERRORS :
The method 'readAsBytesSync' isn't defined for the type 'PickedFile'.
Try correcting the name to the name of an existing method, or defining a method named 'readAsBytesSync'.
2 positional argument(s) expected, but 1 found.
Try adding the missing arguments.
3.The argument type 'String' can't be assigned to the parameter type 'List'.
The argument type 'File' can't be assigned to the parameter type 'Image'.
You can copy paste run full code below
Step 1: Use imageLib.Image _image; not File _image;
Step 2: Use _file.readAsBytesSync()
File _file = File(pickedFile.path);
_image = imageLib.decodeImage(_file.readAsBytesSync());
Step 3: onPressed need to use async and await
onPressed: () async{
await getImage();
working demo
full code
import 'package:flutter/material.dart';
import 'dart:io';
import 'package:flutter/semantics.dart';
import 'package:path/path.dart';
import 'package:photofilters/photofilters.dart';
import 'package:image_picker/image_picker.dart';
import 'package:image/image.dart' as imageLib;
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
imageLib.Image _image;
//File _image;
String fileName;
Filter _filter;
List<Filter> filters = presetFiltersList;
final picker = ImagePicker();
Future getImage() async {
PickedFile pickedFile = await picker.getImage(source: ImageSource.gallery);
fileName = basename(pickedFile.path);
File _file = File(pickedFile.path);
_image = imageLib.decodeImage(_file.readAsBytesSync());
setState(() {
if (pickedFile != null) {
//_image = File(pickedFile.path);
} else {
print('No image selected.');
}
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton.extended(
onPressed: () async{
await getImage();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => PhotoFilterSelector(
title: Text("Photo Filter Example"),
image: _image,
filters: filters,
filename: fileName,
loader: Center(child: CircularProgressIndicator()),
),
));
},
label: Text("+"),
icon: Icon(
Icons.print,
color: Colors.black,
),
),
);
}
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(),
);
}
}

Share local image with Flutter

I want to share an image that I took from the CameraController.
I location of the file is as example /data/user/0/com.user.test/cache/2019-09-10 16:32:52.281842.png
How it is possible to share this local image?
I added these two line for read/write to local storage:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
I use the share component from https://pub.dev/packages/esys_flutter_share which works great.
void _sharePicture() async {
print('Share picture');
print(this.imagePath);
final ByteData bytes = await rootBundle.load(this.imagePath);
await Share.file('esys image', 'esys.png', bytes.buffer.asUint8List(), 'image/png', text: 'My optional text.');
}
this.imagePath is the local location of the file: :/data/user/0/com.user.test/cache/2019-09-10 16:32:52.281842.png
Do you first have to save the image? And the use it for sharing? How is it possible to share this local image?
The idea is share Uint8List
This demo use camera_camera package's example. https://github.com/gabuldev/camera_camera/tree/master/example
camera_camera package https://pub.dev/packages/camera_camera is an greate package have well made features and use camera plugin inside
code snippet
after click take picture, the system return a file (val in this example), read bytes and transfer to Uint8List
print("path ${val}");
List<int> bytes = await val.readAsBytes();
Uint8List ubytes = Uint8List.fromList(bytes);
await Share.file('ESYS AMLOG', 'amlog.jpg', ubytes, 'image/jpg');
full code
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:camera_camera/camera_camera.dart';
import 'dart:typed_data';
import 'package:esys_flutter_share/esys_flutter_share.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: HomeScreen(),
);
}
}
class HomeScreen extends StatefulWidget {
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
File val;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Rully")),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.camera_alt),
onPressed: () async {
val = await showDialog(
context: context,
builder: (context) => Camera(
mode: CameraMode.fullscreen,
orientationEnablePhoto: CameraOrientation.landscape,
/*
imageMask: CameraFocus.square(
color: Colors.black.withOpacity(0.5),
),
*/
));
print("path ${val}");
List<int> bytes = await val.readAsBytes();
Uint8List ubytes = Uint8List.fromList(bytes);
await Share.file('ESYS AMLOG', 'amlog.jpg', ubytes, 'image/jpg');
setState(() {});
}),
body: Center(
child: Container(
height: MediaQuery.of(context).size.height * 0.7,
width: MediaQuery.of(context).size.width * 0.8,
child: val != null
? Image.file(
val,
fit: BoxFit.contain,
)
: Text("Tire a foto"))));
}
}
demo screen
In camera_camera example take picture button will show in landscape mdoe
file path display in bottom
For camera plugin official example, I only change the following
code snippet
void onTakePictureButtonPressed() {
takePicture().then((String filePath) async{
if (mounted) {
setState(() {
imagePath = filePath;
videoController?.dispose();
videoController = null;
});
if (filePath != null) {
showInSnackBar('Picture saved to $filePath');
File val = File(filePath);
List<int> bytes = await val.readAsBytes();
Uint8List ubytes = Uint8List.fromList(bytes);
await Share.file('ESYS AMLOG', 'amlog.jpg', ubytes, 'image/jpg');
}
}
});
}