Asset images File path in flutter? - flutter

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.

Related

Undefined name 'FlutterAbsolutePath'

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(),
],
),
);
}
}

Is it possible to get the number of pages from a File?

Guys I'm using file_picker to get files from the device. I use open_file to display the file. Is there any way to get the number of pages from the file? I have already seen the possibility with .pdf, but I would like to get from .docs as well.
Try Flutter FileReader
https://pub.dev/packages/flutter_filereader
A local file view widget,Support a variety of file types, such as Doc Eexcl PPT TXT and so on,Android is implemented by Tencent X5,iOS is implemented by WKWebView
import 'package:flutter/material.dart';
import 'package:flutter_filereader/flutter_filereader.dart';
class FileReaderPage extends StatefulWidget {
final String filePath;
FileReaderPage({Key: Key, this.filePath});
#override
_FileReaderPageState createState() => _FileReaderPageState();
}
class _FileReaderPageState extends State<FileReaderPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("doc"),
),
body: FileReaderView(
filePath: widget.filePath,
),
);
}
}
OR open_document
Opening pdf, xlsx, docs, ppt and zip files #
https://pub.dev/packages/open_document

How can I download an image from the network and save it in a locally directory?

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,
),
),
);
}
}

flutter for web: Get width/height form NetworkImage before displaying it

I want to get attribute values, such as width and height, from NetworkImage or Image.network before displaying the image.
I found the following good posts, but it doesn't work. It got the size values, but the image is not loaded in FutureBuilder.
How do I determine the width and height of an image in Flutter?
How do I tell when a NetworkImage has finished loading?
My code is as below;
import 'dart:async';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
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> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: FutureBuilder(
future: _getImage(),
builder: (BuildContext context, AsyncSnapshot<Image> snapshot) {
print(snapshot.hasData);
if (snapshot.hasData) {
return snapshot.data;
} else {
return Text('Loading...');
}
},
),
),
);
}
Future<Image> _getImage() async {
final Completer completer = Completer();
final String url = 'http://images-jp.amazon.com/images/P/4101098018.09.MZZZZZZZ';
final image = NetworkImage(url);
image.resolve(ImageConfiguration())
.addListener(ImageStreamListener((ImageInfo info, bool isSync) {
print(info.image.width);
completer.complete(info.image);
}));
return completer.future;
}
}
The result is;
- The screen only shows "Loading..." and the image is not loaded.
- print output is as below. This should means, FutureBuilder is called twice before loading the image, and we can get the width but FutureBuilder is not called after that.
false
false
112
Environment:
Flutter 1.13.0 • channel dev (due to flutter web)
Chrome Version 79.0.3945.79
Couple of observations based on the reference post you provided.
You have mixed up ui.Image with Image widget.
If you separate the info logic from widget building then you will not have access to the Image widget meaning you will have to recreate it. Instead you can create a widget and return it.
In your http based answer response.body.length might not exactly represent the image dimension. You have to see if the response headers has any information about the image.
Also note FutureBuilder's build method will be called more than once with different ConnectionState depending on the state of the future like waiting or done. Check here
Option 1:
If you don't care about the Image widget then your current code can work with some slight modification. This is exactly identical to the original post but modified to match to the way you defined it in your post.
import 'dart:async';
import 'package:flutter/material.dart';
import 'dart:ui' as ui;
class ImageSizeTestWidget extends StatefulWidget {
ImageSizeTestWidget({Key key, this.title}) : super(key: key);
final String title;
#override
_ImageSizeTestWidgetState createState() => _ImageSizeTestWidgetState();
}
class _ImageSizeTestWidgetState extends State<ImageSizeTestWidget> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: FutureBuilder<ui.Image>(
future: _getImage(),
builder: (BuildContext context, AsyncSnapshot<ui.Image> snapshot) {
print(snapshot.hasData);
if (snapshot.hasData) {
return Text('${snapshot.data.width} X ${snapshot.data.height}');
} else {
return Text('Loading...');
}
},
),
),
);
}
Future<ui.Image> _getImage() async {
final Completer<ui.Image> completer = Completer<ui.Image>();
final String url =
'http://images-jp.amazon.com/images/P/4101098018.09.MZZZZZZZ';
Image image = Image.network(url);
image.image
.resolve(ImageConfiguration())
.addListener(ImageStreamListener((ImageInfo info, bool isSync) {
print(info.image.width);
completer.complete(info.image);
}));
return completer.future;
}
}
Option 2:
Just use the code as is in the original post bringing the Image widget creation and information extraction into the build method.
Based on the advice from Abion47, I successfully get the image with http package. But I still cannot get width and/ or height values even after getting the image.
Alternatively, I use response.body.length to check whether the downloaded image is valid or not.
Future<Image> _getImage() async {
Image _image;
final String url = 'http://images-jp.amazon.com/images/P/4101098018.09.MZZZZZZZ';
var response = await http.get(url);
print("Response status: ${response.statusCode}"); // 200
_image = Image.memory(response.bodyBytes);
print(_image.width); // still null
print(response.body.length); // this shows numbers. I'll use this.
return _image;
}
You are halfway there with your self-answer code. From there, you can convert the bytes to a ui.Image object with instantiateImageCodec.
Future<Image> _getImage() async {
Image _image;
final String url = 'http://images-jp.amazon.com/images/P/4101098018.09.MZZZZZZZ';
var response = await http.get(url);
print("Response status: ${response.statusCode}"); // 200, ideally
final bytes = response.bodyBytes);
final codec = await instantiateImageCodec(bytes);
final frame = await codec.getNextFrame();
final uiImage = frame.image; // a ui.Image object, not to be confused with the Image widget
print(uiImage.width); // The width of the image in pixels
print(uiImage.height); // The heightof the image in pixels
_image = Image.memory(bytes);
return _image;
}
It kind of sucks that you have to do it this way as the image will get decoded twice, but short of creating your own custom Image widget that can take the ui.Image object directly, I don't think there's much that can be done about that.

flutter download an Image from url

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