I build an user profile page where you may change the profile image. The default picture is in assets. The selected picture, either from gallery or camera, is stored localy. All this works fin. My code to display the profile picture looks like:
Container(
width: 140.0,
height: 140.0,
decoration: new BoxDecoration(
shape: BoxShape.circle,
image: new DecorationImage(
image: new FileImage(File(_image.path)),
//image: new ExactAssetImage(_image.path),
fit: BoxFit.cover,
),
))
The FileImage shows the local image correctly. The ExactAssetImage shows the default asset image correctly. My question: how to check if local image exists and display it or use the default assset image?
Update:
I initialize my _image like:
File _image = File('assets/images/user_profile_static.png');
Once I have chosen the new image I save it localy using following code:
void _imgFromGallery() async {
final imageFile = await ImagePicker().getImage(source: ImageSource.gallery);
if (imageFile == null) return;
Directory directory = await getApplicationDocumentsDirectory();
File tmpFile = File(imageFile.path);
tmpFile = await tmpFile.copy('${directory.path}/my_profile.jpg');
setState(() {
_image = tmpFile;
});
}
So on next visit of the page, if my_profile.jpg exists, show it , else show default image.
I think this should work
Image(image: FileImage(image)??AssetImage(assetName),),
Related
I have been trying to do a cache management system in my flutter app. Ideally I want to retrieve images from firebase storage and display them along with other details. I retrieve the snapshots from firestore and have used cachednetworkimage to display the images. But the amount of images I display is a lot and is causing my app to crash. I believe if I was caching the image locally, that problem would be solved. And besides that, I also want to cache json files so that in offline mode, my app will display both the cached images and the other details available in the cache memory.
I want to display posts, which contain username, user profile picture, the image post itself, caption and comments. So the way I retrieve the posts is according to the following...
void fetchFeed() async {
auth.User currentUser = await _repository.getCurrentUser();
User user = await _repository.fetchUserDetailsById(currentUser.uid);
setState(() {
this.currentUser = user;
});
setState(() {
loadingPosts = true;
});
Query query = _firestore.collection("users").doc(user.uid).collection("following").orderBy("uid").limit(perPage);
QuerySnapshot querySnapshot = await query.get();
for (var i = 0; i < querySnapshot.docs.length; i++) {
followingUIDs.add(querySnapshot.docs[i].id);
}
for (var i = 0; i < followingUIDs.length; i++) {
Query posts = _firestore.collection("users").doc(followingUIDs[i]).collection("posts").orderBy("time").limit(perUser);
QuerySnapshot postSnapshot = await posts.get();
lastPost = postSnapshot.docs[postSnapshot.docs.length -1];
for (var i = 0; i < postSnapshot.docs.length; i++) {
feedlist.add(postSnapshot.docs[i]);
}
}
setState(() {
loadingPosts = false;
});
}
And after I retrieved the posts, I put them in a listview and show them sequentially. The problem I am getting is that since the images are not cached locally, I use cached network image widget to display them. And whenever I navigate to another page and return, all the cached network images get reloaded and that puts a big load on the app, which causes it to crash.
CachedNetworkImage(
imageUrl: list[index].data()['imgUrl'],
placeholder: ((context, url) => Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/Black.png'),
fit: BoxFit.cover),
))),
fit: BoxFit.fitWidth,
),
Alternatively, I tried to download the images and save them locally using the following function. And I call the function for every image item I retrieve from firebase. But that just distorts the images for some reason.
Future <Null> downloadFile(String httpPath) async{
final StorageReference ref = await FirebaseStorage.instance.getReferenceFromUrl(httpPath);
final StorageFileDownloadTask downloadTask = ref.writeToFile(file);
final int byteNumber = (await downloadTask.future).totalByteCount;
print(byteNumber);
setState(() => _cachedFile = file);
}
The http path is a download url I got for each image. But I am not sure if this is the best way to download images. Since I don't have a way to know the image file names as they appear in firebase storage, this was my only option.
Can someone tell me an alternative way to download and cache images, and also json files (which contain username, comments, caption) in my case, so that I can show them offline?
For this purpose use cached_network_image package. which also support placeholders and fading images in as they’re loaded.
CachedNetworkImage( imageUrl: 'https://picsum.photos/250?image=9');
Complete Example
`
return MaterialApp(
title: title,
home: Scaffold(
appBar: AppBar(
title: Text(title),
),
body: Center(
child: CachedNetworkImage(
placeholder: (context, url) => CircularProgressIndicator(),
imageUrl:
'https://picsum.photos/250?image=9',
),
),
),
);
`
I am building a demo wallpaper app using flutter where users can upload images to firebase. When loading those images I first want to load a small version of the image and only once the user clicks on the image, load the full version.
In order to achieve this I thought I would simply upload 2 versions in the background once a user picks the image. Now I am struggling with how to achieve this.
Here is how the user picks the image using ImagePicker into a file var.
Future pickImage() async {
var tempImage = await ImagePicker.pickImage(source: ImageSource.gallery, maxHeight: 2000);
print(tempImage.runtimeType);
setState(() {
inspirationimage = tempImage;
});
String result = await uploadImage();
}
As you can see the tempimage is the full size version. I would now have sth like this:
var smallImage = tempImage.resize(height: 200);
Obviously this does not work as tempImage is of type file. Any ideas how this is usually solved?
Thanks
Since you are using Firebase, you can use the Firebase "Resize Image" extension. If you want to do it on client side however, take a look at this answer.
Why don't you let your user crop the image by using this
image_cropper 1.3.1 plugin?
link : https://pub.dev/packages/image_cropper
Example
// File image = await ImagePicker.pickImage(source: source);
final _picker = ImagePicker();
PickedFile image = await _picker.getImage(source: source);
if (image != null) {
// Remove crop attribute if we don't want to resize the image
File cropped = await ImageCropper.cropImage(
sourcePath: image.path,
aspectRatio: CropAspectRatio(ratioX: 1, ratioY: 1),
compressQuality: 100, // 100 means no compression
maxWidth: 700,
maxHeight: 700,
compressFormat: ImageCompressFormat.jpg,
androidUiSettings: AndroidUiSettings(
toolbarColor: primaryColor,
toolbarTitle: "RPS Cropper",
statusBarColor: primaryColor,
backgroundColor: Colors.white,
//toolbarWidgetColor: primaryColor,
activeControlsWidgetColor: primaryColor,
//dimmedLayerColor: primaryColor,
cropFrameColor: primaryColor,
cropGridColor: primaryColor,
),
);
I have managed to upload an image using the image picker package as shown below:
final picker = ImagePicker();
Future selectPhoto() async {
final pickedFile = await picker.getImage(source: ImageSource.gallery);
setState(() {
_image = File(pickedFile.path);
});
}
The image has been displayed on the device where I have a remove button which I can use to remove the image and upload another before saving it.
child: Container(
height: height * 0.2,
width: width * 0.2,
child: Image.file(
_image,
fit: BoxFit.fill,
),
),
My question is how can I remove the image from cache as this piece is not working
onTap: () {
setState(() {
imageCache.clear();
print('removes $_image');
});
},
You have a misunderstanding of what the cache is compared to explicitly storing a file in memory with your code. Flutter may store images that you use in widgets in a cache so that they may load faster in the future. imageCache.clear(); does clear the cache and is likely doing it's work in your code. However, your method of checking if the image is still cached is flawed.
imageCache.clear(); only clears the cache, it does not delete the file that you're passing to the Image.file widget. This means that _image(the file variable you have stored in memory) will persist even over the cache clearing. To truly delete this image you could use the delete method or if you just want to stop showing the image, deference the file by setting the file reference to null:
_image = null;
Solved it by calling a method within the button which had set state method where the path was returned back to null
clearimage() {
setState(() {
_image = null;
});
}
I'm working with saved image from Url with Gallery Saver. Everything it's oke , i can insert image from URL, but i don't know how to fetch image from picture Directory .
It's different about getApplicationDocumentsDirectory() or getExternalStorageDirectory() ?
I want to display the image that was just saved.
Any solution ?
Save image Code :
void _testSaveImage() async {
String path = "${Urls.BASE_API_IMAGE}/berita/${widget.gambarBerita}";
GallerySaver.saveImage(path).then((bool success) {
print('Success add image $path');
}).catchError((onError) {
print('Error add image $path');
});
}
Location Image saved
Then just return the path you have and use a Image.file() widget to display it, lets say you have a Column():
Column(children: <Widget>[
[...]
Text('Here is my image:'),
if (path.isNotEmpty && path != null)
SizedBox(
height: 200,
width: 200,
child: Image.file(File(path),
),
Text('Caption of the image'),
[...]
),
Docs for Image class here
Load local saved images using path and use it
var file = new File('path');
Image.file(file )
I'm using Image Picker package in my Flutter project
I choose image from gallery then preview it in Image.asset widget
The problem here is if image name "example_name.png" (without spaces) the image is visible on the screen, but if image name "example name.png" (with spaces) the image is invisible like this Screenshot.
Error: Unable to load asset: /storage/emulated/0/Download/images (9).jpeg
File _image;
Image.asset(
_image != null
? "${_image.path}"
: getImage("icon.png"),
fit: BoxFit.cover,
width: 120,
height: 120,
);
...
Future chooseFile() async {
await ImagePicker.pickImage(source: ImageSource.gallery).then((image) {
setState(() {
_image = image;
});
});
}
You are using the wrong Image constructor. Use Image.file instead of Image.asset. Image.asset load files packaged in the application (assets section of pubspec.yaml) and ImagePicker does not have access to them.
in the image_picker (version 0.6.7 + 22) I was able to recover the image with this condition
if (photo == null) {
return Image (
image: AssetImage ('assets / no-image.png'),
height: 300.0,
fit: BoxFit.cover,
);
} else {
return Image.file (
Photo,
height: 300.0,
fit: BoxFit.cover,
);
}
Using Image.file is a good option but you like to display it in an effective way use
Image.file(_image).image this will help you to convert Image file to image provider