IText & Fying-Saucer ( HTML ==> PDF )

IText, Fying-Saucer sont deux libraires  de génération et de manipulation des documents PDF.

Ce billet aborde les principales fonctionnalités de IText  et introduit la libraie Fying-Saucer pour étendre et simplifier la transformation des templates Html/Xml en PDF.

Logo_iText

IText
est une libraire open Source de génération et de manipulation
des documents PDF. Elle permet de transformer
les templates HTML/XML en document PDF.
IText est disponible pour
java , .net et Android.

Dans ce blog je vais présenter les principales fonctionnalités
d'IText , je mettrait l'accent sur la transformation des templates Html/Xml vers PDF et le problème de l’arrière plan image. et à
la fin j'introduis la librairie Flying-Saucer qui résout ce
problème.

Voici la dépendance Maven pour IText :
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.0.6</version>
</dependency>

1 - Les Principales Fonctionnalités d'IText

1.1 Création
des Documents Pdf (PdfWriter)

La création d'un nouveau document avec IText se fait en
cinq étapes

  • Création de l'objet Document

  • Récupérer l'instance de
    l'objet PdfWriter

  • Ouvrir le Document

  • Ajout du contenu

  • Fermeture du Document

Exemple1 :

package
com.indom.exempleItext;

import
java.io.FileOutputStream;

import
java.io.IOException;

import
com.itextpdf.text.Document;

import
com.itextpdf.text.DocumentException;

import
com.itextpdf.text.Paragraph;

import
com.itextpdf.text.pdf.PdfWriter;

public
class

Exemple1

{

public
static
void

main(final
String[] args) throws
IOException, DocumentException

{

final
String pdfFile = "./src/test/resources/PDF/exemple1.pdf";

//
step 1

final
Document document = new
Document();

//
step 2

PdfWriter.getInstance(document,
new
FileOutputStream(pdfFile));

//
step 3

document.open();

//
step 4

document.add(new
Paragraph(" insérer ici une
paragraphe qui contient des phrases et des mots "));

//
step 5

document.close();

}

}

Résultat de l'exemple 1

Un autre exemple plus riche qui introduit les objets suivants:

Paragraph, Chapter, Section, PdfPTable,
PdfPCell

Exemple2 :

package
com.indom.exempleItext;

import
java.io.FileOutputStream;

import
java.io.IOException;

import
com.itextpdf.text.Chapter;

import
com.itextpdf.text.Document;

import
com.itextpdf.text.DocumentException;

import
com.itextpdf.text.Font;

import
com.itextpdf.text.List;

import
com.itextpdf.text.ListItem;

import
com.itextpdf.text.Paragraph;

import
com.itextpdf.text.Section;

import
com.itextpdf.text.pdf.PdfPCell;

import
com.itextpdf.text.pdf.PdfPTable;

import
com.itextpdf.text.pdf.PdfWriter;

public
class

Exemple2

{

public
static
void

main(final
String[] args) throws
IOException, DocumentException

{

final
Exemple2 pdf
= new
Exemple2();

final
String pdfFile = "./src/test/resources/PDF/exemple2.pdf";

//
step 1

final
Document document = new
Document();

//
step 2

PdfWriter.getInstance(document,new
FileOutputStream(pdfFile));

//
step 3

document.open();

// Création des metas data du documents

document.addTitle("Exemple2
PDF");

document.addSubject("
Creation Pdf avec iText");

document.addKeywords("Java,
PDF, iText");

document.addAuthor(System.getProperty("user.name"));

document.addCreator(System.getProperty("user.name"));

// Création de la première page

final
Paragraph fistPage = new
Paragraph();

fistPage.add(new
Paragraph("Titre du document
...", new
Font(Font.getFamily("TIMES_ROMAN"),
18, Font.BOLD)));

fistPage.add(new
Paragraph(" "));

fistPage.add(new
Paragraph(" "));

fistPage.add(new
Paragraph(" "));

fistPage.add(new
Paragraph("Infotrmation sur
l'auteur ....", new
Font(Font.getFamily("TIMES_ROMAN"),
12, Font.BOLD)));

fistPage.add(new
Paragraph(" "));

fistPage.add(new
Paragraph(" "));

fistPage.add(new
Paragraph(" "));

fistPage.add(new
Paragraph("Résumé du Rapport
...", new
Font(Font.getFamily("TIMES_ROMAN"),
12, Font.BOLD)));

document.add(fistPage);

//---------- Création de la deuxième page

document.newPage();

// création de la première chapitre

final
Chapter chapitre1 = new
Chapter(new
Paragraph("Premier Chapitre",new
Font(Font.getFamily("TIMES_ROMAN"),
18, Font.BOLD)),
1);

//
ajout du la section1 au chapitre1

Paragraph subPara = new
Paragraph("Section 1",
new
Font(Font.getFamily("TIMES_ROMAN"),
16, Font.BOLD));

Section Section =
chapitre1.addSection(subPara);

Section.add(new
Paragraph("Coucou (pour ne pas
mettre toto...)."));

//
ajout du section2 au chapitre1

subPara = new
Paragraph("Section 2",
new
Font(Font.getFamily("TIMES_ROMAN"),
16, Font.BOLD));

Section =
chapitre1.addSection(subPara);

//
ajout des paragraphes à la section 2

Section.add(new
Paragraph("Paragraphe 1"));

Section.add(new
Paragraph("Paragraphe 2"));

Section.add(new
Paragraph("Paragraphe 3"));

// ajout
du chapitre1 au document.

document.add(chapitre1);

//---------- Création de la deuxième page

document.newPage();

// création de la première chapitre

final
Chapter chapitre2 = new
Chapter(new
Paragraph("Deuxiéme
Chapitre",new
Font(Font.getFamily("TIMES_ROMAN"),
18, Font.BOLD)),
2);

// création de la section 1

subPara = new
Paragraph("Section 1",
new
Font(Font.getFamily("TIMES_ROMAN"),
16, Font.BOLD));

Section =
chapitre2.addSection(subPara);

// Création d'une PdfPTable avec 3 colonnes

final
PdfPTable table = new
PdfPTable(3);

// Création 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 des 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");

//
si le nombre de lignes est strictement inférieur à trois alors

//
il ne crée pas la ligne

table.addCell("4.1");

table.addCell("4.2");

//
Ajout d'un espace entre la PdfPTable et l'élément précédent.

table.setSpacingBefore(25f);

table.setSpacingAfter(25f);

Section.add(table);

//
ajout des listes à puce

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"));

Section.add(list);

document.add(chapitre2);

//
step 5

document.close();

}

}

Résultat de l'exemple 2

1.2
Manipulation des Documents Pdf Existants (PdfReader)

IText permet la manipulation des fichiers PDF existants en
offrant plusieurs objets tel que :

PdfReader:
Lecture de fichier PDF.

PdfImportedPage:
Importation
des pages PDF.

PdfCopy:
Copie des pages PDF.

PdfStamper:
Modification de
fichier PDF.

Exemple3:

package
com.indom.exempleItext ;

import
java.io.FileOutputStream;

import
java.io.IOException;

import
com.itextpdf.text.Document;

import
com.itextpdf.text.DocumentException;

import
com.itextpdf.text.pdf.PdfCopy;

import
com.itextpdf.text.pdf.PdfReader;

public
class

Exemple3

{

/**

* Cette exemple montre
comment lire et copier à partir d'un document PDF

* vers au un autre.

*

*/

public
static
void

main(final
String[] args) throws
IOException, DocumentException

{

final
String source = "./src/test/resources/PDF/exemple2.pdf";

final
String cible = "./src/test/resources/PDF/exemple3.pdf";

//
Lecture du fichier

final
PdfReader reader = new
PdfReader(source);

//
sélection de la partie à lire

reader.selectPages("2-3");

final
int

n = reader.getNumberOfPages();

//
copier les pages selectionnées vers un nouveau fichier.

final
Document document = new
Document();

final
PdfCopy copy = new
PdfCopy(document, new
FileOutputStream(cible));

document.open();

for
(int
i = 0; i < n;) {

copy.addPage(copy.getImportedPage(reader,
++i));

}

document.close();

}

}

Résultat de l'exemple 3

Exemple
4:

package
com.indom.exempleItext ;

import
java.io.FileOutputStream;

import
java.io.IOException;

import
com.itextpdf.text.DocumentException;

import
com.itextpdf.text.Image;

import
com.itextpdf.text.pdf.BaseFont;

import
com.itextpdf.text.pdf.PdfContentByte;

import
com.itextpdf.text.pdf.PdfReader;

import
com.itextpdf.text.pdf.PdfStamper;

public
class

Exemple4

{

/**

* Cet Exemple montre comment
manipuler les fichiers PDF

* mettre une image comme
arrière plan

* ajout du contenu à une
position précise

*

*

*/

public
static
void

main(final
String[] args)

{

try

{

final
PdfReader pdfReader = new
PdfReader("./src/test/resources/PDF/exemple3.pdf");

final
PdfStamper pdfStamper = new
PdfStamper(pdfReader,

new
FileOutputStream("./src/test/resources/PDF/exemple4.pdf"));

final
Image image =
Image.getInstance("./src/test/resources/PDF/image.jpg");

for(int
i=1; i<= pdfReader.getNumberOfPages(); i++)

{

final
PdfContentByte content_under = pdfStamper.getUnderContent(i);

image.setAbsolutePosition(100f,
700f);

//
ajout de l'image comme arrière plan dans tous les pages

content_under.addImage(image);

}

//
Ajout du contenu dans la page 2 à la position 450/450

final
PdfContentByte content_over = pdfStamper.getUnderContent(2);

//
ajout du contenu dans le flux fichier pdf

final
BaseFont bf = BaseFont.createFont(BaseFont.TIMES_BOLD,
BaseFont.WINANSI,
false);

content_over.setFontAndSize(bf,
20);

content_over.beginText();

content_over.showTextAligned(PdfContentByte.ALIGN_CENTER,
"Paragraph ajouté : Netapsys"
, 450, 450, 0);

content_over.endText();

pdfStamper.close();

} catch
(final
IOException e) {

e.printStackTrace();

} catch
(final
DocumentException e) {

e.printStackTrace();

}

}

}

Résultat de l'exemple 4

1.3
Conversion du XML / HTML en PDF (HTMLWorker, XMLWorker)

IText offre une fonctionnalité très utile qui permet de
convertir des templates HTML, XHTML ou XML en PDF. Pour cela on a
deux objets sont principalement utilisés :

  • HTMLWorker:  
    Convertit les templates HTML en PDF. Cette conversion se fait malgré que le
    fichier d'origine n'est pas bien formé ( manque des balises
    fermantes …).
  • XMLWorker: 
    Convertit les templates XHTML/XML en PDF. Contrairement à l'objet précédent
    , la conversion ne s'effectue pas si la template n'est bien formées.

Exemple 5 :

package
com.indom.exempleItext ;

import
java.io.FileOutputStream;

import
java.io.IOException;

import
java.io.StringReader;

import
com.itextpdf.text.Document;

import
com.itextpdf.text.DocumentException;

import
com.itextpdf.text.PageSize;

import
com.itextpdf.text.html.simpleparser.HTMLWorker;

import
com.itextpdf.text.pdf.PdfWriter;

public
class

Exemple5

{

/**

* Dans cet exemple on va
convertir du html en pdf

* on va essayer de mettre une
image comme arrière plan

*/

public
static
void

main(final
String[] args) throws
DocumentException, IOException

{

final
Document myPdf = new
Document(PageSize.A4,
10, 10, 10, 15);

final
FileOutputStream baosPDF = new
FileOutputStream("./src/test/resources/PDF/exemple5.pdf");

final
String htmlString ="<html><head><h1>Exmeple
de template</h1></head><body background=image.jpg>
</br>" +

"<div
align=center>Itext permet de convertir les templates HTML en
PDF </div> </body></html>";

//
création du docment pdf

final
PdfWriter pdfWriter = PdfWriter.getInstance(
myPdf, baosPDF);

myPdf.open();

//
création de l'objet HtmlWorker

final
HTMLWorker htmlWorker = new
HTMLWorker(myPdf);

//
conversion du template HTML vers PDF

htmlWorker.parse(new
StringReader(htmlString));

myPdf.close();

pdfWriter.close();

}

}

Résultat de l'exemple 5

Cet exemple montre que
HtmlWorker ne tiens pas compte de l'attribut background=image.jpg.

2 - Problématique

Comme le montre l'exemple
précédent Itext ne couvre pas tous les éléments de HTML

Ce qui veut dire qu'on ne peut
pas convertir n'importe quel template HTML vers PDF en utilisant
Itext.

Dans notre cas si on veut
convertir un document HTML qui a une image comme arrière plan alors
on a deux solutions :

  • Soit via IText en utilisant
    l'objet HtmlWorker et PdfStamper :

L'exemple 4 montre comment
mettre une image comme arrière plan en utilisant PdfStamper

          ==> Solution compliqué et
spécifique à ce cas précis,

  • Soit en utilisant Flying
    saucer.

3 - Flying-Saucer

Flying
Saucer est une librairie java Open Source développée par la
communauté java et .net

Il
prend en entrée un flux XML ou XHTM, lui applique le style CSS 2.1 et
rend :

-
un PDF (via ITEX)

-
GUI interfaces (via Swing Jpanel)

-
Images

Flying
Saucer se base sur Itext pour générer les Pdfs, et accepte plus
d’éléments xhtml/xml/CSS que Itext (background-image).

Les
principales objets de Flying Saucer:

XHTMLPanel :
Convertit les templates XML/HTML vers GUI Swing

ImageRenderer :
Convertit les templates XML/HTML vers une Image

ItextRenderer :
Convertit les templates XML/HTML vers Pdf

Dépendance
Maven :

<dependency>

<groupId>org.xhtmlrenderer</groupId>

<artifactId>flying-saucer-core</artifactId>

<version>9.0.1</version>

</dependency>

<dependency>

<groupId>org.xhtmlrenderer</groupId>

<artifactId>flying-saucer-pdf</artifactId>

<version>9.0.2</version>

</dependency>

<dependency>

<groupId>org.xhtmlrenderer</groupId>

<artifactId>flying-saucer-pdf-itext5</artifactId>

<version>9.0.2</version>

</dependency>

Exemple 6:

package
com.indom.exempleItext;

import
java.io.FileOutputStream;

import
java.io.IOException;

import
org.xhtmlrenderer.pdf.ITextRenderer;

import
com.lowagie.text.DocumentException;

public
class

Exemple6

{

/**

* Utilisation de
Flying-saucer

* pour convertir du
HTML/XHTML vers PDF

* Résout problème de bacground image.

*/

public
static
void

main(final
String[] args) throws
DocumentException, IOException

{

final
FileOutputStream baosPDF = new
FileOutputStream("./src/test/resources/PDF/exemple6.pdf");

final
String htmlString ="<html><head>"
+

"<style>
<!-- .bgtab{"+

"background-image:url(./src/test/resources/PDF/image.jpg);"+

"background-repeat:
no-repeat;}"+

"--></style>"+

"<h1>Exmeple
de template</h1></head>"
+

"<body
class='bgtab'>"+

"<div
align='center'>Itext permet de convertir les templates HTML en
PDF </div> " +

"</body></html>";

// création de l'objet ITextRenderer

final
ITextRenderer renderer = new
ITextRenderer();

// indiquer au render que le document se basera sur la chaine de
caractéres passée en paramétre

renderer.setDocumentFromString(htmlString);

renderer.layout();

// création du flux pdf

renderer.createPDF(baosPDF);

baosPDF.close();

}

}

Résultat de l'exemple 6

2 commentaires

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Captcha *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.