I\'m currently working on a WebSocket application that is displaying images send by a C++ server. I\'ve seen a couple of topics around there but I can\'t seem to get rid of
Thanks, it's working great!!
So I figure I'd share my final javascript code:
var socket = new WebSocket('ws://'+host+':'+port, protocol);
socket.binaryType = 'arraybuffer';
try {
socket.onopen = function() {
document.getElementById('status').style.backgroundColor = '#40ff40';
document.getElementById('status').textContent = 'Connection opened';
}
socket.onmessage = function(msg) {
var arrayBuffer = msg.data;
var bytes = new Uint8Array(arrayBuffer);
var image = document.getElementById('image');
image.src = 'data:image/png;base64,'+encode(bytes);
}
socket.onclose = function(){
document.getElementById('status').style.backgroundColor = '#ff4040';
document.getElementById('status').textContent = 'Connection closed';
}
} catch(exception) {
alert('Error:'+exception);
}
don't really understand why the blob version is so tricky but this did the trick!
Thanks to the other answers, I managed to receive a jpeg image by websocket and display it in a new window :
socket.binaryType = "arraybuffer";
socket.onmessage = function (msg)
{ var bytes = new Uint8Array(msg.data);
var blob = new Blob([bytes.buffer]);
window.open(URL.createObjectURL(blob),'Name','resizable=1');
};
I think the cleanest solution would be to change the base64 encoder to operate directly on a Uint8Array instead of a string.
Important: You'll need to set the binaryType of the web socket to "arraybuffer" for this.
The onmessage method should look like this:
socket.onmessage = function(msg) {
var arrayBuffer = msg.data;
var bytes = new Uint8Array(arrayBuffer);
var image = document.getElementById('image');
image.src = 'data:image/png;base64,'+encode(bytes);
};
The converted encoder should then look like this (based on https://stackoverflow.com/a/246813/1464608):
// public method for encoding an Uint8Array to base64
function encode (input) {
var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
var output = "";
var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
var i = 0;
while (i < input.length) {
chr1 = input[i++];
chr2 = i < input.length ? input[i++] : Number.NaN; // Not sure if the index
chr3 = i < input.length ? input[i++] : Number.NaN; // checks are needed here
enc1 = chr1 >> 2;
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
enc4 = chr3 & 63;
if (isNaN(chr2)) {
enc3 = enc4 = 64;
} else if (isNaN(chr3)) {
enc4 = 64;
}
output += keyStr.charAt(enc1) + keyStr.charAt(enc2) +
keyStr.charAt(enc3) + keyStr.charAt(enc4);
}
return output;
}
This is very simple using a Blob:
// Small red dot image
const content = new Uint8Array([137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 0, 5, 0, 0, 0, 5, 8, 6, 0, 0, 0, 141, 111, 38, 229, 0, 0, 0, 28, 73, 68, 65, 84, 8, 215, 99, 248, 255, 255, 63, 195, 127, 6, 32, 5, 195, 32, 18, 132, 208, 49, 241, 130, 88, 205, 4, 0, 14, 245, 53, 203, 209, 142, 14, 31, 0, 0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130]);
document.getElementById('my-img').src = URL.createObjectURL(
new Blob([content.buffer], { type: 'image/png' } /* (1) */)
);
Should display a small red dot: <img id="my-img">
Works also with a simple array instead of Uint8Array:
// Small red dot image
const content = [137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 0, 5, 0, 0, 0, 5, 8, 6, 0, 0, 0, 141, 111, 38, 229, 0, 0, 0, 28, 73, 68, 65, 84, 8, 215, 99, 248, 255, 255, 63, 195, 127, 6, 32, 5, 195, 32, 18, 132, 208, 49, 241, 130, 88, 205, 4, 0, 14, 245, 53, 203, 209, 142, 14, 31, 0, 0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130];
document.getElementById('my-img').src = URL.createObjectURL(
new Blob(content /* (1) */)
);
(1) It works without specifying the Blob MIME type.
Another alternative
let urlObject;
socket.onmessage = function(msg) {
const arrayBuffer = msg.data;
const image = document.getElementById('image');
if (urlObject) {
URL.revokeObjectURL(urlObject) // only required if you do that multiple times
}
urlObject = URL.createObjectURL(new Blob([arrayBuffer]));
image.src = urlObject;
};
You may write it much simpler:
socket.onmessage = function(msg) {
var arrayBuffer = msg.data;
var bytes = new Uint8Array(arrayBuffer);
var blob = new Blob([bytes.buffer]);
var image = document.getElementById('image');
var reader = new FileReader();
reader.onload = function(e) {
image.src = e.target.result;
};
reader.readAsDataURL(blob);
};