I want to send an image the user selected from their machine along with form data all wrapped up in a JSON object and sent to server. I am using Node for the server. Is it possible to place the image in the JSON object along with the other form elements and read in Node?
The common ways I encountered are using the Base64 string approach: you encode your image into a Base64 string and set it as part of the JSON Object that you send over to your server.
Another approach seems to be using the Binary Data in JSON but I'd never tried this before so not much info from me.
Here's a code sample to do a Base64 encoding in Javascript. Specifically look for the method below
function getBase64Image(imgElem) {
// imgElem must be on the same server otherwise a cross-origin error will be thrown "SECURITY_ERR: DOM Exception 18"
var canvas = document.createElement("canvas");
canvas.width = imgElem.clientWidth;
canvas.height = imgElem.clientHeight;
var ctx = canvas.getContext("2d");
ctx.drawImage(imgElem, 0, 0);
var dataURL = canvas.toDataURL("image/png");
return dataURL.replace(/^data:image\/(png|jpg);base64,/, "");
}
There is a way to achieve this: use image data.
In Javascript, on client side, the FileReader will allow you to read binary image data, and get them into a base64 encoded string.
On client side:
var file = $('.file-upload > input')[0].files[0];
function upload(file) {
var reader = new FileReader();
// when image data was read
reader.onload = function(event) {
// I usually remove the prefix to only keep data, but it depends on your server
var data = event.target.result.replace("data:"+ file.type +";base64,", '');
// make here your ajax call
$.ajax({
url: 'and_so_on',
json: {
data: data
}
});
// read data from file
reader.readAsDataURL(file);
}
On server side, you will received base64 encoded image that you can easilly translate into binary with the Buffer constructor
var buffer = new Buffer(data, 'base64');
Be warned that FileReader is not supported by all browsers
Related
JIRA Ticket created due to base64encode failure: https://jira.appcelerator.org/browse/TC-5876
My Current CFG:
Titanium SDK 5.1.2.GA
Testing on an iPhone iOS 9.1
I'm stuck in a problem in a project for a client that requires images took on device (using the camera) to be sent to a WebService and afterwards be seen on any device using the app (both Android and iOS devices).
Titanium provides a Ti.Blob object (event.media) after taking a picture (which is not JSON serializable) and I need somehow to send this to the server. The server responds always a JSON object, thus this Blob must be somehow JSON serializable.
I've tried many ways without success:
1 - Base64Encode the Blob
var base64blob = Ti.Utils.base64encode(event.media);
Doesn't work, it stucks the app and throws a ASL exceeded maximum size error. I imagine that the image is too large to be base64encoded.
2 - Read the Blob into a Buffer
var blobStream = Ti.Stream.createStream({ source: event.media, mode: Ti.Stream.MODE_READ });
var buffer = Ti.createBuffer({ length: event.media.length });
var bytes = blobStream.read(buffer);
It works but I have no idea how can I transform this buffer holding the image contents into something that the server can return in a JSON object and later be transformed into an Image Blob again.
The server can't manage Ti.Blob objects or Ti.Buffer objects because, first of all, they are Titanium objects and the server is C# based, and second due to Ti.Blob and Ti.Buffer aren't JSON serializable, thus the JSON return doesn't work.
What I need is basically described in the imaginary example below:
var imageBlob = event.media;
var JSONSerializableImg = imageBlob.toJSON();
sendImageToServer(JSONSerializableImg);
var imgFromServer = getImageFromServer();
var imageBlob = imgFromServer.toBlob();
var imgView = createImageView({
image: imageBlob
});
I hope someone can help me with any conversion method possible.
Thank's
OK,
This is what I think you have to do. Looking at the API, this is very doable.
1: You need to create an object Server side that will hold the BLOB.
public class BlobContainer
{
public string fileName{get;set;}
//... (Other properties)
public byte[] data {get;set;}
}
2: Convert the important information from the BLOB into a binary array and send to server.
var blobStream = Ti.Stream.createStream({ source: myBlob, mode: Ti.Stream.MODE_READ });
var newBuffer = Ti.createBuffer({ length: myBlob.length });
var bytes = blobStream.read(newBuffer);
3: Then send the byte data to the server through Ajax requests. Be mindful of how big your array is that you are sending. It might be advantageous to split the array up and combine it on the other side (Might not be necessary):
var dataObjects: [
{ id: 1, data: [BYTE_DATA_PART] },
{ id: 2, data: [BYTE_DATA_PART] }...
]
$.each(dataObjects, function(i,a) {
$.ajax({ url: "BLA", data: JSON.stringify(a), dataType: "json", type: "POST",
success: function() { //CONTINUE\\ },
error: function() {alert("ERROR BRO"})
});
});
4: Then server side get each request in your little blob container, store in a session object or cache object and once you have N out of N, piece it all together and store that sucker in the Database.
5: Retrieve the stuff in the reverse order. Just remember that it is stored as byte[] data. You may have to fuddle with it and store it as a string because of the way the TI buffer creates bytes and the way c# interprets bytes. Best thing is trial and error. Once you have all the pieces back on the client.
var newBuffer = Ti.Stream.read(data, 0, data.length);
var newBlob = newBuffer.toBlob();
To send and receive binary data to and from a server it's best to use Ti.Network.HTTPClient which can send and receive binary data.
There's a guide on uploading and downloading files here:
http://docs.appcelerator.com/platform/latest/#!/guide/File_Uploads_and_Downloads
JSON isn't designed to carry binary data, although base64encoded binary data should work. This is what Ti.Utils.base64encode() indeed is for. If you believe the "ASL exceeded maximum size error" you get shouldn't happen, please create a ticket on Appcelerator JIRA
I solved this issue by creating a separate method on server-side specially to upload photos. I followed the link below for server side:
PHP code
In Titanium I had to set XHR's header like this:
this.xhr.setRequestHeader("ContentType", "image/png");
this.xhr.setRequestHeader('enctype', 'multipart/form-data');
That's it!
Thank's for all the answers.
I've used the following method before (not in Titanium, but another web-based mobile app platform).
function convertToDataURLviaCanvas(url, callback, outputFormat){
var img = new Image();
img.crossOrigin = 'Anonymous';
img.onload = function(){
var canvas = document.createElement('CANVAS');
var ctx = canvas.getContext('2d');
var dataURL;
canvas.height = this.height;
canvas.width = this.width;
ctx.drawImage(this, 0, 0);
dataURL = canvas.toDataURL(outputFormat);
callback(dataURL);
canvas = null;
};
img.src = url;
}
convertToDataURLviaCanvas('http://example.com/image.png', function(base64Img){
// Base64DataURL
});
I used this to send the base64 encoded image string as JSON to my backend server. Then re-encoded the image on the server. It worked for me, but the base64 encoded string is huge.
in a Node.js with Socket.io project, i get an image via Socket.io like this:
socket.on('newImage', function (data) {
var desc = data.description;
var image = data.img; //i want file size of this
}
in this code, image variable contains image binary data, i want to detect file size of that image. how?
Depending on how the data is encoded you can retrieve the byte length by using the byteLength method:
var encoding = 'binary';
var data = new Buffer('hello world', encoding);
Buffer.byteLength(data, encoding); // 11
I am struggling to convert my canvas URL to a blob format, specifically in PNG format. The DataURL is generating quite perfectly when I tested it without the conversion code, the problem comes in when trying to convert it to Blob. I am using an html button that triggers the JavaScript function with the ID buttonTextArea.
I need the Blob file to be linked to my APEX page item, which I use the $s('P9_IMAGE_CODE', Blob) format, which also works when I tested it using text only. Once the page is processed, that item will be sent into a blob column within my table.
Here is my code:
$("#buttonTextArea").click(function(dataURL) {
var BASE64_MARKER = ';base64,';
var canvas = document.getElementById('myCanvas');
var dataURL = canvas.toDataURL();
if (dataURL.indexOf(BASE64_MARKER) == -1) {
var parts = dataURL.split(',');
var contentType = parts[0].split(':')[1];
var raw = decodeURIComponent(parts[1]);
return new Blob([raw], {type: contentType});
}
var parts = dataURL.split(BASE64_MARKER);
var contentType = parts[0].split(':')[1];
var raw = window.atob(parts[1]);
var rawLength = raw.length;
var uInt8Array = new Uint8Array(rawLength);
for (var i = 0; i < rawLength; ++i) {
uInt8Array[i] = raw.charCodeAt(i);
}
return new Blob([uInt8Array], {type: contentType});
document.getElementById("textArea").value = dataUrl;
$s('P9_IMAGE_CODE', Blob); --P9_IMAGE_CODE IS THE ITEM ON MY PAGE
});
I have been trying examples from :
https://github.com/blueimp/JavaScript-Canvas-to-Blob/blob/master/README.md
and
https://code.google.com/p/chromium/issues/detail?id=67587
Thank you in advance.
As Jeffrey pointed out, the javasscript "Blob" is not the same as the Oracle BLOB datatype.
The toDataURL function is already returning a base64 encoded string, so what you'd need to do is to save that string and then after submit convert it into a real blob.
Sending it to the database may be a bit of an issue since there is a limit of 32k bytes on an item's content. This means you'll likely have to send the string in chunks to the database. This is then not a VARCHAR2 (which also has a limit of 32k) but a CLOB.
As Wesley points out, there are some workarounds for that. The blog he linked to is one such example. There is also a plugin to facilitate the handling of clobs in apex.
Once you get the base64 string to the database, you'll have to convert it to a real blob. There is no built-in to quickly do this, but once again this is something several people have already solved.
A script is provided here by Tim Hall to convert a CLOB to a BLOB.
So:
In the browser, get the dataURL, which is a base64 encoded string
send it in chunks to the database, where it'll be a CLOB
after everything has been sent, convert the CLOB to a BLOB and save
it in your table
I'm trying to store images in DB2 Database as BLOB contents. I used JS to convert the image content to base64.
function loadImageFileAsURL()
{
var filesSelected = document.getElementById("inputFileToLoad").files;
if (filesSelected.length > 0)
{
var fileToLoad = filesSelected[0];
var fileReader = new FileReader();
fileReader.onload = function(fileLoadedEvent)
{
var textAreaFileContents = document.getElementById
(
"textAreaFileContents"
);
textAreaFileContents.innerHTML = fileLoadedEvent.target.result;
var ImgContent = fileLoadedEvent.target.result;
$("#IMAGE").attr("src",ImgContent);
};
fileReader.readAsDataURL(fileToLoad);
}
}
Now I need to convert this base64 content to binary and store them to my DB2 Database. Is there any way to do this in JavaScript?
And how to fetch this data from the database and display it on my mobile app using Adapters. ?
Why do you not simply store the image as encoded to base64 in database? I think this would be better in your scenario...
You receive an image
You use some library to handle the encoding to base64
Review this question: Base64 encoding and decoding in client-side Javascript
You store the image-now a string, in the database
When you need to display the image in the app, fetch the contents and decode it (see step 2)
I'm attempting to consume server-side code that is owned by another team and that I can't easily change. It is processing an image and returning it via Response.BinaryWrite:
MemoryStream ms = new MemoryStream();
image.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
var imageToReturn = ms.ToArray();
Response.ContentType = "image/jpg";
Response.BinaryWrite(imageToReturn);
However, when I attempt to do standard client-side processing of the result, like using Javascript's btoa() to convert it from a byte array to an ArrayBuffer, I get messages like "'btoa' failed: The string to be encoded contains characters outside of the Latin1 range".
I really just want to be able to display and work with this image - so any approach that would get it to appear in a canvas, or convert it to a data URL, etc., would help me out. Am I missing something?
If you just want to display the image, why don't you just src attribute of img tag to the url of the ASP.Net page, which is writing the JPG in the in the response.
If you want to display the image in canvas, you can do it in following way
myimage = new Image();
myimage.onload = function () {
var canvas = document.getElementById('canv');
var ctx = canvas.getContext('2d');
ctx.drawImage(myimage, x, y);
}
myimage.src = '<url to the asp.net page>';