Cordova android URL.createObjectURL(blob) not working - android

I am building a cordova application and I need to retrieve a blob from an image file and use that as the src of an img tag. Right now the image is stored locally, but will be pulled from a database in the future. Everything is working as expected, but the source of the image is not being set when I use URL.createObjectURL(blob), it seems the url is corrupt.
Here is my code:
takePicture() {
// eslint-disable-next-line no-undef
const srcType = Camera.PictureSourceType.CAMERA;
const options = {
// Some common settings are 20, 50, and 100
quality: 10,
// eslint-disable-next-line no-undef
destinationType: Camera.DestinationType.FILE_URI,
// In this app, dynamically set the picture source, Camera or photo gallery
sourceType: srcType,
// eslint-disable-next-line no-undef
encodingType: Camera.EncodingType.PNG,
// eslint-disable-next-line no-undef
mediaType: Camera.MediaType.PICTURE,
allowEdit: true,
correctOrientation: true, //Corrects Android orientation quirks
};
navigator.camera.getPicture(
function cameraSuccess(imageUri) {
window.resolveLocalFileSystemURL(
imageUri,
function success(fileEntry) {
fileEntry.file(
function(file) {
const reader = new FileReader();
reader.onloadend = function() {
const blob = new Blob([new Uint8Array(this.result)], { type: 'image/png' });
const elem = document.getElementById('img');
elem.src = URL.createObjectURL(blob);
};
reader.readAsArrayBuffer(file);
},
function(e) {
alert(e);
}
);
},
function() {}
);
},
function cameraError(error) {
alert('Unable to obtain picture: ' + error, 'app');
},
options
);
If I remove this line of code: elem.src = URL.createObjectURL(blob);
And replace it with this: elem.src = imageUri;
Everything works fine, so I know the image is being saved correctly. Is it possible that the image is to large, and therefore being rejected?
                            

OK, after doing some more troubleshooting, I figured out the problem was the tag was missing the img-src directive. To fix this I simply added img-src '*' data: blob: ; to the tag, and everything is working.
Note: Just adding '*' did not work. I also had to add blob: as well

Related

How do i upload a photo from the Android camera with FormData on Ionic / Angular

I'm currently developing a Android app where the user can take his or hers picture and upload it to a PATCH API endpoint that would listen to the key 'avatar'.
I'm using the Cordova Camera and the Advanced HTTP plugin to handle it.
Below is the function that triggers when taking a photo.
takePicture() {
const options: CameraOptions = {
quality: 50,
destinationType: this.camera.DestinationType.FILE_URI,
encodingType: this.camera.EncodingType.JPEG,
mediaType: this.camera.MediaType.PICTURE,
correctOrientation: true, // Corrects Android orientation quirks
allowEdit: false, // Post process aanpassingen
sourceType: this.camera.PictureSourceType.CAMERA // Pak de selfie camera
};
this.camera.getPicture(options).then((imageData) => {
const formData = new FormData();
formData.append('avatar', imageData, 'pic.jpg');
this.web.updateUserInfo(formData).subscribe(() => {});
}, (err) => {
console.error('Camera Error: ' + err);
});
}
Here is the API handling
updateUserInfo(newData: any) {
return new Observable((obs) => {
this.http2.patch('localhost/user', {newData}, {
'X-Subdomain': 'host',
'X-Token': this.apiKey,
}).then(() => {console.log('Camera API success!'); obs.next(); }).catch(error => {
console.error(error);
});
});
}
No errors are being given out so it is hard for me to see where the issue is. I have little experience working with Cordova and Ionic so this is all new to me.
Problem is destinationType: this.camera.DestinationType.FILE_URI,
you are sending, file url over http and not the base64 of image
Change your destination type:
destinationType: this.camera.DestinationType.DATA_URL,
DATA_URL Return base64 encoded string. DATA_URL can be very memory intensive and cause app crashes or out of memory errors. Use FILE_URI or NATIVE_URI if possible
UPDATE
In this video you can check how to send base64 to api as File
https://www.youtube.com/watch?v=tph5Nk4Ab1g

Ionic 4 - Native camera plugin issues

I have developed an android application using Ionic4. I am facing some issues with Ionic Native Camera plugin. The following is my code. The issues that i am facing is given below. The version if camera plugin i am using is "#ionic-native/camera": "^5.3.0",.
Issues
Gallery is not opening
Captured image is not returning.
Application crashes after taking picture
html
<img [src]="studentImage!==null ? studentImage: 'assets/icon/ic_avatar.png'" class="add-picture" (click)="addImage()">
.ts
public addImage() {
this.genericServices.presentActionSheet(this.openGallery, this.openCamera);
}
private openCamera = () => {
this.studentImage = this.genericServices.selectPicture('camera');
console.log('Captured Image:=>' + this.studentImage);
}
private openGallery() {
this.studentImage = this.genericServices.selectPicture('gallery');
}
service
public async selectPicture(source) {
let base64Image = null;
const cameraOptions: CameraOptions = {
quality: 75,
destinationType: this.camera.DestinationType.DATA_URL,
encodingType: this.camera.EncodingType.PNG,
mediaType: this.camera.MediaType.PICTURE,
sourceType: source === 'camera' ? this.camera.PictureSourceType.CAMERA : this.camera.PictureSourceType.PHOTOLIBRARY,
correctOrientation: true
};
await this.camera.getPicture(cameraOptions).then((imageData) => {
console.log('Returned Image=>' + base64Image);
return base64Image = 'data:image/jpeg;base64,' + imageData;
}).catch(() => {
});
}
Hard to say what your problem is. I would probably write the code slightly different, like this:
async selectImage() {
const actionSheet = await this.actionCtrl.create({
header: "Select Image source",
buttons: [{
text: 'Load from Library',
handler: () => {
this.takePicture(this.camera.PictureSourceType.PHOTOLIBRARY);
}
},
{
text: 'Use Camera',
handler: () => {
this.takePicture(this.camera.PictureSourceType.CAMERA);
}
},
{
text: 'Cancel',
role: 'cancel'
}
]
});
await actionSheet.present();
}
And then in the takePicture() method decide what destinationType should be, default is FILE_URI (1).
takePicture(sourceType: PictureSourceType) {
var options: CameraOptions = {
quality: 80,
sourceType: sourceType,
saveToPhotoAlbum: false,
correctOrientation: true,
destinationType: 1,
targetWidth: 1240,
targetHeight: 768,
};
this.camera.getPicture(options)
.then((imageData) => {
// do something with the imageData, should be able to bind it to a variable and
// show it in your html file. You might need to fix file path,
// remember to import private win: any = window, and use it like this.
this.imagePreview = this.win.Ionic.WebView.convertFileSrc(imageData);
}).catch((err) => {
console.warn("takePicture Error: " + err);
});
}
This should work fine... i just tested it. But as i said, there could be several things wrong with your setup. Hope it helps in one way or another... otherwise create a fiddle, and i will gladly look at the code for you.

Not allowed to load local resource: ionic 3 android

I am using ionic 3 android build apk and trying to laod image from file:///storage/emulated/0/data/io.ionic.vdeovalet/cache/image.jpeg
takePicture(sourceType) {
try {
// Create options for the Camera Dialog
var options = {
quality: 100,
destinationType: this.camera.DestinationType.FILE_URI,
encodingType: this.camera.EncodingType.JPEG,
sourceType: sourceType,
};
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());
this.lastImage = filePath;
});
} else {
var currentName = imagePath.substr(imagePath.lastIndexOf('/') + 1);
var correctPath = imagePath.substr(0, imagePath.lastIndexOf('/') + 1);
this.copyFileToLocalDir(correctPath, currentName, this.createFileName());
}
}, (err) => {
this.presentToast('Error while selecting image.');
});
} catch (e) {
console.error(e);
}
}
Error: Not allowed to load local resource
android 6.0.1
No Need To Downgrade just write this code.
private win: any = window;
this.win.Ionic.WebView.convertFileSrc(path);
I had the same issues and it turns out that
The new ionic webview plugin is the cause for the problem.
The new plugin: cordova-plugin-ionic-webview # 2.x seem unstable...
to get it working downgraded back to cordova-plugin-ionic-webview#1.2.1 and all should work
Steps:
1. uninstall webview
ionic cordova plugins rm cordova-plugin-ionic-webview
2. install old one:
ionic cordova plugins add cordova-plugin-ionic-webview#1.2.1
3. clean cordova
cordova clean android
When Ionic is used with Capacitor, we can get the correct path of an image or other resource on a native device by:
import { Capacitor } from '#capacitor/core';
Capacitor.convertFileSrc(filePath);
https://ionicframework.com/docs/core-concepts/webview
The only thing that worked for me was convertFileSrc()
let win: any = window;
let safeURL = win.Ionic.WebView.convertFileSrc(this.file.dataDirectory+'data/yourFile.png');
Hope this helps
Try This:
1) https://devdactic.com/ionic-2-images/
In this tutorial, ionic 2 & ionic 3 is the best way to upload and upload images.
2) https://devdactic.com/ionic-4-image-upload-storage/ In this tutorial, ionic 4 is the best way to upload and upload images.
i also use these... and it working fine...
And I have also faced the problem of
not allowed to load local resource
You can see here :
#ionic/angular 4.0.0-beta.13 : Not allowed to load local resource : with webview 2.2.3 - Ionic CLI 4.3.1
Try this:
const options: CameraOptions = {
quality: 10
, destinationType: this.camera.DestinationType.DATA_URL
, mediaType: this.camera.MediaType.PICTURE
// Optional , correctOrientation: true
, sourceType: sourceType == 0 ? this.camera.PictureSourceType.CAMERA : this.camera.PictureSourceType.PHOTOLIBRARY
// Optional , saveToPhotoAlbum: true
};
this.camera.getPicture(options).then(imageBase64 => {
let txtForImage = `data:image/jpeg;base64,` + imageBase64;
this.imageToLoad = txtForImage;
})
.catch(error => {
alert("Error: " + error);
console.error(error);
});
Copy this line into your index.html
<meta http-equiv="Content-Security-Policy" content="default-src *;
style-src 'self' 'unsafe-inline';
script-src 'self' 'unsafe-inline' 'unsafe-eval';
img-src 'self' data: https://s-media-cache-ak0.pinimg.com;
script-src 'self' https://maps.googleapis.com;" />
Then, write this function instead of your one, note that what this script does is returning the photo as base64
getImageFromCamera() {
const options: CameraOptions = {
quality: 20,
saveToPhotoAlbum: true,
destinationType: this.camera.DestinationType.FILE_URI,
sourceType: this.camera.PictureSourceType.CAMERA,
encodingType: this.camera.EncodingType.JPEG,
allowEdit: false
};
this.camera.getPicture(options).then((imageData) => {
this.imageURI = imageData;
this.imageName = imageData.substr(imageData.lastIndexOf('/') + 1);
// Create a folder in memory location
this.file.checkDir(this.file.externalRootDirectory, 'Demo')
.then(() => {
this.fileCreated = true;
}, (err) => {
console.log("checkDir: Error");
this.presentToast("checkDir Failed");
});
if (this.fileCreated) {
this.presentToast("Directory Already exist");
}
else {
this.file.createDir(this.file.externalRootDirectory, "Demo", true)
.then((res) => {
this.presentToast("Directory Created");
}, (err) => {
console.log("Directory Creation Error:");
});
}
//FILE MOVE CODE
let tempPath = this.imageURI.substr(0, this.imageURI.lastIndexOf('/') + 1);
let androidPath = this.file.externalRootDirectory + '/Bexel/';
this.imageString = androidPath + this.imageName;
this.file.moveFile(tempPath, this.imageName, androidPath, this.imageName)
.then((res) => {
this.presentToast("Image Saved Successfully");
this.readImage(this.imageString);
}, (err) => {
console.log("Image Copy Failed");
this.presentToast("Image Copy Failed");
});
//Complete File Move Code
this.toDataURL(this.imageURI, function (dataUrl) {
console.log('RESULT:' + dataUrl);
});
}, (err) => {
console.log(JSON.stringify(err));
this.presentToast(JSON.stringify(err));
});
}
presentToast(msg) {
let toast = this.toastCtrl.create({
message: msg,
duration: 2000
});
toast.present();
}
toDataURL(url, callback) {
let xhr = new XMLHttpRequest();
xhr.onload = function () {
let reader = new FileReader();
reader.onloadend = function () {
callback(reader.result);
};
reader.readAsDataURL(xhr.response);
};
xhr.open('GET', url);
xhr.responseType = 'blob';
xhr.send();
}
readImage(filePath) {
let tempPath = filePath.substr(0, filePath.lastIndexOf('/') + 1);
let imageName = filePath.substr(filePath.lastIndexOf('/') + 1);
this.file.readAsDataURL(tempPath, imageName)
.then((res) => {
this.presentToast("Image Get Done");
this.imageUrl = res;
}, (err) => {
this.presentToast("Image Get Error");
});
}
It sees like it's an issue with content CSP (content security policy), the meta tag should fix this issue, then the code will read the photo as base64, then here you go, in HTML:
<img [src]="imageUrl">
And you can modify the function to remove unnecessary console.log, i was just testing.
All I had to do was use the proper Imagepicker Options, the output type did it:
const options: ImagePickerOptions = {
maximumImagesCount: 1,
outputType: 1,
quality: 50
};
let win: any = window; // hack ionic/angular compilator
var myURL = win.Ionic.WebView.convertFileSrc(myURL);

Angular and Ionic Camera function wont save photo

I have an app to take photos and upload them when the user synchronises their app. However, it keeps giving me errors after I take the photo and doesnt save it at all to phone.
Here is my code:
(function () {
'use strict';
var serviceId = 'camera';
angular.module('app').service(serviceId, ['$cordovaCamera', '$cordovaFile', '$q', function ($cordovaCamera, $cordovaFile, $q) {
this.takePhoto = function () {
if (window.Camera) {
var options = {
quality: 75,
destinationType: Camera.DestinationType.FILE_URI,
sourceType: Camera.PictureSourceType.CAMERA,
allowEdit: false,
encodingType: Camera.EncodingType.JPEG,
targetWidth: 800,
targetHeight: 800,
saveToPhotoAlbum: true,
correctOrientation: true
};
return $cordovaCamera.getPicture(options).then(function (imageData) {
console.log("Photo Success: " + imageData);
return imageData;
}, function (err) {
console.error("Error taking photo: " + JSON.stringify(err));
throw err;
});
} else {
var deferred = $q.defer();
deferred.resolve("/img/sunrise.jpg");
return deferred.promise;
}
}
}]);
})();
What am I doing wrong here?
First make sure that you include the Camera and File plugins in your project.If not please add this two plugins,
cordova plugin add org.apache.cordova.camera
and
cordova plugin add org.apache.cordova.file
I have made small example for you.Here I am using Ionic’s ngCordova to implement the Camera functionality,.
Conroller
$scope.photoSave = function() {
if (window.cordova) {
var options = {
quality: 100,
destinationType: Camera.DestinationType.FILE_URI,
sourceType: Camera.PictureSourceType.CAMERA,
encodingType: Camera.EncodingType.JPEG,
cameraDirection: 1,
saveToPhotoAlbum: true
};
$cordovaCamera.getPicture(options).then(function(imagePath) {
$scope.imgURI = imagePath;
//Grab the file name of the photo in the temporary directory
var currentName = imagePath.replace(/^.*[\\\/]/, '');
//Create a new name for the photo
var d = new Date(),
n = d.getTime(),
newFileName = n + ".jpg";
//Move the file to permanent storage
$cordovaFile.moveFile(cordova.file.tempDirectory, currentName, cordova.file.dataDirectory, newFileName).then(function(success) {
//success.nativeURL will contain the path to the photo in permanent storage, do whatever you wish with it, e.g:
//createPhoto(success.nativeURL);
}, function(error) {
//an error occured
});
}, function(error) {
//An error occured
});
}
};
HTML
<ion-view>
<ion-content>
<button ng-click="photoSave()">Capture</button>
</ion-content>
</ion-view>
Refer

Ionic / Cordova : Upload image from phone's gallery

I would like the user to be able to either take a picture or select an image from his phone's gallery.
I successfully manage to take a picture and get the imageURI.
I'm using Genymotion as emulator since i need to access to some functionalities such as camera. I know there are some other solutions. It is a little bit hard to debug while emulating but this is the only way i found to access to the camera for now. Therefor i can't see what is going on on the second part (Select an image from Gallery).
$scope.uploadPopup = function() {
var uploadPopup = $ionicPopup.show({
title: "Edit profile's picture",
templateUrl: 'templates/partials/upload-img.html',
buttons: [
{
text: '',
type: 'button-energized icon-center ion-ios7-camera',
onTap: function(e) {
// e.preventDefault() will stop the popup from closing when tapped.
e.preventDefault();
alert('Getting camera');
Camera.getPicture({
quality: 100,
saveToPhotoAlbum: false
}).then(function(imageURI) {
alert(imageURI);
$scope.lastPhoto = imageURI;
}, function(err) {
alert(err);
});
}
},
{
text: 'From gallery',
type: 'button',
onTap: function(e) {
e.preventDefault();
alert('Getting gallery');
Camera.getPicture({
quality: 100,
sourceType: Camera.PictureSourceType.PHOTOLIBRARY
}).then(function(imageURI) {
alert(imageURI);
$scope.lastPhoto = imageURI;
}, function(err) {
alert(err);
});
}
}
]
});
};
Service :
app.factory('Camera', ['$q', function($q) {
return {
getPicture: function(options) {
var q = $q.defer();
navigator.camera.getPicture(function(result) {
// Do any magic you need
q.resolve(result);
}, function(err) {
q.reject(err);
}, options);
return q.promise;
}
}
}]);
Is it the correct way to do? Any hints or ideas?
UPDATE :
When i add :
sourceType: Camera.PictureSourceType.CAMERA
to the first function (take a picture from camera). It does not work any more. While without (using the default one probably) it does work.
When i added the sourceType instead of using the default sourceType(CAMERA)
sourceType: Camera.PictureSourceType.CAMERA
It was not working anymore so i guessed something was wrong here.
The correct syntax is :
navigator.camera.PictureSourceType.CAMERA
OR (with different option) :
navigator.camera.PictureSourceType.PHOTOLIBRARY
Not sure why "navigator.camera" and not "Camera", i'm guessing "Camera" is an alias of "navigator.camera".
I think your code is on the right track, like you said it is hard to tell without being able to test it on a device. So i can help you there. go grab the intel xdk https://software.intel.com/en-us/html5/tools. import your ionic project, then make an account. after you log in go to the test tab and push your app to a test server. Then install the intel app preview on your phone/tablet (is on android and ios). open the app, log in, and hit server apps at the bottom, you will see your app and be able to run it on your phone. You can also use the intel xdk to run an app on your phone with live debugging. Hope this helps! cheers!
Here is the code for my ngCordova plugin:
//opens up the phones camera in order to take a picture
//requires module ngCordova and the method $cordovaCamera
//sets Data.Image to a base 64 string
$scope.takePhoto = function () {
document.addEventListener("deviceready", function () {
var options = {
quality: 100,
destinationType: Camera.DestinationType.DATA_URL,
sourceType: Camera.PictureSourceType.CAMERA,
allowEdit: false,
encodingType: Camera.EncodingType.PNG,
targetWidth: 800,
targetHeight: 1100,
popoverOptions: CameraPopoverOptions,
saveToPhotoAlbum: false
};
$cordovaCamera.getPicture(options).then(function (imageData) {
$scope.image = "data:image/png;base64," + imageData;
}, function (err) {
// error
});
}, false);
};

Categories

Resources