One Year With Wkhtmltopdf: One Thousand One Problems, One Thousand One Solutions

In the previous article, we saw how to use wkhtmltopdf. But, when I did it, I encountered problems that I really want to share with you.

Each problem has a solution

First, you have to understand what wkhtmltopdf does: rendering the html with ‘its own browser‘. So, when something does not seem to work, try:

  • To add an option to wkhtmltopdf’s browser configuration
  • Modify the html you gave to wkhtmltopdf’s browser

Now, we can improve the rendering of our pdf!

How to handle the dimensions of the pdf


First, we need to define these two new functions:

// controller.js

// Return the width and the height of the document
// In the way the user see it
getSize = function(html) {
  return {
    width: html.offsetWidth,
    height: html.offsetHeight,

// Return the real full height of the document
// With no scroll
getRealHeight = function(html) {
  clone = angular.copy(html) = 'auto'
  realHeight = clone.offsetHeight

  return realHeight

And give these two new values to our back-end

// controller.js

$scope.print = function() {
  var html = document.getElementsByTagName('html')[0];
  var body = {
    html: html,
    size: getSize(html),
    realHeight: getRealHeight(html),

  $'api/pdf/print', body, {responseType: 'arraybuffer'})
  .success(function(response) {
    var file = new Blob([ response ], {type: 'application/pdf'});
    FileSaver.saveAs(file, 'print.pdf');

In the back-end you just have to set the following options

  • viewport-size is used to emulate the window size
  • page-width and page-height are used to set the pdf size
// pdf.js
  var size = req.body.size
  var realHeight = req.body.realHeight

  var options = {
    'viewport-size': size.width + 'x' + size.height,
    // I found a 0.271 ratio
    'page-width': (size.width * 0.271),
    'page-height': (realHeight * 0.271),
    'user-style-sheet': CSSLocation,

This way you have exactly what you see on your navigator!

Nota Bene: the page-width and page-height values were given in mm, so I thought I should have a 0.264583333 ratio from pixel to mm. But when I tried, I found 0.271 as a better approximation. (This was useful on my project because of SVG with inline dimensions)


 How to display the images correctly

You need to know one thing: wkhtmltopdf needs absolute paths for images. In my project, I used this fix:

// pdf.js

// Replace relativ path of img by absolute path
html = html.replace(/static\/images\//g, projectLocation + 'client/www/static/images/')

But you have to change the regex /static\/images\//g and the path client/www/static/images/ according to where the images are stored.

How to modify the pdf before printing it

If you understand how wkhtmltopdf works, this hint won’t surprise you: modify the html you send!

// controller.js
  var body = {
    html: getModifiedHtml(html),
    size: getSize(html),
    realHeight: getRealHeight(html),

Now you can do what you want with your pdf:

// controller.js
getModifiedHtml = function(html) {
  newHtml = angular.copy(html)
  newHtml = removeHeader(newHtml)
  newHtml = removeFooter(newHtml)
  newHtml = addNewHeader(newHtml)
  newHtml = addNewFooter(newHtml)
  newHtml = doStuff(newHtml)
  // ...
  return newHtml

But the first line newHtml = angular.copy(html) is really important.
Do not forget to start by copying the html you got before modifying it.
Otherwise, your user will be surprised…


You liked this article? You'd probably be a good match for our ever-growing tech team at Theodo.

Join Us