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...
});
Related
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 want to receive an image via socket.io on node.js and would like forward it to a client (browser), but the image sent via the message to the browser is not recognised and therefore not show.
However, when I save the message/image first on the node.js server and load the saved file again to forward the image it works fine. I can also open the jpeg file on the server from the file system without a problem. Sending a different jpeg directly from the server works also as expected.
socket.on('image', function(msg) {
var fileName = 'clientImage.jpg';
// First save the file
fs.writeFile(fileName, msg.buffer, function() {});
// reload the image and forward it to the client
fs.readFile(__dirname +'/clientImage.jpg', function(err, buf){
socket.emit('serverImage', {image: true, buffer: buf});
});
}
If I simplify the function to forward the message (msg) received without the "fs" workaround, like:
socket.emit('serverImage', {image: true, buffer: msg.buffer});
or in the simples expected way
socket.emit('serverImage', msg);
the message will not be recognised as an image on the browser and the client does not fire the "onload" event for the Image.
Client code (works with jpeg files fine):
socket.on('serverImage', function(msg) {
var blob = new Blob([msg.buffer], {type: 'image/jpeg'} );
var url = URL.createObjectURL(blob);
var limg = new Image();
limg.onload = function () {
console.log(' -- image on load!');
rcontext.drawImage(this, 0, 0);
URL.revokeObjectURL(url);
};
limg.src = url;
});
Is there a way that the message can be adopted/converted somehow i.e. encoding, to be recognised directly without the "fs" library, or any other suggestions?
many thanks!
Many thanks for the responses,
I did further tests and found a workaround / solution by using an additional buffer variable specifying the type in front of the socket.emit :
var nbuffer = new Buffer(msg.buffer,'image/jpeg');
socket.emit('serverImage', {image: true, buffer: nbuffer});
with this additional step, the browser recognises now the message as image.
Many thanks for your help!
writeFile is asynchronous. It takes time to write a file to the disk. You passed it a callback function, but it's empty. Re-read the image inside that callback function.
// First save the file
fs.writeFile(fileName, msg.buffer
, function() { // When writing is done (that's the important part)
// reload the image and forward it to the client
fs.readFile(__dirname +'/clientImage.jpg', function(err, buf){
socket.emit('serverImage', {image: true, buffer: buf});
});
});
I'm working on a Node.JS application that utilizes ExpressJS as a web server.
I want to set up a route /get/thumbnail/by_guid/:guid that will return an image as a real image, not a base64 string, so I can set up the source of an image tag using <img src="/get/thumbnail/by_guid/ABCD" > and the actual image will display.
I'm storing the thumbnails as BLOBs in my database and am retrieving them. When I retrieve them, they become buffers in my node application. I'm then sending those buffers in my route as shown below, where img is a buffer object that contains the image.
router.get('/get/thumbnail/by_guid/:guid', function(req, res){
image_helper.guidToImage(req.params.guid).then(function(img){
res.set('Content-Type', 'image/jpeg');
res.set('Content-Length', img.length);
res.end(img, 'latin1');
}, function(err){
res.err(err);
});
});
guidToImage returns the image as a buffer.
When I go to the url described by a thumbnail I know at, for instance, /get/thumbnail/by_guid/ABCD, I see a white box like this:
When I look in the network tab of chrome dev tools, the request looks like this:
The response just shows my base64 string:
And the image shows as broken when I source it:
How can I achieve what I'm trying to do?
I've spent 6 hours trying to get this working right now.
Thanks for the help.
Changed route to get the binary to show properly.
router.get('/get/thumbnail/by_guid/:guid', function(req, res){
image_helper.guidToImage(req.params.guid).then(function(img){
var im = new Buffer(img.toString('binary'), 'base64');
res.writeHead(200, {
'Content-Type': 'image/jpg',
'Content-Length': im.length
});
res.end(im);
}, function(err){
res.err(err);
});
});
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.