I am trying to upload an image (as base64 format) from phone gap application to amazon s3. The image is uploaded successfully, but it's displayed as boxes when I try to view the image in Amazon server. I used the below link for my reference.
Uploading image to S3 using phonegap, how to?
I also tried to upload the image (as imageURI) using the below link, but it throws an error Body.params is required
https://github.com/ccoenraets/phonegap-s3-upload/blob/master/client/phonegap-s3-upload/www/app.js
Please find the snippets of code,
// take picture
var options = {
quality: 75,
targetWidth: 320,
targetHeight: 320,
destinationType: 1, // 0 = base 64, 1 = imageURI
sourceType: 1, // 0:Photo Library, 1=Camera, 2=Saved Photo Album
encodingType: 0 // 0=JPG 1=PNG
};
// Take picture using device camera and retrieve image as base64-encoded string
navigator.camera.getPicture(onSuccess,onFail,options);
---------
uploading the image
var imageData = 'data:image/jpeg;base64,'+ $scope.lastPhoto;
var params = {
Key: 'test5.jpg', // for testing purpose
Body: imageData, // base64 data
ContentEncoding: 'base64',
ContentType: 'image/jpeg'
};
var fileName = "" + (new Date()).getTime() + ".jpg";
console.log ('data params' + params.Body);
bucket.upload(params, function(err, data){
$scope.hide($ionicLoading);
var result = err ? 'ERROR!' : 'UPLOADED SUCCESSFULLY...';
var alertPopup = $ionicPopup.alert({
title: 'Amazon Confirmation',
template: 'Result : ' + result
});
Can you check this link how to save canvas data to file
var data = img.replace(/^data:image/\w+;base64,/, "");
AWS.config.update({
accessKeyId : 'your-ACCESSKEYID',
secretAccessKey : 'SECRETACCESSKEY'
});
$cordovaCapture.captureVideo().then(function(videoData) {
$scope.file=videoData[0].name;
var first='file:/storage/sdcard0/DCIM/Camera/';
$cordovaFile.readAsDataURL(first,$scope.file)
.then(function (success) {
var bucket = new AWS.S3({params: { Bucket: 'your-bucket-name' }});
var params = {Key: videoData[0].name, ContentEncoding: 'base64', ContentType: 'video/mp4; charset=UTF-8' , Body: success};
bucket.upload(params).on('httpUploadProgress', function(evt) {
$scope.uploading = true;
$scope.progress = parseInt((evt.loaded * 100) / evt.total)+'%';
console.log("Uploaded :: " + $scope.progress );
$scope.$apply();
}).send(function(err, data) {
$scope.uploading = false;
/*$scope.images.push(data.Location);*/
console.log(data.Location);
$scope.$apply();
});
}, function (error) {
console.log("==========error==========");
console.log(error);
})
})
}
Related
I need to upload all type of files in my application and for images I need to get image height and width and for that I am using:
$scope.uploadFile = function(){
$scope.imageUploading = true;
var options = {
quality: 70,
//~ targetWidth: 1005,
//~ targetHeight: 693,
destinationType: Camera.DestinationType.FILE_URI,
sourceType: Camera.PictureSourceType.PHOTOLIBRARY,
mediaType: Camera.MediaType.PICTURE,
correctOrientation: true
};
$cordovaCamera.getPicture(options).then(function(imageData) {
imageData = imageData.split('?');
var imageURI = imageData[0];
// This function is called once an imageURI is rerturned from PhoneGap's camera or gallery function
window.resolveLocalFileSystemURL(imageURI, function(fileEntry) {
fileEntry.file(function(fileObject){
// Create a reader to read the file
var reader = new FileReader();
// Create a function to process the file once it's read
reader.onloadend = function(evt) {
// Create an image element that we will load the data into
var image = new Image()
image.onload = function(evt) {
// The image has been loaded and the data is ready
var image_width = this.width
var image_height = this.height
if(parseInt(image_width) < confArr.image_sizes.portfolio.large.w || parseInt(image_height) < confArr.image_sizes.portfolio.large.h){
Auth.toastMessage($rootScope.appMainLang.formvalidation.upload_resolution_limit.replace('%s',parseInt(confArr.image_sizes.portfolio.large.w)),'long','center');
$scope.imageUploading = false;
$ionicLoading.hide();
}else{
$scope.imageUploading = true;
$scope.jrCrop(imageURI);
}
image = null
}
// Load the read data into the image source. It's base64 data
image.src = evt.target.result
}
// Read from disk the data as base64
reader.readAsDataURL(fileObject)
}, function(){
Auth.toastMessage("There was an error reading or processing this file.","long", "center");
})
})
}, function(err) {
$scope.imageUploading = false;
$ionicLoading.hide();
// Auth.toastMessage(Auth.getlocal("timeoutText","string"),"long", "center");
});
}
when I use
mediaType: Camera.MediaType.PICTURE,
in above code it returns path of file as "file:///storage/emulated/0/...." and is working correctly.
but as I need to upload all types of files so I replaced above line with
mediaType: Camera.MediaType.ALLMEDIA
and with this path of file becomes "/storage/emulated/0/..." and then it do not enters in "window.resolveLocalFileSystemURL" function.
So is there a way to convert this later path to above mentioned like path?
Just add the file:// to the string. Like this:
var imageURI = 'file://' + imageData[0];
I am getting "Code 3" (connection refused) error when trying to upload an image file from my ionic app to remote server using FileTransfer plugin.
I used the camera plugin and have the captured image moved to permanent storage
$scope.selectPicture = function(sourceType) {
var options = {
quality: 75,
destinationType: Camera.DestinationType.FILE_URI,
sourceType: Camera.PictureSourceType.CAMERA,
allowEdit: true,
encodingType: Camera.EncodingType.JPEG,
popoverOptions: CameraPopoverOptions,
saveToPhotoAlbum: false,
correctOrientation:true
};
$cordovaCamera.getPicture(options).then(function(imagePath) {
var currentName = imagePath.replace(/^.*[\\\/]/, '');
//Create a new name for the photo
var d = new Date(),
n = d.getTime(),
newFileName = n + ".jpg";
localStorage.setItem('checklist',newFileName);
var namePath = imagePath.substr(0, imagePath.lastIndexOf('/') + 1);
// Move the file to permanent storage
$cordovaFile.moveFile(namePath, currentName, cordova.file.dataDirectory, newFileName).then(function(success){
$scope.image = newFileName;
localStorage.setItem('checklist',newFileName);
}, function(error){
$scope.showAlert('Error', error.exception);
});
}, function(err) {
// error
});
};
then I upload the image using the FileTransfer plugin
$scope.reportSending = function(){
$scope.report_no = localStorage.getItem('reportNumber');
$scope.imageLoc = localStorage.getItem('checklist');
var server = "http://localhost/api/api/public/api/sendreport",
filePath = cordova.file.dataDirectory + $scope.imageLoc;
var date = new Date();
var options = {
fileKey: "file",
fileName: $scope.imageLoc,
chunkedMode: false,
mimeType: "multipart/form-data",
params : {
report_no : $scope.report_no
}
};
$cordovaFileTransfer.upload(server, filePath, options).then(function(result) {
console.log(JSON.stringify(result.response));
}, function(err) {
console.log("ERROR: " + JSON.stringify(err));
//alert(JSON.stringify(err));
}, function (progress) {
// constant progress updates
});
};
when I execute the reportSending() function it returns an error it says:
ERROR: {"code":3,"source":"file:///data/user/0/com.ionicframework.appnew343084/files/1483519701226.jpg","target":"http://localhost/api/api/public/api/sendreport","http_status":null,"body":null,"exception":"Connection refused"}
it says "connection refused" in the exception but when I try the API in postman I can successfully upload a file.
So after searching tons of forums I found out that my problem was very simple..
changing the API url fixed the issue.
from
var server = "http://localhost/api/api/public/api/sendreport",
to
var server = "http://192.168.1.17/api/api/public/api/sendreport";
instead of using localhost I pointed the URL to my local server's IP
and I also noticed that I used comma , instead of semi-colon at the end of my variable declaration for the API.
now everything works as it should.
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.
I want to use camera plugin cordova 3.4. I need two options. First it can take a photo with camera and Second i can select photo in gallery.
This is my code that i use only camera
function Photo(id, data, format) {
this.id = id;
this.data = data;
this.format = format || "png";
this.name = function() {
var date = new Date();
return "" + date.getTime() + "_" + this.id + "." + this.format;
};
}
SiteCamera = {
dataWithMimeType: function(data) {
return 'data:image/png;base64,' + data;
},
takePhoto: function(idField, updated) {
SiteCamera.id = idField;
SiteCamera.updated = updated;
navigator.camera.getPicture(SiteCamera.onSuccess, SiteCamera.onFail, {
quality: 50,
destinationType: Camera.DestinationType.DATA_URL,
sourceType : Camera.PictureSourceType.CAMERA,
encodingType: Camera.EncodingType.JPEG
});
},
onSuccess: function(imageData) {
var imageId = SiteCamera.updated ? "update_" + SiteCamera.id : SiteCamera.id;
var image = document.getElementById(imageId);
var photo = new Photo(SiteCamera.id, imageData);
image.src = SiteCamera.dataWithMimeType(imageData);
PhotoList.add(photo);
},
onFail: function() {
alert("Failed");
}
};
Who can help me i want function that can allow me to use camera option or select photo in gallery. The code that i show all everyone just only chose. if i use 1st option i can use this option only but i need both but i don't know how to do it.
var destinationType = navigator.camera.DestinationType;
var source = navigator.camera.PictureSourceType.PHOTOLIBRARY;
navigator.camera.getPicture(function (imageURI) {
/*Success callback*/
},
function (e) {
/*Fail callback*/
},
{
quality: 100,
destinationType: destinationType.FILE_URI,
sourceType: source
});
You can get image from Camera, Photo Library and Album, to do that just change the source type.
source = navigator.camera.PictureSourceType.PHOTOLIBRARY; //From PhotoLibrary
source = navigator.camera.PictureSourceType.SAVEDPHOTOALBUM; //From Album
source = navigator.camera.PictureSourceType.CAMERA; //From Camera(Default)
On Android, I'm trying to upload the output from Cordova/Phonegap getPicture() using Google Drive API: Insert File. Is there a way to do this using the FILE_URI instead of DATA_URL (base64)?
I tried Camera.DestinationType.DATA_URL first, but it didn't return Base64 data like it was supposed to, it just returned the same thing as FILE_URI. So now I'm trying to figure out how to pass FILE_URI to Google Drive Insert File (which takes Base64). Is there a way to convert FILE_URI to Base64?
Cordova code:
navigator.camera.getPicture(onSuccess, onFail,
{ quality: 50, destinationType: Camera.DestinationType.FILE_URI });
function onSuccess(imageURI) {
var image = document.getElementById('myImage');
image.src = imageURI;
// need to do something like this:
var fileData = ConvertToBase64(imageURI);
insertFile(fileData);
}
Google Drive code:
/**
* Insert new file.
*
* #param {File} fileData File object to read data from.
* #param {Function} callback Function to call when the request is complete.
*/
function insertFile(fileData, callback) {
const boundary = '-------314159265358979323846';
const delimiter = "\r\n--" + boundary + "\r\n";
const close_delim = "\r\n--" + boundary + "--";
var reader = new FileReader();
reader.readAsBinaryString(fileData);
reader.onload = function(e) {
var contentType = fileData.type || 'application/octet-stream';
var metadata = {
'title': fileData.fileName,
'mimeType': contentType
};
var base64Data = btoa(reader.result);
var multipartRequestBody =
delimiter +
'Content-Type: application/json\r\n\r\n' +
JSON.stringify(metadata) +
delimiter +
'Content-Type: ' + contentType + '\r\n' +
'Content-Transfer-Encoding: base64\r\n' +
'\r\n' +
base64Data +
close_delim;
var request = gapi.client.request({
'path': '/upload/drive/v2/files',
'method': 'POST',
'params': {'uploadType': 'multipart'},
'headers': {
'Content-Type': 'multipart/mixed; boundary="' + boundary + '"'
},
'body': multipartRequestBody});
if (!callback) {
callback = function(file) {
console.log(file)
};
}
request.execute(callback);
}
}
I realize this is a bit old - but it now looks like you can use a FileReader in phoneGap.
I haven't tested this yet, but something like this should also work, without the canvas hack.
[EDIT - tested and revised the code below. works for me :D ]
var cfn = function(x) { console.log(x) };
var cameraOps = { quality: 50, destinationType: Camera.DestinationType.FILE_URI };
navigator.camera.getPicture(function(imagePath) {
window.resolveLocalFileSystemURL(imagePath, function(fileEntry) {
fileEntry.file(function (file) {
var reader = new FileReader();
reader.onloadend = function(evt) {
console.log("read success!!!");
console.log(evt.target.result);
};
reader.readAsDataURL(file);
}, cfn);
}, cfn);
}, cfn);
Yes you can....
Specify Destination Type as FILE_URI itself and in imagedata you will be getting the images file uri place it in a image tag and then place it inside HTML5 canvas and canvas has one method called toDataURL where you will be able to get the base64 of the corresponding image.
function onSuccess(imageData)
{
var $img = $('<img/>');
$img.attr('src', imageData);
$img.css({position: 'absolute', left: '0px', top: '-999999em', maxWidth: 'none', width: 'auto', height: 'auto'});
$img.bind('load', function()
{
var canvas = document.createElement("canvas");
canvas.width = $img.width();
canvas.height = $img.height();
var ctx = canvas.getContext('2d');
ctx.drawImage($img[0], 0, 0);
var dataUri = canvas.toDataURL('image/png');
});
$img.bind('error', function()
{
console.log('Couldnt convert photo to data URI');
});
}
Thanks to Arun for pointing me in the right direction. I ended up using this javascript function, which was based off http://jsfiddle.net/jasdeepkhalsa/L5HmW/
function getBase64Image(imgElem) {
// imgElem must be on the same server otherwise a cross-origin error will be thrown "SECURITY_ERR: DOM Exception 18"
var canvas = document.createElement("canvas");
canvas.width = imgElem.clientWidth;
canvas.height = imgElem.clientHeight;
var ctx = canvas.getContext("2d");
ctx.drawImage(imgElem, 0, 0);
var dataURL = canvas.toDataURL("image/jpeg");
dataURL = dataURL.replace(/^data:image\/(png|jpg|jpeg);base64,/, "");
return dataURL;
}