Passer au contenu principal

PDF

Traiter des fichiers PDF personnalisés.

Introduction​

Netuno génère des fichiers PDF avec prise en charge des images, tableaux, polices et bien plus encore, grâce à la ressource PDF qui permet une abstraction low-code de iTextPDF pour les différents langages de programmation supportés par Netuno.

L'application fournie avec Netuno nommée demo (application de démonstration) contient de nombreux exemples des implémentations de code possibles dans plusieurs langages, y compris la démonstration de l'exportation en PDF via le service export-pdf qui se trouve dans :

  • netuno/apps/demo/server/services/samples/javascript/export-pdf.js

Initialisation​

Tout d'abord, il est nécessaire de créer l'objet qui contiendra le contexte du nouveau document en cours de création, par défaut la taille des pages est A4.

Lors de la création du document, il est défini où il sera généré.

Si rien n'est défini, il sera généré dans la sortie de données du service, par exemple :

const documentPdf = _pdf.newDocument()

Pour générer un fichier PDF dans le dossier docs de l'application, cela peut être fait ainsi :

const documentPdf = _pdf.newDocument(_app.file("docs/fichier.pdf").output())

S'il faut générer le document dans un nouveau fichier en dehors de l'Application, par exemple :

const documentPdf = _pdf.newDocument(_os.file("/tmp/fichier.pdf").output())

Ou encore dans le storage de l'application :

const documentPdf = _pdf.newDocument(_storage.filesystem("server", "fichier.pdf").output())

Par défaut, le document est créé avec le format de page A4.

Format de Page​

Pour personnaliser le format de la page, il suffit de l'indiquer lors de la création du document.

Crée un nouveau document pour la sortie de données du service avec des pages au format Lettre :

const documentPdf = _pdf.newDocument(_pdf.pageSize("letter"))

Crée un nouveau document pour un fichier à la racine de l'application avec le format de page B3 :

const documentPdf = _pdf.newDocument(_app.file("fichier.pdf").output(), _pdf.pageSize("B3"))

Crée un nouveau document dans le storage de l'application avec le format de page Légal :

const documentPdf = _pdf.newDocument(_storage.filesystem("server", "fichier.pdf").output(), _pdf.pageSize("legal"))

Voir la documentation sur la définition de la taille des pages.

Les documents PDF peuvent être créés avec la définition de la taille de page personnalisée, pour cela utilisez pageSize en passant la valeur de la largeur et hauteur de la page, par exemple :

_pdf.pageSize(50, 30)

En-tête HTTP​

Pour créer un service dans l'API REST qui renvoie un fichier PDF comme sortie de données, il faut ajouter dans l'en-tête le paramètre Content-Type du protocole HTTP.

Exemple de comment définir le contenu comme PDF :

_header.contentType("pdf")

Le code pdf est une abréviation pour :

_header.contentType("application/pdf")

Saut de Page​

Pour créer une nouvelle page, on utilise areaBreak :

documentPdf.add(
_pdf.areaBreak()
)

Paragraphe​

Ajoute un nouveau paragraphe dans le document :

documentPdf.add(
_pdf.paragraph("Mon texte ici...")
.setFontSize(15)
)

Pour ajouter un paragraphe à une position fixe :

documentPdf.add(
documentPdf.add(
_pdf.paragraph("Mon texte fixe...")
.setFixedPosition(100, 500, 200)
.setFontSize(15)
)
)

Dans le code ci-dessus, dans la méthode setFixedPosition, le premier paramètre est la position X (100), le deuxième paramètre est la position Y (500), et le troisième paramètre est la largeur (200).

Attention : si Y est défini avec la valeur 0, cela signifie qu'il se trouve au fond de la page, donc pour monter, il faut augmenter la valeur de Y, plus la valeur de Y est élevée, plus il apparaîtra en haut, mais s'il est trop élevé au-delà de la longueur de la page, il ne sera pas visible.

Documentation avec toutes les méthodes de l'objet Paragraphe d'iText.

Police​

Pour définir une police native, nous pouvons procéder comme suit :

const helvetica = _pdf.font("helvetica")
const helveticaBold = _pdf.font("helvetica-bold")
const helveticaBoldOblique = _pdf.font("helvetica-boldoblique")
const helveticaOblique = _pdf.font("helvetica-oblique")

Pour définir une police personnalisée sur mesure, nous pouvons utiliser storage :

const viksiScript = _pdf.font(_storage.filesystem("server", "samples/export-pdf", "viksi-script.ttf"), true)

Nous pouvons également utiliser un fichier dans l'application, comme cet exemple le montre, la police se trouve dans le dossier fonts à la racine de l'application :

const roboto = _pdf.font(_app.file("fonts/roboto.ttf"), true)

Ou encore utiliser un fichier à n'importe quel chemin du système, donc dans cet exemple la police se trouve dans le dossier fonts qui est dans le dossier des fichiers temporaires du système :

const roboto = _pdf.font(_os.file("/tmp/fonts/roboto.ttf"), true)

Documentation avec toutes les méthodes de l'objet Police d'iText.

Pour utiliser la police dans les textes, il faut passer la constante de la police au paragraphe, de cette façon :

documentPdf.add(
_pdf.paragraph("Utilisation de la police en gras.")
.setFont(helveticaBold)
.setFontSize(15)
)

Image​

L'insertion d'images dans le document PDF généré par programmation se fait de cette façon :

documentPdf.add(
_pdf.image(_storage.filesystem("server", "samples/export-pdf", "logo.png"))
.scaleAbsolute(120, 36)
)

Notez que la méthode scaleAbsolute est très utile pour redimensionner et ajuster la taille de l'image.

Alternativement, nous pouvons utiliser un fichier dans l'application, comme dans cet exemple :

const logoImage = _pdf.image(_app.file("public/images/logo.png")

Ou encore utiliser un fichier à n'importe quel chemin du système, comme dans cet exemple :

const logoImage = _pdf.image(_os.file("/tmp/images/pdf-logo.png")

Pour ajouter une image à une position fixe :

documentPdf.add(
logoImage
.scaleAbsolute(120, 36)
.setFixedPosition(100, 500)
)

Étant donné que ci-dessus, dans la méthode setFixedPosition, le premier paramètre est la position X (100), et le deuxième paramètre est la position Y (500).

Attention : si Y est défini avec la valeur 0, cela signifie qu'il se trouve au fond de la page, donc pour monter, il faut augmenter la valeur de Y, plus la valeur de Y est élevée, plus il apparaîtra en haut, mais s'il est trop élevé au-delà de la longueur de la page, il ne sera pas visible.

Documentation avec toutes les méthodes de l'objet Image d'iText.

Tableau​

Il est possible de créer des tableaux, ce qui permet de présenter un ensemble de données de manière plus lisible.

Le nombre de colonnes du tableau est défini avec le paramètre : _pdf.table(nombreColonnes)

Dans l'exemple ci-dessous, le nombreColonnes est le nombre 1, c'est-à-dire une colonne.

Comme nous ajoutons deux cellules dans le tableau, la deuxième cellule va à la ligne suivante.

Notez :

documentPdf.add(
_pdf.table(1)
.addCell(
_pdf.cell()
.add(
_pdf.paragraph("Personne")
.setFont(helvetica)
.setFontSize(10)
)
.setBorder(_pdf.border("solid", 2))
.setBackgroundColor(_pdf.colorRGB(1, 0, 0))
)
.addCell(
_pdf.cell()
.add(
_pdf.paragraph("Nicole")
.setFont(helvetica)
.setFontSize(10)
)
.setBackgroundColor(_pdf.colorGray(0.5))
)
)

Avec la méthode addCell, il permet d'insérer la définition des cellules avec leur contenu respectif.

Documentation avec toutes les méthodes de l'objet Cellule d'iText.

Fermer et Enregistrer le Document​

Le document n'est totalement sauvegardé ou généré que lorsque la méthode close est appelée, de la façon suivante :

documentPdf.close()

L'endroit où le document est généré est défini lors de l'initialisation, donc c'est lors de l'initialisation du document que nous définissons où sera généré le document final, s'il sera dans la sortie de données du service (output) ou dans un fichier.

Modifier un Fichier​

Il est possible de modifier un document PDF déjà existant, par exemple :

const documentPdf = _pdf.openDocument(_app.file("fichier.pdf"))

Le document final généré sera envoyé dans la sortie de données du service.

C'est très utile pour utiliser un PDF comme base, comme s'il s'agissait d'un modèle.

Exemple pour modifier un document dans le storage de l'application :

const documentPdf = _pdf.openDocument(_storage.filesystem('server', 'fichier.pdf'))

Utilise un document comme base mais enregistre les modifications dans un nouveau fichier PDF :

const documentPdf = _pdf.openDocument(
_app.file("document-base.pdf"),
_app.file("document-final.pdf")
)

Exemple utilisant comme base un document dans le storage mais enregistre dans un autre :

const documentPdf = _pdf.openDocument(
_storage.filesystem("server", "contrat-base.pdf"),
_storage.filesystem("server", "contrat-final.pdf")
)

Avec le document chargé, nous pouvons ajouter des contenus, et en fermant avec la méthode close à la fin, le document final est alors généré avec le nouveau contenu ajouté par programmation.

Exemple de service qui utilise un PDF existant comme modèle pour générer une sortie de fichier PDF avec du contenu dynamique ajouté :

_header.contentType("pdf")

const documentPdf = _pdf.openDocument(_app.file("modele-1.pdf"))

documentPdf.add(
_pdf.paragraph("Mon contenu dynamique.")
.setFixedPosition(37, 730, 100)
.setFontSize(15)
)

documentPdf.close()

Lire un Fichier​

Pour lire un document PDF, en extrayant les informations textuelles.

Nous utilisons la méthode extract, qui obtient toutes les données du fichier PDF dans un objet JSON.

const donneesPdf = _pdf.extract(_app.file("fichier-1.pdf"))

_out.json(donneesPdf)

Le JSON retourné a la clé content avec tout le contenu textuel du fichier PDF, et a la clé metadata avec les diverses propriétés du fichier PDF.

Voici un exemple du JSON retourné par extract :

{
"content": "Tout le contenu textuel du fichier PDF vient ici...",
"metadata":{
"Content-Type":"application/pdf",
"dc:format":"application/pdf; version=1.4",
"dc:title":"Linux 1",
"pdf:PDFVersion":"1.4",
"pdf:charsPerPage":"580",
"pdf:containsDamagedFont":"false",
"pdf:containsNonEmbeddedFont":"false",
"pdf:docinfo:producer":"Skia/PDF m125 Google Docs Renderer",
"pdf:docinfo:title":"Fichier 1",
"pdf:encrypted":"false",
"xmpTPg:NPages":"3",
...
}
}

Il existe de nombreuses autres données obtenues dans metadata mais qui ont été omises dans les ... pour que l'exemple ne soit pas trop long.

Convertir​

Il est possible de convertir programmatiquement le PDF en texte ou même en HTML.

PDF vers Texte​

Nous pouvons extraire tout le contenu du fichier PDF en texte brut en utilisant la méthode :

_pdf.toText(...)

Exemple de comment l'utiliser pour lire un fichier à la racine de l'application :

_out.print(_pdf.toText(_app.file("mon-document.pdf")))

Ou encore en utilisant un fichier dans le storage de l'application :

_out.print(_pdf.toText(_storage.filesystem("server", "mon-document.pdf")))

PDF vers HTML​

Nous pouvons extraire tout le contenu du fichier PDF en HTML en utilisant la méthode :

_pdf.toHTML(...)

Exemple de comment l'utiliser pour lire un fichier à la racine de l'application :

_out.print(_pdf.toHTML(_app.file("mon-document.pdf")))

Ou encore en utilisant un fichier dans le storage de l'application :

_out.print(_pdf.toHTML(_storage.filesystem("server", "mon-document.pdf")))

HTML vers PDF​

Il est possible de générer des fichiers PDF à partir de code HTML, en utilisant la méthode :

_pdf.fromHTML(...)

Exemple de comment l'utiliser pour générer un fichier téléchargeable dans le service :

const icone = _app.file("public/images/icon.png");

const fichierPdf = _pdf.fromHTML(`
<html>
<head>
<link href="https://fonts.googleapis.com/css2?family=Limelight&family=Roboto" rel="stylesheet">
<style>
* {
font-family: Roboto;
}
div.barre-laterale {
position: fixed;
top: 0;
bottom: 0;
left: 0;
width: 100px;
background: #1B5886;
}
div.barre-laterale > div {
position: absolute;
top: 350px;
transform: rotate(-90deg) translate(-50%, -34px);
font-family: Limelight;
font-size: 40px;
color: #89CFF1;
}
main {
padding-left: 150px;
}
h1 {
margin: 0 auto;
text-align: center;
font-family: Limelight;
color: #BA250E;
}
table {
margin: 0 auto;
border: 1px solid black;
border-spacing: 0;
border-collapse: collapse;
}
table > thead {
background: #40712A;
color: #fff;
}
table td, table th {
padding: 5px;
text-align: center;
}
table > tbody > tr:nth-child(even) {
background: #e1e1e1;
}
a {
font-family: Limelight;
font-size: 16px;
font-weight: bold;
text-decoration: none;
color: #1E5FB5;
}
</style>
</head>
<body>
<div class="barre-laterale">
<div>Démonstration</div>
</div>
<main>
<h1>PDF à partir du HTML</h1>
<div style="text-align: center; margin: 30px 0;">
<img width="50" src="${icon.uri()}">
</div>
<p>
Ceci est un exemple HTML pour la génération d'un fichier PDF.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam
tellus arcu, pharetra quis condimentum eget, dapibus convallis metus.
</p>
<table>
<thead>
<tr>
<th>Nom</th>
<th>Âge</th>
</tr>
</thread>
<tbody>
<tr>
<td>Marie Louise</td>
<td>23</td>
</tr>
<tr>
<td>Joseph Matos</td>
<td>38</td>
</tr>
</tbody>
</table>
<hr style="margin-top: 50px; height: 1px; background: #50B6C6; border: none;"/>
<div>
<a href="https://netuno.org" target="_blank">Netuno.org</a>
</div>
</main>
</body>
</html>
`);

_header.contentTypePDF();
_out.copy(fichierPdf.input());

Vidéos​

Voici quelques vidéos exemplifiant comment réaliser la génération de fichiers PDF par programmation :