24.5. Dessiner

24.5.1. Geométrie

Le format PDF utilise la même geométrie que le format PostScript. Elle démarre d'en bas à gauche et est mesuré en points (1/72 inch soit 0,352778 mm).

La taille d'une page peut-être récupéré depuis un objet page :

<?php
$width  = $pdfPage->getWidth();
$height = $pdfPage->getHeight();
?>
            

24.5.2. Couleurs

Le format PDF a d'excellentes capacités dans la représentation des couleurs. Le module Zend_Pdf supporte les espaces de couleur : niveaux de gris, RGB et CMJN. Chacun d'entre eux peut-être utilisé à chaque fois qu'un objet Zend_Pdf_Color est requis. Les classes Zend_Pdf_Color_GrayScale, Zend_Pdf_Color_RGB et Zend_Pdf_Color_CMYK fournissent cette fonctionnalité :

<?php
// $grayLevel (float). 0.0 (noir) - 1.0 (blanc)
$color1 = new Zend_Pdf_Color_GrayScale($grayLevel);

// $r, $g, $b (float). 0.0 (intensité mimimum) - 1.0 (intensité maximum)
$color2 = new Zend_Pdf_Color_RGB($r, $g, $b);

// $c, $m, $y, $k (float). 0.0 (intensité mimimum) - 1.0 (intensité maximum)
$color3 = new Zend_Pdf_Color_CMYK($c, $m, $y, $k);
?>
        

Les différentes couleurs HTML sont aussi fourni avec la classe Zend_Pdf_Color_Html :

<?php
$color1 = new Zend_Pdf_Color_Html('#3366FF');
$color2 = new Zend_Pdf_Color_Html('silver');
$color3 = new Zend_Pdf_Color_Html('forestgreen');?>
        

24.5.3. Dessiner des formes

Toutes les opérations de dessins peuvent-étre réalisées dans le contexte d'une page PDF.

La classe Zend_Pdf_Page fournit les outils de dessins :

<?php
/**
 * Dessine une ligne de x1,y1 à x2,y2.
 *
 * @param float $x1
 * @param float $y1
 * @param float $x2
 * @param float $y2
 */
public function drawLine($x1, $y1, $x2, $y2);
?>
            

<?php
/**
 * Dessine un rectangle.
 *
 * Type de remplissage:
 * Zend_Pdf_Page::SHAPE_DRAW_FILL_AND_STROKE - remplit le rectangle et dessine le contour (par défaut)
 * Zend_Pdf_Page::SHAPE_DRAW_STROKE      - trace uniquement le contour du rectangle
 * Zend_Pdf_Page::SHAPE_DRAW_FILL        - remplit le rectangle
 *
 * @param float $x1
 * @param float $y1
 * @param float $x2
 * @param float $y2
 * @param integer $fillType
 */
public function drawRectangle($x1, $y1, $x2, $y2, $fillType = Zend_Pdf_Page::SHAPE_DRAW_FILL_AND_STROKE);
?>
            

<?php
/**
 * Dessine un polygone.
 *
 * Si $fillType est Zend_Pdf_Page::SHAPE_DRAW_FILL_AND_STROKE ou Zend_Pdf_Page::SHAPE_DRAW_FILL,
 * le polygone est automatiquement fermé.
 * Regardez la description détaillée de ces méthodes dans la
 * documentation du format PDF
 * (section 4.4.2 Path painting Operators, Filling)
 *
 * @param array $x  - tableau de float (les coordonnés X des sommets)
 * @param array $y  - tableau de float (les coordonnés Y des sommets)
 * @param integer $fillType
 * @param integer $fillMethod
 */
public function drawPolygon($x, $y,
                            $fillType = Zend_Pdf_Page::SHAPE_DRAW_FILL_AND_STROKE,
                            $fillMethod = $fillMethod = Zend_Pdf_Page::FILL_METHOD_NON_ZERO_WINDING);
?>
            

<?php
/**
 * Dessine un cercle avec comme centre  x, y et comme rayon radius.
 *
 * Les angles sont en radian
 *
 * Signatures des méthodes:
 * drawCircle($x, $y, $radius);
 * drawCircle($x, $y, $radius, $fillType);
 * drawCircle($x, $y, $radius, $startAngle, $endAngle);
 * drawCircle($x, $y, $radius, $startAngle, $endAngle, $fillType);
 *
 *
 * Ce n'est pas réellement un cercle, car le format supporte uniquement des courbe de Bezier cubique.
 * Mais c'est une très bonne approximation.
 * La différence avec un vrai cercle est de au maximum 0.00026 radians
 * (avec les angle PI/8, 3*PI/8, 5*PI/8, 7*PI/8, 9*PI/8, 11*PI/8, 13*PI/8 et 15*PI/8).
 * Avec les angles 0, PI/4, PI/2, 3*PI/4, PI, 5*PI/4, 3*PI/2 et 7*PI/4 c'est exactement la tangente d'un cercle.
 *
 * @param float $x
 * @param float $y
 * @param float $radius
 * @param mixed $param4
 * @param mixed $param5
 * @param mixed $param6
 */
public function drawCircle($x, $y, $radius, $param4 = null, $param5 = null, $param6 = null);
?>
            

<?php
/**
 * Dessine une ellipse dans le rectangle spécifié.
 *
 * Signatures des méthodes:
 * drawEllipse($x1, $y1, $x2, $y2);
 * drawEllipse($x1, $y1, $x2, $y2, $fillType);
 * drawEllipse($x1, $y1, $x2, $y2, $startAngle, $endAngle);
 * drawEllipse($x1, $y1, $x2, $y2, $startAngle, $endAngle, $fillType);
 *
 * Les angles sont en radians
 *
 * @param float $x1
 * @param float $y1
 * @param float $x2
 * @param float $y2
 * @param mixed $param5
 * @param mixed $param6
 * @param mixed $param7
 */
public function drawEllipse($x1, $y1, $x2, $y2, $param5 = null, $param6 = null, $param7 = null);
?>
            

24.5.4. Dessiner du texte

Les opérations de dessins existent bien sûr dans le contexte d'une page PDF. Vous pouvez dessiner une seule ligne de texte à n'importe quelle endroit dans la page en fournissant les coordonnées x et y de la ligne de base. La police courant ainsi que sa taille seront utilisées pour le dessin (voir la description ci-dessous).

<?php
/**
 * Dessine une ligne de texte à la position x,y.
 *
 * @param string $text
 * @param float $x
 * @param float $y
 * @param string $charEncoding (optionnel) encodage des caractères du texte.
 * Par défaut le réglage système est utilisé.
 * @throws Zend_Pdf_Exception
 */
public function drawText($text, $x, $y, $charEncoding = '');
?>
            

Exemple 24.5. Dessiner une ligne dans la page

<?php
...
$pdfPage->drawText('Bonjour le monde!', 72, 720);
...
?>
            

Par défaut, les chaînes de texte sont interprétées en utilisant l'encodage du système. Si vous avez une chaîne qui utilise un encodage différent (comme les chaînes UTF-8 lues depuis une fichier sur le disque, ou une chaîne MacRoman obtenue depuis une base de données), vous pouvez indiquer l'encodage au moment du dessin et Zend_Pdf gérera la conversion pour vous. Vous pouvez fournir des chaînes dans n'importe quel encodage supporté par la fonction iconv() de PHP:

Exemple 24.6. Dessiner une chaîne UTF-8 sur une page

<?php
...
// Lit une chaîne UTF-8 à partir du disque
$unicodeString = fread($fp, 1024);

// Dessine une chaîne dans la page
$pdfPage->drawText($unicodeString, 72, 720, 'UTF-8');
...
?>
            

24.5.5. Utiliser des polices de caractères

Zend_Pdf_Page::drawText() utilise la police courante ainsi que sa taille, qui sont définies avec la méthode Zend_Pdf_Page::setFont() :

<?php
/**
 * Choisit la police courante.
 *
 * @param Zend_Pdf_Resource_Font $font
 * @param float $fontSize
 */
public function setFont(Zend_Pdf_Resource_Font $font, $fontSize);
?>
            

Les documents PDF supportent PostScript Type 1 et les polices TrueType, mais également deux types spécifiques PDF, Type3 et les polices composites. Il y a aussi 14 polices Type 1 standard intégré dans tout lecteur de PDF : Courier (4 styles), Helvetica (4 styles), Times (4 styles), Symbol, et Zapf Dingbats.

Zend_Pdf supporte actuellement les 14 polices standard mais également vos propres police TrueType. Les objets de police obtenus via une des deux factory méthodes : Zend_Pdf_Font::fontWithName($fontName) pour les 14 polices PDF standard ou Zend_Pdf_Font::fontWithPath($filePath) pour les polices personnalisées.

Exemple 24.7. Créer une police standard

<?php
...
// Crée une nouvelle police
$font = new Zend_Pdf_Font_Standard(Zend_Pdf_Font::FONT_HELVETICA);

// Applique la police
$pdfPage->setFont($font, 36);
...
?>
            

Les constantes pour les 14 polices standard sont définis dans la classe Zend_Pdf_Font :

  • Zend_Pdf_Font::FONT_COURIER

  • Zend_Pdf_Font::FONT_COURIER_BOLD

  • Zend_Pdf_Font::FONT_COURIER_ITALIC

  • Zend_Pdf_Font::FONT_COURIER_BOLD_ITALIC

  • Zend_Pdf_Font::FONT_TIMES

  • Zend_Pdf_Font::FONT_TIMES_BOLD

  • Zend_Pdf_Font::FONT_TIMES_ITALIC

  • Zend_Pdf_Font::FONT_TIMES_BOLD_ITALIC

  • Zend_Pdf_Font::FONT_HELVETICA

  • Zend_Pdf_Font::FONT_HELVETICA_BOLD

  • Zend_Pdf_Font::FONT_HELVETICA_ITALIC

  • Zend_Pdf_Font::FONT_HELVETICA_BOLD_ITALIC

  • Zend_Pdf_Font::FONT_SYMBOL

  • Zend_Pdf_Font::FONT_ZAPFDINGBATS

Vous pouvez aussi prendre n'importe quelle police TrueType (extension habituelle '.ttf') ou OpenType ('.otf') si elles ont une silhouette TrueType. Pour l'instant non supportée, les polices Mac Os X .dfont et les collections TrueType Microsoft ('.ttc') seront intégrées dans une version future.

Pour utiliser une police TrueType, vous devez fournir le chemin de fichier complet vers cette police. Si la police ne peut pas être lue pour uune quelconque raison, ou si ce n'est pas une police TrueType, la méthode lèvera une exception :

Exemple 24.8. Créer une police TrueType

<?php
...
// Crée la nouvelle police
$goodDogCoolFont = Zend_Pdf_Font::fontWithPath('/chemin/vers/GOODDC__.TTF');

// Applique cette police
$pdfPage->setFont($goodDogCoolFont, 36);
...
?>
            

Par défaut, les polices personnalisées seront incorporées dans le document PDF résultant. Cela permet aux destinataires de voir la page comme prévu, même s'ils ne font pas installer les polices appropriées sur leur système. En cas de problème avec la taille du fichier généré, vous pouvez demander que la police ne soit pas incorporé en passant l'option 'ne pas inclure' à la méthode de création :

Exemple 24.9. Créer une police TrueType sans l'incorporer dans le document PDF

<?php
...
// Crée la nouvelle police
$goodDogCoolFont = Zend_Pdf_Font::fontWithPath('/chemin/vers/GOODDC__.TTF',
                                               Zend_Pdf_Font::EMBED_DONT_EMBED);

// Applique cette police
$pdfPage->setFont($goodDogCoolFont, 36);
...
?>
            

Si les polices ne sont pas incorporées mais que le destinataire du fichier PDF a ces polices installées sur son système, il verra le document comme prévu. Si la police correcte n'est pas installée, l'application visualiseur PDF fera de son mieux pour synthétiser une police de remplacement.

Quelques polices ont les règles de licence très spécifiques qui les empêchent d'être incorporées dans des documents PDF. Donc vous devez faire attention, si vous essayez d'utiliser une police qui ne peut pas être incorporée, la méthode de création lèvera une exception.

Vous pouvez toujours utiliser ces polices, mais vous devez passer le paramètre 'ne pas inclure' comme décrit ci-dessous, ou vous pouvez simplement bloquer l'exception :

Exemple 24.10. Ne pas lever d'exception pour les polices ne pouvant être incorporées

<?php
...
$font = Zend_Pdf_Font::fontWithPath('/chemin/vers/PoliceNonIncorporable.ttf',
                                    Zend_Pdf_Font::EMBED_SUPPRESS_EMBED_EXCEPTION);
...
?>
            

Cette technique de suppression est préférée si vous permettez aux utilisateurs de choisir leurs propres polices. Les polices qui peuvent être incorporées dans le document de pdf le seront ; les autres ne le seront pas.

Les fichiers de police peuvent être assez grands, certains peuvent atteindre des dizaines de méga-octets. Par défaut, toutes les polices incorporées sont comprimées en utilisant le schéma de compression Flate, ayant pour résultat un gain d'espace de 50% en moyenne. Si, pour une quelconque raison, vous ne voulez pas comprimer la police, vous pouvez le neutraliser avec une option :

Exemple 24.11. Ne pas compresser une police incorporée

<?php
...
$font = Zend_Pdf_Font::fontWithPath('/chemin/vers/PoliceDeGrandeTaille.ttf',
                                    Zend_Pdf_Font::EMBED_DONT_COMPRESS);
...
?>
            

En conclusion, si nécessaire, vous pouvez combiner les options d'incorporation en employant l'opérateur binaire OR :

Exemple 24.12. Combiner les options de polices incorporées

<?php
...
$font = Zend_Pdf_Font::fontWithPath($cheminVersPoliceQuelconque,
                                    (Zend_Pdf_Font::EMBED_SUPPRESS_EMBED_EXCEPTION |
                                     Zend_Pdf_Font::EMBED_DONT_COMPRESS));
...
?>
            

24.5.6. Insertion d'images

La classe Zend_Pdf_Page fournis la méthode drawImage() pour dessiner une image :

<?php
/**
 * Insère une image à la position spécifiée dans la page
 *
 * @param Zend_Pdf_Resource_Image $image
 * @param float $x1
 * @param float $y1
 * @param float $x2
 * @param float $y2
 */
public function drawImage(Zend_Pdf_Resource_Image $image, $x1, $y1, $x2, $y2);
?>
            

Les objets Image peuvent être créés avec la méthode Zend_Pdf_Image::imageWithPath($filePath) (les images JPG, PNG et TIFF sont maintenant supportées) :

Exemple 24.13. Insertion d'images

<?php
...
//Charger une image
$image = new Zend_Pdf_Image::imageWithPath('mon_image.jpg');

$pdfPage->drawImage($image, 100, 100, 400, 300);
...
?>
            

Important! Le support JPEG nécessite que l'extension PHP GD soit installé. Important! Le support PNG nécessite que l'extension ZLIB soit configuré pour accepter les images avec canaux Alpha.

Lisez la documentation de PHP pour plus d'informations (http://www.php.net/manual/fr/ref.image.php et http://www.php.net/manual/en/ref.zlib.php).

24.5.7. Style de lignes

Le style de ligne est définit par l'épaisseur, la couleur et le style de tiret. Tout ces paramètres peuvent être assignés par les méthodes de la classe Zend_Pdf_Page :

<?php
/** Choisit la couleur de ligne. */
public function setLineColor(Zend_Pdf_Color $color);

/** Choisit l'épaisseur de ligne. */
public function setLineWidth(float $width);

/**
 * Choisit le modèle de tiret.
 *
 * modele est un tableau de floats: array(longueur_visible, longueur_invisible, longueur_visible, longueur_invisible, ...)
 * phase est le décalage à partir du début de la ligne.
 *
 * @param array $modele
 * @param array $phase
 */
public function setLineDashingPattern($pattern, $phase = 0);
?>
            

24.5.8. Style de remplissage

Les méthodes Zend_Pdf_Page::drawRectangle(), Zend_Pdf_Page::drawPoligon(), Zend_Pdf_Page::drawCircle() et Zend_Pdf_Page::drawEllipse() prennent en argument optionnel le type de remplissage: $fillType. Il peut être :

  • Zend_Pdf_Page::SHAPE_DRAW_STROKE - trace le contour de la forme

  • Zend_Pdf_Page::SHAPE_DRAW_FILL - remplit uniquement la forme

  • Zend_Pdf_Page::SHAPE_DRAW_FILL_AND_STROKE - remplissage et contour (par défaut)

La méthode Zend_Pdf_Page::drawPoligon() prend aussi paramètre supplémentaire $fillMethod :

  • $fillMethod = Zend_Pdf_Page::FILL_METHOD_NON_ZERO_WINDING (par défaut)

    La référence du format PDF décrit la règle comme ceci :

    The nonzero winding number rule determines whether a given point is inside a path by conceptually drawing a ray from that point to infinity in any direction and then examining the places where a segment of the path crosses the ray. Starting with a count of 0, the rule adds 1 each time a path segment crosses the ray from left to right and subtracts 1 each time a segment crosses from right to left. After counting all the crossings, if the result is 0 then the point is outside the path; otherwise it is inside. Note: The method just described does not specify what to do if a path segment coincides with or is tangent to the chosen ray. Since the direction of the ray is arbitrary, the rule simply chooses a ray that does not encounter such problem intersections. For simple convex paths, the nonzero winding number rule defines the inside and outside as one would intuitively expect. The more interesting cases are those involving complex or self-intersecting paths like the ones shown in Figure 4.10 (in a PDF Reference). For a path consisting of a five-pointed star, drawn with five connected straight line segments intersecting each other, the rule considers the inside to be the entire area enclosed by the star, including the pentagon in the center. For a path composed of two concentric circles, the areas enclosed by both circles are considered to be inside, provided that both are drawn in the same direction. If the circles are drawn in opposite directions, only the "doughnut" shape between them is inside, according to the rule; the "doughnut hole" is outside.

  • Zend_Pdf_Page::FILL_METHOD_EVEN_ODD

    La référence du format PDF décrit la règle comme ceci :

    An alternative to the nonzero winding number rule is the even-odd rule. This rule determines the "insideness" of a point by drawing a ray from that point in any direction and simply counting the number of path segments that cross the ray, regardless of direction. If this number is odd, the point is inside; if even, the point is outside. This yields the same results as the nonzero winding number rule for paths with simple shapes, but produces different results for more complex shapes. Figure 4.11 (in a PDF Reference) shows the effects of applying the even-odd rule to complex paths. For the five-pointed star, the rule considers the triangular points to be inside the path, but not the pentagon in the center. For the two concentric circles, only the "doughnut" shape between the two circles is considered inside, regardless of the directions in which the circles are drawn.

24.5.9. Rotations.

Les pages PDF peuvent être tourner avant appliquer les opérations de dessin. Cela peut-être fait en utilisant la méthode Zend_Pdf_Page::rotate() :

<?php
/**
 * Effectue une rotation de la page autour du point ($x, $y), l'angle est en radians.
 *
 * @param float $angle
 */
public function rotate($x, $y, $angle);
?>
            

24.5.10. Sauvegarder et restaurer l'état graphique.

L'état graphique (police courante, taille de caractère, couleur de ligne, couleur de remplissage, style de ligne, sens de la page, zone de dessin) peut-être sauvegarder à tout moment. L'opération de sauvegarde empile le contexte dans une pile de contexte graphique, l'opération de restauration récupère le contexte depuis la pile.

Il y a deux méthodes dans la classe Zend_Pdf_Page pour réaliser ces opérations :

<?php
/**
 * Sauvegarde l'état graphique de la page.
 * Cela prend un instantané des styles courants, des zones de dessins
 * et de toutes les rotations/translations/changements de taille appliqués.
 */
public function saveGS();

/**
 * Restaure le dernier état graphique sauvegarder avec saveGS().
 */
public function restoreGS();
?>
            

24.5.11. Zone de dessin

Le format PDF et le module Zend_Pdf supporte le découpage de la zone de dessin. La zone de dessin courante limite la zone de la page affectée par l'utilisation des opérateurs de dessins. Initialement c'est toute la page.

La classe Zend_Pdf_Page fournit des méthodes pour les opérations de découpage.

<?php
/**
 * Découpe la zone courante avec un rectangle.
 *
 * @param float $x1
 * @param float $y1
 * @param float $x2
 * @param float $y2
 */
public function clipRectangle($x1, $y1, $x2, $y2);
?>
            

<?php
/**
 * Découpe la zone courante avec un polygone.
 *
 * @param array $x  - tableau de float (les coordonnées X des sommets)
 * @param array $y  - tableau de float (les coordonnées Y des sommets)
 * @param integer $fillMethod
 */
public function clipPolygon($x, $y, $fillMethod = Zend_Pdf_Page::FILL_METHOD_NON_ZERO_WINDING);
?>
            

<?php
/**
 * Découpe la zone courante avec un cercle.
 *
 * @param float $x
 * @param float $y
 * @param float $radius
 * @param float $startAngle
 * @param float $endAngle
 */
public function clipCircle($x, $y, $radius, $startAngle = null, $endAngle = null);
?>
            

<?php
/**
 * Découpe la zone courante avec une ellipse.
 *
 * Signatures des méthodes:
 * drawEllipse($x1, $y1, $x2, $y2);
 * drawEllipse($x1, $y1, $x2, $y2, $startAngle, $endAngle);
 *
 * @todo s'occuper des cas spéciaux avec $x2-$x1 == 0 ou $y2-$y1 == 0
 *
 * @param float $x1
 * @param float $y1
 * @param float $x2
 * @param float $y2
 * @param float $startAngle
 * @param float $endAngle
 */
public function clipEllipse($x1, $y1, $x2, $y2, $startAngle = null, $endAngle = null);
?>
            

24.5.12. Styles

La classe Zend_Pdf_Style fournit les fonctionnalités de style.

Les styles peuvent être utilisés pour stocker des paramètre d'état graphique et de les appliquer à une page PDF en une seule opération :

<?php
/**
 * Choisit le style à utiliser pour les futures opérations de dessin sur cette page
 *
 * @param Zend_Pdf_Style $style
 */
public function setStyle(Zend_Pdf_Style $style);

/**
 * Renvoie le style appliqué à la page.
 *
 * @return Zend_Pdf_Style|null
 */
public function getStyle();
?>
            

La classe Zend_Pdf_Style fournit des méthodes pour choisir ou récupérer différents paramètres de l'état graphique :

<?php
/**
 * Choisit la couleur de ligne.
 *
 * @param Zend_Pdf_Color $color
 */
public function setLineColor(Zend_Pdf_Color $color);
?>
            

<?php
/**
 * Récupère la couleur de ligne.
 *
 * @return Zend_Pdf_Color|null
 */
public function getLineColor();
?>
            

<?php
/**
 * Choisit l'épaisseur de ligne.
 *
 * @param float $width
 */
public function setLineWidth($width);
?>
            

<?php
/**
 * Récupère l'épaisseur de ligne.
 *
 * @return float
 */
public function getLineWidth($width);
?>
            

<?php
/**
 * Choisit le style de tiret
 *
 * @param array $pattern
 * @param float $phase
 */
public function setLineDashingPattern($pattern, $phase = 0);
?>
            

<?php
/**
 * Récupère le style de tiret
 *
 * @return array
 */
public function getLineDashingPattern();
?>
            

<?php
/**
 * Récupère le modèle de tiret
 *
 * @return float
 */
public function getLineDashingPhase();
?>
            

<?php
/**
 * Choisit la couleur de remplissage.
 *
 * @param Zend_Pdf_Color $color
 */
public function setFillColor(Zend_Pdf_Color $color);
?>
            

<?php
/**
 * Récupère la couleur de remplissage.
 *
 * @return Zend_Pdf_Color|null
 */
public function getFillColor();
?>
            

<?php
/**
 * Choisit la police.
 *
 * @param Zend_Pdf_Font $font
 * @param Zend_Pdf_Resource_Font $font
 * @param float $fontSize
 */
public function setFont(Zend_Pdf_Resource_Font $font, $fontSize);
?>
            

<?php
/**
 * Modifie la taille de police.
 *
 * @param float $fontSize
 */
public function setFontSize($fontSize);
?>
            

<?php
/**
 * Récupère la police courante
 *
 * @return Zend_Pdf_Resource_Font $font
 */
public function getFont();
?>
            

<?php
/**
 * Récupère la taille de la police
 *
 * @return float $fontSize
 */
public function getFontSize();
?>