Technical skills, technology news, analysis ….

Main menu

Post navigation

Creating PDF Documents with Zend Framework

Portable Printing

First released in 1993, Adobe’s Portable Document Format (PDF) is now ubiquitous. It’s a great way to create printable documents that work across multiple platforms without any loss of fidelity, and it also supports interactive features like bookmarks, annotations and forms.

PHP comes with a number of options to help developers dynamically generate PDF files from within their applications. The Haru and PDFlib extensions offer a complete API for dynamic PDF generation, and there also exist a number of open-source PHP components that can be used for the same purpose. This article will introduce you to one such component, the Zend_Pdf component that ships as part of the Zend Framework, and illustrate how it can be used to perform sophisticated PDF operations from within a PHP application.

The Name Of The Rose

Before diving into the code, a few notes and assumptions. I’ll assume throughout this article that you have a working Apache/PHP/MySQL development environment, and that you have downloaded and installed the latest version of the Zend Framework. I’ll also assume that you know the basics of working with classes and objects in PHP.

The Zend_Pdf component is a “pure PHP” implementation of the PDF standard, and no external libraries are required to use it. This can come in handy when operating in a shared hosting environment that does not allow individual access to custom extensions. The component supports most common PDF operations, including adding and deleting pages; inserting text and images on pages; drawing and colorizing shapes; and updating document meta-data.

Let’s begin with a simple example that illustrates Zend_Pdf in action:

This script begins by setting up the Zend auto-loader, which takes care of automatically loading Zend Framework components as needed. It then initializes an instance of Zend_Pdf, and creates a new page as an instance of the Zend_Pdf_Page object. This object constructor is passed a constant indicating the size of the required page.

Next, a font resource is defined, as an instance of Zend_Pdf_Font. This may be either one of the 14 built-in font constants (look in the Zend_Pdf_Font class definition for a list of font constants), or an external font file. This font resource is then attached to the page with a call to the Zend_Pdf_Page object’s setFont() method.

The next step is to write some text to the page, which is easily accomplished with the Zend_Pdf_Page object’s drawText() method. This method accepts the string to be written, together with the X and Y coordinates of the page location where writing should begin. Note that the Zend_Pdf coordinate system uses Postscript geometry: the origin is the bottom left corner of the page, and units are measured in points, where 1 point = 1/72 inch.

The final step is to attach the page to the Zend_Pdf document, via the latter’s $pages array, and then save the result to disk with itssave() method. Here’s what the output looks like:

Pictures and Words

If you’d prefer to use a custom font, instead of the built-in fonts, you can do this using the Zend_Pdf_Font object’s static fontWithPath()method. This is illustrated in the following variant of the previous example:

If you’d like to insert an image into the PDF document, this is easily accomplished with the drawImage() method, which accepts a Zend_Pdf_Image resource and a set of coordinates, and then writes the image to that position in the document. JPEG, PNG and TIFF images are currently supported, and the system will auto-detect the image type based on the file extension. Here’s an example of it in use:

Wrapping Up

There’s one drawback to the drawText() method discussed in the previous section: it won’t automatically wrap text to the next line. This can create problems when you have a large block of text to be dynamically written to a PDF document. Fortunately, there’s a solution: a community enhancement to Zend_Pdf_Page by Nico Edtinger, which adds a few methods to handle this task.

These additional methods calculate the width of the string using the given font face and size, and then automatically determine where the string should be wrapped, given the width of the containing text block. Word boundaries are taken into account when making this determination. To see how it all works, replace your original Zend_Pdf_Page with the updated definition (remember to backup the original), and then try out the example below:

This script introduces the custom drawTextBlock() method, which creates a text container that supports line wrapping. The method accepts the text string, the starting coordinates, width and height of the container, and an optional constant indicating how the text should be aligned. It then writes the text to this container, automatically wrapping long lines as needed. The method is intelligent enough to break lines at word boundaries as well. Here’s an example of the output:

The Shortest Distance Between Two Points

Why stop there? Zend_Pdf comes with a whole bag of functions designed to let you draw lines, circles and other shapes in your PDF document. Consider the following example, which demonstrates the process of drawing a line:

With Zend_Pdf, drawing a line is a one-step process: call the drawLine() method with the X and Y coordinates of the line’s start and end points, and Zend_Pdf will take care of drawing a line between those points. The line color is set via a call to the Zend_Pdf_PagesetLineColor() method, which accepts a Zend_Pdf_Color object corresponding to the required color. Zend_Pdf_Color objects can be defined using RGB, CMYK, hexadecimal or HTML color notation.

Now, look closely at the script above and you’ll see that it actually draws more than just a single line. It actually draws two lines, one in the page header and one in the page footer, and it also mixes things up a little by adding an image to the top left corner of the page and footer text to the bottom right corner, using methods you’ve seen in previous examples. Here’s an example of what the final output looks like:

Shape-Shifting

Zend_Pdf comes with methods to draw other two-dimensional shapes as well. Consider the next example, which uses thedrawRectangle() method to great effect:

The drawRectangle() method draws a rectangle using the supplied bottom left and top right coordinates. It can accept an additional constant that indicates whether the rectangle should be drawn in outline (stroked), filled or both. The stroke color is defined by thesetLineColor() method, while the fill color is defined by the setFillColor() method.

Here’s what the output looks like:

You can also draw rectangles, circles, ellipses and polygons. Take a look at the next example, which revises the previous one to add a few different shapes:

The drawCircle() method draws a circle using the supplied center coordinates and radius length. A starting and ending angle can be optionally provided to adjust the shape of the circle.

The drawEllipse() method draws an ellipse within a rectangular box, using the supplied bottom left and top right box coordinates. A start and end angle can be optionally provided to adjust the ellipse angle.

The drawPolygon() method draws a polygon using the supplied X and Y coordinate arrays.

As before, all of these methods can be passed an additional constant indicating whether or not the shape should be filled.

Here’s another example, this one accepting a set of numeric values as a GET variable, and converting them into slices of a pie chart:

This script begins by reading a comma-separated list of numbers from the $_GET request variable into an array, and then converting those numbers into percentages of a circle. Given the radius and center coordinates of the circle, it’s now possible to calculate the end-points of each pie slice, and draw line segments to these points from the center. Once all the slices are marked out, a circle is drawn around them to complete the pie.

Style Gallery

Zend_Pdf also introduces the concept of “styles”, which are essentially collections of pre-defined formatting rules for line color, fill color, font face, font size and line style. The setStyle() method allows developers to quickly switch between styles when creating PDF pages, making it possible to efficiently and consistently apply different formatting to different sections of a document.

Here’s an example, which defines two styles, ‘cerulean’ and ‘crimson’, and switches between them during the course of creating a page:

Turning The Tables

A common requirement when building PDFs dynamically involves representing data in a table. Zend_Pdf doesn’t support this function natively and so, one way to accomplish this is to manually perform all the calculations necessary to precisely draw a table line by line, split it into rows, columns and cells, and then write text to each cell. This can be a very tedious and not at all maintainable approach, requiring recalculation every time the table content or structure changes, and so, you should instead consider using Zend_Pdf_Table, an unofficial open-source component that was written to address just this problem.

To use Zend_Pdf_Table, download it from SourceForge, copy it to your Zend Framework library directory, and then try it out using the following script:

This script initializes a Zend_Db instance, connects it to a MySQL database and then executes a SELECT query that returns a result set. This result set is then converted to a PDF table via the My_Pdf_Table component. The elements of each record are represented as My_Pdf_Table_Cell objects, and these cells are grouped together into rows; the rows are then attached to the parent My_Pdf_Table object via its addRow() method. Once the table is complete, it’s added to the page via the page object’s addTable() method, and the entire document is saved to disk. If the table is too large for a single page, the My_Pdf_Table component will automatically detect this, creating and attaching additional pages as necessary.

Here’s an example of what the output looks like:

Birds-Eye View

Zend_Pdf also allows developers to programmatically create a document outline, or a bookmark tree, that allows users to quickly jump to specific destinations of a document. These destinations are represented by Zend_Pdf_Destination objects, and they can be attached to the Zend_Pdf object’s ‘outlines’ property in a tree structure, as shown below:

Taking Credit

Finally, you can set document information with the Zend_Pdf object’s ‘properties’ property; this information identifies the document creator, title, subject and content keywords. You can also set the document’s creation and last modification date in a similar manner. The following example demonstrates:

And that’s about all we have time for. The previous examples were just the tip of the iceberg – there’s a lot more you can do with Zend_Pdf, so don’t be afraid to try experimenting with it. Happy coding!