Programmer's Reference Guide

Änderungen an PDF Dokumenten speichern

Arbeiten mit Seiten

Erstellen von Seiten

Die Seiten in einem PDF Dokument werden durch Zend_Pdf_Page Instanzen in Zend_Pdf abgebildet.

PDF Seiten werden entweder aus einem vorhandenen PDF gelesen oder erstellt indem die API von Zend_Pdf verwendet wird.

Neue Seiten können durch die Instanzierung neuer Zend_Pdf_Page Objekte erstellt werden, entweder direkt oder durch den Aufruf der Zend_Pdf::newPage() Methode, die ein Zend_Pdf_Page Objekt zurückgibt. Zend_Pdf::newPage() erstellt eine Seite die bereits an ein Dokument angehängt ist. Ungebundene Seiten können nicht mit verschiedenen PDF Dokumenten verwendet werden, sind aber etwas schneller. [1]

Die Zend_Pdf::newPage() Methode und der Zend_Pdf_Page Konstruktor benötigen die gleichen Parameter welche die Größe der Seite spezifizieren. Sie können entweder die Seitengröße ($x, $y) in Punkten (1/72 Zoll) nehmen oder eine vordefinierte Konstante, die den Seitentyp repräsentiert:

  • Zend_Pdf_Page::SIZE_A4

  • Zend_Pdf_Page::SIZE_A4_LANDSCAPE

  • Zend_Pdf_Page::SIZE_LETTER

  • Zend_Pdf_Page::SIZE_LETTER_LANDSCAPE

Dokumentseiten werden im öffentlichen $pages Attribut der Zend_Pdf Klasse abgelegt. Das Attribut enthält ein Array mit Zend_Pdf_Page Objekten und definiert die komplette Instanz und die Reihenfolge der Seiten. Dieses Array kann wie ein normales PHP Array verändert werden:

Beispiel #1 Verwaltung von PDF Dokumentseiten

  1. ...
  2. // Umgekehrte Seitenreihenfolge
  3. $pdf->pages = array_reverse($pdf->pages);
  4. ...
  5. // Füge eine neue Seite hinzu
  6. $pdf->pages[] = new Zend_Pdf_Page(Zend_Pdf_Page::SIZE_A4);
  7. // Füge eine neue Seite hinzu
  8. $pdf->pages[] = $pdf->newPage(Zend_Pdf_Page::SIZE_A4);
  9.  
  10. // Entferne eine bestimmte Seite
  11. unset($pdf->pages[$id]);
  12.  
  13. ...

Klonen von Seiten

Bestehende PDF Seiten können durch das Erstellen eines neuen Zend_Pdf_Page Objektes geklont werden indem eine existierende Seite als Parameter angegeben wird:

Beispiel #2 Klonen bestehender Seiten

  1. ...
  2. // Die Template Seite in einer separaten Variable speichern
  3. $template = $pdf->pages[$templatePageIndex];
  4. ...
  5. // Neue Seite hinzufügen
  6. $page1 = new Zend_Pdf_Page($template);
  7. $pdf->pages[] = $page1;
  8. ...
  9.  
  10. // Andere Seite hinzufügen
  11. $page2 = new Zend_Pdf_Page($template);
  12. $pdf->pages[] = $page2;
  13. ...
  14.  
  15. // Die Quell Template Seite von den Dokumenten entfernen
  16. unset($pdf->pages[$templatePageIndex]);
  17.  
  18. ...

Das ist nützlich wenn verschiedene Seite mit Hilfe eines Templates erstellt werden sollen.

Achtung

Wichtig! Geklonte Seiten verwenden die gleichen PDF Ressourcen mit der Template Seite. Diese kann also nur innerhalb des gleichen Dokuments als Template Seite verwendet werden. Modifizierte Dokumente können als neue abgespeichert werden.

[1] Dies ist eine Einschränkung der aktuellen Zend Framework Version. Sie wird in zukünftigen Versionen beseitigt werden. Aber ungebundene Seiten werden immer ein besseres (also optimaleres) Ergebnis für gemeinsame Benutzung in Dokumenten liefern.

Änderungen an PDF Dokumenten speichern

Comments

I've created a very usefull utilityclass. I've used some code from the forums.


<?php 

require_once 'Zend/Pdf.php';

class 
My_Pdf extends Zend_Pdf{
    
    
/**
     * The default encoding
     * 
     * @var string
     */
    
public static $encoding 'UTF-8';

    
/**
     * Align text at left of provided coordinates
     * 
     * @var string
     */
    
const TEXT_ALIGN_LEFT 'left';
    
    
/**
     * Align text at right of provided coordinates
     * 
     * @var string
     */
    
const TEXT_ALIGN_RIGHT 'right';
    
    
/**
     * Center-text horizontally within provided coordinates
     * 
     * @var string
     */
    
const TEXT_ALIGN_CENTER 'center';
    
    
/**
     * Extension of basic draw-text function to allow it to vertically center text
     *
     * @param Zend_Pdf_Page $page
     * @param string $text
     * @param int $x1
     * @param int $y1
     * @param int $x2
     * @param int $position
     * @param string $encoding
     * @return Zend_Pdf_Page
     */
    
public static function drawText(Zend_Pdf_Page $page$text$x1$y1$x2 null$position self::TEXT_ALIGN_LEFT$encoding null){
        if( 
$encoding == null $encoding self::$encoding;
        
        
$bottom $y1// could do the same for vertical-centering
        
switch ($position) {
            case 
self::TEXT_ALIGN_LEFT :
                
$left $x1;
                break;
            case 
self::TEXT_ALIGN_RIGHT :
            if (
null === $x2) {
                    throw new 
Exception "Cannot right-align text horizontally, x2 is not provided" );
                }
                
$textWidth self::getTextWidth $text$page );
                
$left $x2 $textWidth;
                break;
            case 
self::TEXT_ALIGN_CENTER :
                if (
null === $x2) {
                    throw new 
Exception "Cannot center text horizontally, x2 is not provided" );
                }
                
$textWidth self::getTextWidth $text$page );
                
$left $x1 $textWidth 2;
                break;
            default :
                throw new 
Exception "Invalid position value \"$position\"" );
        }
        
        
// display multi-line text
        
$page->drawText $text$left$y1$encoding );
        return 
$page;
    }
    
    
/**
     * Draw text inside a box using word wrap
     * 
     * @param Zend_Pdf_Page $page
     * @param string $text
     * @param int $x1
     * @param int $y1
     * @param int $x2
     * @param int $position
     * @param float $lineHeight
     * @param string $encoding
     * 
     * @return integer bottomPosition
     */
    
public static function drawTextBox(Zend_Pdf_Page $page$text$x1$y1$x2 null$position self::TEXT_ALIGN_LEFT$lineHeight 1.1$encoding null){
        if( 
$encoding == null $encoding self::$encoding;
        
        
$lines explode(PHP_EOL$text);
        
        
$bottom $y1;
        
$lineHeight $page->getFontSize() * $lineHeight;
        foreach( 
$lines as $line ){
            
preg_match_all('/([^\s]*\s*)/i'$line$matches);
            
            
$words $matches[1];
            
            
$lineText '';
            
$lineWidth 0;
            foreach( 
$words as $word ){
                
$wordWidth self::getTextWidth($word$page);
                
                if( 
$lineWidth+$wordWidth $x2-$x1 ){
                    
$lineText .= $word;
                    
$lineWidth += $wordWidth;
                }else{
                    
self::drawText$page$lineText$x1$bottom$x2$position$encoding );
                    
$bottom -= $lineHeight;
                    
$lineText $word;
                    
$lineWidth $wordWidth;
                }
            }
            
            
self::drawText$page$lineText$x1$bottom$x2$position$encoding );
            
$bottom -= $lineHeight;
        }
        
        return 
$bottom;
    }
    
    
/**
     * Create pages from a text using wrapping
     * 
     * @param Zend_Pdf_Page $template    The template where all new pages are created on
     * @param string $text                The text
     * @param array $margins              array(top, right, bottom, left) Margins from the borders of the document
     * @param align $position            self::TEXT_ALIGN_LEFT
     * @param lineheight $lineHeight    The lineheight, by default 1.1 = 110% of text-height
     * @param string $encoding            If null the self::$encoding is used
     * @return array $pages                Array of created pages
     */
    
public static function createPagesZend_Pdf_Page $template$text$margins=array(40,28,40,28), $position self::TEXT_ALIGN_LEFT$lineHeight 1.1$encoding null ){
        if( 
$encoding == null $encoding self::$encoding;
        
        
$pages = array();
        
$currentPage null;
        
        
$lines explode("\n"$text);
        
        
$lineHeight $template->getFontSize() * $lineHeight;
        
$x1 $margins[1];
        
$x2 $template->getWidth() - $margins[1];
        
$y1 $template->getHeight() - $margins[0] - $lineHeight;
        
$y2 $margins[2];
        
        
$bottom $y1;
        foreach( 
$lines as $line ){
            
            if( 
$currentPage == null || $bottom <= $y2 ){
                
$pages[] = $currentPage = new Zend_Pdf_Page$template );
                
$currentPage->setFont$template->getFont(), $template->getFontSize() );
                
$bottom $y1;
            }
            
            
preg_match_all('/([^\s+\-,.\\/]*[\s+\-,.\\/]*)/i'$line$matches);
            
            
$words $matches[1];
            
            
$lineText '';
            
$lineWidth 0;
            foreach( 
$words as $word ){
                
$wordWidth self::getTextWidth($word$currentPage);
                
                if( 
$lineWidth+$wordWidth $x2-$x1 ){
                    
$lineText .= $word;
                    
$lineWidth += $wordWidth;
                }else{
                    
self::drawText$currentPage$lineText$x1$bottom$x2$position$encoding );
                    
$bottom -= $lineHeight;
                    
$lineText $word;
                    
$lineWidth $wordWidth;
                }
            }
            
            
self::drawText$currentPage$lineText$x1$bottom$x2$position$encoding );
            
$bottom -= $lineHeight;
        }
        
        return 
$pages;
    }
    
    
/**
     * Return length of generated string in points
     *
     * @param string                     $text
     * @param Zend_Pdf_Resource_Font|Zend_Pdf_Page     $font
     * @param int                         $fontSize
     * @return double
     */
    
public static function getTextWidth($text$resource$fontSize null$encoding null) {
        if( 
$encoding == null $encoding self::$encoding;
        
        if( 
$resource instanceof Zend_Pdf_Page ){
            
$font $resource->getFont();
            
$fontSize $resource->getFontSize();
        }elseif( 
$resource instanceof Zend_Pdf_Resource_Font ){
            
$font $resource;
            if( 
$fontSize === null ) throw new Exception('The fontsize is unknown');
        }
        
        if( !
$font instanceof Zend_Pdf_Resource_Font ){
            throw new 
Exception('Invalid resource passed');
        }
        
        
$drawingText iconv ''$encoding$text );
        
$characters = array ();
        for(
$i 0$i strlen $drawingText ); $i ++) {
            
$characters [] = ord $drawingText [$i] );
        }
        
$glyphs $font->glyphNumbersForCharacters $characters );
        
$widths $font->widthsForGlyphs $glyphs );
        
$textWidth = (array_sum $widths ) / $font->getUnitsPerEm ()) * $fontSize;
        return 
$textWidth;
    }
    
}
I've created a very usefull utilityclass. I've used some code from the forums.


<?php 

require_once 'Zend/Pdf.php';

class 
My_Pdf extends Zend_Pdf{
    
    
/**
     * The default encoding
     * 
     * @var string
     */
    
public static $encoding 'UTF-8';

    
/**
     * Align text at left of provided coordinates
     * 
     * @var string
     */
    
const TEXT_ALIGN_LEFT 'left';
    
    
/**
     * Align text at right of provided coordinates
     * 
     * @var string
     */
    
const TEXT_ALIGN_RIGHT 'right';
    
    
/**
     * Center-text horizontally within provided coordinates
     * 
     * @var string
     */
    
const TEXT_ALIGN_CENTER 'center';
    
    
/**
     * Extension of basic draw-text function to allow it to vertically center text
     *
     * @param Zend_Pdf_Page $page
     * @param string $text
     * @param int $x1
     * @param int $y1
     * @param int $x2
     * @param int $position
     * @param string $encoding
     * @return Zend_Pdf_Page
     */
    
public static function drawText(Zend_Pdf_Page $page$text$x1$y1$x2 null$position self::TEXT_ALIGN_LEFT$encoding null){
        if( 
$encoding == null $encoding self::$encoding;
        
        
$bottom $y1// could do the same for vertical-centering
        
switch ($position) {
            case 
self::TEXT_ALIGN_LEFT :
                
$left $x1;
                break;
            case 
self::TEXT_ALIGN_RIGHT :
            if (
null === $x2) {
                    throw new 
Exception "Cannot right-align text horizontally, x2 is not provided" );
                }
                
$textWidth self::getTextWidth $text$page );
                
$left $x2 $textWidth;
                break;
            case 
self::TEXT_ALIGN_CENTER :
                if (
null === $x2) {
                    throw new 
Exception "Cannot center text horizontally, x2 is not provided" );
                }
                
$textWidth self::getTextWidth $text$page );
                
$left $x1 $textWidth 2;
                break;
            default :
                throw new 
Exception "Invalid position value \"$position\"" );
        }
        
        
// display multi-line text
        
$page->drawText $text$left$y1$encoding );
        return 
$page;
    }
    
    
/**
     * Draw text inside a box using word wrap
     * 
     * @param Zend_Pdf_Page $page
     * @param string $text
     * @param int $x1
     * @param int $y1
     * @param int $x2
     * @param int $position
     * @param float $lineHeight
     * @param string $encoding
     * 
     * @return integer bottomPosition
     */
    
public static function drawTextBox(Zend_Pdf_Page $page$text$x1$y1$x2 null$position self::TEXT_ALIGN_LEFT$lineHeight 1.1$encoding null){
        if( 
$encoding == null $encoding self::$encoding;
        
        
$lines explode(PHP_EOL$text);
        
        
$bottom $y1;
        
$lineHeight $page->getFontSize() * $lineHeight;
        foreach( 
$lines as $line ){
            
preg_match_all('/([^\s]*\s*)/i'$line$matches);
            
            
$words $matches[1];
            
            
$lineText '';
            
$lineWidth 0;
            foreach( 
$words as $word ){
                
$wordWidth self::getTextWidth($word$page);
                
                if( 
$lineWidth+$wordWidth $x2-$x1 ){
                    
$lineText .= $word;
                    
$lineWidth += $wordWidth;
                }else{
                    
self::drawText$page$lineText$x1$bottom$x2$position$encoding );
                    
$bottom -= $lineHeight;
                    
$lineText $word;
                    
$lineWidth $wordWidth;
                }
            }
            
            
self::drawText$page$lineText$x1$bottom$x2$position$encoding );
            
$bottom -= $lineHeight;
        }
        
        return 
$bottom;
    }
    
    
/**
     * Create pages from a text using wrapping
     * 
     * @param Zend_Pdf_Page $template    The template where all new pages are created on
     * @param string $text                The text
     * @param array $margins              array(top, right, bottom, left) Margins from the borders of the document
     * @param align $position            self::TEXT_ALIGN_LEFT
     * @param lineheight $lineHeight    The lineheight, by default 1.1 = 110% of text-height
     * @param string $encoding            If null the self::$encoding is used
     * @return array $pages                Array of created pages
     */
    
public static function createPagesZend_Pdf_Page $template$text$margins=array(40,28,40,28), $position self::TEXT_ALIGN_LEFT$lineHeight 1.1$encoding null ){
        if( 
$encoding == null $encoding self::$encoding;
        
        
$pages = array();
        
$currentPage null;
        
        
$lines explode("\n"$text);
        
        
$lineHeight $template->getFontSize() * $lineHeight;
        
$x1 $margins[1];
        
$x2 $template->getWidth() - $margins[1];
        
$y1 $template->getHeight() - $margins[0] - $lineHeight;
        
$y2 $margins[2];
        
        
$bottom $y1;
        foreach( 
$lines as $line ){
            
            if( 
$currentPage == null || $bottom <= $y2 ){
                
$pages[] = $currentPage = new Zend_Pdf_Page$template );
                
$currentPage->setFont$template->getFont(), $template->getFontSize() );
                
$bottom $y1;
            }
            
            
preg_match_all('/([^\s+\-,.\\/]*[\s+\-,.\\/]*)/i'$line$matches);
            
            
$words $matches[1];
            
            
$lineText '';
            
$lineWidth 0;
            foreach( 
$words as $word ){
                
$wordWidth self::getTextWidth($word$currentPage);
                
                if( 
$lineWidth+$wordWidth $x2-$x1 ){
                    
$lineText .= $word;
                    
$lineWidth += $wordWidth;
                }else{
                    
self::drawText$currentPage$lineText$x1$bottom$x2$position$encoding );
                    
$bottom -= $lineHeight;
                    
$lineText $word;
                    
$lineWidth $wordWidth;
                }
            }
            
            
self::drawText$currentPage$lineText$x1$bottom$x2$position$encoding );
            
$bottom -= $lineHeight;
        }
        
        return 
$pages;
    }
    
    
/**
     * Return length of generated string in points
     *
     * @param string                     $text
     * @param Zend_Pdf_Resource_Font|Zend_Pdf_Page     $font
     * @param int                         $fontSize
     * @return double
     */
    
public static function getTextWidth($text$resource$fontSize null$encoding null) {
        if( 
$encoding == null $encoding self::$encoding;
        
        if( 
$resource instanceof Zend_Pdf_Page ){
            
$font $resource->getFont();
            
$fontSize $resource->getFontSize();
        }elseif( 
$resource instanceof Zend_Pdf_Resource_Font ){
            
$font $resource;
            if( 
$fontSize === null ) throw new Exception('The fontsize is unknown');
        }
        
        if( !
$font instanceof Zend_Pdf_Resource_Font ){
            throw new 
Exception('Invalid resource passed');
        }
        
        
$drawingText iconv ''$encoding$text );
        
$characters = array ();
        for(
$i 0$i strlen $drawingText ); $i ++) {
            
$characters [] = ord $drawingText [$i] );
        }
        
$glyphs $font->glyphNumbersForCharacters $characters );
        
$widths $font->widthsForGlyphs $glyphs );
        
$textWidth = (array_sum $widths ) / $font->getUnitsPerEm ()) * $fontSize;
        return 
$textWidth;
    }
    
}
nice,
but where i can put this class ?
and how used it in Controller ?
@storeman: Nice class, but your center text align calculation is wrong.

Replace: $left = $x1 + $textWidth / 2;

With: $left = $x1 + ( ($x2 - $x1) - $textWidth ) /2;
Thank u veeeeeeeeeery much! it worked perfectly!
@storeman: Thank you for the class, it helped me a lot. There is another problem in the preparation of array of glyphs, because strlen() and ord() functions are not multibyte. Your version looses widths of multibyte characters.

Please replace this piece of code in getTextWidth:
$characters = array ();
for($i = 0; $i < strlen ( $drawingText ); $i ++) {
$characters [] = ord ( $drawingText [$i] );
}

with the following line only:
$characters = self::unistrToOrds($drawingText);

Function unistr_to_ords can be found in comments of PHP's ord function manual at http://php.net/manual/en/function.ord.php. Its code looks like:
protected static function unistrToOrds($str, $encoding = 'UTF-8')
{
$str = mb_convert_encoding($str,"UCS-4BE",$encoding);
$ords = array();

for($i = 0; $i < mb_strlen($str,"UCS-4BE"); $i++){
$s2 = mb_substr($str,$i,1,"UCS-4BE");
$val = unpack("N",$s2);
$ords[] = $val[1];
}
return($ords);
}

+ Add A Comment

Please do not report issues via comments; use the ZF Issue Tracker.

If you have a JIRA/Crowd account, we suggest you login first before commenting.

  • BBCode is allowed in the comment markup

  • Select a Version

    Languages Available

    Components

    Search the Manual