Alessandro Zago
Alessandro Zago

Reputation: 803

node PDFkit blank pages

i'm creating a PDF with node.js and this package : https://github.com/devongovett/pdfkit

My problem is that when i download the pdf on the browser it is totaly blanck... server-side code :

    PDFDocument = require('pdfkit');

function creaEtichetta(req, res){
    doc = new PDFDocument
        size: 'a4'
        bufferPages: true



    doc.addPage().fontSize(25).text('Here is some vector graphics...', 100, 100);

    doc.save()
   .moveTo(100, 150)
   .lineTo(100, 250)
   .lineTo(200, 250)
   .fill("#FF3300");

   doc.addPage().fillColor("blue").text('Here is a link!', 100, 100).link(100, 100, 160, 27, 'http://google.com/')

    doc.pipe(res);
    doc.end();
}
exports.creaEtichetta = creaEtichetta;

client-side code :

var data = {};
    data.azione = "getEtichettaProdotto";

    //Scarico i dati anagrafica
    $.ajax({
        type: 'POST',
        data: JSON.stringify(data),
        contentType: 'application/json',
        url: 'http://46.101.209.16/endpoint',                       
        success: function(etichettas) {
            var blob=new Blob([etichettas]);
            var link=document.createElement('a');
            link.href=window.URL.createObjectURL(blob);
            link.download="Label"+".pdf";
            link.click();
        }//SUCCESS
    });

sorry for bad english, i'm italian

Upvotes: 2

Views: 5054

Answers (2)

Thomas Urban
Thomas Urban

Reputation: 5071

I was running in the same issue but without any client-side code involved. So this issue isn't simply client-side. Obviously, the server-side response PDFKit is piping into isn't encoding "binary" as requested by PDFKit, but applying "utf8".

Sadly, as of today there is no way of assigning some default encoding to the stream provided by ServerResponse. See https://github.com/nodejs/node/issues/14146

In my case I was working around this issue for now by collecting chunked output from PDFKit and writing at once. Instead of

var doc = new PDF();

res.type( "pdf" ).attachment( "test.pdf" );
doc.pipe( res );

I am using this:

var doc = new PDF();

res.type( "pdf" ).attachment( "test.pdf" );

var buffers = [];
doc.on( "data", function( chunk ) { buffers.push( chunk ); } );
doc.on( "end", function() {
    res.end( Buffer.concat( buffers ), "binary" );
} );

This comes with a disadvantage: since all PDFs are cached in memory this code has an impact on server side memory consumption when it comes to high number of simultaneous requests or to generating huge PDF files.

Confusingly, trying to hand over PDFKit output chunk by chunk didn't work again:

var doc = new PDF();

res.type( "pdf" ).attachment( "test.pdf" );

doc.on( "data", function( chunk ) { res.write( chunk, "binary" ); } );
doc.on( "end", function() { res.end(); } );

Upvotes: 1

MikeH
MikeH

Reputation: 707

It could be that the binary characters in your pdf aren't being correctly coded in the transfer, which would explain why locally its ok but not when transferred - pdfs are a mix of ascii and binary characters, and if the binary is corrupted it seems that you get a blank pdf.

That's likely to be a browser side issue, this approach worked for me: https://stackoverflow.com/a/27442914/2900643

Coupled with this: https://stackoverflow.com/a/33818646/2900643

EDIT: Better still use: https://github.com/eligrey/FileSaver.js/

Server:

var doc = new PDFDocument();
doc.pipe(res);
doc.circle(280, 200, 50).fill("#6600FF");
doc.end();

Browser:

angular.module('app')
.service('PdfService', function($http) {
  var svc = this;

  svc.getPdf = function() {
    return $http.get('/getpdf/', { responseType : 'arraybuffer' });
  };
});

angular.module('app')
.controller('PdfCtrl', function($scope, PdfService) {

  $scope.getPdf = function() {
   PdfService.getPdf().success(function(data) {
    var fileName = 'hello.pdf';
    var pdf = new Blob([data], {type : 'application/pdf'});
    saveAs(pdf, fileName);
   })
 };
});

Upvotes: 2

Related Questions