Le monde du web et celui de l’impression, ont décidément du mal à se rencontrer.
La prise en charge de l’impression est bien souvent très problématique dans le cas d’un projet web.
Dans la plupart des cas, il est possible de s’en sortir en utilisant les possiblités offertes par les feuilles de style CSS.
Mais le rendu final du document n’est pas garanti, les différents navigateurs interprètent la feuille de style selon leur humeur
et cela ne fonctionne pas dans le cas de documents complexes.
Dans ce cas, l’unique solution est de produire un document au format PDF, unique garantie pour une impression de qualité.
Je vais donc décrire dans cet article, la solution que nous avons mis en place dans le cadre du projet MAVISE.
Historique
La base de données MAVISE fourni les données sur l’ensemble des chaînes de télévision accessibles dans l’Union européenne.
Elle a été développé par la société Easter-eggs en collaboration avec l’Observatoire européen de l’audiovisuel (OEA) pour le compte de la DG Communication de la Commission Européenne.
Dans la 1ère phase du projet nous avons développé un système d’impression avec des feuilles de style.
Ce système ne donnait pas entièrement satisfaction au client.
En effet, les pages du projet étant très complexes, le résultat de l’impression produite par les différents navigateurs était très aléatoire (coupure en plein milieu d’un tableau, impression sur plusieurs pages et saut de pages inexpliqués).
Le résultat n’était pas professionnel et il était difficile pour le client d’alimenter un rapport avec les contenu de la base.
Nous avons donc proposé de mettre en place un export PDF pour l’ensemble des éléments de l’application.
Choix techniques
Au fils du temps, je suis devenu un expert de la production de document PDF,
en effet, j’ai été en charge de l’export PDF dans de nombreux projets.
J’ai eu le plaisir d’utiliser plusieurs API pour produire des documents au format PDF, comme par exemple :
Le travail pour produire des documents PDF consiste dans la plupart des cas à dessiner avec l’aide de ces diffèrentes
API, le contenu du document. (texte, tableaux, graphique et mise en page).
Il s’agit d’un travail long et fastidieux, qui consiste à fournir une suite d’instructions pour former le document.
Cette technique montre vite ses limites :
- les demandes de modification de la mise en page du document produit, sont lourdes et nécessitent beaucoup de temps ;
- le code pour produire le document est difficilement rationalisable ;
- elle ne convient pas à des documents de grande taille.
Dans le modèle MVC, qu’utilise la plupart des applications Web, nous utilisons un système de template pour l’affichage (la vue).
Alors pourquoi bon “coder” la présentation des documents PDF?
Pour cette raison, j’ai proposé au client de bâtir le système d’impression des documents PDF sur un système de template.
Ce système repose sur le langage de programmation XSL-FO, les projets Apache FOP et Apache Cocoon.
Architecture du système d’impression
- Lorsque l’utilisateur clique sur le lien PDF, il est redirigé vers Apache Cocoon ;
- Cocoon, récupère l’ensemble des informations directement sur le site web, via l’API REST ;
- Il agrége les informations dans un document XML ;
- Ce document est transformé en FO à l’aide d’une feuille de style XSLT ;
- Le document est produit par Apache FOP ;
- L’utilisateur obtient le document final.
L’interface entre le Site Web et Apache Cocoon
L’architecture du système d’impression repose sur le fait que l’ensemble des variables manipulées par notre application sont accessibles à l’aide d’URL REST.
En effet, il est possible d’afficher le contenu des diffèrentes variables manipulées par l’application à l’aide d’adresses URL spécifiques.
Voici un exemple de sortie :
<?xml version="1.0" encoding="UTF-8"?>
<array>
<is_admin />
<country>
<id>1</id>
<iso3166>FR</iso3166>
<name>France</name>
<enabled>t</enabled>
<minimal_age_of_audience>4+</minimal_age_of_audience>
</country></array>
...
Il est donc possible de récupèrer l’ensemble des informations du site à l’aide du protocol REST.
Nous avons aussi de très nombreux tableaux dans l’application, pour les récupérer, nous utilisons le format XML natif du contrôleur de tableaux dhtmlxGrid.
Voici un exemple de sortie : fichier XML pour dhtmlxGrid.
Agrégation des données dans un seul fichier
Pour récupérer l’ensemble des données du site dans un fichier XML, j’utilise la directive include, offerte par Cocoon :
$ cat /var/lib/tomcat5/webapps/cocoon/mavise/program/program.xml
<?xml version="1.0"?>
<page name='program' xmlns:i="http://apache.org/cocoon/include/1.0">
<i:include src='cocoon:/webui_program'/>
...
Cette directive dit à Cocoon, d’inclure le contenu qui se trouve à l’url cocoon:/webui_program, défini dans le fichier
sitemap.xmap :
<!-- Webui -->
<map:match pattern="webui_*/*">
<map:generate src='http://localhost/{1}?id={2}&presenter=rest&filter=webui'/>
<map:serialize type="exml"/>
</map:match>
Transformation XSLT
Pour transformer les données contenues dans ce fichier, nous avons créé notre propre feuille de style XSLT, pour produire un document FO.
Cette feuille de style prend en compte la mise en forme des diffèrentes données du site.
Grâce à ce système, l’ensemble de la mise en forme est centralisé dans un seul fichier.
Il est aussi possible d’ajouter du contenu statique dans le PDF à l’aide de balises dédiées.
Comme par exemple, une balise copyright, qui sera transformées en un texte statique dans tous les documents PDF.
Le pipeline pour les documents PDF
Voici le pipeline final pour produire des documents PDF :
<!-- PDF -->
<map:match pattern="*/*/*.pdf">
<map:generate src='{1}/{3}.xml'/>
<map:transform src="mk_id.xsl" type="xslt">
<map:parameter name="val" value="{2}" />
</map:transform>
<map:transform type="include">
<map:parameter name="parallel" value="true"/>
<map:parameter name="support-caching" value="true"/>
<map:parameter name="expires" value="600"/>
</map:transform>
Le point intéressant à noter dans ce pipeline est l’encodage des arguments passés via l’URL pour le document PDF.
En effet, les URL pour produire les PDF sont formés de la manière suivante :
http://mavise.obs.coe.int/cocoon/mavise/channel/2157/channel.pdf
L’URL contient, le nom du module et l’identifiant de la chaîne.
De cette manière, il est possible de passer d’autres arguments au système d’impression (comme par exemple, changer l’orientation du document).
Performances
Au niveau des performances du système d’impression, nous n’avons pas une charge très importante sur la génération des documents PDF.
La production des documents est une tâche complexe et nécessite donc de manière génèrale beaucoup de ressources.
Néanmoins, il y a une chose intéressante à noter au niveau de la génération des documents PDF.
Celle-ci est plus rapide que l’affichage dans un navigateur.
En effet cela est lié au fait que les échanges de données se font en local sur le serveur, il y a donc moins de bande passante utilisée que dans le cas de l’affichage de cette même page par le navigateur.
Les petits désagréments du format PDF
Nous avons rencontré un petit problème, avec la gestion des polices UTF-8, en effet, comme la base contient des données sur des chaînes de télévision et des entreprises Turques, nous avons eu besoin d’embarquer une police UTF-8 à l’intérieur du document.
Et visiblement cela pose des problèmes à certains lecteurs.
Quelques liens utiles
Voici quelques liens utiles qui nous ont aidé dans la réalisation de ce système d’impression :
- Le guide d’installation d’Apache Cocoon, FOP sur Debian GNU/Linux ;
- Documentation de la version 2.1 d’Apache Cocoon ;
- XPath Tutorial ;
- XSLT Tutorial ;
- XSL-FO ;
Conclusion
En conclusion, j’aimerais remercié l’Observatoire européen de l’audiovisuel (OEA), pour nous avoir fait confiance pour la mise en place de cette solution.
Au 1er abord, le schéma de l’architecture n’est pas très engageant ;-)
J’espère que cette solution donnera des idées à d’autres personnes, pour leur système d’impression.
L’objectif final est de faire des économies de papier par rapport à une impression faite via Internet Explorer ;-)