I have been struggling for a few days with taking a photo with the phone camera, using Ionic and Android device, and sending it to the server in a post request. Optionally, I want to display the image to the screen.
I read a lot of previous posts with similar problems, but none of the solutions worked for me. I want to mention that I am quite new to the ionic world, so I am still learning. Maybe it is a stupid problem that I cannot see.
Before adding the code that I tried, I want to list the things that I have tried so far:
Used FILE_URL and DATA_URL for the destinationType option
Manually convert the image to base 64
Used domSanitizer.bypassSecurityTrustUrl(b64img) in the .html file
Please, see below the code that I tried:
This is the code for taking the photo:
const options: CameraOptions = { // photo options
quality: 50,
destinationType: this.camera.DestinationType.DATA_URL,
encodingType: this.camera.EncodingType.JPEG,
mediaType: this.camera.MediaType.PICTURE,
} // take picture
this.camera.getPicture(options).then((imageData) => {
this.imageData = imageData;
this.image = ( < any > window).Ionic.WebView.convertFileSrc(imageData);
//extra http://localhost/file.. and I slice it to remove extra chars
this.image = this.image.slice(27);
},
(err) => {
this.helperService.showAlert(JSON.stringify(err));
});
This is the code for uploading the photo to the server:
upload() { // upload method
let url = 'url/to/post';
const date = new Date().valueOf();
const imageName = date + '.jpeg';
console.log(this.imageData);
-- - > undefined
//slice it to remove extra chars
this.imageData = this.imageData.slice(27);
const imageBlob = this.dataURItoBlob(this.imageData);
const imageFile = new File([imageBlob], imageName, {
type: 'image/jpeg'
});
let postData = new FormData();
postData.append('file', imageFile);
let data: Observable < any > = this.httpClient.post(url, postData);
data.subscribe((result) => {
this.helperService.showSuccess(result);
});
}
And this is the blob function:
dataURItoBlob(dataURI) {
const byteString = window.atob(dataURI);
const arrayBuffer = new ArrayBuffer(byteString.length);
const int8Array = new Uint8Array(arrayBuffer);
for (let i = 0; i < byteString.length; i++) {
int8Array[i] = byteString.charCodeAt(i);
}
const blob = new Blob([int8Array], {
type: 'image/jpeg'
});
return blob;
}
This is my HTML file:
<ion-content>
<ion-grid>
<img [src]="DomSanitizer.bypassSecurityTrustUrl(image)">
</ion-grid>
<ion-button (click)="upload()" color="success">
<ion-icon slot="icon-only" name="checkmark"></ion-icon>
</ion-button>
</ion-content>
Problems:
The photo is not displayed on the screen and my image is Undefined - I tried both with and without DomSanitizer
this.imageData is undefined inside the upload() method
This is the reference post that I followed, but I cannot manage to see the problems:
Capture and upload image to server using Ionic 4
Looking at this reference post, I sliced even the extra characters displayed in front of the image, but I did not manage to solve the problems.
Let me know if I should add any other information. Thank you for your help!
I manage to display the image on the screen by using:
let b64 = 'data:image/jpeg;base64,' + imageData;
this.image = b64;
instead of
this.image = (<any>window).Ionic.WebView.convertFileSrc(imageData);
Unfortunately, this.imageData is still undefined, and I cannot figure out why.
Update: Looks like the photo is sent to bakend now, but its size is 0 and backend (which is Nodejs) cannot use it. What should I do? Should I parse it in some way?
Thank you!
Related
I have an IONIC 5 + capacitor + Angular 9 APP which does load an array of images from the server. It does load the image one by one. Each image component calls a document service which returns the Blob downloaded from the server:
this.documentService.download(fileDocumentDownloadRequest)
.subscribe((r: Blob) => {
if (r) {
const reader = new FileReader();
reader.onloadend = () => {
this.loading = false;
this.imageSrc = reader.result;
};
reader.readAsDataURL(r);
} else {
this.loading = false;
}
},
async e => {
console.log('Error loading image', e);
},
() => {
this.loading = false;
});
All works fine however if I have 2 images (the HTML displays the images in a 2-col grid display) it does not work as in the images get downloaded however they don't get rendered.
If I have multiple images, let's say 8, they get rendered except the last one. I played around in the UI and as soon as I click somewhere the last image gets rendered. What I did then was adding the changeDetectorRef.detectChanges() call inside the onloadend event. That works but I'm sure that's not the way of doing it.
The HTML I have for this:
<div class="w-100 h-125px"
(click)="imageSelected = !imageSelected; showImageActions()"
[ngClass]="{'border-yellow': imageSelected}">
<div class="position-absolute w-100 h-100 background-light-gray"></div>
<ion-img *ngIf="!loading && imageSrc"
[src]="imageSrc"
class="position-relative z-index-plus-1 w-100 h-100 object-fit-cover">
</ion-img>
<ng-container *ngIf="loading">
<div class="position-absolute content-centered-middle">
<ion-spinner></ion-spinner>
</div>
</ng-container>
</div>
I have tried both the onload event as well as the onloadend event. With both I get the exact same result.
By the way, I could not use the standard new FileReader() constructor to get the file reader to work on the Android device. Reading various posts I found a solution that worked:
private getFileReader(): FileReader {
const fileReader = new FileReader();
const zoneOriginalInstance = (fileReader as any)['__zone_symbol__originalInstance'];
return zoneOriginalInstance || fileReader;
}
So my question is whether this is an actual bug on IONIC or the file reader events should be handled differently - I'm fairly new in mobile development and would like to understand why this is happening.
Many thanks!
I understand that Android automatically creates a thumbnail, for every picture taken by the camera. I need to be able to display that thumbnail.
I'm using nativescript-imagepicker plugin to select images. The plugin returns only the size and src of the selected image(s), for instance:
'/storage/emulated/0/DCIM/DSCF2060.jpg'
How could i use this src, to retrieve the corresponding thumbnail(is it even possible?).
The Android API is very confusing for me(not to mention the Java), so any help will be greatly appreciated.
Use ThumbnailUtils
export function onGetImageButtonTap(args) {
let context = imagepicker.create({
mode: "single"
});
context
.authorize()
.then(function () {
return context.present();
})
.then(function (selection) {
selection.forEach(function (selected) {
const size = layout.toDevicePixels(96);
const bitmap = android.media.ThumbnailUtils.extractThumbnail(android.graphics.BitmapFactory.decodeFile(selected.android),
size, size);
args.object.page.getViewById("thumbnailImg").src = fromNativeSource(bitmap);
});
}).catch(function (e) {
console.log(e)
});
}
Playground Sample
Iam new in ionic with sharepoint
I have developed a Mobile app using ionic3 with sharepoint.
Now i have to get user profile picture in my app.
I have tried these are the way can't achieve here is my tried code.
First way tried like this
Passing Url:-
"https://abc.sharepoint.com/sites/QA/_layouts/15/userphoto.aspx?size=M&accountname=admin#abc.onmicrosoft.com"
Second way tried like this
Passing Url:-
These url iam geting using people picker result. PictureURL property
"https://abc.sharepoint.com/User Photos/Profile Pictures/admin_abc_onmicrosoft_com_MThumb.jpg"
These Second method always return
401 UNAUTHORIZED
Above url using to call this method.
public downloadFile(url: string, fileName: string) {
let options = this._apiHeaderForImageURL();
this._http.get(url, options)
.subscribe((data) => {
//here converting a blob to base 64 For internal view purpose in image src
var reader = new FileReader();
reader.readAsDataURL(data.blob());
reader.onloadend = function () {
console.log("Base64", reader.result);
}
//Here Writing a blob file to storage
this.file.writeFile(this.file.externalRootDirectory, fileName, data.blob(), { replace: true })
.then((success) => {
console.log("File Writed Successfully", success);
}).catch((err) => {
console.log("Error While Wrinting File", err);
});
});
}
public _apiHeaderForImageURL() {
let headers = new Headers({ 'Content-Type': 'image/jpeg' });
headers.append('Authorization', 'Bearer ' + localStorage.getItem("token"));
let options = new RequestOptions({ headers: headers, responseType: 3 });
return options;
}
The first api call worked fine result also sucess but image not displayed properly. Thats the problem iam facing.
The result comes an default image like this only.
pls help me to achieve this. Any help warmly accepted.
Iam doning long time stuff to achieve this still i cant achieve pls give some idea.
Is any other way is available to get user picture in ionic 3 using sharepoint?
Need little help on cordovaSocialShare plugin
I'm trying to share an image via Whatsapp which was selected in my ionic app but i'm not able to share the image
<form name = myForm controller="ExampleController" ng-
submit="ShareAnywhere(myForm)">
<div class="myDivClass">
<input type="file" ng-model="share.shareImage">
<button ng-click="Submitted=true">Share</button>
</div>
<form>
and below goes my controller
app.controller('ExampleController',function($scope, $cordovaSocialSharing, $filter){
$scope.shareAnywhere=function(myForm){
var eDate = new Date();
var message = "Hi! this is an wahtsapp msg";
var image = this.share.shareImage;
var link = 'http://myAwsomeWebsite.com';
var subject = 'My Subject';
$cordovaSocialSharing.share(message, subject, image, link);
}
});
I'm able to share the text but it wouldn't add image with it
I might be doing it completely wrong please let me know what is the correct way to do it thanks in advance
For capturing the image on click of button added at HTML file:
takePicture(){
Camera.getPicture({
destinationType: Camera.DestinationType.DATA_URL,
targetWidth: 1000,
targetHeight: 1000
}).then((imageData) => {
// imageData is a base64 encoded string
this.base64Image = "data:image/jpeg;base64," + imageData;
}, (err) => {
console.log(err);
});
}
sharePicture(){
// Share via whatsapp
this.socialSharing.shareViaWhatsApp(this.message,this.base64Image,this.url).then(() => {
// Success!
}).catch(() => {
// Error!
});
}
Just declare the message, image and url as string.
the parameter image should be a path(URL) to the Image. and not the Image data.
I'd like to send pictures, from my app (iOS and Android) to my server. My code works with small pictures, but if the size is too big, when I send the data, nothing happens and the application slows down.
Could you explain me the problems in my code and how to resolve it ? Thanks a lot :)
Here is my code :
var attached_media = [];
var file_btn = Ti.UI.createButton({ title: L('select') });
file_btn.addEventListener('click',function(e){
Titanium.Media.showCamera({
success:function(e) {
if(e.mediaType == Ti.Media.MEDIA_TYPE_PHOTO) {
attached_media.push(Ti.Utils.base64encode(e.media).text);
}
},
saveToPhotoGallery:true,
allowEditing: false,
mediaTypes: [Ti.Media.MEDIA_TYPE_PHOTO]
});
});
var send_button = Titanium.UI.createButton({
title: 'Send',
});
send_button.addEventListener('click',function(e){
var req = ......
req.send({ 'medias':JSON.stringify(attached_media), 'user_id':Ti.App.Properties.getInt('user_id')});
});
I removed the unnecessary code, because it was too long ! :)
What I was able to understand from the provided info is that you are having problems while uploading large size pics, like the one from camera which turns out to be more than 2-3MB.
The only solution at present I can suggest you is to compress the image using this iOS-Android module Ti-ImageFactory before saving or sending it to server.
I recommend to compress the image right after you captured it in Camera's success callback like this:
file_btn.addEventListener('click',function(e){
Titanium.Media.showCamera({
success:function(e) {
if(e.mediaType == Ti.Media.MEDIA_TYPE_PHOTO) {
Ti.API.info("Initial pic bytes = " + e.media.length);
// if bytes length of pic is larger than 3MB or 3145728 bytes, set compression to 0.5,
// else keep it to default which is 0.7
var imf = require('ti.imagefactory');
var compressedPic = (e.media.length > 3145728) ? imf.compress(0.5) : imf.compress();
attached_media.push(Ti.Utils.base64encode(compressedPic).text);
Ti.API.info("Compressed pic bytes = " + compressedPic.length);
compressedPic = null;
}
},
saveToPhotoGallery:true,
allowEditing: false,
mediaTypes: [Ti.Media.MEDIA_TYPE_PHOTO]
});
});
Added Code - If captured picture size is more than 3MB, then compress it by 0.5 level, else compress it using default level 0.7. Also checking the initial pic size & compressed pic size to match better results as per app's requirements for faster uploading.
You can also pass a compression level in compress() method. See docs for more.