I'm trying to capture an image using the camera and upload it to my AJAX endpoint. I've confirmed that this endpoint can accept the file (I created a test HTML file on my desktop that sends a form with an image in it). I'm using Cordova (phonegap) 1.7.0, and am trying to get the fileTransfer() to work. Here is the link for the documentation that I followed:
http://docs.phonegap.com/en/1.0.0/phonegap_file_file.md.html#FileTransfer
The success callback triggers, but no $_FILES data is to be found on the endpoint.
I then found this article:
http://zacvineyard.com/blog/2011/03/25/upload-a-file-to-a-remote-server-with-phonegap/
Which suggested using options.chunkedMode = false. Now the upload takes an age and a half, before eventually failing with an error code of 3, which I believe is FileError.ABORT_ERR.
Am I missing something?
My code from the app below:
navigator.camera.getPicture(function(imageURI){
console.log('take success! uploading...');
console.log(imageURI);
var options = new FileUploadOptions();
options.fileKey = 'file';
options.fileName = 'spot_image.jpeg';
options.mimeType = 'image/jpeg';
var params = new Object();
params.spot_id = 1788;
params.param2 = 'something else';
options.params = params;
options.chunkedMode = false;
var ft = new FileTransfer();
ft.upload(imageURI,serverURL + '/ajax.php?fname=appuploadspotimage',function(r){
console.log('upload success!');
console.log(r.responseCode);
console.log(r.response);
console.log(r.bytesSent);
},function(error){
console.log('upload error')
console.log(error.code);
},options,true);
console.log('after upload');
},function(message){
console.log('fail!');
console.log(message);
},{
quality: 50,
destinationType: navigator.camera.DestinationType.DATA_URL,
sourceType: navigator.camera.PictureSourceType.PHOTOLIBRARY
});
serverURL is defined as the domain for my AJAX endpoint, which has been whitelisted in cordova.xml.
I've seen a number of questions here in SO regarding this, which varying opinions as to whether chunkedMode should be used. Anyone having this issue as well?
Am trying this on a Samsung Galaxy S, running ICS.
May the person who helps me solve this issue mysteriously inherit a beer factory.
You can not use imageUri that you get from camera success callback in FileTransfer upload method, you have to first resolve uri as a filename like this:
navigator.camera.getPicture(function(imageURI){
window.resolveLocalFileSystemURI(imageUri, function(fileEntry) {
fileEntry.file(function(fileObj) {
var fileName = fileObj.fullPath;
//now use the fileName in your method
//ft.upload(fileName ,serverURL + '/ajax.php?fname=appuploadspotimage'...);
});
});
});
After puzzling a bit, it seems to me you can use the image uri directly....
see my answer here: (this works for me on android):
android phonegap camera and image uploading
Related
I'm trying to submit an image (either taken from camera, or selected from gallery) to my upload server by using cordova file-transfer plugin.
The camera plugin works fine, I can see the image -- taken with camera or selected from gallery -- being displayed on screen (by using <img /> tag).
When trying to implement the FileTransfer.Upload, the docs states that the upload method has some arguments, including success/error callback functions.
This is my portion of code:
function uploadPhoto() {
var imageURI = document.getElementById('ImageSource').getAttribute("src");
if (!imageURI) {
alert('Please select an image first.');
return;
}
console.log("imageURI = " + imageURI);
var url=encodeURI("http://my.server.path/upload.php");
var options = new FileUploadOptions();
options.fileKey = "file";
options.mimeType = "multipart/form-data";
options.chunkedMode = false;
console.log("Starting Transfer...");
var ft = new FileTransfer();
ft.upload(imageURI, url,
function (r) {
alert('Finished upload!');
}, function (error) {
console.log(error);
alert('Error uploading image with code: ' + error.code)
},
options
);
console.log("Finishing Transfer...");
}
The Callbacks are not firing
Running the app on an Android Emulator, I get no alert. I can't tell whether it was a success or a failure. But the strange thing is: the image file get uploaded to my server, and I can see these two lines delievered on the log:
D/CordovaLog( 2487): file:///android_asset/www/js/app.js: Line 123 : imageURI = content://media/external/images/media/24
D/CordovaLog( 2487): file:///android_asset/www/js/app.js: Line 147 : Starting Transfer...
D/CordovaLog( 2487): file:///android_asset/www/js/app.js: Line 163 : Finishing Transfer...
Can somebody kindly point me out, where should I look? Because I can't handle the response. I need to get the server response, and display a processed image back to the screen.
I'm developing a mobile app for iOS and Android using Cordova and Ionic Framework. There needs to be 'Send Photo' and related functionality, and I'm using Cordova's FileTransfer to do this.
It works perfectly on iOS simulator, but throws "error code = 1" on Android device.
I know this means file_not_found or similar.
Note it happens if I take a picture from camera, or choose one from gallery.
Here is my code:
$scope.takePic = function() {
var options = {
quality: 50,
destinationType: navigator.camera.DestinationType.FILE_URI,
sourceType: 0, // 0:Photo Library, 1=Camera, 2=Saved Photo Album
encodingType: 0 // 0=JPG 1=PNG
}
navigator.camera.getPicture(onSuccess, onFail, options);
}
var onSuccess = function(FILE_URI) {
window.resolveLocalFileSystemURL(FILE_URI, function(fileEntry) {
alert("full: " + JSON.stringify(fileEntry));
var realUrl = fileEntry.toURL();
$scope.picData = realUrl;
$scope.$apply();
console.log("real URL", realUrl);
});
};
var onFail = function(e) {
console.log("On fail " + e);
}
function win(r) {
console.log("Code = " + r.responseCode);
console.log("Response = " + r.response);
console.log("Sent = " + r.bytesSent);
Flash.success("Wysłano");
var response = JSON.parse(r.response);
$scope.attachment_id = response.data;
$scope.$apply();
$http.post($rootScope.baseServerUrl + 'Members/changeAvatar', {attachment_id: response.data}).success( function (response){
console.log(response);
});
}
function fail(error) {
alert("An error has occurred: Code = " + error.code);
console.log("upload error source " + error.source);
console.log("upload error target " + error.target);
}
$scope.send = function() {
Flash.warning('wysyłam');
var myImg = $scope.picData;
alert(myImg);
var options = new FileUploadOptions();
options.headers = {
Accept: "application/json",
Connection: "close"
}
options.fileKey="file";
options.fileName=$scope.picData.substr($scope.picData.lastIndexOf('/')+1);
options.mimeType="image/jpeg";
options.chunkedMode = false;
var ft = new FileTransfer();
ft.upload(myImg, encodeURI($rootScope.baseServerUrl + 'media/Attachments/add'), win, fail, options);
}
$scope.takePic and send are called by button clicks. There are a lot of alerts and console because I'm trying to find why its not working.
After picking a picture from the gallery on android I get:
file:///storage/sdcard0/download/file-name.jpg
on iOS simulator:
file:///Users//Library/Application%20Support/iPhone%20Simulator/7.1/Applications/B5FB2081-54E7-4335-8856-84C6499E6B07/tmp/cdv_photo_038.jpg
and by using this path I can show this picture by using <img src="{{picData}}"> this works on both platforms.
But if I try to send it on an Android device I get error Code = 1. On iOS sim it sends, photo, gets proper response, changes avatar...everything.
Both Cordova and plugins File and FileTransfer are up to date.
It looks like you might have a path error, file:///storage.sdcard0/download/file-name.jpg should be file:///storage/sdcard0/download/file-name.jpg if I'm not mistaken.
From perusing your code, it doesn't appear that you are parsing anything incorrectly. Maybe you want to try using an older more stable version of the file plugin if it is returning the wrong URI (and maybe file a bug report)? I haven't used the file plugin since they released 1.0, but from personal experience there have been bugs/regressions in the bleeding edge releases before.
You can target specific plugin versions from the cordova-cli using # like cordova plugin add org.apache.cordova.file#1.0.0
As well as specific tags/releases from github using # like cordova plugin add https://github.com/apache/cordova-plugin-file-transfer#r0.4.2
Maybe late but I've kinda fixed it.
In my view file I use:
<input id="file" name="file" type="file" onchange="angular.element(this).scope().addFile(this)" class="upload" accept="image/*" capture="camera"/>
so it fires $scope.addFile() from my controller as soon as you pick up file from galery:
$scope.addFile = function(item){
function uploadComplete(evt) {
/* This event is raised when the server send back a response */
$scope.imgId = JSON.parse(evt.target.responseText).data;
$scope.$apply();
$http.post($rootScope.baseServerUrl + 'Members/changeAvatar', {attachment_id: $scope.imgId}).success( function (response){
console.log(response);
$scope.User.attachment_id = $scope.imgId;
$scope.$apply();
});
}
function uploadFailed(evt) {
alert("There was an error attempting to upload the file.")
};
var updateImage = function (element) {
$scope.$apply(function() {
$scope.theFile = element.files[0];
var formData = new FormData();
formData.append("file", $scope.theFile);
var xhr = new XMLHttpRequest()
xhr.addEventListener("load", uploadComplete, false)
xhr.addEventListener("error", uploadFailed, false)
xhr.open("POST", $scope.baseServerUrl + "media/Attachments/add")
xhr.setRequestHeader("Accept","application/json")
$scope.progressVisible = true
xhr.send(formData);
});
};
updateImage(item)
}
Works for all Android devices I tested, above 4.0 excluding 4.4 because of input type="file" bug, works on iOS simulator and devices with 8.1 system (should also on older but I didn't test it).
It's not a perfect solution, because you can use only pictures you already got on your phone. I couldnt figure it out how to use Cordova FileTransfer with our server authentication way: I was always getting "please log in" in response, even when I tried adding all needed headers, tokens, anything...
So even though this solution is far from what I wanted to achieve - it works. Hope it helps anyone.
this code returns:
Cannot read property 'getPicture' of undefined
Have no idea what im doing wrong, can you please help me with the code?
My App:
angular.module('Todo', ['ionic', 'Todo.controllers','ngStorage',
'Todo.services', 'ngCordova'])
my Controller:
.controller('profileEditCtrl', function($scope,Camera, $localStorage,
$cordovaCamera)
{
$scope.$storage = $localStorage.$default({ data:[]});
$scope.takePicture = function()
{
navigator.camera.getPicture(onSuccess, onFail, { quality: 50,
destinationType: Camera.DestinationType.DATA_URL });
function onSuccess(imageData) {
var image = document.getElementById('myImage');
image.src ="data:image/jpeg;base64," + imageData;
}
function onFail(message) {
alert('Failed because: ' + message);
}
}});
Your code is correct, just add an html button with ng-click="takePicture()".
There is no problem here, It's sure that the browser "cannot read
property 'getPicture' of undefined" because it has no configuration
for a mobile camera that you defined, which means you should test your application on
a real device using:
> ionic run android.
Notice that the new update of Google Chrome has a new feature which
helps your test your device on the browser if it is connected to the
PC/laptop, for testing go to chrome's navigation panel >> More tools >> Inspect devices
or just go to this link:
chrome://inspect/#devices
I'm sure your camera will function normally if you have the plugin cordova plugin add org.apache.cordova.camera installed in the app,
I hope this helps you.
After trying various solutions with no luck for my cordova project, I simply went ahead to use the built-in JavaScript APIs. Essentially:
async function startCapturing() { // get ready to shoot
await getPermission('android.permission.CAMERA');
let stream = await navigator.mediaDevices.getUserMedia({ video: {width: 480, height: 320, facingMode:'environment' }, audio: false });
let video = document.getElementById("pVideo"); // a <video> element
video.srcObject = stream;
video.play();
video.style.display = "block";
}
function shootPhoto(){ // take a snapshot
let video = document.getElementById("pVideo");
let canvas = document.getElementById("pCanvas"); // a <canvas> element
let context = canvas.getContext('2d');
context.drawImage(video,0,0,480,320);
document.getElementById('fsPhotoI').src = Photo.current.src = canvas.toDataURL('image/png');
Photo.current.changed = Profile.current.changed = true;
video.style.display = "none";
}
In particular, some plugins did not work for me because they could't use the Android rear camera right away. The following in getUserMedia(...) does the trick:
facingMode:'environment'
Also make sure you have the CAMERA permission in your AndroidManifest.xml.
I'm able to upload an image using the the camera, but I can't seem to get the correct file name to upload (error code 1 NOT_FOUND_ERR) when trying to upload a file from my app. What I'm trying to do is upload a default profile image to server when a user first signs up.
Here is my code, which is almost identical to the working camera upload I have:
// Source
path = 'images/default.jpeg';
// Destination
var url = 'http://serverloc/data';
// Upload Options
var options = new FileUploadOptions();
options.fileKey = 'file';
options.fileName = path.substr(path.lastIndexOf('/') + 1);
options.mimeType = 'image/jpeg';
options.chunkedMode = false;
var params = new Object();
params.fullpath = path;
params.name = options.fileName;
options.params = params;
// Upload
var ft = new FileTransfer();
ft.upload(path, url,
function(result) {
// hasn't worked yet
},
function(error) {
alert('Error uploading default image: ' + error.code);
// 1 - NOT_FOUND_ERR
},
options);
Testing on Android.
Update: Since I can't this working, I guess my next best option is to add a marker property for each user, and if that propery (default-img say) is "yes", then I'll display the default image in-app, rather than having it stored on the server.
I'm trying to send image files using phonegap's filetransfer.upload, but the returned file is broken and looking at logcat it the sent file seems to be 200 bytes too short.
Here is my code for sending the file
sendImageFile = function (imageURI, imageName) {
writelog("Sending image file", 1);
var options = new FileUploadOptions();
options.fileKey="file";
options.fileName=imageURI.substr(imageURI.lastIndexOf('/')+1);
options.mimeType="image/jpeg";
var params = new Object();
params.value1 = "image name";
options.params = params;
options.chunkedMode = false;
var ft = new FileTransfer();
writelog("image uri length " + imageURI.length, 1);
writelog("Image options set up successfully", 1);
var ft = new FileTransfer();
ft.upload(imageURI, uploadurl, win, transFail, options);
}
and here are some pertinent lines from logcat
01-07 12:27:30.743: D/FileTransfer(20066): Uploaded 114688 of 145432 bytes
01-07 12:27:31.571: D/FileTransfer(20066): got response from server
01-07 12:27:31.696: D/CordovaLog(20066): Code = 200
01-07 12:27:31.696: D/CordovaLog(20066): Response = 12099
01-07 12:27:31.696: D/CordovaLog(20066): Sent = 145236
Any help would be greatly appreciated.
Thanks
Matt
Solution found. My server was accepting all the data sent as a file, as opposed to breaking it up from a form submit (i believe). This was causing there to be several lines of text just before the main image data.
To get round this I installed an old fileTransfer plugin (https://github.com/phonegap/phonegap-plugins/tree/master/Android/FileUploader), reverted to version 1.8.1 of phonegap (as i was unsure how to update the older plugin for the moment).
Edited the fileUpload.java file to remove all text before the file to send. Now it is readable by the server
You can not use imageUri that you get from camera success callback on Android in FileTransfer upload method, you have to first resolve uri as a filename like this:
navigator.camera.getPicture(function(imageURI){
window.resolveLocalFileSystemURI(imageURI, function(fileEntry) {
fileEntry.file(function(fileObj) {
var fileName = fileObj.fullPath;
//now use the fileName in your upload method
var options = new FileUploadOptions();
options.fileKey = "file";
options.fileName = fileName.substr(fileName.lastIndexOf('/')+1);
//...
});
});
}, errorFn, cameraParams);