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.
Related
I am trying to save images i take with the camera on my phonegap app to a more permanent destination. I run the app on iOS and Android so i need this to work on ios and android.
So far i can get the image file name and temporary storage path.
I can also get the base file system path for the device i am running (currently an Android Galaxy S7 edge).
However, i am unable to move/copy the file from the temporary storage to the new one as it fails.
Ive got the following code and ive got a try/catch around the code which moves the images. in the catch i have an alert which triggers always as there is something wrong with my code.
Ive tried changing the moveTo to CopyTo and changing the code from output.moveTo to things like cordova.file.moveTo without success.
If anyone could help i would be greatful.
Thanks Kind regards
const tempFilename = imageURI.substr(imageURI.lastIndexOf('/') + 1);
const tempBaseFilesystemPath = imageURI.substr(0, imageURI.lastIndexOf('/') + 1);
const newBaseFilesystemPath = cordova.file.dataDirectory;
var output=tempBaseFilesystemPath+tempFilename;
var saveOutput=newBaseFilesystemPath+tempFilename;
alert(tempFilename+","+tempBaseFilesystemPath+","+newBaseFilesystemPath+","+tempFilename);
try{
output.moveTo(tempBaseFilesystemPath, tempFilename, newBaseFilesystemPath,tempFilename)
.then(function (success) {
alert("done");
}, function (error) {
alert("not done");
});
}
catch{
alert("didnt run");
}
const storedPhoto = output;
localStorage.setItem('imageLoc',storedPhoto);
localStorage.setItem('goodPic','not');
},
function( message ) {
},
{
quality: 30,
destinationType: Camera.DestinationType.FILE_URI,
});
}
I want to create Android/iOS/Windows app using cordova.
I have a problem to access the camera. I've used getUserMedia but in this way I cannot access the camera of my tablet. What is another way to access it? I have to use only a rear camera. Thanks a lot!
getUserMedia code:
navigator.getUserMedia = navigator.getUserMedia ||navigator.webkitGetUserMedia
|| navigator.mozGetUserMedia || navigator.msGetUserMedia;
var cam_video_id = "camsource"
window.addEventListener('DOMContentLoaded', function() {
// Assign the <video> element to a variable
var video = document.getElementById(cam_video_id);
var options = {
"audio": false,
"video": true
};
// Replace the source of the video element with the stream from the camera
if (navigator.getUserMedia) {
navigator.getUserMedia(options, function(stream) {
video.src = (window.URL && window.URL.createObjectURL(stream)) || stream;
}, function(error) {
console.log(error)
});
// Below is the latest syntax. Using the old syntax for the time being for backwards compatibility.
// navigator.getUserMedia({video: true}, successCallback, errorCallback);
} else {
$("#qr-value").text('Sorry, native web camera streaming (getUserMedia) is not supported by this browser...')
return;
}
}, false);
You should obviously be using the Camera plugin of Cordova. The documentation is available on link and you can set to use the rear camera by passing
cameraDirection: Camera.Direction.BACK
to options when opening camera like (from documentation)
navigator.camera.getPicture(onSuccess, onFail, {
quality: 50,
destinationType: Camera.DestinationType.FILE_URI,
cameraDirection: Camera.Direction.FRONT
});
function onSuccess(imageURI) {
var image = document.getElementById('myImage');
image.src = imageURI;
}
function onFail(message) {
alert('Failed because: ' + message);
}
You may try ionic (based on cordova), it has qr reading functionalities
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.
I have a app using cordova 3.4 and file 1.1.0.
If I copy a image using the camera-modul, I use
myFileObj.path = file.toNativeURL()
to get the file-path. If I put this path into a img-tag I get shown the picture on Android.
On iOS it doesn't work. The result of file.toNativeURL():
myFileObj.path -> file:///Users/.../Library/Application%20Support/..../myFolder/myImage.JPG
Using file 1.0 I had to build the url and it looked like this:
myFileObj.path = dirTarget.toURL() + '/' + targetFileName
myFileObj.path -> cdvfile://localhost/persisten/myFolder/myImage.JPG
Where videos and audios didn't work, but at least pictures.
Using file 1.1.0/1.1.1 the result of this method is different too:
myFileObj.path -> file:///Users/mak/Library/.../myFolder/myImage.JPG?id=.....&ext=JPG
This doesn't work on iOS either.
How can I get a working file-path by using cordova file-module version 1.1.0 and 1.1.1?
EDIT: What am I doing and what doesn't work:
I copy images from the media-library and put it into a folder I create myself.
What works in Android and doesn't work in iOS:
In Android the media-tags src attribute is able to display the resource, iOS can't find a resource at the src-path.
catching a file from the media-library:
navigator.camera.getPicture(onSuccess, onFail, {
destinationType: Camera.DestinationType.NATIVE_URI,
sourceType : Camera.PictureSourceType.PHOTOLIBRARY,
mediaType: Camera.MediaType.ALLMEDIA
});
success-callback:
function onSuccess(imageData) {
A.StoreFile(imageData, id);
}
create a folder and store file:
A.StoreFile = function(file, idBox) {
var targetDirectory = Config.getRootPath();
window.resolveLocalFileSystemURL(file, resolveFileSystemSuccess, resolveFileSystemError);
function resolveFileSystemSuccess(fileEntry) {
fileEntry.file(function(filee) {
mimeType = filee.type;
getFileSuccess(fileEntry, mimeType);
}, function() {
});
}
function getFileSuccess(fileEntry, mimeType) {
var targetFileName = name + '.' + fileNativeType;
var parentName = targetDirectory.substring(targetDirectory.lastIndexOf('/')+1),
parentEntry = new DirectoryEntry(parentName, targetDirectory);
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function(fileSystem) {
fileSystem.root.getDirectory(targetDirectory, {create: true, exclusive: false}, function(dirTarget) {
fileEntry.copyTo(dirTarget, targetFileName, function(entry) {
addFileToLocalStorage(entry);
}, function() {
})
})
}, resolveFileSystemError);
}
store file-information to a localStorageObject
function addFileToLocalStorage(file) {
fileList.addFile(
{
name:file.name,
internalURL: file.toNativeURL()
});
}
adding files dynamically to the dom:
myElement.find('.myMimeTypeTag').attr('src', fileList[f].internalURL);
This works with android, and not with iOS.
iOS-result of img-container:
Error-message:
DEPRECATED: Update your code to use 'toURL'
toURL doesn't work either
id="org.apache.cordova.file"
version="1.1.1-dev"
I've just tested this out, with a slightly simplified version of your code (you seem to have a lot of extra structure to your code that isn't shown, but if there's a significant difference between what I've done here and what your app does, then let me know. The problem will be in the difference.)
I've run this with Cordova 3.5.0, just released, using File 1.1.0 and Camera 0.2.9.
To create the app, I used the cordova command line tool, and just ran
cordova create so23801369 com.example.so23801369 so23801369
cd so23801369
cordova platform add ios
cordova plugin add org.apache.cordova.file
cordova plugin add org.apache.cordova.camera
This creates a default "Hello, Cordova" app, to which I've added some code that (I believe) replicates what your code does.
I added two lines to index.html:
<button id="doit">Do it</button>
<img class="myMimeTypeTag" src="file:///nothing" />
And I edited www/js/index.js to look like this:
var app = {
initialize: function() {
// Don't activate the button until Cordova is initialized
document.addEventListener('deviceready', this.onDeviceReady, false);
},
onDeviceReady: function() {
document.getElementById('doit').addEventListener('click', app.runTest, false);
},
runTest: function(ev) {
var StoreFile = function(file) {
var targetDirectory = "myFolder";
window.resolveLocalFileSystemURL(file, resolveFileSystemSuccess, resolveFileSystemError);
function resolveFileSystemSuccess(fileEntry) {
console.log("resolveLocalFileSystemURL returned: ", fileEntry.toURL());
fileEntry.file(function(filee) {
mimeType = filee.type;
getFileSuccess(fileEntry, mimeType);
}, function() {
});
}
function resolveFileSystemError() {
console.log("resolveFileSystemError: FAIL");
console.log(arguments);
alert("FAIL");
}
function getFileSuccess(fileEntry, mimeType) {
var targetFileName = "myImage.JPG";
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function(fileSystem) {
fileSystem.root.getDirectory(targetDirectory, {create: true, exclusive: false}, function(dirTarget) {
fileEntry.copyTo(dirTarget, targetFileName, function(entry) {
console.log("copyTo returned: ", entry.toURL());
// I have replaced the localstorage handling with this code
// addFileToLocalStorage(entry);
var img = document.querySelector('.myMimeTypeTag');
img.setAttribute('src', entry.toNativeURL());
}, function() {
});
});
}, resolveFileSystemError);
}
};
var onSuccess = function(imageData) {
console.log("getPicture returned: ", imageData);
StoreFile(imageData);
};
var onFail = function() {
console.log("getPicture FAIL");
console.log(arguments);
alert("FAIL");
};
ev.preventDefault();
ev.stopPropagation();
navigator.camera.getPicture(onSuccess, onFail, {
destinationType: Camera.DestinationType.NATIVE_URI,
sourceType : Camera.PictureSourceType.PHOTOLIBRARY,
mediaType: Camera.MediaType.ALLMEDIA
});
}
};
When I run this, I can pick an image from the media library, and it successfully displays it in the page, with the image src set to the URL of the copied image file. If I connect Safari dev tools to the iPad, I see this console output:
[Log] getPicture returned: assets-library://asset/asset.JPG?id=F9B8C942-367E-433A-9A71-40C5F2806A74&ext=JPG (index.js, line 49)
[Log] resolveLocalFileSystemURL returned: cdvfile://localhost/assets-library/asset/asset.JPG?id=F9B8C942-367E-433A-9A71-40C5F2806A74&ext=JPG (index.js, line 18)
[Log] copyTo returned: file:///var/mobile/Applications/9C838867-30BE-4703-945F-C9DD48AB4D64/Documents/myFolder/myImage.JPG (index.js, line 36)
[Log] DEPRECATED: Update your code to use 'toURL' (Entry.js, line 202)
This shows the camera and file plugins going through three different types of URL:
Camera returns an assets-library:// URL, with query parameters to identify the asset
calling resolveLocalFileSystemURL on that turns it into a cdvfile:// URL, also with query paramaters, as an internal Cordova representation.
After being copied, File returns a new file:/// URL showing the image's new place on the filesystem. This URL has no query parameters. (Calling toNativeURL() on this entry returns the same URL now, as of File 1.1.0)
This final URL is usable by iOS as an image source, and so that's what gets assigned to the <img> element.
The problem was, that the new file-plugin has to be case-sensitve.
I created a folder with capital letters and refered the copy-instruction to a folder with lowercase letters. The point is that android is case insensitive and ios is not.
This came out with the new file-plugin where the output was case sensitive.
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