Store image to Firebase storage from cordova camera plugins on Ionic - ionic-framework

I've red some topics on the subject (e.g: Uploading image to Firebase Storage from Cordova app) but didn't find my answer...
I'm working on a IONIC project with the implementation of the ngCordova camera plugin to take picture and get pic from the librairy.
So I got the result as a image URI and I want to upload it in Firebase storage (as file or Blob).
Here is my code :
$scope.fromCamera = function() {
$ionicPlatform.ready(function() {
var options = {
quality: 75,
destinationType: Camera.DestinationType.FILE_URI,
sourceType: Camera.PictureSourceType.CAMERA,
allowEdit: true,
encodingType: Camera.EncodingType.JPEG,
targetWidth: 300,
targetHeight: 300,
saveToPhotoAlbum: true e
};
$cordovaCamera.getPicture(options).then(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" });
// Create the storage ref
var ref = storageRef.child('images/test');
// Upload the file
uploadPhoto(blob, ref);
};
reader.readAsArrayBuffer(file);
});
}, function (error) {
console.log(error)
});
});
});
};
I read the file and convert it into a Blob before uploading it into firebase. And I got an 'Encoding error' telling me "A URI supplied to the API was malformed, or the resulting Data URL has exceeded the URL length limitations for Data URLs."
I'm running it an chrome browser with the Cordova Mocks extension.
Any help is welcome!
Thanks

uploadPhoto() is my function to upload the file on firebase storage (and save the URL in firebase database)
var storageRef = Firebase.storageRef();
var databaseRef = Firebase.databaseRef();
var uploadPhoto = function(file, ref) {
var task = ref.put(file);
// Update progress bar
task.on('state_changed', function(snapshot){
// nothing
}, function(error) {
// Handle unsuccessful uploads
}, function() {
// Handle successful uploads on complete
$scope.downloadURL = task.snapshot.downloadURL;
$scope.actualKey = databaseRef.child('posts').push().key;
databaseRef.child('posts/' + $scope.actualKey).update({
url : $scope.downloadURL,
id : $scope.actualKey,
time : firebase.database.ServerValue.TIMESTAMP,
});
}
);
}

try changing...
[new Uint8Array(this.result)]
to just this
[this.result]
alternate approach using $cordovaFile
var fileName = imageURI.replace(/^.*[\\\/]/, '');
$cordovaFile.readAsArrayBuffer(cordova.file.tempDirectory, fileName)
.then(function (success) {
// success - get blob data
var imageBlob = new Blob([success], { type: "image/jpeg" });
// Create the storage ref
var ref = storageRef.child('images/test');
// Upload the file
uploadPhoto(imageBlob, ref);
}, function (error) {
// error
});
Instead of getting the path from the URI, in the code, I assume the following...
// modify the image path when on Android
if ($ionicPlatform.is("android")) {
path = cordova.file.cacheDirectory
} else {
path = cordova.file.tempDirectory
}
feel free to parse the path to get the directory

Related

How could I load video files from my library? Ionic 3

I observed that the Native File has not been supported by the Ionic View anymore see list here.
I am trying to get a video from my library by using Native Camera to access the videos. It can return me 3 different formats of path to my videos (DATA_URL, FILE_URI, and NATIVE_URI).reference to Native Camera here
I am currently using FILE_URI as recommended in this post. It returns something like "/storage/emulated/0/DCIM/Camera/VID_20180312_210545.mp4"
Please have a look at my code below. Aiming a better understanding, the current behavior is highlighted by comments with "//** comment ***" :
addVideoToOffer(){
this.platform.ready().then(() =>{
const options: CameraOptions = {
sourceType: this.camera.PictureSourceType.PHOTOLIBRARY,
destinationType: this.camera.DestinationType.FILE_URI,
mediaType: this.camera.MediaType.VIDEO,
}
this.camera.getPicture(options).then((data_uri) => {
this.readVideoFileasGeneral(data_uri);
});
});
}
readVideoFileasGeneral(data_uri) {
if(!data_uri.includes('file://')) {
data_uri = 'file://' + data_uri;
}
return this.file.resolveLocalFilesystemUrl(data_uri)
.then((entry: FileEntry) => {
//***it does not get in here***
this.presentQuickToastMessage(data_uri);
return new Promise((resolve)=>{//, reject) => {
entry.file((file) => {
let fileReader = new FileReader();
fileReader.onloadend = () => {
let blob = new Blob([fileReader.result], {type: file.type});
resolve({blob: blob, file: file});
};
fileReader.readAsArrayBuffer(file);
});
})
})
.catch((error) => {
this.presentQuickToastMessage(error);
//***it presents "plugin_not_installed" here***
});
}
I understand that I am having this message because Native File is not supported anymore (maybe reason of the plugin_not_installed message). However, I still have to do this task. So, if someone has any idea of what I could be using in order to have the selected videos in a blob, it would be great!
Thanks for reading until here,
Cheers,
Roger A L
makeFileIntoBlob(uri) {
// get the correct path for resolve device file system
let pathIndex = uri.indexOf('var');
let correctPath = uri.slice(+pathIndex);
this.file
.resolveLocalFilesystemUrl((this.platform.is('ios') ? 'file:///' : '') + correctPath)
.then(entry => (<FileEntry>entry).file(file => this.readFile(file)))
.catch(err => console.log('ERROR: ', err));
}
readFile(file) {
if(file) {
const reader = new FileReader();
reader.onloadend = () => {
const blob: any = new Blob([reader.result], { type: file.type });
blob.name = file.name;
console.log(blob);
return blob;
};
reader.readAsArrayBuffer(file);
}
}
You need to get rid of the /private/ and keep file:///, so that your path goes like file:///var/
I'm currently working on something similar.. I have the video recorded with media-capture and then I can display it within a normal video html tag.. if this is all you need then this code may help you...
this.mediaCapture.captureVideo({duration: 10, quality: 0}).then(
(data: MediaFile[]) => {
if (data.length > 0) {
let originname = data[0].fullPath.substr(data[0].fullPath.lastIndexOf('/') + 1);
let originpath = data[0].fullPath.substr(0, data[0].fullPath.lastIndexOf('/') + 1);
let alerta = this.alerts.create({
buttons: ['ok'],
message: this.file.externalDataDirectory
});
alerta.then(set => set.present());
this.file.copyFile(originpath, originname, this.file.externalDataDirectory, 'video.mp4')
.then(result =>{
let videopath = this.webview.convertFileSrc(result.nativeURL)
let video = (document.getElementById('myvideo') as HTMLVideoElement).src = videopath;
.... rest of the code
The problem raise when you try to use the native File plugin... converting files with any method (readAsDataURL, readAsArrayBuffer or readAsBinaryString) will never resolve, this is a known problem with the Ionic Native File plugin but is not taken care of...
What I did is to take the ionic native Filesystem and use it to read the file, this does read the file and get you with a base64 (pretty sure as I don't specify the encoding field) and then you can handle it the way you want...
const data = Filesystem.readFile({
path: result.nativeURL
})
.then(data =>{
...handle data as base64
...rest of the code

picture do not show in sails.js view

My assets folder :
assets
| images
| media
| book
| pictures
i want to create new book when i upload book picture in above path, But when i try to show this image in view, the image can not be displayed and there is no error either.
my code is:
//BookController
create: function (request, response, next) {
var title = request.body.title;
var subject = request.body.subject;
var brief = request.body.brief;
var author = request.body.author;
var origin_pic_name = null;
request.file('pic').upload({
dirname: '../../assets/images/media/book/pictures/',
},function (err, file) {
if(err) console.log(err);
origin_pic_name = file[0]['fd'].split('\\').reverse()[0] ;
Book.create({title:title,subject:subject,brief:brief,author:author,pic:origin_pic_name}).exec(function (err) {
if(err) response.end(500, {error: 'Database Error'});
response.redirect('/');
});
});},
index : function (request, response, next) {
Book.find({}).exec(function (err, books) {
if(err) response.end(500, {error: 'Database Error'});
response.view('book/index', {books:books});
});},
//my index.ejs
<ol>
<% books.forEach(function (value) {%>
<h3><li> <%= value.title %></li></h3>
<ul><%= value.author %></ul>
<ul><%= value.subject %></ul>
<ul><%= value.brief %></ul>
<ul><img src="/images/media/book/pictures/<%= value.pic %>"/></ul>
<% })%>
</ol>
thank you
Out of the box, sails caches assets during the sails lift process. To get around this, for file uploads, you can alter your controller to copy the file immediately after upload.
Here is an example of how you might do that with your current controller. You may need to edit the directory strings to suit your needs.
// BookController
create: function (request, response, next) {
var title = request.body.title;
var subject = request.body.subject;
var brief = request.body.brief;
var author = request.body.author;
var origin_pic_name = null;
request.file('pic').upload({
dirname: '../../assets/images/media/book/pictures/',
},function (err, file) {
if(err) console.log(err);
origin_pic_name = file[0]['fd'].split('\\').reverse()[0];
// Variable to hold the current directory
var currentDir = '../../assets/images/media/book/pictures/' + origin_pic_name;
// Variable to hold the temp directory
var tempDir = '.tmp/public/images/media/book/pictures/' + origin_pic_name;
// copy the image from the current directory to the temp to the temp folder
fs.createReadStream(currentDir).pipe(fs.createWriteStream(tempDir));
Book.create({title:title,subject:subject,brief:brief,author:author,pic:origin_pic_name}).exec(function (err) {
if(err) response.end(500, {error: 'Database Error'});
response.redirect('/');
});
});
},
You need to be very careful when uploading images to Sails:
The Problem
Grunt is watching for changes in some folders, including the assets dir and subdirs. But that is only possible (activacted, tbh) in "Development" enviroment.
The solution
Create a images/ dir in your root.
When uploading the image, make skipper save the image there.
Write a mediaController that will catch routes like /images/media/book/:name and will try to locate and send a file:
// MediaController.js
var fs = require('fs');
var path = require('path');
module.exports = {
get : function(req, res){
var filepath = req.name.slice(1,req.name.length);
// remove this Sync to an Async
if(fs.existsSync(path.resolve(filepath))){
return res.sendfile(filepath);
} else {
return res.notFound();
}
}
}
//Routes.js
'get /images/books/:name' : 'MediaController.get'
Advantages
You can now restrict the access of images with policies, if you want to!
Better handling at image and 100% control over the fs. Good with DO Spaces, for example...

ngCordova filetransfer not getting path for picture from camera

I have a mobile app that I've created where I want users to be able to take a picture and save it to a server.
I've followed the tutorials, but for some reason the file transfer is not working.
Here is my code:
$cordovaCamera.getPicture(options).then(function( imageData ) {
// self.imgURI = "data:image/jpeg;base64," + imageData;
var server = API_ENDPOINT + '/fileuploads'
var filePath = "data:image/jpeg; base64," + imageData;
document.addEventListener('deviceready', function() {
$cordovaFileTransfer.upload(server, filePath)
.then(function(result) {
// Success!
}, function(err) {
// Error
}, function(progress) {
// constant progress updates
});
}, false);
}
The Cordova plugin for the camera works great, just an issue with saving the file.
If you are specifically looking to get File Url of the image returned from the Camera plugin, following should be the options for the camera plugin:
var options = {
destinationType: Camera.DestinationType.FILE_URI,
sourceType: Camera.PictureSourceType.CAMERA,
};
If you are facing any other specific issue, please mention.
Hope this helps.

ionic 1.x : crop image

I have two buttons, the first one for browse image from gallery and the second one for taking photo. I'm using cordova camera plugin for two cases.
After choosing an image, I want to crop it before to send to server using cordova file transfer plugin. I've tried to use several plugins such as jr-crop, angular-image-crop, ngImgCrop. The problem is that plugins returns a base64 image, but I want to get the image url (not dataUrl). Any help please !
My solution (#egycode) :
$scope.image_gallery = function() {
var options = {
quality: 100,
correctOrientation: true,
sourceType: 0
};
$cordovaCamera.getPicture(options).then(function(data) {
console.log(data);
$scope.crop(data);
console.log('camera data image_gallery: ' + angular.toJson(data));
}, function(error) {
console.log('camera error image_gallery: ' + angular.toJson(error));
});
}
$scope.crop = function(url) {
$jrCrop.crop({
url: url,
width: 261,
height: 362
}).then(function(canvas) {
console.log(canvas);
var image = canvas.toDataURL();
//var image is the result, you can show it using : $scope.pictureUrl = image;
}, function() {
// User canceled or couldn't load image.
});
}

Cannot read property 'download' of undefined $cordovaFileTransfer in Ionic

I want to use $cordovaFileTransfer in my app to dowload image data, but after trying to implement the code, this error is showing up:
Cannot read property 'download' of undefined
here is my code:
var url = "blablabla.com/img.png";
var targetPath = "img/"+ imgpaths;
var trustHosts = true;
var options = {};
$cordovaFileTransfer.download(url, targetPath, options, trustHosts)
.then(function(result) {
// Success!
console.log('Download Success' + targetPath);
}, function(err) {
// Error
}, function (progress) {
$timeout(function () {
var downloadProgress = (progress.loaded / progress.total) * 100;
console.log('Progress : '+downloadProgress);
});
});
anybody can help me?
Check this issues list:
http://ngcordova.com/docs/common-issues/
For example have you wrapped the call to $cordovaFileTransfer.download() inside deviceready handler or better inside $ionicPlatform.ready() ?