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

wkhtmltopdf3

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)
  clone.style.height = '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),
  };

  $http.post('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)

PDF

 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…

wkhtmltopdf4


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

Join Us

  • James Nixon

    We’re using wkhtmltopdf as well, with many of the same successes/troubles you’ve had. One interesting problem we’ve found is “spaces” appearing like evil HTML demons in text we don’t want. It creates a problem when we are later displaying the PDF and enabling searching for key words – the new HTML demon spaces cause the search to fail. Have you had any thoughts or experience on resolving this? We are running 0.12.4 stable.

    Thanks for the intro articles; it’s good to see the product we use also in use elsewhere. I hope you’ve earned many a beer from this.

  • Vincent Langlet

    Thanks, I’m glad you liked my articles.

    I’m sorry, I only generated pdf with a lot of images and a few lines of text. I didn’t know about this issue. Did you look at https://github.com/wkhtmltopdf/wkhtmltopdf/issues ?
    You can create one, there is a lot of activity.