Nativescript send camera capture to server - nativescript

In my Nativescript application I would like to capture an image using the camera module and then send the bytes directly to the server via http call.
Here is my code (incomplete for brevity):
var cameraModule = require("camera");
var http = require("http");
...
cameraModule.takePicture().then(function (img) {
// how to extract the actual bytes from img???
http.request({
url: some_url,
method: "POST",
headers: { "Content-Type": "application/octet-stream" },
content: ???
});
});
Is there a way to do that?
I was looking at nativescript-background-http and it seems to fit my requirements exactly, but the example shows the file being loaded from a path only. I did not have any luck making this to work on iOS.
Any help is greatly appreciated.
Thank you.

A couple things;
"img" is actually a image source.
At this point the built in HTTP module does not support direct binary transfers, so we need to convert it to something that can be sent over the wire. So base64 is a text representation that can support binary, and it is a common encoding/decoding method.
Since we already have it as a image source we just use the cool toBase64String ability which give us the Base 64 data.
So here is basically is how I would do it (tested under android).
var cameraModule = require('camera');
var some_url="http://somesite";
// img is a image source
cameraModule.takePicture().then(function (img) {
// You can use "jpeg" or "png". Apparently "png" doesn't work in some
// cases on iOS.
var imageData = img.toBase64String("jpeg");
http.request({
url: some_url,
method: "POST",
headers: { "Content-Type": "application/base64" },
content: imageData
}).then(function() {
console.log("Woo Hoo, we sent our image up to the server!");
}).catch(function(e) {
console.log("Uh oh, something went wrong", e);
});
});

There are a few ways to do this. If your backend can take a base64 string you can use the image-source class and manipulate the data. I'm on my phone or I'd mock up a sample. It really depends what you expect on the server to be honest but most options are possible with NativeScript using the image-source and ui/image component.
http://docs.nativescript.org/api-reference/classes/_image_source_.imagesource.html#tobase64string
Going from memory here but try this when you get the (IMG) back.
var data = img.tobase64string(); that should give you a base 64 string of the image.
Just found this awesome sample from another question https://stackoverflow.com/a/37815237/1893557
This will work to send the file after you save it locally and uses the background-http plugin.

Related

Microsoft Cognitive Services Emotion API. Error: 'Image size is too small or too big.'

I have noticed a rather strange error with the Emotion API from the Cognitive Services suite.
Everything works just fine as long as I send it URL's. When sending it image attachments. I receive this JSON error:
{ error: { code: 'InvalidImageSize', message: 'Image size is too small or too big.' } }
Sending it smaller or larger versions does not help.
Send a URL of the same image, and suddenly it works fine again.
I stream the attachment to the API service in the exact same way I do for another Cognitive Services API, namely Computer Vision. And that works great with streamed attachments.
The code is on GitHub: https://github.com/sebsylvester/botbuilder-mcs
I know the APIs are still in preview, but this is still a weird issue.
Unfortunately, the Emotion and Face APIs do not support chunked transfers, as noted here. The 'workaround' is to load the image bits synchronously prior to making the web request. The code snippet from that project is thus:
function _postImageSync(url, image, options) {
return new _Promise(function (resolve, reject) {
request.post({
uri: host + rootPath + url,
headers: {
'Ocp-Apim-Subscription-Key': key,
'Content-Type': 'application/octet-stream'
},
qs: options,
body: fs.readFileSync(image)
}, (error, response) => {
response.body = JSON.parse(response.body);
_return(error, response, resolve, reject);
});
});
}

Getting binary file content instead of UTF-escaped using file.get

I'd like to know if it's possible to get exact binary data using callback from drive.files.get method of NodeJS Google API. I know that object returned by calling this API endpoint is a normal request object that could be e.g. piped like this:
drive.files.get({
fileId: fileId,
alt: 'media'
}).pipe(fs.createWriteStream('test'));
However I would like to know if it's possible to get binary data from within callback using this syntax:
drive.files.get({
fileId: fileId,
alt: 'media'
}, function(err, data) {
// Here I have binary data exposed
});
As far as I know, it should be possible to get that kind of data from request during its creation, passing {encoding: null} in request options object like this:
var requestSettings = {
method: 'GET',
url: url,
encoding: null // This is the important part
};
request(requestSettings, function(err, data) {/.../})`
however it seems that Google obscures this configuration object in its library.
So my question is - is it possible to do so without interfering/hacking the library?
Ok, so i found answer that could be useful for others :)
Aforementioned drive.files.get method returns Stream object, so it could be directly handled using proper event handlers. Then, buffer parts could be concatenated into one part and sent back in callback like this:
var stream = drive.files.get({
fileId: fileId,
alt: 'media'
});
// Build buffer
var chunks = [];
stream.on('data', (chunk) => {
chunks.push(chunk);
});
stream.on('end', () => {
return cb(null, Buffer.concat(chunks));
});

Cloud Code: Creating a Parse.File from URL

I'm working on a Cloud Code function that uses facebook graph API to retrieve users profile picture. So I have access to the proper picture URL but I'm not being able to acreate a Parse.File from this URL.
This is pretty much what I'm trying:
Parse.Cloud.httpRequest({
url: httpResponse.data["attending"]["data"][key]["picture"]["data"]["url"],
success: function(httpImgFile)
{
var imgFile = new Parse.File("file", httpImgFile);
fbPerson.set("profilePicture", imgFile);
},
error: function(httpResponse)
{
console.log("unsuccessful http request");
}
});
And its returning the following:
Result: TypeError: Cannot create a Parse.File with that data.
at new e (Parse.js:13:25175)
at Object.Parse.Cloud.httpRequest.success (main.js:57:26)
at Object.<anonymous> (<anonymous>:842:19)
Ideas?
I was having trouble with this exact same problem right now. For some reason this question is already top on Google results for parsefile from httprequest buffer!
The Parse.File documentation says
The data for the file, as 1. an Array of byte value Numbers, or 2. an Object like { base64: "..." } with a base64-encoded String. 3. a File object selected with a file upload control. (3) only works in Firefox 3.6+, Safari 6.0.2+, Chrome 7+, and IE 10+.
I believe for CloudCode the easiest solution is 2. The thing that was tripping me earlier is that I didn't notice it expects an Object with the format { base64: {{your base64 encoded data here}} }.
Also Parse.Files can only be set to a Parse.Object after being saved (this behaviour is also present on all client SDKs). I strongly recommend using the Promise version of the API as it makes much easier to compose such asynchronous operations.
So the following code will solve your problem:
Parse.Cloud.httpRequest({...}).then(function (httpImgFile) {
var data = {
base64: httpImgFile.buffer.toString('base64')
};
var file = new Parse.File("file", data);
return file.save();
}).then(function (file) {
fbPerson.set("profilePicture", file);
return fbPerson.save();
}).then(function (fbPerson) {
// fbPerson is saved with the image
});

Inconsistent AJAX POST status 400 . Issues with image complexity

Our team has developed a JS HTML5 canvas based paint application. In the following code, the image data is fetched from the canvas as base 64 encoding and posted to a servlet via ajax. The data post behaves erratically. If the image is simple , as in a straight line, I get Ajax status = 200 and the image gets saved. If the image is complex, then I get a status = 400 and the data is not saved.
Why should the content of the POST create issues with posting of the data itself?
function getCode(){
var canvas = document.getElementById('imageView');
var context = canvas.getContext('2d');
// draw cloud
context.beginPath();
// save canvas image as data url
var dataURL = canvas.toDataURL();
// set canvasImg image src to dataURL
// so it can be saved as an image
document.getElementById('canvasImg').src = dataURL;
var uri= document.getElementById('canvasImg').src;
uri = uri.replace('data:image/png;base64,','');
uri = uri.replace('=', '');
uri = uri.trim();
alert("uri is "+uri);
var ajaxobject ;
if(window.XMLHttpRequest){
ajaxobject = new XMLHttpRequest();
} else if(window.ActiveXObject){
ajaxobject = new ActiveXObject("Microsoft.XMLHTTP");
}else if(window.ActiveXObject){
ajaxobject = new ActiveXObject("Msxml2.XMLHTTP");
}
ajaxobject.open("POST", "SaveImageServlet?image="+uri, true);
ajaxobject.setRequestHeader("Content-type","application/x-www-form-urlencoded");
ajaxobject.onreadystatechange = function(){
if(ajaxobject.readyState==4){
alert(ajaxobject.status);
if(ajaxobject.status==200){
alert(ajaxobject.responseText);
}}
};
ajaxobject.send(null);
}
From looking at your code, the problem seems that you're passing the data in querystring instead of using the request body (as you should be doing since you're setting the POST verb).
Your uri should look like this:
SaveImageServlet
without the question mark and the parameter. The parameter should be set in the request body. Using jquery ajax your request would look like this:
$.ajax({
contentType: 'text/plain',
data: {
"image": yourBase64string
},
dataType: 'application/json', // or whatever return dataType you want
success: function(data){
// callback in case of success
},
error: function(){
// callback in case of error
},
type: 'POST',
url: '/SaveImageServlet'
});
On server side you should be reading the data from the appropriate place. For example, if you're using .Net read it like this:
Request.Form["image"]
instead of:
Request.Querystring["image"]
This should work as intended and consistently.
#Matteo, Thanks for your help and effort. However, AJAX issue never got solved. I found a way to send the base64 image data to the servlet. Just appended it to a hidden field and sent it as a regular form field.

Problems serving a binary image passed through stdout with Node

I'm attempting to create a node server that serves up a png image generated using the node-wkhtml module (basically just a wrapper for the wkhtmltoimage/wkhtmltopdf command line utility). Here's what I have so far:
var http = require('http');
var Image = require("node-wkhtml").image();
http.createServer(function (request, response) {
new Image({ url: "www.google.com" }).convert (function (err, stdout) {
//var theImage = new Buffer (stdout, 'binary');
response.writeHead(200, {'Content-Type' : 'image/png',
'Content-Length' : stdout.length
});
response.write (stdout, 'binary');
response.end ();
//write out an error, if there is one
if (err)
console.log (err);
});
}).listen(8124);
Basically, the module calls the command:
wkhtmltoimage www.google.com -
which then generates a png image and writes it to the stdout. The amount of data served seems to be correct, but I can't get the browser to display it (nor does it work if I download it as a file). I tried the following command:
wkhtmltoimage www.google.com - > download.png
and sure enough, download.png was created and contained a snapshot of the google homepage, meaning that the wkhtmltoimage utility is working correctly, and the command works. I'm a beginner at node, so I'm not super familiar how to serve up a binary file like this, can anyone see any glaring issues? Here's the node module code that works the magic:
Image.prototype.convert = function(callback) {
exec(util.buildCommand(this), {encoding: 'binary', maxBuffer: 10*1024*1024}, callback);
}
(the buildCommand function just generates the "wkhtmltoimage www.google.com -" command, and I've verified it does this correctly, using node inspector.
UPDATE:
In case anyone finds this later and is interested, I found the solution. The plugin I was using (node-wkhtml) was not properly handling large buffers, due to the choice of using child-process.exec I changed the plugin code to use child-process.spawn instead, and it worked as desired.

Resources