Download a file to a base64 string - node.js

I'm running Node.js code on a readonly file system and I would like to download a file and convert this file directly to a base64 string but without writing the file on the disk.
Now I have the following:
let file = fs.createWriteStream(`file.jpg`);
request({
uri: fileUrl
})
.pipe(file).on('finish', () => {
let buff = fs.readFileSync(file);
let base64data = buff.toString('base64');
})
But this solution is writing on the disk so this is not possible for me.
I would like to do the same but without the need of the temp file on the disk. Is it possible?

You don't pipe() into a variable. You collect the data off the stream into a variable as the data arrives. I think you can do something like this:
const Base64Encode = require('base64-stream').Base64Encode;
const request = require('request');
let base64Data = "";
request({
uri: fileUrl
}).pipe(new Base64Encode()).on('data', data => {
base64Data += data;
}).on('finish', () => {
console.log(base64Data);
}).on('error', err => {
console.log(err);
});

Related

How to stream a file without saving it down first?

I have put together the below code that creates a CSV called example.csv, using the json2csv library.
I would prefer to not have to save down and store the CSV file before it is passed to the front end to be downloaded.
I can't seem to figure out how to stream or pipe the file to the front end, without saving it first.
How to take the output CSV file of the json2csv library and send it straight tot he front end?
Some of my code
const input = new Readable({ objectMode: true });
input._read = () => {};
input.push(JSON.stringify(parsed));
input.push(null);
var outputPath = "example.csv";
const output = createWriteStream(outputPath, { encoding: "utf8" });
const json2csv = new Transform(opts, transformOpts);
// Pipe to output path
input.pipe(json2csv).pipe(output);
res.setHeader("Content-Type", "text/csv");
res.download(outputPath);
You can simply pipe the json2csv stream to the res object, e.g:
const ReadableStream = require('stream').Readable;
const Json2csvTransform = require('json2csv').Transform;
app.get('/csv', (req, res) => {
const stream = new ReadableStream();
stream.push(JSON.stringify(data));
stream.push(null);
const json2csv = new Json2csvTransform({}, transformOpts);
res.setHeader('Content-disposition', 'attachment; filename=data.csv');
res.writeHead(200, { 'Content-Type': 'text/csv' });
stream.pipe(json2csv).pipe(res);
})

File created by writing contents of createReadStream does not match the original data

I expected that the code below would work. I am doing a basic sanity check to test whether I can read a file into a readStream, preserving the encoding and then write it out to a file. My expectation was that the resulting file would be the same as the file that I read the data from but this seems to not be the case.
My code is
const zipPath = path.join(__dirname, 'inputFile.zip')
const rs = fs.createReadStream(zipPath, { encoding: 'ascii' }) // yes it is ascii
let fileData = ''
rs.on('data', chunk => fileData += chunk)
rs.on('end', () => {
console.log("data written got ", fileData)
// now test making a file from this
fs.writeFile('./outputFile.zip', fileData, 'ascii', (err) => {
if (err) console.error(err)
console.log("WRITTEN")
})
})
Currently what happens is that I can't unzip the resulting file.
Could someone let me know what I am doing wrong?
guess it had to do with encodings... this was more or less of a sanity check and it looks like just using pipe without encoding works fine...
const rs = fs.createReadStream(zipPath) // , { encoding: ENCODING })
const ws = fs.createWriteStream('./output.zip') // , { encoding: ENCODING })
rs.pipe(ws)

Check if binary data file type if PDF or not?

I have a PDF file or any other file. When I read that file content in Node.js, it gives me binary data. How can I determine if a binary data file type is PDF or not in Node.js?
Check this https://github.com/MaraniMatias/isPDF
const fs = require("fs");
const isPDF = require("is-pdf-valid");
const file = fs.readFileSync("./test.pdf")
console.log(isPDF(file));
You can use a PDF parsing library such as pdf-parse to check if a file, buffer etc. is a valid PDF:
const rp = require("request-promise-native");
const pdf = require('pdf-parse');
const testUrl1 = "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf";
const testUrl2 = "https://en.wikipedia.org/wiki/Cat#/media/File:Cat_poster_1.jpg";
function getPDF(url) {
return rp({ uri: url, encoding: null});
}
function isPDF(buffer) {
return pdf(buffer).then(function(data) {
return { isPDF: true, info: data.info };
}, (err) => {
return { isPDF: false, info: null };
});
}
async function testPDFCheck(url) {
let pdfBuffer = await getPDF(url);
let result = await isPDF(pdfBuffer);
console.log(`Is PDF result: (${url}): `, result);
}
testPDFCheck(testUrl1);
testPDFCheck(testUrl2);

NodeJS: Unable to convert stream/buffer to base64 string

I need to create base64 string that I need to send to a third party API. I have the stream and buffer. Form stream I am able to create an image so there is no way the stream is corrupted. Here are the two variables:
var newJpeg = new Buffer(newData, "binary");
var fs = require('fs');
let Duplex = require('stream').Duplex;
let _updatedFileStream = new Duplex();
_updatedFileStream.push(newJpeg);
_updatedFileStream.push(null);
No matter whatever I try, I can not convert either of them in base64 string.
_updatedFileStream.toString('base64');
Buffer(newJpeg, 'base64');
Buffer(newData, 'base64');
None of the above works. Sometimes I get Uint8Array[arraySize] or Gibberish string. What am I doing wrong?
Example using promises (but could easily be adapted to other approaches):
return new Promise((resolve, reject) => {
let buffers = [];
let myStream = <...>;
myStream.on('data', (chunk) => { buffers.push(chunk); });
myStream.once('end', () => {
let buffer = Buffer.concat(buffers);
resolve(buffer.toString('base64'));
});
myStream.once('error', (err) => {
reject(err);
});
});

Get PDFKit as base64 string

I'm searching a way to get the base64 string representation of a PDFKit document. I cant' find the right way to do it...
Something like this would be extremely convenient.
var doc = new PDFDocument();
doc.addPage();
doc.outputBase64(function (err, pdfAsText) {
console.log('Base64 PDF representation', pdfAsText);
});
I already tried with blob-stream lib, but it doesn't work on a node server (It says that Blob doesn't exist).
Thanks for your help!
I was in a similar predicament, wanting to generate PDF on the fly without having temporary files lying around. My context is a NodeJS API layer (using Express) which is interacted with via a React frontend.
Ironically, a similar discussion for Meteor helped me get to where I needed. Based on that, my solution resembles:
const PDFDocument = require('pdfkit');
const { Base64Encode } = require('base64-stream');
// ...
var doc = new PDFDocument();
// write to PDF
var finalString = ''; // contains the base64 string
var stream = doc.pipe(new Base64Encode());
doc.end(); // will trigger the stream to end
stream.on('data', function(chunk) {
finalString += chunk;
});
stream.on('end', function() {
// the stream is at its end, so push the resulting base64 string to the response
res.json(finalString);
});
Synchronous option not (yet) present in the documentation
const doc = new PDFDocument();
doc.text("Sample text", 100, 100);
doc.end();
const data = doc.read();
console.log(data.toString("base64"));
I just made a module for this you could probably use. js-base64-file
const Base64File=require('js-base64-file');
const b64PDF=new Base64File;
const file='yourPDF.pdf';
const path=`${__dirname}/path/to/pdf/`;
const doc = new PDFDocument();
doc.addPage();
//save you PDF using the filename and path
//this will load and convert
const data=b64PDF.loadSync(path,file);
console.log('Base64 PDF representation', pdfAsText);
//you could also save a copy as base 64 if you wanted like so :
b64PDF.save(data,path,`copy-b64-${file}`);
It's a new module so my documentation isn't complete yet, but there is also an async method.
//this will load and convert if needed asynchriouniously
b64PDF.load(
path,
file,
function(err,base64){
if(err){
//handle error here
process.exit(1);
}
console.log('ASYNC: you could send this PDF via ws or http to the browser now\n');
//or as above save it here
b64PDF.save(base64,path,`copy-async-${file}`);
}
);
I suppose I could add in a convert from memory method too. If this doesn't suit your needs you could submit a request on the base64 file repo
Following Grant's answer, here is an alternative without using node response but a promise (to ease the call outside of a router):
const PDFDocument = require('pdfkit');
const {Base64Encode} = require('base64-stream');
const toBase64 = doc => {
return new Promise((resolve, reject) => {
try {
const stream = doc.pipe(new Base64Encode());
let base64Value = '';
stream.on('data', chunk => {
base64Value += chunk;
});
stream.on('end', () => {
resolve(base64Value);
});
} catch (e) {
reject(e);
}
});
};
The callee should use doc.end() before or after calling this async method.

Resources