Zend_Pdf tutorial

September 7, 2007

Tutorials, Zend Framework

By: Alexander Veremyev


The Zend_Pdf component of the Zend Framework is intended to allow you to create or manipulate PDF documents from within your applications. In addition to its text handling capabilities, it comes complete with drawing features that allow you to create or manipulate graphical primitives. When working with text Zend_Pdf gives you the option of using the built-in fonts or custom TrueType fonts. Its page manipulation capabilities allow you to create new pages, remove existing pages or change the order of pages already in the document. In this tutorial my goal is to give you an overview of the capabilities of Zend_Pdf.

Loading Zend_Pdf module.

First things first, you should make sure that you have the latest version of the Zend Framework installed and properly configured. If you are in doubt, check out the Zend Framework manual for instructions.

Now, let’s dive right in and look at the code. If you are working in an applications written with the Zend Framework, you can use the loadClass() method to load Zend_Pdf.

// Load Zend_Pdf class 

However, if you are using Zend_Pdf standalone in your application, you can simply include it with a require_once() call:

// Load Zend_Pdf class 

Creating new or loading existing document.

Once you have the class loaded you can create an instance. PDF document is represented by Zend_Pdf class. There are three ways to accomplish this.

  • Create a new PDF
    // Create new PDF document. 
    $pdf = new Zend_Pdf();

  • Load an existing document
     // Load PDF document from a file. 
    $fileName = '/path/to/your/file.pdf'; 
    $pdf = new Zend_Pdf($fileName); 

  • Create a document by parsing a string
    // Parse PDF document from a string. 
    $pdf = Zend_Pdf::parse($pdfString); 

Document pages

Now that we have our document, we can start manipulating the pages. To access the pages of our document, we turn to the public property ‘pages’. Pages is an array of Zend_Pdf_Page objects. Because it is a native PHP array, any of PHP’s array handling methods can be used to manipulate it. For instance.

// Reverse document pages. 
$pdf->pages = array_reverse($pdf->pages); 

// Add new page 
$pdf->pages[] = new Zend_Pdf_Page(Zend_Pdf_Page::SIZE_A4); 

// Add new page 
$pdf->pages[] = $pdf->newPage(Zend_Pdf_Page::SIZE_A4); 

// Remove specified page. 

There are two methods that you can use to create a new page. First, you can directly instantiate a Zend_Pdf_Page object and add it to the array yourself. Second, you can use the newPage() method of Zend_Pdf object. newPage() method is a little bit faster, but needs document object. Either way, you end up with a new Zend_Pdf_Page object to work with. Both methods take page size as a parameter. Page size may be specified using one of the following Zend_Pdf_Page class constants.

  • Zend_Pdf_Page::SIZE_A4
  • Zend_Pdf_Page::SIZE_A4_LANDSCAPE
  • Zend_Pdf_Page::SIZE_LETTER

using special pagesize name (names are case insensitive):

  • ‘A4′
  • ‘A4-Landscape’
  • ‘Letter’
  • ‘Letter-Landscape’

or using special notation: ‘x_size:y_size:’ where size is given in points.

// Add new page (A4 size) 
$pdf->pages[] = $pdf->newPage('595:842:'); 

Saving A Document

So far you have created your document, you’ve added pages, you’ve made it pretty. Let’s save it now so you can share it with others. There are three ways to save a PDF once you have created it. The easiest is to simply call the save() method. save() takes one parameter, a file name. Even if you’ve already saved the document once, or you loaded it form an existing document, you still have to specify the file name again.

// Save document as a new file or rewrite existing document 

The second way is to use the “incremental update” PDF feature. Using this, only file modifications are appended. If you want to use the incremental update feature, you pass true as the second parameter of save().

// Update existing document 
// (only document modifications are appended to a file) 
$pdf->save($fileName, true); 

You should be careful when using this second method. You have to use the same file name for loading and for saving the updates.

Finally, prepared PDF document can be also rendered into a string. This is useful if you plan to return file through HTTP.

// Create new PDF 
$pdf = new Zend_Pdf(); 

// Add new page to the document 
$page = $pdf->newPage(Zend_Pdf_Page::SIZE_A4); 
$pdf->pages[] = $page; 

// Draw something on a page 

// Get PDF document as a string 
$pdfData = $pdf->render(); 

header("Content-Disposition: inline; filename=result.pdf"); 
header("Content-type: application/x-pdf"); 
echo $pdfData; 

Text drawing

So, we have a page, but honestly, a PDF full of blank pages isn’t that exciting. To use the PDF to convey ideas we need text and we need images. Let’s work with Text first. For those not familiar with PDFs, everything is “drawn” on the page, even text. Therefore we will refer to the placing of text on the page from here on out as “drawing text”.

Here is an example of most simple text drawing:

// Create new PDF 
$pdf = new Zend_Pdf(); 

// Add new page to the document 
$page = $pdf->newPage(Zend_Pdf_Page::SIZE_A4); 
$pdf->pages[] = $page; 

// Set font 
$page->setFont(Zend_Pdf_Font::fontWithName(Zend_Pdf_Font::FONT_HELVETICA), 20); 

// Draw text 
$page->drawText('Hello world!', 100, 510); 

Congratulations, you have created your Hello World PDF! See, it wasn’t nearly as hard as you thought it would be. Now, before we move on, there are some other things you need to know about drawing text. First, Zend_Pdf supports the 14 standard PDF fonts. Here is a list of the fonts.

  • Zend_Pdf_Font::FONT_COURIER
  • Zend_Pdf_Font::FONT_COURIER_BOLD
  • Zend_Pdf_Font::FONT_COURIER_OBLIQUE (identical to Zend_Pdf_Font::FONT_COURIER_ITALIC)
  • Zend_Pdf_Font::FONT_COURIER_BOLD_OBLIQUE (identical to Zend_Pdf_Font::FONT_COURIER_BOLD_ITALIC)
  • Zend_Pdf_Font::FONT_HELVETICA
  • Zend_Pdf_Font::FONT_HELVETICA_OBLIQUE (identical to Zend_Pdf_Font::FONT_HELVETICA_ITALIC)
  • Zend_Pdf_Font::FONT_SYMBOL
  • Zend_Pdf_Font::FONT_TIMES_ROMAN
  • Zend_Pdf_Font::FONT_TIMES
  • Zend_Pdf_Font::FONT_TIMES_BOLD
  • Zend_Pdf_Font::FONT_TIMES_ITALIC

Second, you always have to set a font before drawing text onto the page. (always) Here is another example of the drawText() command.

// Set font 
$page->setFont(Zend_Pdf_Font::fontWithName(Zend_Pdf_Font::FONT_HELVETICA), 20); 
// Draw text 
$page->drawText($message, 100, 510, 'UTF-8'); 

The second and third parameters are the drawing coordinates and are given in points starting from left bottom page corner. The forth and optional parameter of drawText() is the encoding. Each of the standard 14 fonts, with the exceptions of Symbol and ZapfDingbats, support the Latin character set which may be represented in any encoding supported by iconv library.

In addition to the standard 14 fonts, Zend_Pdf also supports custom TrueType. Custom TrueType fonts may be added into your document with Zend_Pdf_Font::fontWithPath() method, like this.

// Set font 
$page->setFont(Zend_Pdf_Font::fontWithName(Zend_Pdf_Font::fontWithPath($fontPath)), $size); 

// Draw text 
$page->drawText('Hello world!', $x, $y); 

In the example above $size is the font size to draw in. Font sizes are expressed in points.

Image Drawing

Text is great, text helps convey ideas, but you know the old saying about the worth of a picture. Lucky for us, PDF and Zend_Pdf support drawing images. Raster images are drawn on a page using special image object. JPEG (requires GD PHP extension), PNG (requires ZLIB PHP extension for images with Alpha channel) and TIFF images are supported.

// Load image 
$image = Zend_Pdf_Image::imageWithPath($imagePath); 

// Draw image 
$page->drawImage($image, $left, $bottom, $right, $top); 

drawImage() takes 5 parameters, first the image represented as a Zend_Pdf_Image object. Then the four corners of the placement box represented by $left, $bottom, $right and $top.

Shape drawing

In addition to placing raster images on the page, Zend_Pdf_Page has a number of methods for drawing common shapes

  • Zend_Pdf_Page::drawLine(…)
  • Zend_Pdf_Page::drawRectangle(…)
  • Zend_Pdf_Page::drawPolygon(…)
  • Zend_Pdf_Page::drawCircle(…)
  • Zend_Pdf_Page::drawEllipse(…)

See Zend_Pdf documentation for more details.

Let’s take a look at sample code to draw a few shapes.

// Draw rectangle 
$page->setFillColor(new Zend_Pdf_Color_GrayScale(0.8)); 
$page->setLineColor(new Zend_Pdf_Color_GrayScale(0.2)); 
$page->setLineDashingPattern(array(3, 2, 3, 4), 1.6); 
$page->drawRectangle(60, 400, 400, 350); 

// Draw circle 
$page->setFillColor(new Zend_Pdf_Color_Rgb(1, 0, 0)); 
$page->drawCircle(85, 375, 25); 

// Draw sectors 
$page->drawCircle(200, 375, 25, 2*M_PI/3, -M_PI/6); 
$page->setFillColor(new Zend_Pdf_Color_Cmyk(1, 0, 0, 0)); 
$page->drawCircle(200, 375, 25, M_PI/6, 2*M_PI/3); 
$page->setFillColor(new Zend_Pdf_Color_Rgb(1, 1, 0)); 
$page->drawCircle(200, 375, 25, -M_PI/6, M_PI/6); 

// Draw ellipse 
$page->setFillColor(new Zend_Pdf_Color_Rgb(1, 0, 0)); 
$page->drawEllipse(250, 400, 400, 350); 
$page->setFillColor(new Zend_Pdf_Color_Cmyk(1, 0, 0, 0)); 
$page->drawEllipse(250, 400, 400, 350, M_PI/6, 2*M_PI/3); 
$page->setFillColor(new Zend_Pdf_Color_Rgb(1, 1, 0)); 
$page->drawEllipse(250, 400, 400, 350, -M_PI/6, M_PI/6); 

// Draw and fill polygon 
$page->setFillColor(new Zend_Pdf_Color_Rgb(1, 0, 1)); 
$x = array(); 
$y = array(); 
for ($count = 0; $count < 8; $count++) { 
$x[] = 140 + 25*cos(3*M_PI_4*$count); 
$y[] = 375 + 25*sin(3*M_PI_4*$count); 
$page->drawPolygon($x, $y, 

// Draw line 
$page->drawLine(60, 375, 400, 375); 

Result of this code usage:

Colors and Line Dashing Patterns

The code above demonstrates usage of colors objects and assigning them to fill color and line color. In addition, lines may also be decorated with Zend_Pdf_Page::setLineDashingPattern($pattern, $phase) method, where $pattern is an array of floats: array(on_length, off_length, on_length, off_length, …) and $phase is a shift from the beginning of line.

The Zend_Pdf component operates with gray scale, RGB, CMYK and HTML colors.

// $grayLevel (float number). 0.0 (black) - 1.0 (white) 
$color1 = new Zend_Pdf_Color_GrayScale($grayLevel); 

// $r, $g, $b (float numbers). 0.0 (minimum intensity) - 1.0 (maximum intensity) 
$color2 = new Zend_Pdf_Color_Rgb($r, $g, $b); 

// $c, $m, $y, $k (float numbers). 0.0 (minimum intensity) - 1.0 (maximum intensity) 
$color3 = new Zend_Pdf_Color_Cmyk($c, $m, $y, $k); 

// HTML colors 
$color4 = new Zend_Pdf_Color_Html('#3366FF'); 
$color5 = new Zend_Pdf_Color_Html('silver'); 
$color6 = new Zend_Pdf_Color_Html('forestgreen'); 

Using Styles

An instance of the Zend_Pdf_Style object may be used to assign a set of drawing properties.

// Create new Style 
$style = new Zend_Pdf_Style(); 

After creation style may collect number of drawing settings like line color, fill color, line width, line dashing pattern and phase, current font and font size.

$style->setFillColor(new Zend_Pdf_Color_Rgb(0, 0, 0.9)); 
$style->setLineColor(new Zend_Pdf_Color_GrayScale(0.2)); 
$style->setLineDashingPattern(array(3, 2, 3, 4), 1.6); 
$style->setFont(Zend_Pdf_Font::fontWithName(Zend_Pdf_Font::FONT_HELVETICA_BOLD), 32); 

Then all these settings may be applied through one step.

// Apply style 


Because nothing is ever quite as easy as it seems, to get angled text or graphics on a page, you need to rotate the page before drawing; luckily for you, Zend_Pdf makes this easy. Zend_Pdf_Page has a method rotate() that will allow you to easily rotate a page by a given angle, around a specific point on the page. Ok, that sounds a bit confusing so just read the code.

// Rotate page coordinate system 
$page->rotate($x, $y, $angel); 

See, not nearly as difficult as it sounds.

Here is an example of several scripts and resulting pages (axes drawing is skipped):

1. Source page.

$page->drawText('Hello world!', 150, 100); 

2. Page rotated around left bottom corner.

$page->rotate(0, 0, M_PI/12); 
$page->drawText('Hello world!', 150, 100); 

3. Page rotated around specified point.

$page->rotate(150, 100, M_PI/12); 
$page->drawText('Hello world!', 150, 100); 


Clipping is the process of limiting the region a paint operator will work on. The default for a paint operator paints the entire page, in most cases, this is not the desired result. Clipping effects can also be applied to images, as can be seen in this example below.

// Create new image object 
$image = Zend_Pdf_Image::imageWithPath($imagePath); 

// Draw part of the image within a circle 
$page->clipCircle(200, 150, 50);
$page->drawImage($image, 200, 100, 300, 200);

Result without clipping:

Result with clipping:

Graphics state

The last thing we need to cover is “graphics state”. Any time the graphic state of the page changes (current font, font size, line color, fill color, line style, page rotation, clip area) you can use saveGS() and restorGS() to save it or restore it. This allows you to save the current graphic state, make changes and draw things, then restore it. Each save graphics state call mast have corresponded restore graphic state method:

foreach ($pdf->pages as $page){ 
$page->rotate(0, 0, M_PI_2/3); 

$page->clipCircle(550, -10, 50); 
$page->drawImage($stampImage, 500, -60, 600, 40); 

$page->drawText('Modified', 150, 0); 


We really hope that this short tutorial has given you a taste for what is possible with Zend_PDF and more importantly, sparked your imagination on how you can use it in your own applications.
As with all parts of the Zend Framework, Zend_Pdf is constantly undergoing review, refactoring and enhancement. as of this writing, there are new features that have been checked in for release in Zend Framework 1.1 and additional features on the roadmap that have yet to be pinned down.

  • Document info processing.
    Get/set document title, author, subject and other pieces of metadata about the document.
  • Pages cloning.
    Allows to clone existing page and use it as a template for another pages. This feature is complete, tested, planned to be included into ZF 1.1 It is already available if you fetch the Zend Framework from SVN or download a nightly snapshot.
  • Detaching page (and other resources) from a PDF document.
    This feature, coupled with page cloning will allow developers to mix pages from different documents to create a new one. This feature is scheduled to be available at the release of Zend Framework 1.1
  • Rich text drawing functions.

For more information on Zend_Pdf or the Zend Framework in general, check out the extensive documentation. If you still have questions, pop over to the #zftalk channel on freenode.net and chat with other Zend Framework users. We also encourage you to voice your opinion. What new features of Zend_Pdf are important to you?

About Cal Evans

Many moons ago, at the tender age of 14, Cal touched his first computer. (We're using the term "computer" loosely here, it was a TRS-80 Model 1) Since then his life has never been the same. He graduated from TRS-80s to Commodores and eventually to IBM PC's. For the past 10 years Cal has worked with PHP and MySQL on Linux OSX, and when necessary, Windows. He has built on a variety of projects ranging in size from simple web pages to multi-million dollar web applications. When not banging his head on his monitor, attempting a blood sacrifice to get a particular piece of code working, he enjoys building and managing development teams using his widely imitated but never patented management style of "management by wandering around". Cal is happily married to wife 1.31, the lovely and talented Kathy. Together they have 2 kids who were both bright enough not to pursue a career in IT. Cal blogs at http://blog.calevans.com and is the founder and host of Nomad PHP

View all posts by Cal Evans

18 Responses to “Zend_Pdf tutorial”

  1. nandakumar444 Says:

    I am creating an ZF application where there is need of creating PDF reports of account for an entire financial year.

    The number of pages will be about 75-120 pages.So the conversion should be faster.
    The PDF document should be in a table format.

    How can i implement using ZF ?

    thanks in advance

  2. shadedream Says:

    I’m having an issue getting the tutorial to work. I’m trying to drawText() a simple "Hello World!", but all I’m getting is a blank PDF. I found a 2 year old bug report stating a problem with iconv could be causing this but nothing to help me fix it. Any ideas on something simple that would cause this issue?

  3. venimus Says:

    first disable layouts and viewrenderer to ensure you only output the pdf

    echo $pdf->render();

  4. bernietheevilf1ruler Says:

    Heres a roundabout method I used to extract the text from some pdfs so I could data mine the text data

    It uses Zend pdf to get the number of pages – then pdftotext to get the content.

    $attachment_content = file_get_contents("file_name.pdf");
    $pdf1 = Zend_Pdf::parse($attachment_content) ;
    }catch(Zend_Pdf_Exception $e){
    $rand = rand(1000,9999) ; //Use random name to prevent issues with 2 updates simultaneously

    //Save pdf file to a temp directory
    $pdf1->save("/tmp/{$rand}.pdf") ;
    }catch(Zend_Pdf_Exception $e){
    $num_pages = count($pdf1->pages) ;

    for($x = 1;$x <= $num_pages;$x++){
    exec("pdftotext -enc UTF-8 -htmlmeta -f $x -l $x /tmp/grdc_{$rand}.pdf /tmp/{$rand}_{$x}.txt") ;
    $text_content .= "<hr id=’page_{$x}’>" . file_get_contents("/tmp/{$rand}_{$x}.txt") ;

    $text_content = mb_convert_encoding($text_content,"UTF-8",mb_detect_encoding($string,"UTF-8, ISO-8859-1, ISO-8859-15",true)) ;


  5. femiji Says:

    my script indeed was outputs html tag with the intended string to be rendered

    how do i get to stop the html tags from displaying with the output?
    i have layout and renderer disabled and i am working with zend framework mvc.

    do i need some sort of extension enabled to work with zend_pdf

  6. danillo Says:

    You shoud use this first:

  7. labarcag Says:

    Maybe your script output html or spaces before you start to build the PDF document


  8. femiji Says:

    I tried Zend_Pdf outputting to the browser and i get this alert
    ‘file does not begin with ‘%PDF-‘.

    I tried this code

    // Create new PDF
    $pdf = new Zend_Pdf();

    // Add new page to the document
    $page = $pdf->newPage(Zend_Pdf_Page::SIZE_A4);
    $pdf->pages[] = $page;

    // Draw something on a page

    // Get PDF document as a string
    $pdfData = $pdf->render();

    header("Content-Disposition: inline; filename=result.pdf");
    header("Content-type: application/x-pdf");
    echo $pdfData;

    and still got the same result.

    I am using acrobat reader 7, I have disable the Zend_Layout, viewRenderer for the Controller I am using to create the PDF and I still get the same alert message.

    What am I doing wrong or have not done?

    Joseph Iruafemi

  9. vlatkobasic Says:


    Any chance for a short tutorial (or extending this one) about reading PDFs with Zend_PDF?



  10. _____anonymous_____ Says:

    Like much of the reference materials available on the Zend site, this is a very useful tutorial, HOWEVER I find navigating the Zend site completely exasperating when searching for anything in particular.

    There isn’t any PDF tutorial in the framework wiki, nor is there any link to this tutorial from any place that I can find within the framework reference area. The actual documentation for the PDF class is awfully sparse with one example that lets you draw shapes and colors to your heart’s content. This tutorial almost has more information that the refernece manual.

    How do you format large blocks of text in a table format? Can you create a PDF from HTML? How do you make a template for the re-use that is frequently mentioned, but never explained?

    After google found me this article, I tried searching for it using "pdf" or "pdf tutorial" or "framework pdf" on the devzone site and couldn’t find it again.

    I would think that the framework class would be incredibly useful to folks who have previously had to rely on 3rd party tools for PDF generation, if only you could find the information.

  11. ajessica Says:

    Zend_PDF is great, but how I can use them if we don’t use Zend Framework ?
    thanks in advance

  12. _____anonymous_____ Says:

    Thanks for this tutorial!

    I’d like to ask if there is any possibility to extract text from PDF files using Zend_Pdf in a similar manner as with text2pdf (part of xpdf).

    Any help appreciated!

  13. grandgeorg Says:

    First, thx for the tutorial.

    What I do not really understand is the setLineDashingPattern-method:

    $style->setLineDashingPattern(array(3, 2, 3, 4), 1.6);

    What does it do and what is effected by changing the parameters (I cannot see any difference in the output.)?

    By the way, there is also a nice tutorial about ZF-Pdf on:
    (you have to have an ibm user-account to log in)

  14. snefit Says:


    Just read and tried your article. Thanks!

    Just the font didn’t work with the given method:
    $page->setFont(Zend_Pdf_Font::fontWithName(Zend_Pdf_Font::fontWithPath($fontPath)), $size);

    When using:
    $page->setFont(Zend_Pdf_Font::fontWithPath(‘C:windowsfontsL_10646.ttf’), 20);

    it worked well.

  15. mediaplatforms Says:

    This function will give you a width of a specific string using different font and font sizes. You can use this to create a font wrapper function quite easiliy.

    * Returns the total width in points of the string using the specified font and
    * size.
    * This is not the most efficient way to perform this calculation. I’m
    * concentrating optimization efforts on the upcoming layout manager class.
    * Similar calculations exist inside the layout manager class, but widths are
    * generally calculated only after determining line fragments.
    * @param string $string
    * @param Zend_Pdf_Resource_Font $font
    * @param float $fontSize Font size in points
    * @return float
    function widthForStringUsingFontSize($string, $font, $fontSize)
    $drawingString = iconv(‘UTF-8′, ‘UTF-16BE//IGNORE’, $string);
    $characters = array();
    for ($i = 0; $i < strlen($drawingString); $i++) {
    $characters[] = (ord($drawingString[$i++]) << 8) | ord($drawingString[$i]);
    $glyphs = $font->cmap->glyphNumbersForCharacters($characters);
    $widths = $font->widthsForGlyphs($glyphs);
    $stringWidth = (array_sum($widths) / $font->getUnitsPerEm()) * $fontSize;
    return $stringWidth;



  16. amir_laher Says:

    Great tutorial thanks.
    For me there’s one major thing missing, which I couldn’t find in the manual nor the API docs – how can you wrap text within a particular area?
    It is possible to wrap text with FPDF (another inline-php pdf library), although FPDF itself is somewhat less elegant to use.
    Please let me know if this is indeed possible, or even if it’s possible to calculate the word wraps using font-specific formulae

  17. amir_laher Says:

    Great tutorial thanks.
    For me there’s one major thing missing, which I couldn’t find in the manual nor the API docs – how can you wrap text within a particular area?
    It is possible to wrap text with FPDF (another inline-php pdf library), although FPDF itself is somewhat less elegant to use.
    Please let me know if this is indeed possible, or even if it’s possible to calculate the word wraps using font-specific formulae

  18. ulab Says:

    I’m fairly new to ZF, but I think that I’ll really love "Rich text drawing functions" in the 1.1 release…

    At least if that’s what I’m thinking it is :-)