I'm programming a game with socket.io drawing in an HTML5 canvas and when the time is over send the image to the node.js server. Is there some way to convert that canvas in an image, send the image in base64 to the node.js app, an finally save it into the server?
Yes, the canvas element provides a method named toDataURL(). This method returns a data: URL which includes the base64 representation of the image in the specified format, or PNG by default:
var canvas = document.getElementsByTagName('canvas')[0];
var dataUrl = canvas.toDataURL();
Assuming you are using socket.io, you can send this data URI over the socket by emitting an event:
var socket = io.connect('http://localhost');
socket.emit('image', dataUrl);
On the Node side, you can listen to this event on the socket to retrieve the image:
io.sockets.on('connection', function (socket) {
socket.on('image', function (dataUrl) {
console.log(dataUrl);
});
});
You can then trim the prefix data:image/png;base64, if necessary and upload the content to a server.
Read more on the MDN documentation for the canvas element.
Related
The Problem:
I record Audio from within the Browser which gives me a BLOB when the recording is done:
let blob = new Blob(chunks, { 'type' : 'audio/webm;codecs=opus' });
Changing the mime-type here won't help since the chunks already come with their MIME-Type which is audio/webm;codecs=opus for almost all browsers. So can not do anything here.
Sending this Blob via XHR to an node.js server will result in recieving a buffer from that blob:
Client:
var xhr = new XMLHttpRequest();
xhr.open('POST', 'http://localhost:3000/audio', true);
xhr.send(blob);
Server:
app.post('/audio' , (req, res) =>{
req.on('readable',()=>{
let buffer = req.read();
// sending this buffer to the external API results in error
// since it expects the mime-type audio/wav
});
res.send({msg: 'success'});
});
Most solutions out there require you to write the file to your disk and convert that ( ffmpeg).
Others use Browser-features which are experimental or not compatible with older browsers...
I also tried using the wavfile npm package, but that creates a corrupted file if i try writing it with the UInt8Array from that webm-formatted buffer (playable file but it only contains noise and is much shorter than the actual recording should be)
There must be a simple solution to convert the binary data server side, right? Best I could wish for would be a function convertWebmBufferToWavBuffer.
In express, I'm trying to respond with an image to a React request, however, I get the image binary file instead of the image file.
I tried using res.sendFile and res.download, but they send the binary file. I also tried res.attachment but it works inconsistently, and somehow makes the respond pending.
I tried specifying the file type with res.type("image/jpeg"), but it doesn't make a difference.
router.get("/photo", (req, res) => {
res.type("image/jpeg");
res.sendFile("/absolute/path/image.jpg");
});
I'm expecting an image file with normal properties of name, size, etc.
I think the distinction you are drawing between an "image file" and an "image binary file" is misleading you. All bitmap image files are encoded in binary (or, on rare occasions, base64), so I don't think that gets to the root of your problem.
res.sendFile should work just fine. The problem is in your client-side JavaScript.
To display image data in the browser, you will ultimately have to use canvas or img HTML elements. The easiest way to asynchronously load an image in your app would be to update the src attribute of an img element that already exists in the DOM to the address of the image and let the browser handle the loading for you.
However, if you want to manipulate the image data prior to loading it to an img or canvas element, I would recommend using the FileReader API, as opposed to manually parsing the binary.
The key step with this approach is to set the response data type to "blob" when you make your get request
The blob data type references the binary image file, but allows you to use the browser's built-in File interface.
The code below requests an image file as a blob and then converts the blob into a base64 encoded data url that you can use as the src attribute of an img element or load to a canvas.
var xhr = new XMLHttpRequest();
xhr.responseType = "blob";
xhr.onload = function(event) {
fileToDataUrl(event.target.response, function(result){
console.log(result);
});
};
xhr.open('GET', "https://i.imgur.com/7VhSUEH.jpg", true);
xhr.send();
function fileToDataUrl(fileObj, callback) {
var reader = new FileReader();
reader.addEventListener("load", function() {
console.log("result")
callback(reader.result);
}, false);
reader.readAsDataURL(fileObj);
}
Try this:
const fs = require("fs");
router.get("/photo", (req, res) => {
fs.readFile("/absolute/path/image.jpg", function(err, data) {
if (err) return next(err);
res.set("Content-Type", "image/jpeg");
return res.status(200).end(data, 'binary');;
});
});
var filename = __dirname+ imagePath;
var readStream = fs.createReadStream(filename);
readStream.on('open', function () {
readStream.pipe(res);
});
readStream.on('error', function(err) {
res.end(err);
});
Please don't forget to put fs dependency
My application requires a section for users to communicate each other. For this, I am using socket-io. For sending text(as strings). I use utf-8, which works perfectly.
However, when sending an image or a video on a socket, how do I approach this? Would I turn the image or the video into binary format, and send that on the socket?
Yes there is an example about how to send your files with socket.io :
var fileReader = new FileReader(),
slice = file.slice(0, 100000);
fileReader.readAsArrayBuffer(slice);
fileReader.onload = (evt) => {
var arrayBuffer = fileReader.result;
socket.emit('slice upload', {
name: file.name,
type: file.type,
size: file.size,
data: arrayBuffer
});
}
there is a full tutorial with example about send file with socket.io and receive it in the server nodeJs follow this
I am capturing an image on one client and sending the image to another client via socket.io to be sent out to users as a jpg. On the client capturing the image I am doing :
fs.readFile('./app/image.jpg', function(err, buf) {
socket.emit('image', { image: true, buffer: buf.toString('base64') });
})
This part is working fine and is encoding the image and emiting it. On the other client I have :
socket.on('image', function(img) {
console.log(img);
});
This client is receiving the message and can log out the encoded image.
I am struggling converting the image from base64 to a jpg again. What do I need to do in order to accomplish this?
Something like this:
socket.on('image', function(img) {
var buffer = new Buffer(img, 'base64');
// Now you probably want to save it as a file...
});
I just like to broadcast an image from server to client.
I can upload the image at one end of the client. But its not reflecting on the other side.
What snippet I have to include to make these things work?
I think you should not use Socket.IO for high payload streaming (like pictures).
Try this:
In your server:
var socket = require('socket.io'),
io = socket.listen(yourApp);
io.sockets.on('connection', function(client) {
client.on('imageUploaded', function(imgURL) {
client.broadcast.emit('imageBroadcast', imgURL);
});
});
In your client:
var server = io.connect(yourServerIp);
// You image upload logic here. You can get the URL after uploading and then you call this function:
function imageUploaded(url){
server.emit('imageUploaded', url);
}
server.on('imageBroadcast', function(imgURL){
// Here you decide what to do with the image
});