I am developing a flutter mobile application where I need to upload multiple images through an API. Now I completed the part where pick images from the gallery. Next step is to upload the images. To do that I need the image path. I know that image path can be get by using the below code line but it keep saying that Undefined name 'FlutterAbsolutePath' what is the reason how to fix this issue. I am using multi-image-picker package.
final filePath =
await FlutterAbsolutePath.getAbsolutePath(image.identifier);
It would be really nice if you could provide us with some more information or even a code sample. In case you are using this package, I would strongly advice you to change it to one that is not discontinued (take a look into this one: image_picker; you can select multiple images at once with this one too).
Until further information is provided you can take a look over the following code that uses the image_picker:
After following the installation steps from the documentation you can get images using the next method:
Future<void> getImages() async {
ImagePicker imagePicker = ImagePicker();
List<XFile>? images = await imagePicker.pickMultiImage();
if ((images ?? []).isNotEmpty) {
//get the path of the first image from the select images
String imagePath = images?.first.path ?? '';
//get the content of the first image from the select images as bytes
Uint8List? imageAsBytes = await images?.first.readAsBytes();
//get the content of the first image from the select images as a String based on a given encoding
String? imageAsString = await images?.first.readAsString();
}
}
I hope that I helped you a little bit. Happy coding! :)
Later edit:
Here is a very basic Flutter app that picks an image with multi-picker, creates a temp file for which we know the path and displays the temp file in order to show that the temp file was correctly displayed.
For you, what's of most interest is getFile() method which takes care of creating the temp file that is 1:1 with picked image(s).
For creating the temp file I used: path_provider also take a look into the following: Read and write files
For permission handling: permission_handler
I still strongly suggest that you use other package for image picking as this one is discontinued :).
import 'dart:io';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:multi_image_picker/multi_image_picker.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const HomePage(),
);
}
}
Future<File?> getFile() async {
List<Asset> images = await MultiImagePicker.pickImages(maxImages: 100);
if (images.isNotEmpty) {
ByteData bytesData = await images.first.getByteData();
List<int> bytes = bytesData.buffer
.asUint8List(bytesData.offsetInBytes, bytesData.lengthInBytes)
.cast<int>();
//get the extension jpeg, png, jpg
String extension = (images.first.name ?? '').split('.').last;
//get path to the temporaryDirector
final Directory directory = await getTemporaryDirectory();
//get the path to the chosen directory
String directoryPath = directory.path;
//create a temporary file to the specified path
//you can use the path to this file for the API
File file = File('$directoryPath/myImage.$extension');
//write the bytes to the image
file.writeAsBytesSync(bytes, mode: FileMode.write);
//just for path: file.path -> will return a String with the path
return file;
}
return null;
}
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
#override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
File? file;
#override
Widget build(BuildContext context) {
return Container(
color: Colors.amber,
child: Column(
children: [
const SizedBox(
height: 50,
),
Center(
child: TextButton(
child: const Text('Pick an image'),
onPressed: () async {
await Permission.accessMediaLocation.request();
file = await getFile();
setState(() {});
},
),
),
const SizedBox(
height: 50,
),
file != null
? Image.file(
file!,
height: 200,
width: 200,
)
: Container(),
],
),
);
}
}
Related
TLDR: I understand how to create a new file via Dart and path provider, but I don't know how to get a pre-existing file into the Android/Apple file system.
I'm building this app which works a bit with string manipulation. Ideally, I want it reading strings from a pre-existing CSV file which I'm getting from a client, then manipulating the data to create more CSV files. I found packages for both CSV and Paths. What I don't know is how to get my CSV in there.
As of now I have this file called test.csv in my app's root directory. I tried to access it through my main.dart by using File f = File("$_localPath/test.csv"). The file was nowhere to be found. I then went into the phone's memory using Android Studio, and found the local storage path of the app. My test.csv file was nowhere to be seen. My guess right now is that at compilation, that CSV file becomes garbage machine code. So how can I get it intact into the device's local memory?
I don't want to get the file from the internet because I'm hoping the user can boot up the app for the first time in any setting and be able to have its full functionality.
I just tested this code example and it works on all platforms.
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String _fileContent = '';
final TextEditingController _controller = TextEditingController();
#override
initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
readFile();
});
}
Future<String> getFilePath() async {
Directory appDocumentsDirectory =
await getApplicationDocumentsDirectory(); // 1
String appDocumentsPath = appDocumentsDirectory.path;
String filePath = '$appDocumentsPath/file.csv';
return filePath;
}
void saveFile() async {
File file = File(await getFilePath());
if (mounted) {
file.writeAsString(_controller.text);
setState(() {
_fileContent = _controller.text;
});
_controller.text = '';
}
}
void readFile() async {
File file = File(await getFilePath());
final fileContent = await file.readAsString();
if (mounted) {
setState(() {
_fileContent = fileContent;
});
}
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text('Saving CSV file')),
body: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
Text('Current content = $_fileContent'),
TextField(
controller: _controller,
),
TextButton(
onPressed: saveFile,
child: const Text('Press to save file'),
),
],
),
),
),
);
}
}
This code creates the file and sets a content into it. Then, after restarting the app, it tries to find the file and receive its content. After that it shows the content inside a Text widget.
I used this article for making this example. Hope it will help:)
I have the in-memory bytes of a decrypt epub file, but the package that I want to open this epub file with only accepts dart:io File objects.
I don't want to create real local file => just for security
Is there a way to create a "fake" dart:io File, simply wrapping my in-memory bytes, so that I can pass this "fake" File to the package?
I'm using vocsy_epub_viewer package to open epub files
filePath should be a local file
import 'package:archive/archive.dart';
import 'package:flutter/material.dart';
import 'package:vocsy_epub_viewer/epub_viewer.dart';
import 'package:file_picker/file_picker.dart';
import 'package:path_provider/path_provider.dart';
import 'package:encrypt/encrypt.dart' as en;
import 'dart:io';
import 'package:cross_file/cross_file.dart';
import 'package:file/memory.dart';
import 'package:file/file.dart' as F;
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Ebook(),
);
}
}
class Ebook extends StatefulWidget {
#override
State<Ebook> createState() => _EbookState();
}
class _EbookState extends State<Ebook> {
Directory? _temp;
String? path;
#override
void initState() {
address();
super.initState();
}
Future decodeEpub(String path) async {
final bytes = await File(path).readAsBytes();
Archive archive =
await ZipDecoder().decodeBytes(bytes, password: '7web', verify: true);
final data = await archive.first.content;
final key = en.Key.fromUtf8('qwertyuiopasdfghjklmnbvcxzasdfgh');
final iv = en.IV.fromLength(16);
final decrypted = await en.AES(key).decrypt(en.Encrypted(data), iv: iv);
// XFile file = await XFile.fromData(decrypted,name:'2.epub',path:"${_appDocumentsDirectory!.path}/2.epub" );
// File file1= await File(file.path).create(recursive: true);
// File file = MemoryFileSystem().file('${temp!.path}/2.epub')..create(recursive: true)
// ..writeAsBytesSync(decrypted);
File file = await File('${_temp!.path}/2.epub').writeAsBytes(decrypted); // it must be change ******
print(file.path);
return file.path;
}
void address() async {
final temp = await getTemporaryDirectory();
setState(() {
_temp = temp;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () async {
FilePickerResult? result =
await FilePicker.platform.pickFiles();
if (result != null) {
File file = File(result.files.single.path!);
path = await decodeEpub(file.path);
print('?= $path , ${file.path}');
} else {
print('cancel');
}
},
child: Text('add File')),
ElevatedButton(
onPressed: () {
EpubViewer.setConfig(
themeColor: Theme.of(context).primaryColor,
identifier: "iosBook",
scrollDirection: EpubScrollDirection.ALLDIRECTIONS,
allowSharing: true,
enableTts: true,
nightMode: false);
EpubViewer.open(path!, lastLocation: EpubLocator());
},
child: Text("open"),
),
],
),
),
);
}
}
I don't want to create real local file => just for security
This is not actually true because EPUBs are structured as a zip file and folioreader, the framework used behind the vocsy_epub_viewer, will "unzip" the file to a temp folder (or one predefined). So, in the end, it's not going to be secure anyway.
Just extract the EPUB to the temp folder from path_provider and remove it afterwards. Otherwise, you're going to need a new framework to read EPUBs that don't have this behaviour or even customize the vocsy_epub_viewer/folioreader sources yourself to make it secure.
I'm trying to download an image from the network and save it locally in the Downloads folder of a computer. I need to achieve that for flutter web, I'm not sure how to do it.
I found some questions related to how to achieve download and save a file or an image for android and IOS, such as Flutter save a network image to local directory. I also took a look at How do I read and write image file locally for Flutter Web?. However, I don't see how those answers can help me.
I think that for IOS and Flutter I can use the following function without getting any error, but I don't know where the files are being saved in my emulator:
void _downloadAndSavePhoto() async {
var response = await http.get(Uri.parse(imageUrl));
try {
Directory tempDir = await getTemporaryDirectory();
String tempPath = tempDir.path;
File file = File('$tempPath/$name.jpeg');
file.writeAsBytesSync(response.bodyBytes);
} catch (e) {
print(e.toString());
}
}
However, when I try the above function for flutter web (using a chrome simulator) I get the following error:
MissingPluginException(No implementation found for method getTemporaryDirectory on channel plugins.flutter.io/path_provider)
I will be more than happy if someone knows a way to do it or have some suggestions to implement that functionality.
Thanks in advance!
To achieve this I would suggest you first to add the universal_html package to your pubspec.yaml because in the newer versions of Flutter you will get warnings for importing dart:html.
In pubspec.yaml:
dependencies:
flutter:
sdk: flutter
http: ^0.13.1 // add http
universal_html: ^2.0.8 // add universal_html
I created a fully working example Flutter web app, you can try it, but the only thing that interests you is the downloadImage function.
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
// if you don't add universal_html to your dependencies you should
// write import 'dart:html' as html; instead
import 'package:universal_html/html.dart' as html;
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final imageUrls = <String>[
'https://images.pexels.com/photos/208745/pexels-photo-208745.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940',
'https://images.pexels.com/photos/1470707/pexels-photo-1470707.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940',
'https://images.pexels.com/photos/2671089/pexels-photo-2671089.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940',
'https://images.pexels.com/photos/2670273/pexels-photo-2670273.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940',
];
#override
Widget build(BuildContext context) {
return Scaffold(
body: GridView.count(
crossAxisCount: 3,
children: imageUrls
.map(
(imageUrl) => ImageCard(imageUrl: imageUrl),
)
.toList(),
),
);
}
}
class ImageCard extends StatefulWidget {
#override
_ImageCardState createState() => _ImageCardState();
final String imageUrl;
ImageCard({
#required this.imageUrl,
});
}
class _ImageCardState extends State<ImageCard> {
Future<void> downloadImage(String imageUrl) async {
try {
// first we make a request to the url like you did
// in the android and ios version
final http.Response r = await http.get(
Uri.parse(imageUrl),
);
// we get the bytes from the body
final data = r.bodyBytes;
// and encode them to base64
final base64data = base64Encode(data);
// then we create and AnchorElement with the html package
final a = html.AnchorElement(href: 'data:image/jpeg;base64,$base64data');
// set the name of the file we want the image to get
// downloaded to
a.download = 'download.jpg';
// and we click the AnchorElement which downloads the image
a.click();
// finally we remove the AnchorElement
a.remove();
} catch (e) {
print(e);
}
}
#override
Widget build(BuildContext context) {
return InkWell(
onTap: () => downloadImage(widget.imageUrl),
child: Card(
child: Image.network(
widget.imageUrl,
fit: BoxFit.cover,
),
),
);
}
}
I wanted to ship an app with pre-populated Sqflite database(which can be modified by user).
I have added like 100 images as assets and need to read them as File Images instead of asset images (so it will easy to read & load the images in different screens, without copying the images).
So need to know how to get the file path (path will be hardcoded in sqflite databse) of images stored in Assets folder.
Push in the right direction is appreciated.
So you want to read the images from the Database and load them to the screen instead of reading them from the application assets ?. I think Flutter loads them from the application assets faster and without the overhead of the Database query.
Keep path in sqflite like 'assets/images/1.png' and access with rootBundle
You do not need absolute path such as /sdcard0/....
Keep only assets path
ByteData imageData1 = await rootBundle.load('assets/images/1.png');
Use List of ByteData to keep images
List<ByteData> imageList = [];
With ListView display image with Image.memory
return Image.memory(imageList[index].buffer.asUint8List());
full code
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
List<ByteData> imageList = [];
void _incrementCounter() async{
ByteData imageData1 = await rootBundle.load('assets/images/1.png');
ByteData imageData2 = await rootBundle.load('assets/images/2.png');
print(imageData1.toString());
imageList.add(imageData1);
imageList.add(imageData2);
setState(() {
_counter++;
print(imageList.length.toString());
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: ListView.builder(
itemCount: imageList.length,
itemBuilder: (context, index) {
return Image.memory(imageList[index].buffer.asUint8List());
},
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
I also encountered this situation since I wanted to prepopulate my Hive database with images stored in assets and my app uses FileImage to load the images.
I found out that you can't reference a file or an image path located in Assets since it is ever changing, so better yet:
Load the image/file using rootBundle.load
Duplicate the image/file using writeAsBytesSync
Use the path of the duplicated image and load it from there
reference
You can also use Device File Explorer in Android Studio to inspect where the assets folder is located and see for yourself if it is changing. In my experience it is located in code_cache > build > flutter_assets > assets.
I'm trying to load image from server using networkimage() and I want to download the same once it is loaded.. can anyone suggest me some ideas.
CircleAvatar(
backgroundImage: NetworkImage(url),
maxRadius: 15.0,
);
Here I'm loading image from my server. I want to save to the image to particular path after the image is loaded.
I recently battled this, and decided to solve it without plugins. I hope it helps someone.
The below program downloads a picture from the web, stores it in the device's local path, and then displays it when run. (note, it does not work for flutter web because you don't have access to the local file storage on that platform. Instead you would have to save the image to a local database using a plugin like sqflite, or hive from pub.dev.) Here's the code:
import 'package:flutter/material.dart';
import 'package:http/http.dart' show get;
import 'dart:io';
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: 'Test Image',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Test Image'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
initState() {
_asyncMethod();
super.initState();
}
_asyncMethod() async {
//comment out the next two lines to prevent the device from getting
// the image from the web in order to prove that the picture is
// coming from the device instead of the web.
var url = "https://www.tottus.cl/static/img/productos/20104355_2.jpg"; // <-- 1
var response = await get(url); // <--2
var documentDirectory = await getApplicationDocumentsDirectory();
var firstPath = documentDirectory.path + "/images";
var filePathAndName = documentDirectory.path + '/images/pic.jpg';
//comment out the next three lines to prevent the image from being saved
//to the device to show that it's coming from the internet
await Directory(firstPath).create(recursive: true); // <-- 1
File file2 = new File(filePathAndName); // <-- 2
file2.writeAsBytesSync(response.bodyBytes); // <-- 3
setState(() {
imageData = filePathAndName;
dataLoaded = true;
});
}
String imageData;
bool dataLoaded = false;
#override
Widget build(BuildContext context) {
if (dataLoaded) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Image.file(File(imageData), width: 600.0, height: 290.0)
],
),
),
);
} else {
return CircularProgressIndicator(
backgroundColor: Colors.cyan,
strokeWidth: 5,
);
}
}
}
pubspec.yaml file:
http: ^0.12.1
path_provider: ^1.6.5
flutter version: 1.20.0-3.0.pre.112
dart version 2.9.0-19.0.dev
I recommend image_downloader.
For ios, image is saved in Photo Library.
For Android, image is saved in Environment.DIRECTORY_DOWNLOADS or specified location. By calling inExternalFilesDir(), specification of permission becomes unnecessary.
By callback(), you can get progress status.
The following is the simplest example. It will be saved.
await ImageDownloader.downloadImage(url);
I used image_downloader.
Use await ImageDownloader.downloadImage("url") of image_downloader package's method to download image using it's url.
Note : above method will return value as follows :-
imageId of the saved image if saving succeeded.
null if not been granted permission.
for this you have to ask for storage permission, just add following line into android manifest file :
uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
Otherwise it is a PlatformException.
I tried many solution, but this is simplest solution for my... Just try it
STEP - 1
Add this package in your pubspec.yaml file
dependencies:
image_downloader: ^0.20.1
STEP - 2
Add this in your dart file
import 'package:image_downloader/image_downloader.dart';
STEP - 3
Write this code on press download button
ColButton(
title: 'Download',
icon: Icons.file_download,
onTap: () async {
try {
showLoadingDialog(context);
// Saved with this method.
var imageId =
await ImageDownloader.downloadImage("https://raw.githubusercontent.com/wiki/ko2ic/image_downloader/images/bigsize.jpg");
if (imageId == null) {
return;
}
// Below is a method of obtaining saved image information.
var fileName = await ImageDownloader.findName(imageId);
var path = await ImageDownloader.findPath(imageId);
var size = await ImageDownloader.findByteSize(imageId);
var mimeType = await ImageDownloader.findMimeType(imageId);
Navigator.pop(context);
showToast('Image downloaded.');
} on PlatformException catch (error) {
print(error);
}
},
),
I use this plugin to save image in the phone using an URL
https://pub.dartlang.org/packages/image_picker_saver
For more advanced handling of Image/File downloads, you can consider the flutter_downloader package.
Some of the features that I like are :
Shows OS level download progress
can track all downloads
Has notification