Titanium - Send picture to server : file size bug - android

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.

Related

Ionic Android: Take camera photo and send it to the server

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!

Copying camera image in phonegap/cordova not working

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,
});
}

streaming video with peerjs webrtc from android webview is too slow

I have an android application that sends the camera stream through a webview through peerjs (webrtc) the web application on the browser receives the video and streams it.
Things are working but the video on the web is too slow and the image freezes for some time before getting the second image...
Is there a way to make the resolution lower ? or buffer the video on the web application ? or can it be something wrong with my implementation ?
Android Webview code:
initVideo = function(videoSourceValue) {
var video = document.querySelector('video');
navigator.getUserMedia({video: {optional: [{
sourceId: videoSourceValue
}]
}
},function(stream) {
video.src = window.URL.createObjectURL(stream);
$('#peerId').text("calling : " + SERVER_PEER_ID);
var mediaConnection = peer.call(SERVER_PEER_ID, stream);
mediaConnection.on('stream', function(remoteStream) {
// Show stream in some video/canvas element.
});
},function(e){
console.log('failed',e);
});
}
Web part:
function getVideoStream() {
PEER.on('call', function(call) {
var mediaConnection = navigator.getUserMedia({video: true}, function(stream) {
call.answer(stream); // Answer the call with an A/V stream.
call.on('stream', onReceiveStream);
}, function(err) {
console.log('Failed to get local stream' ,err);
});
});
}
function onReceiveStream(stream){
console.log('received stream');
$('video').prop('src',window.URL.createObjectURL(stream));
}
Thanks
Update 1
I tried to add {reliable : true}, still having the same issue.
I'm also sending location data to the server, and it seems that the video streams and location data are sent together periodically (the chart on the web showing speed and the video move at the same time) but the frame rate is too slow.
When you establish the video/audio stream you can specify some constraints...
var videoOptions = (isCordova) ? {audio: true, video: true} :
{ audio: true,
video: {
mandatory: {
maxWidth: 640,
maxHeight: 360,
// maxAspectRatio:4/3,
// maxFrameRate:1
},
quality: 7,
width: { ideal: 320 },
height: { ideal: 240 }
}
};
navigator.getUserMedia(videoOptions, function (stream) {
In the above code, if you are on a device (android/ios) you don't get to choose, but you can control it on the browser. A quality of 5 is the level that the video driver author deemed as an acceptable trade off between quality and bandwidth. Limiting the dimensions of the picture helps too.
See this link for mode details: https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia
My issue was completely unrelated to bandwidth, I simply didn't put autoplay on the video tag , so the video was only refreshing when a redraw was happening.
Thanks a lot for your answers they really give insight on how things work in webrtc.

Downloading Transparent PNG's on Android using Appcelerator turns the background black

Can anyone shed any light on why, using the Image Factory module to download and store images on Android, does it ignore the transparency on PNG graphics and give them a black background?
It works fine on iOS and everything is "as is".
Do I need to add anything to the download script to retain the transparency?
Help!
Here is my download script, I'm building using Titanium 3.5.1 GA:
function getMarker(url, filename) {
// this will enable us to have multiple file sizes per device
var filename2 = filename.replace(".png", "#2x.png");
var filename3 = filename.replace(".png", "#3x.png");
var mapMarker = Ti.Filesystem.getFile(Ti.Filesystem.applicationDataDirectory, 'map_marker_icons', filename);
var mapMarker2 = Ti.Filesystem.getFile(Ti.Filesystem.applicationDataDirectory, 'map_marker_icons', filename2);
var mapMarker3 = Ti.Filesystem.getFile(Ti.Filesystem.applicationDataDirectory, 'map_marker_icons', filename3);
// now we need to download the map marker and save it into our device
var getMarker = Titanium.Network.createHTTPClient({
timeout: 30000
});
getMarker.onload = function() {
// if the file loads, then write to the filesystem
if (getMarker.status == 200) {
// resize the images into non-retina, retina and retina HD and only download and resize what is actyally required
var getOriginal = ImageFactory.imageWithAlpha(this.responseData, {});
var resized2 = ImageFactory.imageAsResized(getOriginal, {
width: 50,
height: 50
});
mapMarker.write(resized2);
Ti.API.info(filename + " Image resized");
//I ALWAYS NULL ANY PROXIES CREATED SO THAT IT CAN BE RELEASED
mapMarker = null;
} else {
Ti.API.info("Image not loaded");
}
// load the tours in next
loadNav();
};
getMarker.onerror = function(e) {
Ti.API.info('XHR Error ' + e.error);
//alert('markers data error');
};
getMarker.ondatastream = function(e) {
//Ti.API.info('Download progress: ' + e.progress);
};
// open the client
getMarker.open('GET', url);
// change the loading message
MainActInd.message = 'Downloading Markers';
// show the indicator
MainActInd.show();
// send the data
getMarker.send(); }
Any help would be much appreciated!
Simon
Please try the following code, I tried it on Android and iOS with a png Url, first I GET the photo with HTTP client request, then I save it as a file with extension png and then I read it with an ImageView.
index.js:
$.win.open();
savePng("https://cdn1.iconfinder.com/data/icons/social-media-set/29/Soundcloud-128.png");
function savePng(pngUrl) {
var client = Titanium.Network.createHTTPClient({
onload : function(e) {
var image_file = Ti.Filesystem.getFile(Titanium.Filesystem.applicationDataDirectory, "test.png");
image_file.write(this.responseData);
$.img.image = image_file.read();
},
onerror : function(e) {
alert(e.error);
},
timeout : 10000
});
client.open("GET", pngUrl);
client.send();
}
index.xml:
<Alloy>
<Window id="win" backgroundColor="gray">
<ImageView id="img" />
</Window>
</Alloy>

How to show the last captured image from the camera without code in Image view

I am new to the Titanium Android Mobile application development.
My problem is how do i load the last captured image of camera in an image view.
I have a bitton called as click in one window and I have to display that image in second window.
How will I achieve this , remebr no code is needed only using the Titanium android.
Thanks
Try this code...
Ti.Media.showCamera({
success : function(event) {
if (event.mediaType == Ti.Media.MEDIA_TYPE_PHOTO) {
// Here you can do whatever you want with the image captured from the camera
var imgView = Ti.UI.CreateImageView({
image: event.media,
width: Ti.UI.SIZE, height: Ti.UI.SIZE
});
Ti.UI.currentWindow.add(imgView); // It will be added to the centre of the window if you didn't specify top or left or ...
} else {
alert("got the wrong type back =" + event.mediaType);
}
},
cancel : function() {
alert("You have cancelled !");
},
error : function(error) {
alert("error");
},
saveToPhotoGallery : true,
allowEditing : true,
mediaTypes : [Ti.Media.MEDIA_TYPE_PHOTO]
});
You will receive the captured image data via a method of the Callback interface.
Callback interface is used to supply image data from a photo capture.
Camera.PictureCallback
onPictureTaken(byte[] data, Camera camera)
{
......
Your code
......
}
You can do whatever you want to do with image data here. Means you can set the image to imageview here. You will receive data in bytes. Simply convert it to drawable/bitmap and set that drawable/bitmap to the imageview. Thats it!
For converting bytes to bitmap you can use this link :
How to convert byte array to Bitmap
Thanks for all the response ...
I have solved this my own.
var image = event.media;
then capture the native path for the image using nativePath
image.nativePath
and then store this path to the application property and reuse this property using Application getString function.

Categories

Resources