Get PDFKit as base64 string
Asked Answered
S

4

12

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!

Sakhuja answered 25/8, 2016 at 13:51 Comment(0)
T
24

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);
});
Tosch answered 14/9, 2016 at 23:32 Comment(1)
Excellent, thanks! That's exactly what I wanted, and it works perfectly.Sakhuja
A
6

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"));
Alathia answered 3/8, 2022 at 0:15 Comment(0)
G
1

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.

Gaughan answered 5/10, 2022 at 14:16 Comment(0)
D
0

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

Dara answered 12/9, 2016 at 10:50 Comment(1)
ok thanks! yes, the in-memory would be better, since I prefer not to write on the disk. And because de PdfDocument is a stream, it shouldn't be too hard. I'll check your repo.Sakhuja

© 2022 - 2024 — McMap. All rights reserved.