20.5. Dessiner
Précédent | Chapitre 20. Zend_Pdf | Suivant

## 20.5. Dessiner

### 20.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 :

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

### 20.5.2. Couleurs

Le format PDF a d'excellentes capacités dans la représantation des couleurs. Le module `Zend_Pdf` supporte les espaces de couleur : niveaux de gris, RGB et CMJN. Chacun d'entre eux peut-être utilisé à chauque 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é :

    // $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);

### 20.5.3. Dessiner des formes

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

La classe `Zend_Pdf_Page` fournis les outils de dessins :

    /**
     * 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);

    /**
     * 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);

    /**
     * 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é 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);

    /**
     * Dessine un cercle avec comme centre  x, y et comme rayon radius.
     *
     * Les angle 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 rellement un cercle, car le format supporte uniquement des courbe de Bezier cubique.
     * Mais c'est une très bonne approximation.
     * La difféfference avec un vrais 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);

    /**
     * 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);

### 20.5.4. Dessiner du texte

Les opérations de dessins existe 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).

    /**
     * Dessine une ligne de texte à a la position x,y.
     *
     * @param string $text
     * @param float $x
     * @param float $y
     * @param string $charEncoding (optionnel) encodage des caractères du text.
     * Par défaut la locale courante est utilisée.
     * @throws Zend_Pdf_Exception
     */
    public function drawText($text, $x, $y, $charEncoding = '');

Exemple 20.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 de la locale courante. 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 indiquez 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 20.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');
    ...
    ?>

### 20.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()` :

    /**
     * Choisis 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 obtenu via une des deux factory methods : `Zend_Pdf_Font::fontWithName($fontName)` pour les 14 polices PDF standard ou `Zend_Pdf_Font::fontWithPath($filePath)` pour les polices personnalisées.

Exemple 20.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

You can also use any individual TrueType font (which usually has a '.ttf' extension) or an OpenType font ('.otf' extension) if it contains TrueType outlines. Currently unsupported, but planned for a future release are Mac OS X .dfont files and Microsoft TrueType Collection ('.ttc' extension) files.

To use a TrueType font, you must provide the full file path to the font program. If the font cannot be read for some reason, or if it is not a TrueType font, the factory method will throw an exception:

Exemple 20.8. Create a TrueType font.

    <?php
    ...
    // Create new font
    $goodDogCoolFont = Zend_Pdf_Font::fontWithPath('/path/to/GOODDC__.TTF');

    // Apply font
    $pdfPage->setFont($goodDogCoolFont, 36);
    ...
    ?>

By default, custom fonts will be embedded in the resulting PDF document. This allows recipients to view the page as intended, even if they don't have the proper fonts installed on their system. If you are concerned about file size, you can request that the font program not be embedded by passing a 'do not embed' option to the factory method:

Exemple 20.9. Create a TrueType font, but do not embed it in the PDF document.

    <?php
    ...
    // Create new font
    $goodDogCoolFont = Zend_Pdf_Font::fontWithPath('/path/to/GOODDC__.TTF',
                                                   Zend_Pdf_Font::EMBED_DONT_EMBED);

    // Apply font
    $pdfPage->setFont($goodDogCoolFont, 36);
    ...
    ?>

If the font program is not embedded but the recipient of the PDF file has the font installed on their system, they will see the document as intended. If they do not have the correct font installed, the PDF viewer application will do its best to synthesize a replacement.

Some fonts have very specific licensing rules which prevent them from being embedded in PDF documents. So you are not caught off-guard by this, if you try to use a font that cannot be embedded, the factory method will throw an exception.

You can still use these fonts, but you must either pass the do not embed flag as described above, or you can simply suppress the exception:

Exemple 20.10. Do not throw an exception for fonts that cannot be embeded.

    <?php
    ...
    $font = Zend_Pdf_Font::fontWithPath('/path/to/unEmbeddableFont.ttf',
                                        Zend_Pdf_Font::EMBED_SUPPRESS_EMBED_EXCEPTION);
    ...
    ?>

This suppression technique is preferred if you allow an end-user to choose their own fonts. Fonts which can be embedded in the PDF document will be; those that cannot, won't.

Font programs can be rather large, some reaching into the tens of megabytes. By default, all embedded fonts are compressed using the Flate compression scheme, resulting in a space savings of 50% on average. If, for some reason, you do not want to compress the font program, you can disable it with an option:

Exemple 20.11. Do not compress an embedded font.

    <?php
    ...
    $font = Zend_Pdf_Font::fontWithPath('/path/to/someReallyBigFont.ttf',
                                        Zend_Pdf_Font::EMBED_DONT_COMPRESS);
    ...
    ?>

Finally, when necessary, you can combine the embedding options by using the bitwise OR operator:

Exemple 20.12. Combining font embedding options.

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

### 20.5.6. Insertion d'images

La classe `Zend_Pdf_Page` fournis la méthode d`rawImage()` pour dessiner une image :

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

Les objets Image hérite de la classe `Zend_Pdf_Image`.

Seul les images au format JPG sont supportés pour le moment:

Exemple 20.13. Insertion d'images

    <?php
    ...
    $image = new Zend_Pdf_Image_JPEG('my_image.jpg');
    $pdfPage->drawImage($image, 100, 100, 400, 300);;
    ...
    ?>

Important! La classe Zend_Pdf_Image_JPEG nécessite que l'extension PHP GD soit installé.

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

### 20.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é par les méthodes de la classe `Zend_Pdf_Page` :

    /** Choisis la couleur de ligne. */
    public function setLineColor(Zend_Pdf_Color $color);

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

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

### 20.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 optionel 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 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 descrit 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 descrit 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.

### 20.5.9. Rotations.

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

    /**
     * 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);

### 20.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 :

    /**
     * Sauvegarde l'état graphique de la page.
     * Cela prend un instantané des styles courant, 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();

### 20.5.11. Zone de dessins

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

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

    /**
     * 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);

    /**
     * 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);

    /**
     * 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);

    /**
     * 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 speciaux 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);

### 20.5.12. Styles

La classe `Zend_Pdf_Style` fournis les fonctionnalités de style.

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

    /**
     * Choisis le style à utiliser pour les futur opération de dessin sur cette page
     *
     * @param Zend_Pdf_Style $style
     */
    public function setStyle(Zend_Pdf_Style $style);

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

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

    /**
     * Choisis la couleur de ligne.
     *
     * @param Zend_Pdf_Color $color
     */
    public function setLineColor(Zend_Pdf_Color $color);

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

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

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

    /**
     * Choisis le style de tirets
     *
     * @param array $pattern
     * @param float $phase
     */
    public function setLineDashingPattern($pattern, $phase = 0);

    /**
     * Récupère le style de tirets
     *
     * @return array
     */
    public function getLineDashingPattern();

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

    /**
     * Choisis la couleur de remplissage.
     *
     * @param Zend_Pdf_Color $color
     */
    public function setFillColor(Zend_Pdf_Color $color);

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

    /**
     * Choisis 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);

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

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

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

Précédent | Niveau supérieur | Suivant
20.4. Les pages d'un document | Sommaire | 20.6. Exemple d'utilisation du module Zend_Pdf