Am trying to user the $cordovaFileTransfer plugin from ngCordovato upload images in my ionic app.
However the images, never seem to upload. The app is running on my android phone and am debugging with chrome remote inspector, the network tab does not show any request for the upload.
This method gets images from the device
$scope.getImages = function() {
var options = {
maximumImagesCount: 2,
width: 800,
height: 800,
quality: 80
};
$cordovaImagePicker.getPictures(options)
.then(function (results) {
for (var i = 0; i < results.length; i++) {
$scope.queue.push({
filepath: results[i],
progress: 0.00
});
}
$scope.$emit('process:queue');
}, function(error) {
// error getting photos
});
};
And am handling the 'process:queue' event with this method
$scope.startUploadQueue = function() {
var server = encodeURI(serviceUrl());
var options = {
fileKey: "image",
httpMethod: 'PUT',
headers: {
"Authorization": "Bearer "+$user.getToken()
}
};
angular.forEach($scope.queue, function(item) {
$cordovaFileTransfer.upload(server, item.filepath, options, true)
.then(function (result) {
console.log(result);
$scope.media.push(result.data);
}, function (error) {
}, function (progress) {
item.progress = (progress.loaded / progress.total) * 100;
});
});
};
Am doing something incorrectly?. Any help will be appreciated
Related
I'm trying to select multiple images in my ionic app using the ImagePicker plugin, when I select only one image works, but if I select more images the app closes
Versions
ionic: 4.0.3
android: 7.0.0
imagePicker: 2.2.2
Code
getPermission() {
this.imagePicker.hasReadPermission()
.then(res => {
if (res) {
this.openGallery()
} else {
this.imagePicker.requestReadPermission()
.then(res => {
if (res === 'ok') {
this.openGallery()
}
})
}
})
.catch(error => console.log(error))
}
openGallery() {
let options = {
maximumImagesCount: 10,
width: 500,
height: 500,
quality: 100,
outputType: 1
}
this.imagePicker.getPictures(options)
.then(file => {
this.images = new Array(file.length);
for (let i = 0; i < file.length; i++) {
this.images[i] = 'data:image/jpeg;base64,' + file[i]
}
})
}
any help on how to solve this?
constructor(public navCtrl: NavController,
private camera: Camera,
private transfer: FileTransfer,
private file: File,
private fileOpener: FileOpener,
private loadingCtrl: LoadingController,
private plt: Platform,
private imagePicker: ImagePicker,
private base64: Base64,
private sanitizer: DomSanitizer) {
}
images=[];
public items: Array<{ images: string;}> = [];
takePhoto(){
this.imagePicker.hasReadPermission()
.then(res => {
if (res) {
this.openGallery();
} else {
this.imagePicker.requestReadPermission()
.then(res => {
if (res === 'ok') {
this.openGallery();
}
})
}
})
.catch(error => console.log(error));
}
openGallery () {
let options = {
maximumImagesCount: 10,
correctOrientation: true,
quality: 30,
width: 100,
height: 100,
allowEdit : true,
outputType: 1,
}
this.imagePicker.getPictures(options)
.then(file => {
//this.images = new Array(file.length);
for (let i = 0; i < file.length; i++) {
//this.images[i] = 'data:image/jpeg;base64,' + file[i]
this.images.push('data:image/jpeg;base64,' +file[i]);
}
});
}
I've been looking for a solution just like yours for me ... your code is perfect ... see the small changes uqe made by adding ";" and reducing image size and quality ...
Congratulations and thank you for helping me! See on your phone if you use the way to kill all APP as soon as you get out of it, because it can also be a cause for when you access the camera the app stops, because it dies ....
I developed a mobile app to help sharing things. The user has to give infos about what he is sending and he can add a picture of the object. So i used the cordova file, camera and fileTransfert plugins. It worked fine on most of the devices i tested on, but i discovered that in some other phone, it doesn't. While doing some tests and research on one of those phones, i discovered that the upload() method of FileTransfert i use to send images to online server seems like not able to reach the folder where the image is stored. Here is a sample of my code. Would you please help me to confirm if i am rigth and how to make those phones to be able to post pictures on the platform?
public presentActionSheet(picture) {
if(this.translateService.currentLang=='fr'){
let actionSheet = this.actionSheetCtrl.create({
title: 'Quelle est la source?',
buttons: [
{
icon: 'images',
text: 'Mon téléphone',
handler: () => {
this.takePicture(this.camera.PictureSourceType.PHOTOLIBRARY, picture);
}
},
{
icon: 'camera',
text: 'Ma Camera',
handler: () => {
this.takePicture(this.camera.PictureSourceType.CAMERA, picture);
}
},
{
text: 'Annuler',
role: 'cancel'
}
]
});
actionSheet.present();
}else{
let actionSheet = this.actionSheetCtrl.create({
title: 'What is the source?',
buttons: [
{
icon: 'images',
text: 'My Phone',
handler: () => {
this.takePicture(this.camera.PictureSourceType.PHOTOLIBRARY, picture);
}
},
{
icon: 'camera',
text: 'My Camera',
handler: () => {
this.takePicture(this.camera.PictureSourceType.CAMERA, picture);
}
},
{
text: 'Cancel',
role: 'cancel'
}
]
});
actionSheet.present();
}
};
presentToast(message_error) {
let toast = this.toastCtrl.create({
message: message_error,
cssClass: 'alert-box',
position: 'middle',
showCloseButton: true,
closeButtonText: "OK"
});
toast.present();
}
//Here is the function to take a picture
public takePicture(sourceType, picture) {
// Create options for the Camera Dialog
var options = {
quality: 100,
sourceType: sourceType,
saveToPhotoAlbum: false,
correctOrientation: true
};
// Get the data of an image
this.camera.getPicture(options).then((imagePath) => {
// Special handling for Android library
if (this.platform.is('android') && sourceType === this.camera.PictureSourceType.PHOTOLIBRARY) {
this.filePath.resolveNativePath(imagePath)
.then(filePath => {
let correctPath = filePath.substr(0, filePath.lastIndexOf('/') + 1);
let currentName = imagePath.substring(imagePath.lastIndexOf('/') + 1, imagePath.lastIndexOf('?'));
this.copyFileToLocalDir(correctPath, currentName, this.createFileName(), picture);
});
} else {
console.log('In the else condition');
var currentName = imagePath.substr(imagePath.lastIndexOf('/') + 1);
var correctPath = imagePath.substr(0, imagePath.lastIndexOf('/') + 1);
this.copyFileToLocalDir(correctPath, currentName, this.createFileName(), picture);
}
}, (err) => {
if(this.translateService.currentLang=='fr'){
this.presentToast('Erreur, pas d\'image selectionnée.');
}else{
this.presentToast('Error, no image selected.');
}
});
}
// Create a new name for the image
private createFileName() {
var d = new Date(),
n = d.getTime(),
newFileName = n + ".jpg";
return newFileName;
}
// Copy the image to a local folder
//cordova.file.dataDirectory
private copyFileToLocalDir(namePath, currentName, newFileName, picture) {
this.file.copyFile(namePath, currentName, cordova.file.dataDirectory, newFileName).then(success => {
if(picture == "imageOne"){
this.mainImage = newFileName;
}else if(picture == "imageTwo"){
this.secondImage = newFileName;
}else{
this.thirdImage = newFileName;
}
//this.lastImage = newFileName;
}, error => {
if(this.translateService.currentLang=='fr'){
this.presentToast('Erreur, le fichier n\'a pas pu etre sauvegardé.');
}else{
this.presentToast('Error, file could not be saved.');
}
console.log(error);
});
}
// Always get the accurate path to your apps folder
public pathForImage(img) {
if (img === null) {
return '';
} else {
return cordova.file.dataDirectory + img;
}
}
public uploadImage(picture) {
// Destination URL
var url = "http://donation.oneclub1.org/donation-new/web/api/upload/image?context=donations";
// File for Upload
var targetPath: any;
if(picture == "imageOne"){
targetPath = this.pathForImage(this.mainImage);
}else if(picture == "imageTwo"){
targetPath = this.pathForImage(this.secondImage);
}else{
targetPath = this.pathForImage(this.thirdImage);
}
// File name only
var filename: any;
if(picture == "imageOne"){
filename = this.mainImage;
}else if(picture == "imageTwo"){
filename = this.secondImage;
}else{
filename = this.thirdImage;
}
var options = {
fileKey: "file",
fileName: filename,
chunkedMode: false,
mimeType: "multipart/form-data",
params : {'fileName': filename}
};
const fileTransfer: TransferObject = this.transfer.create();
// Use the FileTransfer to upload the image
return fileTransfer.upload(targetPath, url, options);/*.then(data => {
if(picture == "imageOne"){
this.mainImageLocal = parseInt(data.response);
}else if(picture == "imageTwo"){
this.secondImageLocal = parseInt(data.response);
}else{
this.thirdImageLocal = parseInt(data.response);
}
//this.presentToast('this is your image id'+this.mainImageLocal);
}, err => {
this.loading.dismissAll();
this.presentToast('Error while uploading file.');
})*/;
}
publish(){
if(this.mainImage!=null){
this.loading = this.loadingCtrl.create({
content: this.content2,
});
this.loading.present();
//var categoryId: number;
for(let parent of this.categories){
if(parent.name == this.asking_form_group.value.subcategory){
this.categoryId=parent.id;
console.log('Id found and it is:'+this.categoryId);
break;
};
};
//var userId: number;
if(localStorage.getItem('userId')){
this.userId= parseInt(localStorage.getItem('userId'));
console.log('got the user id in nmber:'+this.userId);
};
var headers = new Headers();
headers.append("Accept", 'application/json');
headers.append('Content-Type', 'application/json' );
let options = new RequestOptions({ headers: headers });
this.uploadImage('imageOne').then(data => {
this.mainImageLocal = parseInt(data.response);
this.postParams = {
name: this.asking_form_group.value.name,
category: this.categoryId,
description: this.asking_form_group.value.description,
image: this.mainImageLocal,
user: this.userId
}
this.http.post(this.Api+"/donations/requests?api_key="+localStorage.getItem('userApiKey'), this.postParams, options).map(res => res.json())
.subscribe(data => {
this.loading.dismissAll();
if(this.translateService.currentLang=='fr'){
this.presentToast('Félicitations!!Votre demande a été postée sur la plateforme!')
}else{
this.presentToast ('Congratulations !! Your request has been posted on the platform!')
}
this.events.publish('ask:posted', 1);
this.navCtrl.setRoot(Dashboard);
}, error => {
console.log(error);
//this.asking_form_group.reset();
this.testor = error.response;
this.loading.dismissAll();
this.presentToast(this.error);
});
});
}else{
this.loading = this.loadingCtrl.create({
content: this.content2,
});
this.loading.present();
//var categoryId: number;
for(let parent of this.categories){
if(parent.name == this.asking_form_group.value.subcategory){
this.categoryId=parent.id;
console.log('Id found and it is:'+this.categoryId);
break;
};
};
if(localStorage.getItem('userId')){
this.userId= parseInt(localStorage.getItem('userId'));
console.log('got the user id in nmber:'+this.userId);
};
var headers = new Headers();
headers.append("Accept", 'application/json');
headers.append('Content-Type', 'application/json' );
let options = new RequestOptions({ headers: headers });
this.postParams = {
name: this.asking_form_group.value.name,
category: this.categoryId,
description: this.asking_form_group.value.description,
image: this.mainImageLocal,
user: this.userId
}
this.http.post(this.Api+"/donations/requests?api_key="+localStorage.getItem('userApiKey'), this.postParams, options).map(res => res.json())
.subscribe(data => {
this.loading.dismissAll();
if(this.translateService.currentLang=='fr'){
this.presentToast('Félicitations!!Votre demande a été postée sur la plateforme!')
}else{
this.presentToast ('Congratulations !! Your request has been posted on the platform!')
}
this.events.publish('ask:posted', 1);
this.navCtrl.setRoot(Dashboard);
}, error => {
console.log(error);
//this.asking_form_group.reset();
this.testor = error.response;
this.loading.dismissAll();
this.presentToast(this.error);
});
};
}
Sorry i found what the issue was and i fogot to put it here. The problem was actually about filesize. Filetransfert default limit is 7.5Mo. Sending file greater than that would fail. In some phones, camera default configurations put the picture size to 8 or greater Mpx. So that why it could not work in those phones.
My issue is very similar to this question Cordova - Reading Large Image corrupts image
but I haven't had any success with the solution. I'm also attempting to use the image picker plugin for Cordova
Cordova 7.0.1
Android 6.2.3
SapUI5 1.44.17
fileToBase64: function(fileUrl, callback) {
window.resolveLocalFileSystemURL(fileUrl, function(fileEntry) {
fileEntry.file(function(file) {
var reader = new FileReader();
reader.onload = function(evt) {
callback(evt.target.result);
};
reader.readAsDataURL(file);
}, function(error) {
console.log("File entry error " + error);
});
}, function(error) {
console.log("Resolve system file error " + error);
});
},
The result returned is an incomplete base64 string. Here's the loop through my images
handleImagePicker: function(oEvent) {
var _this = this;
window.imagePicker.getPictures(
function(results) {
var numOfImagesLeftToProcess = results.length;
if(numOfImagesLeftToProcess)
_this.appBusy(true);
for (var i = 0; i < results.length; i++) {
_this.fileToBase64(results[i], function(base64Str) {
console.log(base64Str);
numOfImagesLeftToProcess--;
if(numOfImagesLeftToProcess == 0) {
_this.appBusy(false);
}
});
}
}, function (error) {
console.log('Error: ' + error);
},
{
//outputType: imagePicker.OutputType.BASE64_STRING // default .FILE_URI
}
);
},
Not sure if the callback is being called prematurely. I'm able to view the images fine on the device and I've tested this code on two different devices with two different version of Android.
Any help would be appreciated.
I have a service upload imageto amazon s3 after i sign it with my own backend using cordova file-transfer plugin.
I call this service after taking a picture using cordova camera plugin to upload the taken picture to the s3 bucket.
The app sign correctly with my own backend but when it trigger the function upload i get the error i defined in the title.
This is the service that it call an end point in my backend to sign the file and then upload the image to amazon s3:
//Image upload Service
.factory('S3Uploader', function($q, $window, $http, $ionicPopup, API_URL) {
var signingURI = API_URL + "s3signing";
function upload(imageURI, fileName) {
document.addEventListener('deviceready', function() {
console.log('Uploading ' + fileName + ' to S3');
var deferred = $q.defer(),
ft = new FileTransfer(),
options = new FileUploadOptions();
options.fileKey = "file";
options.fileName = fileName;
options.mimeType = "image/jpeg";
options.chunkedMode = false;
console.log('Requesting signed doc ' + signingURI);
$http.post(signingURI, {
"fileName": fileName
})
.success(function(data) {
console.log('Got signed doc: ' + JSON.stringify(data));
options.params = {
"auth": true,
"key": fileName,
"AWSAccessKeyId": data.awsKey,
"acl": "public-read",
"policy": data.policy,
"signature": data.signature,
"Content-Type": "image/jpeg"
};
ft.upload(imageURI, "https://" + data.bucket + ".s3.amazonaws.com/",
function(e) {
console.log("Upload succeeded");
console.log(JSON.stringify(e));
deferred.resolve(e);
$ionicPopup.alert({
title: 'great',
content: 'The image upload to amazon success'
});
},
function(e) {
deferred.reject(e);
$ionicPopup.alert({
title: 'Oops',
content: 'The image upload failed to amazon'
});
}, options);
})
.error(function(data, status, headers, config) {
console.log(JSON.stringify(data));
console.log(status);
$ionicPopup.alert({
title: 'Oops',
content: 'The image upload failed to sign with node'
});
});
return deferred.promise;
}, false); //device ready
}
return {
upload: upload
}
})
and here is the controller code where am calling the camera plugin and in the success of taking the picture am calling the upload function from the S3Uploader service:
.controller('newItemCtrl', function($scope, $http, $ionicPopup, $timeout, $cordovaCamera, API_URL, me, S3Uploader) {
$scope.selectPicture = function() {
document.addEventListener('deviceready', function() {
var options = {
destinationType: Camera.DestinationType.FILE_URI,
sourceType: Camera.PictureSourceType.CAMERA,
allowEdit: true,
encodingType: Camera.EncodingType.JPEG,
targetWidth: 300,
targetHeight: 300,
};
$cordovaCamera.getPicture(options).then(function(imageURI) {
$scope.imageSrc = imageURI;
// upload to Amazon s3 bucket
var fileName = new Date().getTime() + ".jpg";
S3Uploader.upload(imageURI, fileName).then(function() {
alert("upload to S3 successed");
});
}, function(err) {
alert(err);
});
}, false); // device ready
}; // Select picture
})
i get the erorr in this line of the controller:
S3Uploader.upload(imageURI, fileName).then(function() {
it's also important to mention am using crosswalk with my ionic app.
Your current implementation of S3Uploader.upload does not return a promise, it returns nothing. Move your declaration and return of the promise to directly inside the S3Uploader.upload function and not nested inside the document.addEventListener code.
Change your code to something like:
.factory('S3Uploader', function($q, $window, $http, $ionicPopup, API_URL) {
var signingURI = API_URL + "s3signing";
function upload(imageURI, fileName) {
var deferred = $q.defer()
document.addEventListener('deviceready', function() {
// Removed for brevity
}, false);
return deferred.promise;
}
return {
upload: upload
}
})
You are creating and returning your deferred object and it's promise from an event listener. Not the upload factory method.
Something along these lines is what you need:
.factory('S3Uploader', function($q) {
function upload() {
var deferred = $q.defer();
// listener logic
return deferred.promise;
}
return {
upload : upload
}
});
You will have problems with this, as you will want a new deferred object for each time the listener is fired. Adding a listener to a factory method to perform something seems like a bad pattern to me. The event should wrap the invocation of the factory method.
Let's say I have a API that stores some .mp3 music.
The sample link here:
https://118.69.201.34:8882/api/ApiMusic/Download?songId=2000
Now I want to write an API calling function in Angularjs to download the music to my Android devices with the song's Id number as in the link.
How can I do that? Please help :(
You can use the ngCordova FileTransfer library here: http://ngcordova.com/docs/plugins/fileTransfer/
Here's example code from that page, tweaked to your example URL:
document.addEventListener('deviceready', function () {
var fileid = "2000";
var url = "https://118.69.201.34:8882/api/ApiMusic/Download?songId=" + fileid;
var targetPath = cordova.file.documentsDirectory + fileid + ".mp3";
var trustHosts = true
var options = {};
$cordovaFileTransfer.download(url, targetPath, options, trustHosts)
.then(function(result) {
// Success!
}, function(err) {
// Error
}, function (progress) {
$timeout(function () {
$scope.downloadProgress = (progress.loaded / progress.total) * 100;
})
});
}, false);
I did it finally, here is my code. Just share for those who want to refer to this issue in the future. Thanks you guys for your answers
$scope.download = function(songId, songName) {
$ionicLoading.show({
template: 'Downloading...'
});
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fs) {
fs.root.getDirectory(
"fMusic",
{
create: true
},
function (dirEntry) {
dirEntry.getFile(
songName + ".mp3",
{
create: true,
exclusive: false
},
function gotFileEntry(fe) {
var p = fe.toURL();
fe.remove();
ft = new FileTransfer();
ft.download(
encodeURI(APIUrl + songId),
p,
function (entry) {
$ionicLoading.hide();
$scope.mp3File = entry.toURL();
},
function (error) {
$ionicLoading.hide();
alert("Download Error Source --> " + error.source);
},
false,
null
);
},
function () {
$ionicLoading.hide();
console.log("Get the file failed");
}
);
}
);
},
function () {
$ionicLoading.hide();
console.log("Request for filesystem failed");
});
}