I am using below code to select image from gallery to upload to Firebase Storage in Flutter application, but I want that if the user doesn't select an image, a default image from the assets should be uploaded to the firebase storage. What code should I write for the image to be selected from assets and it is set equal to File avatarImageFile so that it can be uploaded to Firebase storage in flutter application
File avatarImageFile;
Future getImage() async {
File image = await ImagePicker.pickImage(source: ImageSource.gallery);
if (image != null) {
setState(() {
avatarImageFile = image;
isLoading = true;
});
}
uploadFile();
}
You can convert Asset image to File then upload to Firebase!
Here is code to convert:
import 'dart:async';
import 'dart:io';
import 'package:flutter/services.dart' show rootBundle;
import 'package:path_provider/path_provider.dart';
Future<File> getImageFileFromAssets(String path) async {
final byteData = await rootBundle.load('assets/$path');
final file = File('${(await getTemporaryDirectory()).path}/$path');
await file.writeAsBytes(byteData.buffer.asUint8List(byteData.offsetInBytes, byteData.lengthInBytes));
return file;
}
In your example, you would call this function like this:
File f = await getImageFileFromAssets('images/myImage.jpg');
and edit your code:
File avatarImageFile;
Future getImage() async {
File f = await getImageFileFromAssets('path of your asset Image');
File image = await ImagePicker.pickImage(source: ImageSource.gallery);
if (image != null) {
setState(() {
avatarImageFile = image;
isLoading = true;
});
}else{
avatarImageFile = f;
isLoading = true;
}
uploadFile();
}
Related
I have the following code where I fetch an image from firebase storage as an Image. Now, I want to store this image in my CachedNetworkImage so that I don't have to fetch it every time from the DB. Since the cachednetworkimage expects a URL and I am fetching an Image, how do I use the cachednetworkimage?
Here's my code;
final FirebaseStorage storage = FirebaseStorage(
app: Firestore.instance.app,
storageBucket: 'gs://my-project.appspot.com');
Uint8List imageBytes;
String errorMsg;
_MyHomePageState() {
storage.ref().child('selfies/me2.jpg').getData(10000000).then((data) =>
setState(() {
imageBytes = data;
})
).catchError((e) =>
setState(() {
errorMsg = e.error;
})
);
}
#override
Widget build(BuildContext context) {
var img = imageBytes != null ? Image.memory(
imageBytes,
fit: BoxFit.cover,
) : Text(errorMsg != null ? errorMsg : "Loading...");
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: new ListView(
children: <Widget>[
img,
],
));
}
}```
Cached network image and Flutter cache manager
The package Cached network image depends on another package called Flutter cache manager in order to store and retrieve image files.
Flutter cache manager
You need to download your image files and put them in the cache using the package. Here is an example code that gets files and their download urls from Firebase Storage and put them in the cache:
// import the flutter_cache_manager package
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
// ... other imports
class MyCacheManager {
Future<void> cacheImage() async {
final FirebaseStorage storage = FirebaseStorage(
app: Firestore.instance.app,
storageBucket: 'gs://my-project.appspot.com',
);
final Reference ref = storage.ref().child('selfies/me2.jpg');
// Get your image url
final imageUrl = await ref.getDownloadURL();
// Download your image data
final imageBytes = await ref.getData(10000000);
// Put the image file in the cache
await DefaultCacheManager().putFile(
imageUrl,
imageBytes,
fileExtension: "jpg",
);
}
}
Cached network image
Next, you will use CacheNetworkImage widget as it shown in the documentation.
// ... some code
#override
Widget build(BuildContext context) {
return Scaffold(
body: CachedNetworkImage(
imageUrl: "your_image_link_here",
placeholder: (context, url) => CircularProgressIndicator(),
errorWidget: (context, url, error) => Icon(Icons.error),
),
);
}
If you put your image files in the cache by using Flutter cache manager, Cached network image should retrieve them from the cache directly. If your image files expire or the cache is cleared somehow, it will download and put them in the cache for you.
Full Example
import 'package:cached_network_image/cached_network_image.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:flutter/material.dart';
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
class MyCacheManager {
final _storage = FirebaseStorage(
app: FirebaseFirestore.instance.app,
storageBucket: 'gs://my-project.appspot.com',
);
final defaultCacheManager = DefaultCacheManager();
Future<String> cacheImage(String imagePath) async {
final Reference ref = _storage.ref().child(imagePath);
// Get your image url
final imageUrl = await ref.getDownloadURL();
// Check if the image file is not in the cache
if ((await defaultCacheManager.getFileFromCache(imageUrl))?.file == null) {
// Download your image data
final imageBytes = await ref.getData(10000000);
// Put the image file in the cache
await defaultCacheManager.putFile(
imageUrl,
imageBytes,
fileExtension: "jpg",
);
}
// Return image download url
return imageUrl;
}
}
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String _imageUrl;
#override
void initState() {
final myCacheManager = MyCacheManager();
// Image path from Firebase Storage
var imagePath = 'selfies/me2.jpg';
// This will try to find image in the cache first
// If it can't find anything, it will download it from Firabase storage
myCacheManager.cacheImage(imagePath).then((String imageUrl) {
setState(() {
// Get image url
_imageUrl = imageUrl;
});
});
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: _imageUrl != null
? CachedNetworkImage(
imageUrl: _imageUrl,
placeholder: (context, url) => CircularProgressIndicator(),
errorWidget: (context, url, error) => Icon(Icons.error),
)
: CircularProgressIndicator(),
),
);
}
}
Try this way out using firebase_image package. From here . You need to sync with image url (selfies/me2.jpg) and bucket url (gs://my-project.appspot.com)
Image(
image: FirebaseImage('gs://bucket123/userIcon123.jpg'),
// Works with standard parameters, e.g.
fit: BoxFit.fitWidth,
width: 100,
// ... etc.
)
I'm not Fire-store user, but this should work.
It might needs a little modification or something, please share in a comment to update my answer according to that
You can get file object as follow..
import 'dart:io';
import 'dart:typed_data';
Uint8List readyData = imageBytes;
File('my_image.jpg').writeAsBytes(bodyBytes);
and save it using image_gallery_saver, so the code should look like
Future<String> _createFileFromString() async {
final encodedStr = "...";
Uint8List bytes = base64.decode(imageBytes);
String dir = (await getApplicationDocumentsDirectory()).path;
String fullPath = '$dir/abc.png';
print("local file full path ${fullPath}");
File file = File(fullPath);
await file.writeAsBytes(bytes);
print(file.path);
final result = await ImageGallerySaver.saveImage(bytes);
print(result);
return file.path;
}
For your storage instance use some method like so
Future<void> downloadURLExample() async {
String downloadURL = await storage.ref('selfies/me2.jpg')
.getDownloadURL();
// Within your widgets:
// CachedNetworkImage(imageUrl: downloadURL);
}
to get it working with Firebase Storage with included offline functionality I changed it that way
Future<String> cacheImage(String imagePath) async {
var fileinfo = await defaultCacheManager.getFileFromCache(imagePath);
if(fileinfo != null)
{
return fileinfo.file.path;
} else{
final Reference ref = _storage.child(imagePath);
// Get your image url
final imageUrl = await ref.getDownloadURL();
// Check if the image file is not in the cache
// Download your image data
final imageBytes = await ref.getData(10000000);
// Put the image file in the cache
var file = await defaultCacheManager.putFile(
imageUrl,
imageBytes!,
key: imagePath,);
return file.path;
}
}
for anyone still stuck with this.. try this required no hacks and uses CachedNetworkImageProvider built-in retrieval methods.
first screen:
CachedNetworkImage(
imageUrl: "https://whereismyimage.com",
progressIndicatorBuilder:
(context, url, progress) {
return CircularProgressIndicator(
value: progress.progress,
);
},
errorWidget: (context, url, error) => const Icon(Icons.error),
),
then second screen
Image(image: CachedNetworkImageProvider("https://whereismyimage.com)"),
The CachedNetworkImageProvider knows how to retrieve the cached image using the url.
Check out cached_network_image: ^2.5.0 package.
How to use it?
CachedNetworkImage(
imageUrl: "http://via.placeholder.com/350x150",
placeholder: (context, url) => CircularProgressIndicator(),
errorWidget: (context, url, error) => Icon(Icons.error),
),
I am making a face in flutter using different facial images and i want to export it as jpg when the face creation is done. what could i use to achieve it?
You can see here a face is created and i want to export only face as a jpeg.
In this article, use GlobalKey with your widget and save image by following code:
takeScreenShot() async {
RenderRepaintBoundary boundary =
previewContainer.currentContext.findRenderObject();
double pixelRatio = originalSize / MediaQuery.of(context).size.width;
ui.Image image = await boundary.toImage(pixelRatio: pixelRatio);
ByteData byteData = await image.toByteData(format: ui.ImageByteFormat.png);
Uint8List pngBytes = byteData.buffer.asUint8List();
setState(() {
_image2 = Image.memory(pngBytes.buffer.asUint8List());
});
final directory = (await getApplicationDocumentsDirectory()).path;
File imgFile = new File('$directory/screenshot.png');
imgFile.writeAsBytes(pngBytes);
final snackBar = SnackBar(
content: Text('Saved to ${directory}'),
action: SnackBarAction(
label: 'Ok',
onPressed: () {
// Some code
},
),
);
Scaffold.of(context).showSnackBar(snackBar);
}
I'm calling a widget in my code to display the selected image through image-picker plugin; following is my code:
Widget _imagePlaceHolder() {
if (imageSelected == null){
return Text("No File Selected!!");
} else {
Image.file(imageSelected, width: 400, height: 400);
}
}
but I'm getting this error:
The argument type "'PickedFile'" can't be assigned to the parameter type 'File'
on imageSelected under else statement.
I'm picking an image like this from gallery:
Future _openGallery(BuildContext context) async {
var picture = await picker.getImage(source: ImageSource.gallery);
this.setState(() {
imageSelected = picture;
});}
I've defined:
PickedFile imageSelected;
final picker = ImagePicker();
what's going wrong here? Please help..
Image.file() accepts a property of type File class, whereas the ImagePicker().getImage() method returns a type PickedFile.
We have to utilise the getter .path of the returned PickedFile argument and pass that file path to the create a File object as follows:
void _setImage() async {
final picker = ImagePicker();
PickedFile pickedFile = await picker.getImage(source: ImageSource.gallery);
imageFile = File(pickedFile.path);
}
This may be done in one line as follows:
void _setImage() async {
imageFile = File(await ImagePicker().getImage(source: ImageSource.gallery).then((pickedFile) => pickedFile.path));
}
After this, you can use the variable imageFile and pass it inside Image.file() like Image.file(imageFile), or FileImage() like FileImage(imageFile) as required.
For more, see the image_picker documentation on pub.dev
//many time when user import dart.html package than it throw error so keep note that we have to import dart.io
import 'dart.io';
final imagePicker = ImagePicker();
File imageFile;
Future getImage() async {
var image = await imagePicker.getImage(source: ImageSource.camera);
setState(() {
imageFile = File(image.path);
});
}
Change PickedFile imageSelected to File imageSelected and use ImagePicker.pickImage(source: ImageSource.gallery) instead of picker.getImage(source: ImageSource.gallery);
import 'package:image_picker/image_picker.dart';
import 'dart:io';
var image;
void imagem() async {
PickedFile picked = await ImagePicker().getImage(
preferredCameraDevice: CameraDevice.front, source: ImageSource.camera);
setState(() {
image = File(picked.path);
});
}
Or case you need of code full:
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
class Photos extends StatefulWidget {
#override
_PhotosState createState() => _PhotosState();
}
class _PhotosState extends State<Photos> {
var image;
void imagem() async {
PickedFile picked = await ImagePicker().getImage(
preferredCameraDevice: CameraDevice.front, source: ImageSource.camera);
setState(() {
image = File(picked.path);
});
}
#override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Center(
child: Column(
children: [
RaisedButton(
onPressed: imagem,
child: Text("Imagem"),
),
image != null ? Image.file(image) : Text("I")
],
),
));
}
}
Morpheus answer is correct.
Just pass in the PickedFile variable path to File().
Example:
final picker = ImagePicker();
PickedFile pickedFile = await picker.getImage(source: ImageSource.gallery);
imageFile = File(pickedFile.path);
Try converting your imageFile type to PickedImage and return the file in type Casting the imageFile to File, Like:-
// Declaring the variable here
PickedImage imageFile;
And at the time of returning:-
return Image.file(File(imageFile.path),width: 400,height: 400,);
I personally faced this problem, and this solution solved it.
Try this way...
Future pickImageFromGallery() async {
try {
final pickedFile = await picker.pickImage(
source: ImageSource.gallery,
);
setState(() {
widget.imageFile = File(pickedFile!.path);
});
if (pickedFile == null) {
throw Exception('File is not available');
}
} catch (e) {
print(e);
}
Looking for a simple example of how to upload a base64 image to aws S3 using amplify.
Assuming you configured Amplify Storage and set the permissions to public, here is a code example that uses Storage from Amplify to upload images to S3 bucket. The images are fetched from the local device using ImagePicker from Expo.
import React from 'react';
import {
StyleSheet,
ScrollView,
Image,
Dimensions } from 'react-native'
import { ImagePicker, Permissions } from 'expo'
import { Icon } from 'native-base'
import Amplify from '#aws-amplify/core'
import Storage from '#aws-amplify/storage'
import config from './aws-exports'
class App extends React.Component {
state = {
image: null,
}
// fetch a single image from user's device and save it to S3
useLibraryHandler = async () => {
await this.askPermissionsAsync()
let result = await ImagePicker.launchImageLibraryAsync(
{
allowsEditing: false,
//aspect: [4, 3],
}
)
console.log(result);
if (!result.cancelled) {
this.setState({ image: result.uri })
this.uploadImage(this.state.image)
}
}
// add a single image to S3
uploadImage = async uri => {
const response = await fetch(uri)
const blob = await response.blob() // format the data for images
const folder = 'images'
const fileName = 'flower.jpeg'
await Storage.put(folder + '/' + fileName, blob, {
contentType: 'image/jpeg',
level: 'public'
}).then(data => console.log(data))
.catch(err => console.log(err))
}
render() {
let { image } = this.state
let {height, width} = Dimensions.get('window')
return (
<ScrollView style={{flex: 1}} contentContainerStyle={styles.container}>
<Icon
name='md-add-circle'
style={styles.buttonStyle}
onPress={this.useLibraryHandler}
/>
{/*
true && expression always evaluates to expression,
and false && expression always evaluates to false
*/}
{image &&
<Image source={{ uri: image }} style={{ width: width, height: height/2 }} />
}
</ScrollView>
);
}
}
The name of the image is hardcoded which is not good. But this is a very good start nonetheless.
This is a simple method for uploading multiple images. It should work for single image too.
import {Storage} from "aws-amplify";
UploadPhotos(SelectedImages) {
SelectedImages.forEach(async (element) => {
let name = element.filename;
let access = { level: "protected", contentType: "image/jpeg" };
let imageData = await fetch(element.uri);
let blobData = await imageData.blob();
try {
Storage.put(name, blobData, access);
} catch (err) {
console.log("UploadPhotos error: ", err);
}
});
}
I have created a custom component that access the device's camera to snap a picture, set it as source of an ImageView and then save it to a file.
Here is the Javascript code
CAMERA.JS
Here is the initialization of the imageView
export function cameraLoaded(args):void{
cameraPage = <Page> args.object;
imageView = <Image> cameraPage.getViewById("img_upload");...
}
Here I set the imageViews'source to the just taken picture
export function takePicture():void{
camera.takePicture(
{
})
.then(
function(picture){
imageView.imageSource = picture;
},function(error){
});
}
This works perfectly.
Now I try to save the picture to a file.
export function saveToFile():void{
try {
let saved = imageView.imageSource.saveToFile(path,enums.ImageFormat.png);
HalooseLogger.log(saved,"upload");
})
}catch (e){
...
}
}
Here I get an error cannot read property saveToFile of undefined
This is very unusual, in fact if I console.log(imageView) here is the output :
Image<img_upload>#file:///app/views/camera/camera.xml:4:5;
but if I console.log(imageView.imageSource) i see it is ´undefined`.
How is this possible? What am I doing wrong?
ADDITIONAL INFO
The previous code and relatex xml is included in another view as follows :
MAIN.XML
<Page
xmlns="http://schemas.nativescript.org/tns.xsd"
xmlns:cameraPage="views/camera"
loaded="loaded">
<StackLayout orientation="vertical">
<StackLayout id="mainContainer">
<!-- DYNAMIC CONTENT GOES HERE -->
</StackLayout>
</StackLayout>
</Page>
MAIN.JS
This is were the camera view gets loaded dynamically
export function loaded(args):void{
mainPage = <Page>args.object;
contentWrapper = mainPage.getViewById("mainContainer");
DynamicLoaderService.loadPage(mainPage,contentWrapper,mainViewModel.currentActive);
}
The loadPage method does the following :
public static loadPage(pageElement,parentElement,currentActive):void{
let component = Builder.load({
path : "views/camera",
name : "camera",
page : pageElement
});
parentElement.addChild(component);
}
The thing is that as of NativeScript 2.4.0 the Image created for Android will always return null for its property imageSource. Currently, optimisations are on the way to prevent Out of Memory related issues when working with multiple large images and that is why image-asset was presented in nativeScript 2.4.0.
Now I am not sure if you are using the latest nativescript-camera (highly recommended) but if so you should consider that the promise from takePicture() is returning imageAsset. Due to the memory optimization imageSource will always return undefined (for Android) unless you specifically create one. You can do that with fromAsset() method providing the ImageAsset returned from the camera callback.
Example:
import { EventData } from 'data/observable';
import { Page } from 'ui/page';
import { Image } from "ui/image";
import { ImageSource, fromAsset } from "image-source";
import { ImageAsset } from "image-asset";
import * as camera from "nativescript-camera";
import * as fs from "file-system";
var imageModule = require("ui/image");
var img;
var myImageSource: ImageSource;
// Event handler for Page "navigatingTo" event attached in main-page.xml
export function onLoaded(args: EventData) {
// Get the event sender
let page = <Page>args.object;
img = <Image>page.getViewById("img");
camera.requestPermissions();
}
export function takePhoto() {
camera.takePicture()
.then(imageAsset => {
console.log("Result is an image asset instance");
img.src = imageAsset;
fromAsset(imageAsset).then(res => {
myImageSource = res;
console.log(myImageSource);
})
}).catch(function (err) {
console.log("Error -> " + err.message);
});
}
export function saveToFile(): void {
var knownPath = fs.knownFolders.documents();
var folderPath = fs.path.join(knownPath.path, "CosmosDataBank");
var folder = fs.Folder.fromPath(folderPath);
var path = fs.path.join(folderPath, "Test.png");
var saved = myImageSource.saveToFile(path, "png");
console.log(saved);
}