I am trying to upload an image from my Cordova app to the new Firebase Storage. This is what I have attempted so far.
// Get the image from PhotoLibrary
navigator.camera.getPicture(onSuccess, onFail, {
quality: quality,
sourceType: Camera.PictureSourceType.PHOTOLIBRARY,
destinationType: Camera.DestinationType.FILE_URI,
targetWidth: imageSize,
targetHeight: imageSize
});
function onSuccess(imageData) {
var storageRef = firebase.storage().ref();
window.resolveLocalFileSystemURL(imageData,
function(fileEntry) {
fileEntry.file(function(file) {
var uploadTask = storageRef.child('images/test.jpg').put(file);
uploadTask.on('state_changed', function(snapshot){
console.log(snapshot);
});
}
)
};
I am trying to upload an image from my Cordova app to the new Firebase Storage. This is what I have attempted so far.
// Get the image from PhotoLibrary
navigator.camera.getPicture(onSuccess, onFail, {
quality: quality,
sourceType: Camera.PictureSourceType.PHOTOLIBRARY,
destinationType: Camera.DestinationType.FILE_URI,
targetWidth: imageSize,
targetHeight: imageSize
});
function onSuccess(imageData) {
var storageRef = firebase.storage().ref();
window.resolveLocalFileSystemURL(imageData,
function(fileEntry) {
fileEntry.file(function(file) {
var uploadTask = storageRef.child('images/test.jpg').put(file);
uploadTask.on('state_changed', function(snapshot){
console.log(snapshot);
});
}
)
};
This results in the following error
FirebaseError: Firebase Storage: Invalid argument in `put` at index 0: Expected Blob or File.
One other thing I have tried is getting the image as base64 and converting to a Blob, but same result.
Does anyone one know how to get the image in the Javascript File or Blob formats that Firebase Storage requires? Thanks!
Share Improve this question edited May 26, 2016 at 14:12 Frank van Puffelen 599k85 gold badges889 silver badges859 bronze badges asked May 26, 2016 at 5:43 Angus BremnerAngus Bremner 1321 silver badge9 bronze badges 2- Check out solution no.8 in here stackoverflow./questions/5933565/… Works for me. :) – Sam Commented May 30, 2016 at 21:49
- I have designed this plugin for cordova android for the same purpose npmjs./package/cordova-plugin-firebase-files-upload – Phaneendra Charyulu Kanduri Commented Nov 12, 2019 at 5:40
7 Answers
Reset to default 6Didn't like to use XMLHhttpRequest for a local file so after playing with Cordova File Plugin I finally got it working. Hope it helps someone!
function MainController($scope, $cordovaCamera, $cordovaFile) {
$scope.capturarFoto = function (type) {
var opcionesCaptura = {
destinationType: Camera.DestinationType.FILE_URI,
sourceType: Camera.PictureSourceType[type.toUpperCase()],
};
$cordovaCamera.getPicture(opcionesCaptura)
.then(procesarImagen, procesarError);
};
function procesarImagen(pathImagen) {
var directorioFuente = pathImagen.substring(0, pathImagen.lastIndexOf('/') + 1),
archivoFuente = pathImagen.substring(pathImagen.lastIndexOf('/') + 1, pathImagen.length),
nombreParaGuardar = new Date().valueOf() + archivoFuente;
$cordovaFile.readAsArrayBuffer(directorioFuente, archivoFuente)
.then(function (success) {
var blob = new Blob([success], {type: 'image/jpeg'});
enviarFirebase(blob, nombreParaGuardar);
}, function (error) {
console.error(error);
});
}
function enviarFirebase(file, nombre) {
var storageRef = firebase.storage().ref();
var uploadTask = storageRef.child('images/' + nombre).put(file);
uploadTask.on('state_changed', function (snapshot) {
console.info(snapshot);
}, function (error) {
console.error(error);
}, function () {
var downloadURL = uploadTask.snapshot.downloadURL;
console.log(downloadURL);
});
}
function procesarError(error) {
console.error(JSON.stringify(error));
}
}
As @juanwmedia stated in his answer, I don't like to use XMLHhttpRequest for a local file, so here it is his answer without the use of ngCordova, just plain cordova-plugin-file:
navigator.camera.getPicture(function (imageUri) {
window.resolveLocalFileSystemURL(imageUri, function (fileEntry) {
fileEntry.file(function (file) {
var reader = new FileReader();
reader.onloadend = function () {
// This blob object can be saved to firebase
var blob = new Blob([new Uint8Array(this.result)], { type: "image/jpeg" });
sendToFirebase(blob);
};
reader.readAsArrayBuffer(file);
});
}, function (error) {
errorCallback(error);
});
}, errorCallback, options);
The link from Sam above led me in the right direction. Here is a working solution.
navigator.camera.getPicture(onSuccess, onFail, {
quality: quality,
sourceType: Camera.PictureSourceType.PHOTOLIBRARY,
destinationType: Camera.DestinationType.FILE_URI,
targetWidth: imageSize,
targetHeight: imageSize
});
function onSuccess(imageData) {
var storageRef = firebase.storage().ref();
var getFileBlob = function(url, cb) {
var xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.responseType = "blob";
xhr.addEventListener('load', function() {
cb(xhr.response);
});
xhr.send();
};
var blobToFile = function(blob, name) {
blob.lastModifiedDate = new Date();
blob.name = name;
return blob;
};
var getFileObject = function(filePathOrUrl, cb) {
getFileBlob(filePathOrUrl, function(blob) {
cb(blobToFile(blob, 'test.jpg'));
});
};
getFileObject(imageData, function(fileObject) {
var uploadTask = storageRef.child('images/test.jpg').put(fileObject);
uploadTask.on('state_changed', function(snapshot) {
console.log(snapshot);
}, function(error) {
console.log(error);
}, function() {
var downloadURL = uploadTask.snapshot.downloadURL;
console.log(downloadURL);
// handle image here
});
});
}
I had the same issue. Solution no. 8 in here
how to create/initialize the file object using file path html5
works like magic.
if your file upload field is set to multiple=true
then you will get array of objects so you have to choose which one you need to upload.
this may help you
var uploadTask = storageRef.child('images/' + file[0].name).put(file[0]);
Angus Bremner,
I tried to implement your solution and failed. I do not get error and "onSucess" I manage to regain function "imageData" that is : "content: // media / external / images / media / 3384". Any suggestions?
To upload multiple images using ionic and firebase:
$scope.upload = function(sourceType) {
var options = {
quality : 75,
destinationType : Camera.DestinationType.FILE_URI,
sourceType : sourceType,
encodingType: Camera.EncodingType.JPEG,
popoverOptions: CameraPopoverOptions,
targetWidth: 500,
targetHeight: 500,
saveToPhotoAlbum: false
};
$cordovaCamera.getPicture(options).then(function(imageData) {
// $scope.images = imageData;
var storageRef = firebase.storage().ref();
// filename = imageData.name;
var getFileBlob = function(url, cb) {
var xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.responseType = "blob";
xhr.addEventListener('load', function() {
cb(xhr.response);
});
xhr.send();
};
var blobToFile = function(blob, name) {
blob.lastModifiedDate = new Date();
blob.name = name;
return blob;
};
var getFileObject = function(filePathOrUrl, cb) {
getFileBlob(filePathOrUrl, function(blob) {
cb(blobToFile(blob, new Date().getTime()));
});
};
getFileObject(imageData, function(fileObject) {
var metadata = {
'contentType': fileObject.type
};
storageRef.child('images/' + fileObject.name).put(fileObject, metadata);
uploadTask.on('state_changed', null, function(error) {
// [START onfailure]
console.error('Upload failed:', error);
alert('Upload failed:', error);
// [END onfailure]
}, function() {
console.log('Uploaded',uploadTask.snapshot.totalBytes,'bytes.');
console.log(uploadTask.snapshot.metadata);
var url = uploadTask.snapshot.metadata.downloadURLs[0];
console.log('File available at', url);
// [START_EXCLUDE]
document.getElementById('linkbox').innerHTML = '<img src="' + url + '">';
// [END_EXCLUDE]
});
});
}, function(error) {
console.error(error);
alert(error);
});
};