Effective PDF Generation in Drupal

Share this article

A few months ago I had a client requirement for PDF generation, in this case to generate certificates that could be viewed online or printed. I spent some time looking into the best Drupal options available and picked up some advice along the way on how best to accomplish these aims. After mentioning my results to several people, it seemed that PDF generation was a common requirement and now I have the same need again on a personal project, so it seemed a good case study to walk you through what I found.

Key Takeaways

  • Drupal offers two options for PDF generation: the Print module and Views PDF. The Print module is recommended due to its better support, output options, and less server-intensive operation.
  • PDF generation in Drupal requires a change in mindset for web developers. Unlike web design, print design often requires pixel or millimeter perfect design due to its precise nature.
  • The Print module works by recreating HTML markup as other output formats. Customizing the appearance of PDFs can be done through the use of themes and templates.
  • wkhtmltopdf is recommended for PDF generation in Drupal due to its accuracy and ease of use. However, it requires the installation of an executable, which may not be suitable for everyone.
  • Troubleshooting issues with PDF generation in Drupal can involve checking error logs, ensuring correct configuration settings, and potentially updating or reinstalling modules.

Why not just print?

If your requirements are simple, it may be easier to just to tell your website users to print and there’s nothing stopping them doing this. If we want a level of control over what is printed or we want to distribute files for printing, then we need to look into other options.

Web vs Print

PDF generation takes a slight change of mindset. As web developers, we have spent a lot of time convincing designers from a print background to stop producing pixel perfect designs that will be difficult to reproduce on the web. If you want to introduce PDF generation or any form of high designed print output, then we need to relearn some of our old skills we left behind. The nature of print means that it is precise and often needs pixel (or millimeter) perfect design.

What am I trying to accomplish?

I am currently working on a board game and I want to allow players to be able to create their own cards that can be shared on the website and printed for use in the game. We have a specific size and layout that these cards will always be and need to conform to, here’s the initial design that we will partially recreate:

PDF options in Drupal

There are two options in Drupal for creating PDFs. The Print module and Views PDF. Views PDF initially seemed the better option as it would allow us to leverage the power of views and the myriad options it offers. However, it has the PHP module as a dependency and as far as I know, is reliant on the eval() function. PDF generation has the potential to be a server intensive task and this method seemed inefficient to me, aside from my reluctance to ever have any kind of PHP evaluation module enabled in Drupal.

This caused me to settle on the print module, which is also better supported and offers many other options for output that may prove useful.

Next we need to decide on our PDF generation library, I am going to suggest you use wkhtmltopdf and explain why later, as I want to build something to compare first. Do this by visiting the wkhtmltopdf website and follow the instructions for your setup. Remember it will need to be installed on local and production sites. After installing you need to create an alias to the wkhtmltopdf executable into your Drupal libraries folder, i.e.:

ln -s /usr/bin/wkhtmltopdf /var/www/sites/all/libraries/wkhtmltopdf

If you are installing under Ubuntu, I ran into some issues with the official archive, I recommend installing manually from the links above.

Configuring print module

Lets start with general settings at admin/config/user-interface/print/common:

  • Logo Options, Footer Options: Turned off for my example.
  • Keep the current theme CSS: Enable this for theme consistency and less work.

Let’s set how and where we want the links to display to reach our PDF / Print versions, admin/config/user-interface/print/ui.

I am setting mine to be displayed in a block so I can have more control over layout.

The overall configuration options for PDF output are at admin/config/user-interface/print/pdf

I recommend these settings:

  • Open PDF in: New browser window
  • Paper size and orientation: Whatever is appropriate for you. For now I’m using A7 for my card, it’s not quite the same, but close enough for this demo.
  • Caching: I am yet to determine quite how effective this is, but usual rules apply, keep off during development and on in production
  • File name: I will use [site:name] - [node:title], you can use tokens here.

Looking at wkhtmltopdf specifics, admin/config/user-interface/print/pdf/wkhtmltopdf.
As wkhtmltopdf is a more advanced tool, it’s a command line based configuration, about which you can find more details here.

Here are some extras I added:

--margin-bottom 0m --margin-left 0m --margin-top 0m --margin-right 0m --dpi 300

This ensures that we have no margins added by wkhtmltopdf and can rely on our CSS output. We are also rendering at 300dpi for print.

A quick note on images. There are options for setting image dpi rendering here, but of course if someone uploads a 72dpi image and it is upscaled to 300dpi, it will look poor. Getting this right is a combination of configuration and user training.

Creating the HTML

The print module works by recreating HTML markup as other output formats. I find it easier to create the markup and CSS that will result in this output first. In my case this is affecting the default output of my content type, but this could be kept separate through the use of view modes or the print module’s own print output. Below is my content type – I have added a couple of the extra fields that my content type needs, but not all of them:

If you want, the print module also supplies it’s own custom view mode so that we could duplicate the same display or use in combination with techniques mentioned above.

Creating Styles.

The print module comes with its own style sheet (print.css, found in the module folder) that you can use to create styles that only apply to the print module rendered versions of nodes. You will need to add a copy to you theme and add them to your theme’s .info file in the usual way.

If you checked the option Keep the current theme CSS as mentioned above then the print module will use your main theme styles and then check the print.css file for any overrides that you only want in print module rendered output. This makes the most sense to me and feels like the tidiest option. If you don’t use this option then the print.css file is the only style sheet that will affect your output. The rest of this example will assume it is enabled.

Here is a simplified HTML version of the design we saw earlier:

I am using a bootstrap sub theme which comes with its own markup that may be different from your theme. I have some custom fonts loaded through font-your-face and created a custom image style for the image, these field names also represent my fields added above. Image styles don’t let you define sizes in centimeters, to get the right size in pixels I used this tool.

We have a particular print size we are trying to accomplish. You can specify sizes in CSS in a variety of units, so in our case I am using centimeters.

Here is my CSS:

//This is my main content area, will be different in other themes and in mine covers the regions that appear for logged in and anonymous users
    .node-type-event-card .main-container section.col-sm-9,
    .node-type-event-card .main-container section.col-sm-12 {
      border: solid 1px #000000;
      width: 6.8cm;
      height: 9.3cm;
      padding: 0.681cm;
    }
    
    //The card title
    .node-type-event-card .main-container h1.page-header {
      text-align: right;
      margin: 0;
      font-size: 14px;
    }
    
    //Sets card padding
    .node-type-event-card .main-container .content {
      padding: 20px;
    }
    
    //Formats the field contents
    .node-type-event-card .main-container .content .field {
      color: black;
      margin-top: 10px;
      margin-bottom: 10px;
    }
    .node-type-event-card .main-container .content .field-name-body {
      font-size: 12px;
      text-align: center;
    }
    .node-type-event-card .main-container .content .field-name-field-image img {
      width: 100%;
    }

Here is how the PDF output currently looks:

Not quite right.

This is because the print module is using our theme but a different tpl file, print.tpl.php. Copy it from the module and into your theme so we can make some changes. You can add --format to specify the output format, i.e. print--pdf.tpl.php.

The main reason we want to edit this is that the print module by default prints a bunch of links at the top of the page and some hr tags that we don’t want and can’t remove in the UI, so let’s tidy it up. Here is my final HTML:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML+RDFa 1.0//EN"
      "https://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd">
    <html xmlns="https://www.w3.org/1999/xhtml" xml:lang="<?php print $language->language; ?>" version="XHTML+RDFa 1.0" dir="<?php print $language->dir; ?>">
      <head>
        <?php print $head; ?>
        <base href='<?php print $url ?>' />
        <title><?php print $print_title; ?></title>
        <?php print $scripts; ?>
        <?php if (isset($sendtoprinter)) print $sendtoprinter; ?>
        <?php print $robots_meta; ?>
        <?php if (theme_get_setting('toggle_favicon')): ?>
          <link rel='shortcut icon' href='<?php print theme_get_setting('favicon') ?>' type='image/x-icon' />
        <?php endif; ?>
        <?php print $css; ?>
      </head>
      <body>
        <?php if (!empty($message)): ?>
          <div class="print-message"><?php print $message; ?></div><p />
        <?php endif; ?>
        <?php if ($print_logo): ?>
          <div class="print-logo"><?php print $print_logo; ?></div>
        <?php endif; ?>
    
        <?php if (!isset($node->type)): ?>
          <h2 class="print-title"><?php print $print_title; ?></h2>
        <?php endif; ?>
        <div class="print-content"><?php print $content; ?></div>
        <div class="print-footer"><?php print theme('print_footer'); ?></div>
        <?php if ($sourceurl_enabled): ?>
          <div class="print-source_url">
            <?php print theme('print_sourceurl', array('url' => $source_url, 'node' => $node, 'cid' => $cid)); ?>
          </div>
        <?php endif; ?>
        <?php print $footer_scripts; ?>
      </body>
    </html>

And my CSS (print.css) is much the same as the previous CSS but reflects the page structure:

// I have found that clearing the margins helps with the PDF generation    
    body {
          margin: 0;
          padding: 0;
        }
        
        html {
          margin: 0;
        }
        
        .print-content .node {
          border: solid 1px #000000;
          width: 6.8cm;
          height: 9.3cm;
          padding: 0.681cm;
          font-family: 'VT323';
          font-size: 20px;
        }
        
        .print-content h2 {
          text-align: right;
          margin: 0;
          font-size: 14px;
        }
        
        .print-content .content {
          padding: 20px;
        }
        
        .print-content .content .field {
          color: black;
          margin-top: 10px;
          margin-bottom: 10px;
        }
        
        .print-content .content .field-name-body {
          font-size: 12px;
          text-align: center;
        }
        
        .print-content .content .field-name-field-image img {
          width: 100%;
        }

Now, what’s wrong with the fonts? Unfortunately we can’t use custom fonts that are on a remote server (in this case Google Fonts). I’m not sure if this is an issue with the print module (looking at print.tpl.php, it loads styles in a different way) or if it’s a wkhtmltopdf issue. I found a few other potential paths you may be able to follow if you can’t download your font, but I will assume you can and show a foolproof method.

Download your fonts and add them locally, I’m putting them into theme/fonts, and add the following CSS at the top of your print.css file.

@font-face {
      font-family: 'VT323';
      src: url('../fonts/VT323-Regular.ttf');
      font-style: regular;
      font-weight: 400;
    }

Voila!

Well, we still have a margin, but that’s because we’re not using the right paper size. So, that aside, this is pretty great!

Why wkhtmltopdf?

Many of you may be familiar with TCPDF and dompdf – they are commonplace and reasonably lightweight. I tried TCPDF and here are the results:

Not as accurate as wkhtmltopdf out of the box, so I tried dompdf:

Hmm. This is because I am using custom fonts and documentation mentions that with changes I can get this working. However, wkhtmltopdf worked for me straight away with no tweaking or sifting through documentation. It aims to produce a complete copy of HTML so is generally 99% accurate. With my last project (which was far more complicated) I found a few problems when using a couple of CSS techniques that were more appropriate to screen, but even those were fixable.

Whilst wkhtmltopdf offers by far the best PDF output, setup involves installing an executable and this may make it unsuitable for many of you. However, I will make the assumption that if you are working with Drupal and need to achieve this level of layout complexity then you have access to your own server or VPS.

Have you tried any form of PDF (or other formats) generation with Drupal? I would love to hear tips and tweaks that you found.

Frequently Asked Questions (FAQs) about Effective PDF Generation in Drupal

What are the best modules for PDF generation in Drupal?

There are several modules available for PDF generation in Drupal. Some of the most popular ones include Print, PDF, and Email, TCPDF, and DOMPDF. These modules offer different features and capabilities, so the best one for you will depend on your specific needs. For instance, the Print, PDF, and Email module is a versatile tool that allows you to create PDF versions of any webpage. TCPDF, on the other hand, is a PHP class for generating PDF documents without requiring external extensions. DOMPDF is a CSS 2.1 compliant HTML layout and rendering engine written in PHP.

How can I customize the appearance of my PDFs in Drupal?

Customizing the appearance of your PDFs in Drupal can be done through the use of themes and templates. You can create a custom theme for your PDFs, or modify an existing one, to change the layout, fonts, colors, and other design elements. Additionally, you can use templates to define the structure of your PDFs, such as where to place headers, footers, and other elements.

Can I generate PDFs from user-submitted data in Drupal?

Yes, you can generate PDFs from user-submitted data in Drupal. This can be done using modules like Webform and Entity Print. With Webform, you can create forms for users to fill out, and then use the data they submit to generate a PDF. Entity Print allows you to print any Drupal entity or view to PDF.

How can I add a download link for a PDF in Drupal?

Adding a download link for a PDF in Drupal can be done using the File field in the Content type. You can upload the PDF file to this field, and then configure the display settings to show a download link. Alternatively, you can use the Link field to add a URL to the PDF file, which users can click on to download the file.

Can I generate PDFs in multiple languages in Drupal?

Yes, you can generate PDFs in multiple languages in Drupal. This can be done using the Multilingual support feature in Drupal, which allows you to create content in different languages. You can then use a PDF generation module to create PDF versions of this content in the respective languages.

How can I troubleshoot issues with PDF generation in Drupal?

Troubleshooting issues with PDF generation in Drupal can involve several steps. First, check the error logs in Drupal to see if there are any error messages related to PDF generation. Next, check the configuration settings of your PDF generation module to ensure they are correct. If you’re still having issues, you may need to update or reinstall the module, or seek help from the Drupal community.

Can I generate PDFs from views in Drupal?

Yes, you can generate PDFs from views in Drupal. This can be done using modules like Views PDF or Entity Print. With Views PDF, you can create a view of your content and then generate a PDF from this view. Entity Print allows you to print any Drupal entity or view to PDF.

How can I improve the performance of PDF generation in Drupal?

Improving the performance of PDF generation in Drupal can be achieved by optimizing your server configuration, using caching, and minimizing the amount of data that needs to be processed. Additionally, you can use modules like Advanced CSS/JS Aggregation to improve the performance of your site, which can in turn improve the speed of PDF generation.

Can I generate PDFs with dynamic content in Drupal?

Yes, you can generate PDFs with dynamic content in Drupal. This can be done using modules like Entity Print or Views PDF. These modules allow you to create PDFs from any Drupal entity or view, which can include dynamic content such as user-submitted data, content from a database, or content generated by other modules.

How can I secure my PDFs in Drupal?

Securing your PDFs in Drupal can be done using modules like Protected Pages or Content Access. These modules allow you to restrict access to your PDFs based on user roles, permissions, or other criteria. Additionally, you can use the Private Files feature in Drupal to store your PDFs in a directory that is not publicly accessible.

Chris WardChris Ward
View Author

Developer Relations, Technical Writing and Editing, (Board) Game Design, Education, Explanation and always more to come. English/Australian living in Berlin, Herzlich Willkommen!

BrunoSdrupaldrupal-planetdrupal8OOPHPpdfpdf generationPHP
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week