Create PDFs on the fly using TCPDF

Turn your web pages into perfect printouts

TCPDF is a popular open source PHP library that lets you create PDF documents. Its flexibility and versatility lets you create even complex color documents featuring whatever fonts and graphics you need. TCPDF is written entirely in PHP and does all of this PDF magic without requiring any external libraries. This article introduces you to TCPDF, then walks you through reproducing a simple HTML invoice in a downloadable PDF file.

Share:

Chris Herborth (chrish@pobox.com), Freelance Writer, Author

Photo of Chris HerborthChris Herborth is an award-winning senior technical writer with more than 10 years of experience writing about operating systems and programming. When he's not playing with his son, Alex, or hanging out with his wife, Lynette, he spends his time designing, writing, and researching (that is, playing) video games.



10 August 2010

Also available in Russian Japanese Portuguese

Introduction

TCPDF, one of the most active projects hosted on Sourceforge.net, implements a powerful PDF-generation engine, entirely in PHP. This makes it easy to install, even on sites where you can't access the system directories or compile your own code. And it makes iterative development quite easy by letting you immediately see the results generated by your PHP code without any intermediate steps.

TCPDF supports a range of useful image formats, including the SVG vector format and bitmap formats, such as JPEG and PNG. A simple stand-alone utility lets you process TrueType, OpenType, PostScript Type 1, and CID-0 fonts so they can be added to TCPDF-created documents. You can use TCPDF to generate myriad 1-D and 2-D barcode formats, and it supports all of the usual PDF features like bookmarks, document links, compression, annotations, document encryption, and digital signatures.

TCPDF and pages using it are written in PHP, making it easy to create and deploy PDF-generating Web pages. While you can develop and deploy TCPDF using any supported Web server and your favorite PHP development environment, I'll use the following:

  • Eclipse V3.5.2 — One of my preferred open source development environments, which has support for a wide range of programming languages and environments.
  • PHP Development Tools V2.2.0 — A PHP plug-in for Eclipse.
  • MAMP Pro V1.9 — A handy package for Mac OS X, which provides Apache, MySQL, and PHP in an isolated environment with a helpful GUI front end. Even though Mac OS X ships with Apache and PHP installed, I opted to use this because it provides a stable and easily segregated set of Web server/database/PHP.
  • TCPDF V5.0.006 — The current stable version of TCPDF.

You can find download links to all of these in the Resources section.

Let's take a look at how you can use TCPDF in your own web sites, as long as you have PHP installed. We'll go over the installation process, then we'll use PHP to generate a web page showing an invoice-style document that could come from any e-commerce site. After that, we'll use TCPDF to create a printable PDF version of the invoice using similar formatting.


Installing TCPDF

When you download TCPDF from Sourceforge.net, it comes in a self-contained ZIP archive. That is, you can use your favorite ZIP extraction tool to unpack the archive, and you'll end up with a TCPDF directory containing everything you need to get started.

If you add the TCPDF directory to your web documents directory, you can access the TCPDF documentation by loading doc/index.html and view any of the examples, which are also found on the TCPDF web site (see Resources), by loading the examples/index.php file.

Before you can view the examples, however, you need to configure your TCPDF installation.


Configuration — UNIX-like systems

If you're installing TCPDF on a UNIX®-like system, you need to change the file modes so they're not all flagged as executable. This is a side-effect of the TCPDF archive being created on a Microsoft® Windows® system. Luckily, it's easy to adjust these in one whack from the shell (see Listing 1). You also need to make sure that the cache and images directories are writable, since TCPDF will store temporary files there.

Next, you need to assign the files to the user and group the web server; this is often the user www and group www, but it will depend on your system. If you're running TCPDF out of your personal web-site area, (often public_html in your home directory), you can skip this step.

Listing 1. Adjusting file modes and ownership
$ cd tcpdf
$ find . -type f | xargs chmod -x
$ chmod +w cache images
$ chown -R www:www .

Note that the command might use a . instead of : to separate the user and group on some systems; if it complains, check its documentation for details.


Configuration for everyone

Using your favorite text editor, load the config/tcpdf_config.php file. This is TCPDF's configuration settings and lets you control the library's defaults, as well as telling it how to find its support files.

Settings you might want to change in tcpdf_config.php include:

  • PDF_PAGE_FORMAT— Set this to letter if you're not using metric page formats. TCPDF probably supports more page sizes than your printer unless you've got something very exotic on hand.
  • PDF_UNIT— Set this to pt if you'd rather use points instead of millimeters for laying out your PDF document.
  • PDF_CREATOR, PDF_AUTHOR— Default document creator and author, in case your PDF-generating code forgets to set them.

You can adjust any of these settings in your PHP code, too, so don't worry if you're not sure (for example, if you set portrait-mode document layouts here, you can still create landscape documents).

With the default configuration settings, TCPDF should have no trouble rendering any of the examples it ships with, assuming you haven't moved the files and directories away from their original locations.

At this point, you can load the example files to make sure you've got a working TCPDF installation. Let's use it to create a printable version of an invoice.


Creating an invoice

After you've created your e-commerce masterpiece of a web site, your customers are going to order things, and you'll take their money. This is great, but they'll want some sort of invoice in case the order goes wrong or their credit card company messes up the payment.

Let's make a reasonably nice-looking invoice web page so they can see what they've ordered and what you're going to charge them.


First version — The Web page

Using my favorite PHP development environment, I've created a new Invoice folder containing these files:

  • Invoice.php — PHP to generate an invoice
  • Invoice.css — CSS styling for the invoice
  • Azuresol_OnyxTree-S.png — "OnyxTree S" by Azuresol, which you'll use as your company logo (a free icon from the iconfinder.com Web site (see Resources))
  • gentleface_print.png — "Print" by gentleface, which you'll use to trigger the PDF generation (another free icon from iconfinder.com)

Inside Invoice.php, check to see if the page was called with the PDF argument (see Listing 2). When it's not, the user is after a normal web page, so you display the page using the generateHTML function (see Listing 3). You'll look at the generatePDF function later, but it's safe to assume that you'll use it to generate a PDF of the invoice data.

Listing 2. Page-generation control code
if( array_key_exists( 'PDF', $_REQUEST ) ) {
    generatePDF( $invoiceData );
} else {
    generateHTML( $invoiceData );
}

The $invoiceData array holds all of your invoice data; you create it directly in Invoice.php, but you can imagine the data coming from a database, web service, or some sort of online shopping cart system.

Listing 3. Generating the HTML
function generateHTML( $data ) {
?>
... HTML code was here ...
<?php
    foreach( $data['items'] as $item ) {
        echo '<tr class="invoiceRow">' . "\n";
        echo '    <td class="itemCol">' . $item[0] . "</td>\n";
        echo '    <td class="quantityCol">' . $item[1] . "</td>\n";
        echo '    <td class="priceCol">' . $item[2] . "</td>\n";
        echo '    <td class="costCol">' . $item[3]. "</td>\n";
        echo "</tr>\n";
    }
?>
... HTML code was here ...
<?php
    echo '<td class="totalCol">' . $data['total'] . "</td>\n";
?>
... HTML code was here ...
<?php
    echo 'Invoice prepared for ' . $data['user'] . ' on ' . $data['date'] . "\n";
?>
... HTML code was here ...
<?php
    
}

I've cut out all of the HTML markup code here for brevity; you can see it in the Invoice.php found in the CreatingPDFs-Invoice.zip archive, which can be found in the Downloads section.

Using the invoice information passed to the function as $data, create a table containing one row per item, along with its quantity, unit price, and total price. At the end of the table, add a row containing the total cost of the order. The page footer contains the user's user ID and the date/time when the invoice was prepared.

Straightforward stuff, of course, and the main challenges when implementing this on your own site will be interacting with your data sources and getting the CSS styling just right.

Figure 1. The web page invoice in all its glory
Screenshot shows an example of an attractive printable invoice; Sumatra Special has a large quantity of 24, while the others are between 1 and 5

My entirely fictional South Seas Pacifica company supplies fine coffee and tea, and apparently I have a serious addiction to the Sumatran variety. At least their prices are good!

The printer icon in the bottom right is inviting, and you'd expect to be able to click there and get a printout of the invoice. This is where TCPDF comes in. Instead of just printing the web page, you're going to give our valued customers a swanky PDF version they can print at their leisure.


Second version — The PDF

Now that you have the web page invoice looking good, you need to create a PDF version that can be printed.

As you recall from Listing 2, loading the Invoice.php page with the PDF argument (http://.../Invoice.php?PDF) will call the generatePDF function with the same data (see Listing 4).

Listing 4. Generating the PDF invoice
function generatePDF( $data ) {
    # Create a new PDF document.
    $pdf = new InvoicePdf( $data, 'P', 'pt', 'LETTER' );

    # Generate the invoice.
    $pdf->CreateInvoice();
    
    # Output the PDF document.
    $pdf->Output( 'Your_Invoice.pdf', 'D' );
}

The generatePDF function creates an InvoicePdf object, calls its CreateInvoice method, then sends the PDF document as a download named Your_Invoice.pdf to the user's browser. This looks extremely easy, but hides the fact that I had to create the InvoicePdf class myself, duplicating the original Invoice styling. Let's see how.

The InvoicePdf class extends TCPDF's TCPDF class, which is the main PDF-generating engine. In the constructor (see Listing 5), initialize the parent class using the $orientation (page orientation), $unit (measurement unit), and $format (page size) that were passed in. The last three arguments of the TCPDF constructor indicate that the input is Unicode (the default, true), the character encoding of our generated PDF will be UTF-8, and that you shouldn't use disk caching (false). Disk caching reduces the in-memory footprint while creating a PDF, but is slower. Because our document isn't large or complex, there's no point in making this trade-off.

After initializing the parent class, store a reference to the invoice data for later. Next, set the page margins to 72 points on left and right and 36 points at the top using the SetMargins method. The SetMargins final argument indicates that you're overriding the default page margins with our own values. Using the SetAutoPageBreaks method, tell TCPDF to automatically create a new page when you're 36 points from the bottom of the page.

Listing 5. The InvoicePdf class constructor
function __construct( $data, $orientation, $unit, $format ) {
    parent::__construct( $orientation, $unit, $format, true, 'UTF-8', false );

    $this->invoiceData = $data;

    # Set the page margins: 72pt on each side, 36pt on top/bottom.
    $this->SetMargins( 72, 36, 72, true );
    $this->SetAutoPageBreak( true, 36 );
    
    # Set document meta-information
    $this->SetCreator( PDF_CREATOR );
    $this->SetAuthor( 'Chris Herborth (chrish@pobox.com)' );
    $this->SetTitle( 'Invoice for ' . $this->invoiceData['user'] );
    $this->SetSubject( "A simple invoice example for 'Creating PDFs on 
the fly with TCPDF' on IBM's developerWorks" );
    $this->SetKeywords( 'PHP, sample, invoice, PDF, TCPDF' );

    //set image scale factor
    $this->setImageScale(PDF_IMAGE_SCALE_RATIO); 
    
    //set some language-dependent strings
    global $l;
    $this->setLanguageArray($l);
}

After setting up the margins, set the PDF document meta information. This will show up in the document properties window inside your favorite PDF viewer. These are just strings, so you can set them to whatever makes sense for your application.

Using the setImageScale method, use the default image scaling ratio set in TCPDF's configuration file. This is used to adjust bitmapped image sizes from their pixel size to something suitable for the page.

Finally, use setLanguageArray to set some language-dependent strings for the PDF file; these are defined in the language-specific config file loaded by TCPDF's main configuration.

In Listing 6, you override the Header method, which is called to generate the content for each page's header. First, define some variables. Starting with a bigFont size of 14 points, you figure out the relative size of the logo image and the normal text relative to the bigFont size. Then you dig into TCPDF calls.

The ImagePngAlpha method inserts the logo image placing its top-left corner at 72 points in and 36 points down, which matches your margin settings from before. Because it's a square image, you can specify the same width and height (the calculated $imageScale). You'll indicate that it's a PNG image because this call can actually insert PNG and JPEG images (if you have the GD library installed in your PHP setup, it can also load any image supported by GD). Next, specify a null because you're not adding a PDF link (created with the AddLink method) target for this image. Next, use T to indicate that you want the next PDF object to be drawn at the top-right corner of the image area. Finally, tell TCPDF not to resize the image, that it was originally 72 dpi (a common screen resolution), and that the image should be left-aligned on the page.

Clearly, the ImagePngAlpha method gives you a lot of control over how images are added to a page in a PDF document (see Listing 6).

Listing 6. Page header generation
public function Header() {
    global $webcolor;

    # The image is this much larger than the company name text.
    $bigFont = 14;
    $imageScale = ( 128.0 / 26.0 ) * $bigFont;
    $smallFont = ( 16.0 / 26.0 ) * $bigFont;

    $this->ImagePngAlpha('Azuresol_OnyxTree-S.png', 72, 36, 128, 128, 
$imageScale, $imageScale, 'PNG', null, 'T', false, 72, 'L' );
$imageScale, 'PNG', null, 'T', false, 72, 'L' );
    $this->SetFont('times', 'b', $bigFont );
    $this->Cell( 0, 0, 'South Seas Pacifica', 0, 1 );
    $this->SetFont('times', 'i', $smallFont );
    $this->Cell( $imageScale );
    $this->Cell( 0, 0, '', 0, 1 );
    $this->Cell( $imageScale );
    $this->Cell( 0, 0, '31337 Docks Avenue,', 0, 1 );
    $this->Cell( $imageScale );
    $this->Cell( 0, 0, 'Toronto, Ontario', 0, 1 );

    $this->SetY( 1.5 * 72, true );
    $this->SetLineStyle( array( 'width' => 2, 'color' => 
array( $webcolor['black'] ) ) );
    $this->Line( 72, 36 + $imageScale, $this->getPageWidth() - 72, 36 
+ $imageScale );
}

After the logo image has been placed in the header, set the font (Times bold, with your bigFont size), then create a number of cells to hold the company name and address information. These cells contain text, and work a bit like table cells in HTML. The Cell method takes these arguments (and a bunch more, actually; refer to the TCPDF documentation for a complete list):

  • Width— Cell width; if set to 0, the cell will extend all the way to the right-hand margin (or left-hand margin if you're using a right-to-left language).
  • Height— Cell height; if set to 0, the cell's height will expand so its contents fit.
  • Text— The text to draw inside the cell, using the current font and color settings.
  • Border— Indicates whether a border should be drawn around the cell. In this case, you don't want any borders, so you're using 0. You could also pass 1 to draw a complete border around the cell, or a string to indicate specific borders' sides.
  • Position— Indicates where to create the next cell; 1 indicates that you want it to appear at the start of the next line, but you can use 0 to add the next cell beside this one, or 2 to stay at the current X position and move down to the next line.

Finally, our Header method draws a two-point black line all the way across the page's content area at the bottom of the header. Figure 2 shows you how this will look on the page, as rendered by Mac OS X's Preview application.

Figure 2. The print header, just like the web page header
Screenshot shows the header with a graphic logo to the left of the address, the name in a large, bold font, and the address in italics below

Now that you've created a reasonable facsimile of the original header, you also need to override the Footer method so you can generate the footer. This is much simpler, containing just the user's ID and the invoice date, separated from the rest of the page by another two-point black line.

The only part of this method you haven't already seen is calling the SetY method with a negative value. When you do this, the current Y is set relative to the bottom of the page. Here, you're leaving a generous amount of space for the page footer to ensure that you're not drawing too close to the bottom margin (see Listing 7).

Listing 7. Page footer generation
public function Footer() {
    global $webcolor;

    $this->SetLineStyle( array( 'width' => 2, 'color' => 
array( $webcolor['black'] ) ) );
    $this->Line( 72, $this->getPageHeight() - 1.5 * 72 - 2, 
$this->getPageWidth() - 72, $this->getPageHeight() - 1.5 * 72 - 2 );
    $this->SetFont( 'times', '', 8 );
    $this->SetY( -1.5 * 72, true );
    $this->Cell( 72, 0, 'Invoice prepared for ' . 
$this->invoiceData['user'] . ' on ' . $this->invoiceData['date'] );
}

When you create the page, this comes out looking like the web version of the invoice, minus the printer icon. You're leaving this off because this is the print version (it's redundant). Figure 3 has the results.

Figure 3. The printed footer
Screenshot shows the footer, which is a bold horizontal line with details about the recipient, the time and the data

At this point, you have a blank page with a nice header and footer. You need to add the actual invoice content for this to be useful.

After using the AddPage method to start a fresh page (the only page, in this case), set the font to 11-point Helvetica and move the insertion point to 144 points from the top of the page. This leaves us a little room below the header before the table begins.

Next, calculate the amount of indent you'll need to center the table, based on the page width, two 72-point margins, one wide column, and three regular columns.

After that, you create a series of cells to render the column headings using the previously calculated values and drawing full borders for each cell. You also right-align the headers for the numeric columns so they line up with the values. At the end of the header cells, you call the Ln method to move down to the start of the next line.

You do the same sort of layout for each content row via a foreach loop that iterates through the items on the invoice (see Listing 8).

Listing 8. Page content generation
public function CreateInvoice() {
    $this->AddPage();
    $this->SetFont( 'helvetica', '', 11 );
    $this->SetY( 144, true );

    # Table parameters
    #
    # Column size, wide (description) column, table indent, row height.
    $col = 72;
    $wideCol = 3 * $col;
    $indent = ( $this->getPageWidth() - 2 * 72 - $wideCol - 3 * $col ) / 2;
    $line = 18;

    # Table header
    $this->SetFont( '', 'b' );
    $this->Cell( $indent );
    $this->Cell( $wideCol, $line, 'Item', 1, 0, 'L' );
    $this->Cell( $col, $line, 'Quantity', 1, 0, 'R' );
    $this->Cell( $col, $line, 'Price', 1, 0, 'R' );
    $this->Cell( $col, $line, 'Cost', 1, 0, 'R' );
    $this->Ln();

    # Table content rows
    $this->SetFont( '', '' );
    foreach( $this->invoiceData['items'] as $item ) {
        $this->Cell( $indent );
        $this->Cell( $wideCol, $line, $item[0], 1, 0, 'L' );
        $this->Cell( $col, $line, $item[1], 1, 0, 'R' );
        $this->Cell( $col, $line, $item[2], 1, 0, 'R' );
        $this->Cell( $col, $line, $item[3], 1, 0, 'R' );
        $this->Ln();
    }

    # Table Total row
    $this->SetFont( '', 'b' );
    $this->Cell( $indent );
    $this->Cell( $wideCol + $col * 2, $line, 'Total:', 1, 0, 'R' );
    $this->SetFont( '', '' );
    $this->Cell( $col, $line, $this->invoiceData['total'], 1, 0, 'R' );
}

The last bit of code renders the total row. This demonstrates how you can change font styles easily between cells (by calling the SetFont method to turn on and off the bold). The first text cell's width is set to span the first three columns of the table since you want the invoice total to appear at the bottom of the final column.

Once you're done, the invoice item table looks pretty good (see Figure 4).

Figure 4. The items on the invoice
Screenshot of the formatted list of items with quantities, prices and totals

By logically laying out text cells, you've recreated the original web invoice in a format well suited to printing. TCPDF lets you add support for creating PDFs to your existing PHP web pages without requiring changes to the web page itself or any of the underlying data.


Summary

In this article, you were introduced to TCPDF, a popular PHP library for generating PDF documents. TCPDF does this without requiring any extra libraries, making it easy to install as part of your existing PHP web site. You were shown an overview of installing and configuring TCPDF on UNIX-like systems. Then you created a simple web-based invoice, similar to the sort of thing you might see on an e-commerce site specializing in exotic hot drinks.

Once you had a web page that looked like a professional invoice, you extended the TCPDF class to produce a PDF version of the invoice, which the customer could then download or print at leisure. Overriding the Header and Footer methods let us set up the page in a familiar manner, then you wrote an additional method to lay out the invoice items as a table.


Download

DescriptionNameSize
Article source codeos-tcpdf-CreatingPDFs-Invoice.zip21KB

Resources

Learn

Get products and technologies

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Open source on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Open source
ArticleID=505050
ArticleTitle=Create PDFs on the fly using TCPDF
publish-date=08102010