Node-html-pdf: How do I save buffer as PDF in client side(in browser on response as buffer) ?

Created on 10 Oct 2018  路  13Comments  路  Source: marcbachmann/node-html-pdf

This is how I sending buffer in the response.
htmlToPDF.create(finalHTML, options).toBuffer((err, buffer) => { if (err) { res.json(responses.genericError(500, 'Internal server error.')); } else { res.type('application/pdf'); res.statusCode = 200; res.send({ data: buffer, success: true }); } });

Most helpful comment

This is the code that I've written to download pdf on the client side,

    res.writeHead(200, {
      'Content-Type': 'application/pdf',
      'Content-disposition': `attachment; filename=test.pdf`,
    });

    pdf.create(html, option).toStream((err, stream) => {
      stream.pipe(res);
    });

All 13 comments

hi @sanjay555, I am trying something similar but no luck so far. did you find anything useful?

I started to upload buffer to AWS3 and then send the URL to the client.

@jatinderbhola Yo, Yeah that's how I did last time uploaded to AWS because use case was like that for me I wanted to save the document in the cloud. But this time no need to save it, so its kind of redundant to save it to the cloud and download it back. I'll be looking into it today/tomorrow, Wish me luck :)

This is the code that I've written to download pdf on the client side,

    res.writeHead(200, {
      'Content-Type': 'application/pdf',
      'Content-disposition': `attachment; filename=test.pdf`,
    });

    pdf.create(html, option).toStream((err, stream) => {
      stream.pipe(res);
    });

@GunjanSkry I'll check, Thanx for sharing.

@sanjay555, I built this solution with all the web refs, found. The idea is to send the stream from the server which a service will bind using array buffer. using blob and some basic js will do the rest to perform download.
It is not a final solution but it is working for now. if anyone has suggestions then please let me know.

route:

pdf.create(html, PDFOptions)
          .toStream(function(err, stream) {
                if (err) return res.end(err.stack)
                res.setHeader('Content-Type', 'application/pdf');
                res.setHeader('Content-Disposition', 'attachment; filename=quote.pdf');
                // res.contentType("application/pdf");
                //res.attachment('pdfname.pdf');
                stream.pipe(res);
            });

Service:

download: {
            method: 'PUT',
            isArray: false,
            params: {....},
            headers: { 'Content-Type': 'application/json', 'X-Auth-Token': ....},
            responseType: 'arraybuffer', // <- imp. to add
            transformResponse: function(data, header) {
                return { data: data }; 
            }
        },

conroller:

        .download(...)
                       .$promise
                                .then(function(res) {
                                        const blobData = new Blob([res.data]);
                                        const url = window.URL.createObjectURL(blobData);
                                        const link = document.createElement('a');
                                        link.href = url;
                                        link.setAttribute('download', ('somename' + new Date().getTime() + '.pdf'));
                                        document.body.appendChild(link);
                                        link.click();
                                        $scope.showProgressBar = false;
                                    })
                                    .catch(function(err) {
                                        $scope.showProgressBar = false;
                                        console.log(err);
                                    });

HI @sanjay555 @jatinderbhola , am trying to convert the raw html into buffer in server side. it is working for me in Local But it is not working in cloud server.

Here is my code

var html = "<html><head><meta charset='UTF-8' /><title>Invoice</title></head> <body> <h1> Hello World!</h1> </body> </html>"

pdf.create(html).toBuffer(function(err, buffer){
console.log('This is a buffer:', Buffer.isBuffer(buffer));
var data = buffer.toString("base64")
console.log('Buffer data:', data)
});

o/p:-

This is a buffer: undefined
/home/api-actions.js:51
var data = buffer.toString("base64")
^

TypeError: Cannot read property 'toString' of undefined

@sanjay555 @jatinderbhola

In terms of piping the stream, I added res.end() when the finish event is emitted.

The @GunjanSkry response is not right.
Because, if you want to catch the error, it will be return as a PDF.

Here is the code :

const html_pdf = require('html-pdf');

html_pdf.create(html_string).toStream((err, stream) => {
          if (err) return res.end(err.stack);
          res.setHeader('Content-type', 'application/pdf');
          res.setHeader('Content-disposition', 'attachment; filename=export-from-html.pdf'); // Remove this if you don't want direct download
          res.setHeader('Content-Length', ''+stream.length);
          stream.pipe(res);
        });

@cavasinf but how do i save it as a pdf at the client side. Streamsaverjs not support pdf , might need another service worker to work arount it.

@cavasinf but how do i save it as a pdf at the client side. Streamsaverjs not support pdf , might need another service worker to work arount it.

@lowzijian I don't understand..
With that code https://github.com/marcbachmann/node-html-pdf/issues/472#issuecomment-564488260 the server give to the client the PDF version of the html_string.
You need to "catch" that response and save it in the client side. That's it.

i have the res.data in stream , what am i suppose to do with it ? saveAs ? @cavasinf
If i wish to open a window with the html on it , what should i do ?

@lowzijian
If you have
res.setHeader('Content-disposition', 'attachment; filename=export-from-html.pdf'); // Remove this if you don't want direct download
It will automatically popup the "file open or download" on the response of your "controller".
But if you comment this line, your browser will open the stream with a PDF reader (eg Firefox).

Here is my code if you want :

const html_pdf = require('html-pdf');

    res.render('pages/index', { res: res },function (err, html) {
        const html_for_pdf = "<h1>Am I a true HTML ?</h1>";
        html_pdf.create(html_for_pdf ).toStream((err, stream) => {
          if (err) return res.end(err.stack);
          res.setHeader('Content-type', 'application/pdf');
          res.setHeader('Content-disposition', 'attachment; filename=export-from-html.pdf'); // Remove this if you don't want direct download
          res.setHeader('Content-Length', ''+stream.length);
          stream.pipe(res);
        });
    });

On backend, convert your buffer to base64: PDFBuffer.toString('base64') and send it to the client side

Just do these steps on client:

Create a function that converts base64 to blob:

function base64toBlob(base64Data, contentType = '') {
  const sliceSize = 1024;
  const byteCharacters = atob(base64Data);
  const bytesLength = byteCharacters.length;
  const slicesCount = Math.ceil(bytesLength / sliceSize);
  const byteArrays = new Array(slicesCount);

  for (let sliceIndex = 0; sliceIndex < slicesCount; sliceIndex += 1) {
    const begin = sliceIndex * sliceSize;
    const end = Math.min(begin + sliceSize, bytesLength);

    const bytes = new Array(end - begin);
    for (let offset = begin, i = 0; offset < end; i += 1, offset += 1) {
      bytes[i] = byteCharacters[offset].charCodeAt(0);
    }

    byteArrays[sliceIndex] = new Uint8Array(bytes);
  }

  return new Blob(byteArrays, { type: contentType });
}

Download a library to download things in js, i am using download.js

const blobPDF = base64toBlob(base64PDF, 'application/pdf');

download(new Blob([blobPDF]), 'filename.pdf', 'application/pdf');

That's it! I got that from here

Was this page helpful?
0 / 5 - 0 ratings