Node Send Files as URL - javascript

I have an image file in the server side, and would like to send this image to the client side to display it in the web. It seems like URL.createObjectURL can only be used in a DOM, it sounds impossible to convert the image file to URL in expressJS, or is there any other way to return the image as URL from server side?
I am now trying to send the image buffer and try to use URL.createObjectURL on the client side. It seems like res containing a bunch of weird character string, and I tried to create a Blob, but the image does not render on the web at all.
fetch(`http://localhost:9000/foo`)
.then((res) => res.text())
.then((res) => {
var test = new Blob([res], { type: "image/jpeg" });
props.setImageSrc((prev) => [
...prev,
URL.createObjectURL(test),
]);
});
router.get("/", function (req, res, next) {
var buffer = fs.readFileSync("/Users/foo/bar/image1.jpeg");
var bufferBase64 = new Buffer.from(buffer);
res.send(bufferBase64);
});
Below are part of the res I got on the client side
%&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz�������������������

Use this function to convert the base64 buffer string to blob
const b64toblob = (string, fileType) => {
const byteCharacters = atob(string);
const byteNumbers = new Array(byteCharacters.length);
for (let i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
return new Blob([byteArray], { type: `image/${fileType}` });
};
Receive base64 buffer string from server
fetch(`http://localhost:9000/foo`)
.then((res) => res.text())
.then((res) => {
const blob = b64toblob(buffer, "jpeg");
props.setImageSrc((prev) => [
...prev,
URL.createObjectURL(blob),
]);
});
In server, read the file and convert to base64 buffer
router.get("/", function (req, res, next) {
var buffer = fs.readFileSync("/Users/foo/bar/image1.jpeg");
var bufferBase64 = new Buffer.from(buffer);
res.send(bufferBase64.toString("base64"));
});

Related

How do I save an image locally with HTML and JS?

I have an input that the user can upload an image, I want to get this image and pass it to the server side and the server will store this image on a local folder, for example:
I use linux for the server so the server.js is running from the folder /home/user/project/server/server.js. When the server get the image I want it to store on the folder /home/user/project/images/img.jpg
This my code:
HTML:
<input type="file" id="imageFile" accept=".jpg, .jpeg, .png" />
Front-End:
const signup = async () => {
const name = document.getElementById("signup_name").value;
const passwd = document.getElementById("signup_passwd").value;
const image = document.getElementById("imageFile").files[0];
let formData = new FormData();
formData.append("fileToUpload", image);
const response = await fetch("http:/localhost:3000/signup", {
method: "post",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
nome: cadastro_nome,
senha: cadastro_senha,
imagem: formData
}),
});
const result = await response.json();
document.getElementById("cadastro_nome").value = "";
document.getElementById("cadastro_senha").value = "";
alert(result);
};
Back-End:
app.post("/signup", async (req, res) => {
const { name, passwd, image } = req.body;
if (!name || !passwd) {
return res.status(400).json("Dados incorretos!");
}
knex
.transaction((trx) => {
trx
.insert({
login: name,
senha: passwd,
divida: 0,
})
.into("usuarios")
.then(trx.commit)
.catch(trx.rollback)
.then(res.json("Cadastrado com sucesso!"));
})
.catch((err) => {
console.log(err);
return res.json("Login existente, tente novamente!");
});
//PUT SOMETHING HERE TO SAVE IMAGE LOCALLY, MAYBE??
});
Yes, you can first store the uploaded image as a Base64 string using the FileReader, data urls are already base64 so when you call reader.readAsDataURL the e.target.result sent to the reader.onload handler and it will be all you need, but also may need add in your HDD or do it asynchronous using res.json, check the WDN official documentation about FileReader.
(Get user's uploaded image for example)
const imgPath = document.querySelector('input[type=file]').files[0];
const reader = new FileReader();
reader.addEventListener("load", function () {
// Convert file to base64 string and save to localStorage
localStorage.setItem("image", reader.result);
}, false);
if (imgPath) {
reader.readAsDataURL(imgPath);
}
And to read the image back from the localStorage, just use querySelector or getElementById:
const img = document.getElementById('image');
img.src = localStorage.getItem('image');
About the "fd" argument must be of type number, in my case, sometimes I was using:
fs.readSync() when I should have been using fs.readFileSync()
fs.writeSync() usage but should be fs.writeFileSync()
fr.write() could be in your case fs.writeFile()
The comment of #Dimava in your question can work too, I flagged up.
For more help, consult this post related to your similar question! ;)

avoid uint8array object conversion in axios,nodejs

I am trying to send uint8array in Axios payload in POST by doing this
app.post('/upload',upload.single('file') ,async function(req, res){
var fileString = fs.readFileSync('./uploads/file.jpeg')
var u8 = new Uint8Array(fileString);
console.log(u8);
try {
const payload = {
"binData":u8
}
const response = await axios.post("https://xyz/uploadservice",payload)
res.status(200).send({"success":response})
} catch (error) {
res.status(400).send({"error":error})
}
the xyz api endpoint expects binData in bytearray format,but its going in objects format like
binData : {"0":"23","1","255".....}
but it expects like this, binData : [23,255,.....]

How to convert async AsyncIterable<Uint8Array> to File in Javascript

Hello I'm sending/POST a File from a HTML Form on a browser client to a Remix application server.
The Remix applicaton server is sending/handling my File as a async AsyncIterable.
I now need to convert it back to a File object so I can send it to a backend server as FormData.
I tried both with and without buffer for demo:
Does anyone have experiance with convert AsyncIterable to Blob then to File??
const myHandler: UploadHandler = async ({ name, contentType, data, filename }) => {
//'data' is data of type AsyncIterable<Uint8Array>
//'contentType' is 'image/png'
let dataArray1 = []; //test1 without buffer
let dataArray2 = []; //test2 with buffer
for await (const x of data) {
dataArray1.push(x); //without buffer
dataArray2.push(x.buffer); //with buffer
}
const blob1 = new Blob(dataArray1, {type: contentType});
const blob2 = new Blob(dataArray2, {type: contentType});
const file1 = new File([blob1], filename, { type: contentType });
const file2 = new File([blob2], filename, { type: contentType });
console.log('file1.size: ', file1.size);
//file1 size is 1336843 (and for file2)
//but i'm getting content-length 1337028 from my browser Form
//so I'm not sure if it's correct
return file1;
};
[![content-length size][1]][1]
[![enter image description here][2]][2]
[![enter image description here][3]][3]
[![enter image description here][4]][4]
Try passing the blob parts directly into the file constructor.
const myHandler: UploadHandler = async ({ name, contentType, data, filename }) =>
{
const dataArray1 = [];
for await (const x of data)
{
dataArray1.push(x);
}
const file1 = new File(dataArray1, filename, { type: contentType });
return file1;
};

Is it possible to read/decode .avro uInt8Array Container File with Javascript in Browser?

I'm trying to decode an .avro file loaded from a web server.
Since the string version of the uInt8Array starts with
"buffer from S3 Objavro.schema�{"type":"record","name":"Destination",..."
I assume it's avro Container File
I found 'avro.js' and 'avsc' as tools for working with the .avro format and javascript but reading the documentation it sound's like the decoding of a Container File is only possible in Node.js, not in the browser.
(The FileDecoder/Encoder methods are taking a path to a file as string, not an uInt8Array)
Do I get this wrong or is there an alternative way to decode an .avro Container File in the browser with javascript?
Luckily I found a way using avsc with broserify
avro.createBlobDecoder(blob, [{options}])
[avro.js - before browserifying]
var avro = require('avsc');
const AVRO = {
decodeBlob(blob) {
let schema, columnTitles, columnTypes, records = []
return new Promise((resolve) => {
avro.createBlobDecoder(blob, {
// noDecode: true
})
.on('metadata', (s) => {
schema = s
columnTitles = schema.fields.map(f => f.name)
columnTypes = schema.fields.map(f => f.type)
})
.on('data', (data) => {
records.push(data)
})
.on('finish', () => {
resolve(
{
columnTitles: columnTitles,
columnTypes: columnTypes,
records: records
}
)
})
})
}
}
module.exports = AVRO
[package.json]
"scripts": {
"avro": "browserify public/avro.js --s AVRO > public/build/avro.js"
}
[someOtherFile.js]
//s3.getObject => uInt8array
const blob = new Blob([uInt8array]) //arr in brackets !important
const avroDataObj = await AVRO.decodeBlob(blob)
Thanks for posting!
Below is my integration of avro/binary with axios, in case it helps anyone else trying to implement browser side decoding:
[before browserifying]
const axios = require('axios')
const avro = require('avsc')
const config = {
responseType: 'blob'
};
const url = 'https://some-url.com'
axios.get(url, config)
.then(res => {
avro.createBlobDecoder(res.data)
.on('metadata', (type) => console.log(type))
.on('data', (record) => console.log(record))
})
.catch(e => console.error(e))

sending files and body to nodeJS using fetch

how can I send a request to the server (rest) with files and somebody?
what I've tried so far:
func = async(event)=> {
const body = { city_id: 8 }
const filesToServer = new FormData();
Object.values(event.files).forEach(file => filesToServer.append(file.name, file));
myreqFunction(path, [...filesToServer, body]);
}

Categories