Decent PDF generation in Drupal

Decent PDF generation in Drupal

Difficulty: 
Let's Rock

Whether you like it or not PDF is a mainstream adopted format to exchange documents. Your customers will ask, sooner or later, to have some sort of content generated in PDF (be it an invoice, a report, etc...).

Doing a quick search these are the modules that offer some sort of PDF integration in Drupal:

All of them are aimed at outputting Drupal pages (or views) in PDF format, but do not provide a solid API to do low level PDF generation.

Furthermore, the libraries they rely on do not look very promissing (just look at their websites or last updated dates):

We are used to the .Net based professional PDF generation tools that simply get an HTML input and output a resonable browser like rendered PDF with a  powerful and flexible API. We tried nearly all of the PHP offerings with very unsatisfactory results, not to mention how slow they were or the enormous amount of memory they ate. (We did not try wkhtmltopdf because it's a deployment mess - a command line tool - but that one looked like the most promising of the libraries).

These are our favorite PDF generation tools:

  • http://www.websupergoo.com/abcpdf-1.htm [$329] Extremely powerful, lets you pick up the rendering engine to use (has en embedded Gecko HTML engine) or you can pick Internet Explorer (good sometimes to render some old fashiones HTML markup). The only issue is that it has a little bit messy deployment.
  • http://www.xfiniumpdf.com/xfinium-pdf-purchase.html [$499] This is simpler to deploy than ABCPDF and is developed and gets new features at a much faster rate. We've been using this lately for our native Android and iOS projects. It becomes quite expensive because you have to pay individual licenses for each platform (desktop, mobile, mono).

In a sample use case we are trying to get PDF versions of Ubercart invoices. We are aiming at getting a code such as this one:

  private static function GetPDFInvoice($order, $dest = 'I') {
    $build = array(
      '#theme' => 'uc_order',
      '#order' => $order,
      '#op' => 'view',
      '#template' => variable_get('uc_cust_order_invoice_template', 'customer'),
    );
    $themed = theme('uc_order_invoice_page', array('content' => drupal_render($build)));
    return \Drupal\fdf\Utilities\UtilsPDF::HtmlToPDF($themed, $dest);
  }

Short, clean and simple. The way we like it. But the real magic is inside the HtmlToPDF method, and that is where the nightmare started with the PHP based PDF generation tools.

After the frustrating and time consuming experience (I'm more than sure that the time we lost was more than worth the .Net paid licenses) we had with the PHP based PDF generation tools, we decided to revisit the dotnet PHP extension to see if we could talk to Net and use those excelente PDF libraries.

I remember dealing a with the PHP dotnet extension a while ago with frustrating results, but now that the .Net Framework runs on Linux I thought to give it another try. And this was indeed a very interesting experience: we were able to come up with a .Net interoperability layer that overcomes "some" of the major issues when dealing with the dotnet PHP extension.

To make the story short, this is an example code manipulating the XFinium .Net library from PHP:

  public static function SamplePDFManipulation() {
    // Create an assembly manager
    $manager = new NetManager();
    // Load the XFinium assembly and type data
    static::LoadAssemblyAndAliases($manager);
    
    $document = $manager->Create('xfinium', 'PdfFixedDocument')->Instantiate();
    $page = $document->Pages->Add();

    $color = $manager->Create('xfinium', 'PdfRgbColor')->Instantiate()->Red;
    
    $face = $manager->Create('xfinium', 'PdfStandardFontFace')->Enum("Helvetica");
    $font = $manager->Create('xfinium', 'PdfStandardFont')->Instantiate($face, 24);
    
    $brush = $manager->Create('xfinium', 'PdfBrush')->Instantiate($color);

    $page->Graphics->DrawString('Hello World', $font, $brush, 100, 100);
    $document->Save('d:\\hello_world.pdf');
  }

Elegant and readable (I mean, compared to what you would have to do if dealing directly with the COM wrappers). The library is on Github and you can read more here. Generating a PDF from an HTML content (with browser like rendering and super fast results) is now possible with just a few lines of code, and a very powerful API (the ones exposed by these PDF libraries). 

To render a fully Drupal themed page, I recommend taking a look at the code inside the Print module that has done some very nice Drupal reverse engineering to be able to retrieve a partially themed page (for example without headers, footers, etc...). As an example, to render a node programatically it fools the current path, renders the node in it's true context, and reverts the change so that the remaining request has the right context:

// We need to fool the theme function so that it uses the THEME of the path
// we are trying to render.
$current_path = current_path();
menu_set_active_item($path);
// Theme the HTML
$html = theme('print', array('node' => $node, 'query' => $query, $expand, 'format' => $link['format']));
// Restore the path context.
menu_set_active_item($current_path);

 

Comments

I am using dompdf for generating pdf in Drupal 7. its working very fine on localhost. But its not working on online server. There it is not generating page also. It just reload the page again. Anybody please help me.

Add new comment

By: root Saturday, April 11, 2015 - 19:29