Skip to content

Instantly share code, notes, and snippets.

@w33ble
Last active June 8, 2023 12:16
Show Gist options
  • Save w33ble/38c5e0220d491148de1c to your computer and use it in GitHub Desktop.
Save w33ble/38c5e0220d491148de1c to your computer and use it in GitHub Desktop.

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; }
};
@szz-dvl
Copy link

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
Copy link

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