Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?

pdfmake

Use in node.js

The module on npm exposes the pdfmake Printer, which the docs themselves do not cover. Using it is pretty simple though.

var path = require('path');
var Printer = require('pdfmake');

// fonts are available in the test-env/tests/fonts path, this is a helper
function fontPath(file) {
  retrun path.resolve('pdfmake', 'test-env', 'tests', 'fonts', file);
}

// required font setup, requires that you link to the fonts shipped with npm
var fontDescriptors = {
  Roboto: {
    normal: fontPath('Roboto-Regular.ttf'),
    bold: fontPath('Roboto-Medium.ttf'),
    italics: fontPath('Roboto-Italic.ttf'),
    bolditalics: fontPath('Roboto-Italic.ttf'),
  }
}; 
var docDefinition = {}; // this is what you see in all the docs
var printer = new Printer(fontDescriptors);

// get a reference to the PdfKit instance, which is a streaming interface
var pdfDoc = printer.createPdfKitDocument(docDefinition);

// pipe to a file or response object
function streamTo(pdfDoc) {
  // writeStream can be an fs object, response object, etc
  var writeStream = fs.createWriteStream('pdfs/output.pdf');
  var pdfDoc = printer.createPdfKitDocument(docDefinition);
  pdfDoc.pipe(writeStream); // streaming interface
}

// turn the stream into a Buffer
// Usage: getDoc(pdfDoc, function (err, buffer, pages) { var base64 = buffer.toString('base64'); /* app logic */ });
function getDoc(pdfDoc, cb) {
  // buffer the output
  var chunks = [];
  
  pdfDoc.on('data', function(chunk) {
  	chunks.push(chunk);
  });
  pdfDoc.on('end', function() {
  	var result = Buffer.concat(chunks);
  	cb(null, result, pdfDoc._pdfMakePages);
  });
  pdfDoc.on('error', cb);
  
  // close the stream
  pdfDoc.end();
}

createPdfKitDocument takes 2 arguments, docTemplate and an optional options.

docDefinition

Specified as an object, the document definition object.

properties default description
header header, can be a function, placed on every page
footer footer, like header, but at the bottom
content text, table, etc - the meat of the document
defaultStyle { fontSize: 12, font: 'Roboto' } applied to entire document
styles available style dictionaries
pageSize document page size, string or { width: number, height: number }
pageOrientation portrait document orientation, landscape or portrait
pageMargins document margins - [left, top, right, bottom] or [horizontal, vertical]
pageBreakBefore function, executed to determine if there should be a page break before content
background background-layer added on every page, can be a function
images similar to styles, globally-available image content - most useful as 'data:image/jpeg;base64,...'
watermark
info metadata
content metadata

options

Also specified as an object, this is where you can pass a few globally available options to your document. Available options include:

Option Parameter Description
tableLayouts Passed to registerTableLayouts, used to define globally available table layouts (see Tables and Layouts below)
autoPrint ???

Tables and Layouts

Tables have a few pre-defined layouts available (code). They can be used by specifying a layout: 'LayoutName' in the table definition. The included styles are noBorders, headerLineOnly, and lightHorizontalLines, and you can see examples of all three near the bottom of the Tables example in the playground.

If no layout is specified, the default is used. This provides a 1px black line around each cell, with a top/bottom padding of 2px and a left/right padding of 4px (code)

Custom Layouts

You can build your own custom layout as well, specifying your own line width, color and cell padding. Each value takes a callback function, which is passed the row index and table node reference (code)

Here's an example of how to do that, using the default layout as the values:

layout: {
  hLineWidth: function(i, node) { return 1; }, //return node.table.headerRows && i === node.table.headerRows && 3 || 0; },
  vLineWidth: function(i, node) { return 1; },
  hLineColor: function(i, node) { return 'black'; },
  vLineColor: function(i, node) { return 'black'; },
  paddingLeft: function(i, node) { return 4; }, //i && 4 || 0; },
  paddingRight: function(i, node) { return 4; }, //(i < node.table.widths.length - 1) ? 4 : 0; },
  paddingTop: function(i, node) { return 2; },
  paddingBottom: function(i, node) { return 2; }
};
@ThibaultJanBeyer

This comment has been minimized.

Copy link

@ThibaultJanBeyer ThibaultJanBeyer commented Apr 5, 2018

Nice, thanks! This helped me a lot

@alphanumeric0101

This comment has been minimized.

Copy link

@alphanumeric0101 alphanumeric0101 commented Jul 24, 2018

jee whiz, this was clutch thank you! can't believe this isn't mentioned in the documentation. if you want to simply print to fs then the examples folder is ok but if you want dataURI or Base64 it's like what the heck do I do as the getBase64() method doesn't exist.

@brendonlamb

This comment has been minimized.

Copy link

@brendonlamb brendonlamb commented Aug 22, 2018

epic resource, thanks a ton!

FYI - "retrun" on line 13 of the first code example

@szz-dvl

This comment has been minimized.

Copy link

@szz-dvl szz-dvl commented Jan 19, 2019

Hi; I'm trying to use this to pipe the document through an express response object, however if I don't write the document first (using the deprecated function pdfDoc.write) the document is not properly generated. If anyone have an idea it will be welcome.

Thanks in advance.

Szz.

@szz-dvl

This comment has been minimized.

Copy link

@szz-dvl szz-dvl commented Jan 19, 2019

Hey it is solved now, forgot to call doc.end() sorry for the inconvenience!

Thanks again.

Szz

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment