août 05

Après avoir étudié les différents frameworks Java en vue de la génération de documents PDF (ici), entrainons-nous maintenant 2 exemples simples d’implémentation de la librairie iText.

Ce sample se divise en 2 parties :

  • la 1ère montre un exemple de génération de document PDF from scratch.
  • la 2ième partie va générer un document à partir d’un template que nous allons créer dans Open-Office.

Générer un document PDF ‘from scratch’ :

  • 1ère étape : générer un projet Java.

Pour cela, utilisons la commande mvn archetype:generate et choisissons de créer un maven-archetype-quickstart.
Dans notre exemple, le projet est configuré comme suit :

  <groupId>fr.infinit.sample.generationpdf</groupId>
  <artifactId>generationpdf</artifactId>
  <version>1.0.0-SNAPSHOT</version>
  <name>Sample Generation PDF</name>



  • 2ième étape : ajouter la dépendance Maven à iText.

Ajoutons le repository iText ainsi que la dépendance pour iText :

<repositories>
  <repository>
    <id>itextpdf.com</id>
    <name>Maven Repository for iText</name>
    <url>http://maven.itextpdf.com/</url>
  </repository>
</repositories>
<dependencies>
  <dependency>
    <groupId>com.itextpdf</groupId>
    <artifactId>itextpdf</artifactId>
    <version>5.0.2</version>
    <scope>compile</scope>
  </dependency>
</dependencies>



  • 3ième étape : Créer un document PDF vide.

Nous allons utiliser la classe com.itextpdf.text.Document :

    /**
     * Crée un Document vide.
     *
     * @param file Chemin du fichier à créer.
     * @return Document s'il n'y a pas eu d'erreur.
     * @throws IOException s'il y a eu une erreur avec le nom de fichier fourni.
     * @throws DocumentException s'il y a eu une erreur côté iText.
     */
    private Document creerDocument(String file) throws DocumentException, IOException {
        Document document = new Document();

        PdfWriter pdfWriter = PdfWriter.getInstance(document, new FileOutputStream(file));
        pdfWriter.setPageEvent(this);
        // Préférence de lecture : 2 pages en colonne.
        pdfWriter.setViewerPreferences(PdfWriter.PageLayoutTwoColumnLeft);
        document.open();

        return document;
    }

Attention à ne pas oublier de fermer l’objet Document après avoir travaillé sur cet objet !


  • 4ième étape : Ajouter des informations Metadata.

L’ajout de ces informations se fait via la classe com.itextpdf.text.Document :

    /**
     * Ajout de données de type Metadata au document.
     *
     * @param document Document auquel il faut rajouter les metadatas.
     */
    private void addMetaData(Document document) {
        document.addTitle("Sample PDF");
        document.addSubject("Utilisant iText");
        document.addKeywords("Java, PDF, iText");
        document.addAuthor(System.getProperty("user.name"));
        document.addCreator(System.getProperty("user.name"));
    }



  • 5ième étape : Ajouter des lignes vides.

L’ajout de lignes vides se fait en ajoutant des paragraphes avec des espaces :

    /**
     * Ajoute une ligne vide number fois dans le Paragraph passé en paramètre.
     *
     * @param paragraph A remplir avec les lignes vides.
     * @param number Nombre de lignes vides à ajouter.
     */
    private void ajouterLigneVide(Paragraph paragraph, int number) {
        for (int i = 0; i < number; i++) {
            paragraph.add(new Paragraph(" "));
        }
    }



  • 6ième étape : Ajouter des paragraphes avec des polices différentes.

Commençons par définir différentes polices :

    /** Times Roman 18 Bold */
    private static final Font CATFONT = new Font(Font.getFamily("TIMES_ROMAN"), 18, Font.BOLD);

    /** Times Roman 12 Normal */
    private static final Font REDFONT = new Font(Font.getFamily("TIMES_ROMAN"), 12, Font.NORMAL);

    /** Times Roman 16 Bold */
    private static final Font SUBFONT = new Font(Font.getFamily("TIMES_ROMAN"), 16, Font.BOLD);

    /** Times Roman 12 Bold */
    private static final Font SMALLBOLD = new Font(Font.getFamily("TIMES_ROMAN"), 12, Font.BOLD);

Ensuite, ajoutons différents paragraphes à notre document :

    /**
     * Ajoute 4 paragraphes / - Titre du document. - Rapport généré par ... - Ce
     * document décrit ... - Ce document est ...
     *
     * @param document Document à enrichir
     * @throws DocumentException Si un problème survient lors de l'ajout des
     *             données.
     */
    private void addTitlePage(Document document) throws DocumentException {
        Paragraph preface = new Paragraph();

        // Ajout d'une ligne vide
        ajouterLigneVide(preface, 1);

        // Ecriture du header
        preface.add(new Paragraph("Titre du document", CATFONT));
        ajouterLigneVide(preface, 1);

        preface.add(new Paragraph("Rapport généré par: " + System.getProperty("user.name") + ", " + new Date(), SMALLBOLD));
        ajouterLigneVide(preface, 3);

        preface.add(new Paragraph("Ce document décrit quelque chose de très important ", SMALLBOLD));
        ajouterLigneVide(preface, 8);

        preface.add(new Paragraph("Ce document est une version préliminaire et n'est sujet à aucune restriction.", REDFONT));
        document.add(preface);

        // Debut d'une nouvelle page
        document.newPage();
    }


  • 7ième étape : Ajouter du contenu (Chapitre, Section, Sous-section, Anchor).

Les objets Anchor, Chapter, Section permettent de définir différentes zones de contenu dans un document.

Anchor anchor = new Anchor("Premier Chapitre", CATFONT);
anchor.setName("Premier Chapitre");

// Le 2ième paramètre est le numero du chapitre
Chapter catPart = new Chapter(new Paragraph(anchor), 1);

Paragraph subPara = new Paragraph("Sous-Catégorie 1", SUBFONT);
Section subCatPart = catPart.addSection(subPara);
subCatPart.add(new Paragraph("Coucou (pour ne pas mettre toto...)."));

subPara = new Paragraph("Sous-catégorie 2", SUBFONT);
subCatPart = catPart.addSection(subPara);
subCatPart.add(new Paragraph("Paragraphe 1"));
subCatPart.add(new Paragraph("Paragraphe 2"));
subCatPart.add(new Paragraph("Paragraphe 3"));


  • 8ième étape : Ajouter un tableau.

Un tableau se créé avec la classe com.itextpdf.text.pdf.PdfPTable.
Il se compose de com.itextpdf.text.pdf.PdfPCell :

/**
 * Crée un tableau de 3 colonnes et l'ajoute à la Section passée en
 * paramètre.
 * 
 * @param subCatPart Section à remplir avec le tableau.
 * @throws BadElementException Si une erreur survient lors de l'ajout d'un
 *             élément dans la PdfPTable.
 */
private void createTable(Section subCatPart) throws BadElementException {
    // Creation d'une PdfPTable avec 3 colonnes
    final PdfPTable table = new PdfPTable(3);

    // Creation d'une PdfPCell avec un paragraphe
    final PdfPCell cell = new PdfPCell(new Paragraph("header with colspan 3"));

    // Changement du colspan de la PdfCell
    cell.setColspan(3);

    // Ajout de la PdfCell custom à la PdfPTable
    table.addCell(cell);

    // Ajout d'objets String à la PdfPTable
    table.addCell("1.1");
    table.addCell("2.1");
    table.addCell("3.1");
    table.addCell("1.2");
    table.addCell("2.2");
    table.addCell("3.2");

    // Ajout d'un espace entre la PdfPTable et l'élément précédent.
    table.setSpacingBefore(15f);

    subCatPart.add(table);
}


  • 9ième étape : Ajouter une liste à puce.

Une liste à puce dans un document PDF se créé avec l’objet com.itextpdf.text.List.
En voici un exemple :

/**
 * Crée une liste et l'ajoute dans la Section passée en paramètre.
 * 
 * @param subCatPart Section à remplir avec la liste.
 */
private void createList(Section subCatPart) {
    final List list = new List(true, false, 10);
    list.add(new ListItem("Premier point"));
    list.add(new ListItem("Deuxième point"));
    list.add(new ListItem("Troisième point"));
    subCatPart.add(list);
}


  • 10ième étape : Ajouter des numéros de pages.

L’ajout des numéros de page se fait en utilisant la classe com.itextpdf.text.pdf.PdfPageEventHelper.
Elle s’utilise en l’ajoutant comme PageEvent sur le PdfWriter (méthode setPageEvent).
Il suffit ensuite de surcharger les méthodes que l’on souhaite utiliser : onOpenDocument, onEndPage, etc…

Dans notre exemple, la méthode onOpenDocument est utilisée pour créer un com.itextpdf.text.pdf.PdfTemplate qui contiendra le texte des numéros de page.

/**
 * Création du template destiné à recevoir les numéros de page.
 * 
 * @param writer PdfWriter à utiliser.
 * @param document Document à enrichir.
 */
@Override
public void onOpenDocument(PdfWriter writer, Document document) {
    total = writer.getDirectContent().createTemplate(100, 100);
    total.setBoundingBox(new Rectangle(-20, -20, 100, 100));
    try {
        helv = BaseFont.createFont(BaseFont.HELVETICA, BaseFont.WINANSI, BaseFont.NOT_EMBEDDED);
    } catch (DocumentException e) {
        LOG.error(e.getMessage(), e);
        // TODO : gérer l'exception.
    } catch (IOException e) {
        LOG.error(e.getMessage(), e);
        // TODO : gérer l'exception.
    }
}

Note : total est un com.itextpdf.text.pdf.PdfTemplate.

La méthode onEndPage est responsable du remplissage du PdfTemplate pour chaque page via un com.itextpdf.text.pdf.PdfContentByte.

Dans l’exemple suivant, les numéros de page paires sont écrits en bas à gauche et les impaires sont écrits en bas à droite :

/**
 * Ajoute des numeros de page automatiquement. Les numeros paires sont mis
 * en bas à gauche. Les numéros impaires sont mis en bas à droite.
 * 
 * @param writer Pdfwriter à utiliser.
 * @param document Document à utiliser.
 */
@Override
public void onEndPage(PdfWriter writer, Document document) {
    LOG.info("Generation des numeros de page ...");
    final PdfContentByte directcontent = writer.getDirectContent();

    directcontent.saveState();
    final String text = "Page " + writer.getPageNumber();
    final float textBase = document.bottom() - 20;
    final float textSize = helv.getWidthPoint(text, 12);

    directcontent.beginText();
    directcontent.setFontAndSize(helv, 11);

    // Ecriture du numero de page a gauche pour les pages impaires.
    if ((writer.getPageNumber() % 2) == 1) {
        directcontent.setTextMatrix(document.left(), textBase);
        directcontent.showText(text);
        directcontent.endText();
        directcontent.addTemplate(total, document.left() + textSize, textBase);
    } else {
        // Ecriture du numero de page a droite pour les pages paires.
        final float adjust = helv.getWidthPoint("0", 12);
        directcontent.setTextMatrix(document.right() - textSize - adjust, textBase);
        directcontent.showText(text);
        directcontent.endText();
        directcontent.addTemplate(total, document.right() - adjust, textBase);
    }
    directcontent.restoreState();
}

4 Responses to “Sample : génération de document PDF avec iText (1ère partie)”

  1. Remi dit :

    Bonjour,
    Bravo (et merci) pour le mini tuto !
    Par contre, je serais très intéressé par la 2e partie, en se basant sur un template.
    L’avez-vous rédigé ? Si c’est le cas, merci de m’indiquer où, je ne le trouve pas. Sinon, je ne peux que vous encourager à le faire :)

  2. Pkom dit :

    Merci beaucoup, je dois générer des bulletins au format PDF et ce tuto m’aidera beaucoup,
    Encore merci

  3. phlux dit :

    Salut,

    Bon tuto, merci !

    Pour répondre à Rémi, j’ai trouvé ça : http://ashwinrayaprolu.wordpress.com/2011/06/07/pdf-templates-using-openoffice-draw-and-itext-in-java/

  4. Chemsou dit :

    Merci beaucoup c’est vraiment formidable.

Leave a Reply


Creative Commons License
Blog Infin-It par Infin-It est mis à disposition selon les termes de la licence Creative Commons Paternité-Pas d'Utilisation Commerciale 2.0 France.