How to convert blob to xlsx or csv? - javascript

The frontend of the application having a file download option (which can be in the following format: xlsx, csv, dat).
For that, I use fileSaver.js
Everything works fine for the format .dat/.csv but for the .xlsx it does not work the files are corrupted.
I tested the conversion with the following formats :
utf8
base64
binary
Here's how I do :
// /* BACK */ //
// data is
fs.readFile(filePath, (err, data) {...})
// the api give this answer the important part is "filename" & "data"
{"status":"ok","context":"writing the intermediate file","target":"/temp/","fileName":"name.xlsx","data":{"type":"Buffer","data":[72,82,65,67,67,69,83,83,32,10]}}
// /* FRONT */ //
let json = JSON.stringify(data)
let buffer = Buffer.from(JSON.parse(json).data)
let read = buffer.toString('utf8')
let blob = new Blob([read])
FileSaver.saveAs(blob, fileName)

Ok for anybody who pass in this topic, my solution :
(keep in mind the real better solution for dl a file : send file in api response with header 'Content-disposition' or use express for that like this)
The back (Node) work like this :
fs.readFile(filePath, (err, data) => {
if (err) {
console.log(`-------- oups error - read --------`)
console.log(err)
res.send({ status: `erreur`, context: `read the source file`, id: err.errno, code: err.code, message: err.message.replace(/\\/g, '/') })
} else {
res.send({ status: `ok`, context: `send data file`, target: target, fileName: fileName, data: data })
}
})
Here :
target is the path for the front with the name of the file and his
extension (/path/name.ext)
fileName is juste the name and the extension (name.ext)
data is the data send by the readFile ({"type":"Buffer","data":[72,82,65,67,67,69,83,83,32,10]})
The front (React) work like this :
fetch(targetUrl)
.then(res => res.json())
.then(res => {
if (res.status !== `ok`) {
this.setState({
errorDlFile: true,
errorDlFile_context: res.context,
errorDlFile_id: res.id,
errorDlFile_code: res.code,
errorDlFile_message: res.message
})
} else {
const target = res.target
const fileName = res.fileName
const data = res.data
const splitName = res.fileName.split('.')
const format = splitName[splitName.length-1]
// file saver blob solution
let json = JSON.stringify(data)
let buffer = Buffer.from(JSON.parse(json).data)
let readUTF8 = buffer.toString('utf8')
let blob = ''
if (format === 'xlsx') {
blob = new Blob([buffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' })
} else if (format === 'csv') {
blob = new Blob([readUTF8], { type: 'application/vnd.ms-excel' })
} else {
blob = new Blob([readUTF8])
}
FileSaver.saveAs(blob, fileName)
}
})

#Hadock
if you want to download file with .csv extension then you need to pass the type of file like
let blob = new Blob([csv], { type: 'application/vnd.ms-excel' });
instead of
let blob = new Blob([read])
and don't forgot to send filename with extension (test.csv).
For excel file I used different plugin exceljs demo.

you can't save json data directly to .xlsx file, you can convert json data to excel format using library like 'sheetjs' (https://sheetjs.com/)
var ws_name = filename;//"SheetJS";
var wb = new Workbook(), ws = sheet_from_array_of_arrays(data);
/* add worksheet to workbook */
wb.SheetNames.push(ws_name);
wb.Sheets[ws_name] = ws;
var wbout = XLSX.write(wb, { bookType: 'xlsx', bookSST: true, type: 'binary' });
saveAs(new Blob([s2ab(wbout)], { type: "application/octet-stream" }), filename + ".xlsx")

Related

How can I convert a blob file from a react to a url?

This is an issue that occurred while trying to implement a profile image change using React.
Function that receives image values cropped from canvas, converts to blob, and requests it to be saved to the server
//Function that receives image values cropped from canvas, converts to blob, and requests it to be saved to the server
const onClickUploadImage = (canvas, crop) => {
if (!crop || !canvas) {
return;
}
const canvasUrl = canvas.toDataURL("image/png");
const base64Incoding = atob(canvasUrl.split(",")[1]);
const array = [];
for (let i = 0; i < base64Incoding.length; i++) {
array.push(base64Incoding.charCodeAt(i));
}
const file = new Blob([new Uint8Array(array)], { type: "image/png" });
const fd = new FormData();
fd.append("file", file);
//Verify that the blob is created as an url image
console.log("convert file >> ", window.URL.createObjectURL(file));
//conver file >> blob:http://localhost:3000/afdc0910-76bb-4e53-801c-61dc890c651f
const config = {
header: {
processData: false,
"content-type": false,
},
};
axios
.post("/api/users/update/image", fd, config)
.then(({ data }) => {
console.log("data >> ", data);
//data >> { success:true, message:"File saved successfully" }
alert("Profile upload successful.");
})
.catch((err) => {
alert("Profile upload failed.");
});
};
// On the server side, we use the filter module to store very well.
// Type is saved as file.
// The problem is that I want to read this file and display it as an image.
// To do that, I checked to see if the stored blob reads well.
// I tried to read the saved blob file using input and convert it as below code, but failed.
// input ex) <input type="file" onChange={onClickBlobToURL} />
function onClickBlobToURL(e) {
const file = e.target.files[0];
console.log("file > ", file);
//File Attach Output Result Image
const reader = new FileReader();
if (file) {
console.log("blobToURL > ", reader.readAsDataURL(file));
//blobToURL > undifined
}
}
Did you save it the wrong way?
Is it wrong to read blob?
console.log("file > ", file)

How to send a file in array of object to express server?

I have an array of the object, each object contains some properties of type string and a file.
This is how my array looks like:
const args = [
{
name: 'presentation',
price: 9.99,
tags: 'invest, finance, business',
file: File,
thumbnail: File
},
{
name: 'presentation2',
price: 20.99,
tags: 'invest, finance, business',
file: File,
thumbnail: File
}
]
const headers = {
headers: {
Authorization: `Bearer ${token}`
}
};
My goal is to send this whole array of the object to the Express Server. there I will save information to the Mongo and upload the file to S3.
But Currently, I am unable to get the file stream on the server when I send this in a POST request,
even the whole req.body is an empty object when I console.log it
axios.post(`${slidesRoute}/createSlides`, args, headers);
Alternatively, I tried to put everything into FormData.
for example:
let formData = new FormData();
selectedFiles.forEach((selectedFile, i) => {
formData.append(`name_${i}`, selectedFile.name);
formData.append(`price_${i}`, selectedFile.price);
formData.append(`tags_${i}`, selectedFile.tags);
formData.append(`file_${i}`, selectedFile.file);
formData.append(`thumbnail_${i}`, selectedFile.thumbnail);
});
axios.post(`${slidesRoute}/createSlides`, formData, headers);
Then In the backend. I am unable to catch these files using multer. Because the filenames in form data are being generated dynamically like
file_1, file_2 file_3,...
But multer expects the exact filename to be passed
for example multer().array('file')
so in my second approach I am unable to catch files using Multer
You can't include file inside JSON. File is not JSON-serializable. Ideally you should have a separate endpoint to accept your files, send them with content-type: multipart/form-data, receive unique id for that file stored on the server, then send your JSON with ids instead of files.
As a chaper alternative you can Base64 encode your files into a string, insert this string in your request, and then decode it back on the receiving side
FormData key values are array by default
in your code Just change
formData.append(`file_${i}`, selectedFile.file);
to
formData.append(`file`, selectedFile.file);
You should be able to receive the file array in server side using multer().array('file')
Sample below demonstrating FormData key values array behavior
const formData = new FormData();
formData.append('key1', 'value1');
formData.append('key1', 'value2');
formData.append('key2', 'value1');
formData.forEach(function(value, key){
console.log(key, value);
});
I use FormData to send a number of files - and then on the node.js server I use Formidable.
I've pasted some partial code below that may help - sorry it's not a smaller sample.
Hope it helps
On the browser side I have:
let form_data = new FormData()
form_data.append('upload_data', file)
$.ajax({
url: '/file/upload' + remote_path + '/' + filename,
type: 'POST',
data: form_data,
processData: false,
contentType: false,
success: (res) => {
...
On the node.js side (apologies for the length..)I have:
const fs = require('fs')
const formidable = require('formidable')
const path = require('path')
...
app.post('/file/upload/*', (req, res) => {
let filename = req.params[0]
let media = path.basename(filename)
let folder = filename.substring(0, filename.length - media.length)
let form = new formidable.IncomingForm()
// form.encoding = 'utf-8'
form.multiples = true
form.uploadDir = path.join(media_folder, folder)
form.keepExtensions = true
form.parse(req, (err, fields, files) => {
if (err) {
fail(res, 'failed to upload')
} else {
success(res)
}
})
form.on('fileBegin', (name, file) => {
const [fileName, fileExt] = file.name.split('.')
file.path = path.join(form.uploadDir, `${fileName}_${new Date().getTime()}.${fileExt}`)
})
form.on('file', (field, file) => {
fs.rename(file.path, path.join(form.uploadDir, file.name), (err) => {
if (!res.headersSent) { // Fix since first response is received
fail(res, 'an error has occured with form upload' + err)
}
})
})
form.on('error', (err) => {
fail(res, 'an error has occured with form upload' + err)
})
form.on('aborted', (err) => {
fail(res, 'Upload cancelled by browser')
})
})

Sending image via ajax to multer

I'm using Multer to upload an image file into my node server, and it always comes back to giving me undefined for using ajax to send the image.
Ajax :
image = $("#input-file-img").val()
const data = new FormData();
data.append("image", image);
$.ajax({
url: '/uploadfile/' + userName,
method: 'POST',
async: false,
processData: false ,
contentType: false,
data: data
})
Upload.js
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'uploads')
},
filename: function (req, file, cb) {
cb(null, file.originalname)
}
})
var upload = multer({ storage: storage })
router.post('/uploadfile/:userName', upload.single('image'), async (req, res, next) => {
let user = await User.findOne({ userName: req.params.userName })
let file = req.file
let fileName = file.filename
let path = variables.kepler + 'uploads/' + fileName
user.image = path
await user.save()
if (!path) {
const error = new Error('Please upload a file ...')
error.httpStatusCode = 400
return next(error)
}
if (path) {
return res.status(200).send({
status: '200',
message: 'Operation completed successfully ...',
data: user,
path
})
}
})
I checked the image value with console and it shows C:\fakepath\Capture d’écran de 2019-09-19 11-33-59.png'
Would appreciate any help.
I think your server side code is fine, if I modify the client side code as below, everything works nicely, we end up with images in the /uploads folder:
function base64toBlob(base64, mimeType) {
const bytes = atob(base64.split(',')[1]);
const arrayBuffer = new ArrayBuffer(bytes.length);
const uintArray = new Uint8Array(arrayBuffer);
for (let i = 0; i < bytes.length; i++) {
uintArray[i] = bytes.charCodeAt(i);
}
return new Blob([ arrayBuffer ], { type: mimeType });
}
function submitForm() {
const imgRegEx = /^data:(image\/(gif|png|jpg|jpeg))/;
const imageData = $('#input-file-img').attr('src');
const mimeType = imgRegEx.exec(imageData)[1];
const blob = base64toBlob(imageData, mimeType);
const fileExt = mimeType.replace("image/", "");
const fileName = "test-image." + fileExt; // Change as appropriate..
const data = new FormData();
data.append("image", blob, fileName);
$.ajax({
url: '/uploadfile/' + userName,
method: 'POST',
async: false,
processData: false ,
contentType: false,
data: data
})
}
Solved!!!
getting value by
image = $("#input-file-img").val()
that means I was sending a type String as a file
so I had to change it to
image = $('#input-file-img')[0].files[0]
and everything works really well

how to download an PDF from byteArraay in angular 6?

I am currently working in angular 6. i have to download pdf file from bytearray.
when i tried to download an pdf file. it downloads but when i open it. it shows error. please help me with it.
In the download.component.ts i am getting response as two values. first pdfname, second pdfbytearray. i am getting those values from component response.
sample response:
{
pdfName: "test.pdf",
pdfByteArray: "JVBERi0xLjQKJeLjz9MKMSAwIG9iago8PC9Qcm9kdWNlcij"
}
download.service.ts:
generatePdf(id) {
const httpOptions = {
'responseType': 'arraybuffer' as 'json'
};
return this.http.post<any>(URL.BASE_URL + 'application/generate?id='+ id,
{ httpOptions },
);
}
download.component.ts:
import { saveAs } from 'file-saver/FileSaver';
generatePdf() {
this.downloadApiService.generatePdf('4')
.subscribe( pdf => {
console.log('pdf response: ', pdf);
var mediaType = 'application/pdf';
var blob = new Blob([pdf.pdfByteArray], {type: mediaType});
let fileName = pdf.pdfName;
saveAs(blob, fileName);
}, err => {
console.log('Pdf generated err: ', JSON.stringify(err));
});
}

How to use base64 encoding on HTML5 Blob object

I'm building a library to "nodeize" the HTML5 File Api (currently in alpha)[0], to make it work with binary contents and don't have problems with charsets, I'm using Buffer[1] utility.
But the HTML5 File API uses Blob native object. Actualy I'm using the type 'application/octet-stream', and 'binary' from Buffer encoding. But, I want to use base64 in order to prevent any problem:
CoFS.prototype.writeFile = function (fileName, data, encoding, callback) {
var self = this;
if (Buffer.isBuffer(data)) {
callback = encoding;
encoding = undefined;
} else {
data = new Buffer(data, encoding);
}
this._ifready(function () {
self.getFileEntry(fileName, {create: true, exclusive: true}, function (err, fileEntry) {
if (err) return callback(new Error("Error getting file access " + err.message));
fileEntry.createWriter(function(fileWriter) {
fileWriter.onwriteend = function () {
callback(null);
};
fileWriter.onerror = function(e) {
callback(new Error(e.toString()));
};
var blob = new Blob([data.toString('binary')], {type: 'application/octet-stream'});
fileWriter.write(blob);
}, function () {
callback(new Error('Error writing ' + fileName));
});
});
});
};
Exacts on:
var blob = new Blob([data.toString('binary')], {type: 'application/octet-stream'});
I red the MDN page[2] but I didn't see anything about the encoding.
Is there any way to accomplish something like that?:
var blob = new Blob([data.toString('base64')], {type: 'application/octet-stream', encoding: 'base64'});
Thankyou.
0: https://github.com/exos/cofs
1: https://github.com/anodynos/node2web_buffer
2: https://developer.mozilla.org/en-US/docs/Web/API/Blob
I realized the Buffer object is extended from Int8Array, and both are compatible.
My code now is:
var blob = new Blob(
[data], // Data is a buffer!
{
type: 'application/octet-stream'
}
);
fileWriter.write(blob);
And for read, I use readAsArrayBuffer method, you can do:
var d = new Int8Array(arr); // When arr is arrayBuffer
var buf = new Buffer(d); // And works!
This solve my problem. For convert base64 encoded content and use in a blob, with Buffer, can be:
var blob = new Blob(
[new Buffer(cleanData, 'base64')],
{
type: 'application/octet-stream'
}
);

Categories