Génération améliorée de fichiers PDF

Ceci est une ARCHIVE, peut-être périmée. Vérifiez bien les compatibilités !

La génération de fichiers au format PDF à partir de SPIP est une fonctionnalité intéressante, voire bientôt indispensable. Voici une amélioration, et quelques pistes supplémentaires pour la génération de ces fichiers à partir d’un site SPIP.

L’équipe dans laquelle je travaille utilise SPIP tous les jours. SPIP est employé en tant que base de connaissance en intranet, sur laquelle nous publions nos documentations techniques qui permettent le passage de connaissance dans un environnement mouvant.

L’avantage de cette utilisation de SPIP est que nous avons au bout de maintenant plus d’un an des articles qui sont suffisamment génériques pour être utilisables à l’extérieur. Et cette utilisation doit se faire sous une forme présentable, et peu facilement modifiable : le PDF.

Cet article vise deux points : décrire rapidement le fonctionnement de la génération [1]
de PDF depuis SPIP, puis de voir comment cette génération peut être améliorée : ce qui a été fait, et ce qui reste à faire.

Fonctionnement de la génération de PDF

La génération de PDF est basée sur... un squelette SPIP. Le PDF a donc actuellement une base HTML, qui est ensuite passée une classe dérivée de FPDF [2] qui se charge d’analyser le HTML généré par SPIP.

Il est important pour ce qui va suivre de savoir que ce HTML est propre. En effet, l’analyse de HTML s’appuie sur l’ouverture, mais aussi et surtout sur la fermeture des « tags » HTML. Notamment en ce qui concerne :
-  les listes (enfin pas encore, mais c’est comme ça que je le vois) ;
-  les champs <code> (on parle ici du marqueur SPIP, pas de celui de HTML) ;
-  les tableaux.

Pour plus de détails, voir les méthodes OpenTag et CloseTag de la classe PDF (fichier lib_pdf_global.php).

Pour ceux qui font de la rétro-conception (en anglais : reverse-engineering), le gros du code est dérivé des exemples de gestion de tableaux de FPDF, comme l’était le code 0.3 de la génération de PDF de Drop Zone City.

Capacités actuelles de l’extension PDF

Les capacités décrites ici s’appliquent à la version 0.4 (pourquoi pas ?) dont les sources sont joints à cet article.

A noter que cette distribution est partielle : il vous faut installer la version de Drop Zone City, puis remplacer les deux fichiers lib_pdf_global.php et lib_pdf_spip.php par ceux livrés ici. De plus, il vous faudra aussi modifier le fichier mes_fonctions.php3 avec le code fournis en annexe, et aussi remplacer le squelette de l’article par la version fournie ici (article_pdf.html).

J’ai donc fait quelques modifications sur la génération de PDF afin de :

-  gérer un peu mieux les balises SPIP &lt;code>, qui deviennent du texte entouré de marqueurs HTML <TT> ;
-  gérer les images dans le texte (ne pas oublier de n’autoriser que les formats PNG et JPEG en images dans un article, en virant de la table qui va bien les lignes qui vont aussi bien : FIXME) ;
-  gérer correctement les tableaux, pour éviter que le contenu ne déborde des cellules, et adapter la largeur des colonnes à leur contenu ;
-  gérer les balises cadre de SPIP de la même façon que les balises code (ce qui n’a pas été sans mal, cf. l’expression régulière dans mes_fonctions.php3).

A noter plusieurs choses :

-  la gestion des images gère trois cas :

  • images de largeur inférieure à 30 : pas de changement d’échelle, ou plutôt ratio fixe, c’est essentiellement bricolé pour avoir la puce SPIP dans le PDF ;
  • image de 30 à 600 pixels de large : ratio fixe (pour avoir à peu près ce qu’on avoir sur un écran web, soit 600 pixels de largeur utile) ;
  • image de taille > à 600 pixels, on taille dans le gras, et on ne fait pas de détails ;

-  si une image fait passer une page, on regarde si, à 80% de la taille, elle ne passe pas dans la page, de façon à remplir les pages (c’est un peu bête d’abattre des arbres pour 4 lignes entre deux images, surtout pour une documentation utilisateur) ;

Pour rappel, les images GIF ne sont pas gérées officiellement, avec le FPDF officiel en date d’aujourd’hui (1.51), et il n’est pas complètement souhaitable que ce le soit.

Cela dit, j’ai modifié FPDF pour utiliser les classes GIF (en PHP pur) de Yamasoft [3], et ça marche, à plusieurs conditions :

  • ne pas être pressé ;
  • que votre hébergeur ne le soit pas non plus (temps maximal d’exécution d’un script PHP) ;
  • ne pas être gourmand, ni être limité en mémoire (les images sont construite dans l’espace mémoire de PHP).

Cette modification n’est pas encore publiée officiellement sur le site de FPDF, vous l’avez ici en avant-première.

Toujours pour des limitations de PDF (plutôt que de FPDF), les images PNG avec canal alpha ne sont pas non plus supportées.

Le mieux est donc :

  • d’interdire l’utilisation du GIF (avec phpMyAdmin, ça se fait simplement en détruisant la ligne GIF dans la table spip_types_documents, par un DELETE FROM spip_types_documents WHERE extension='gif' and inclus='image') ;
  • d’ajouter la ligne suivante pour modifier la puce par défaut dans mes_fonctions.php3 : $GLOBALS['puce'] = "<img src='puce.png' align='top' alt='- ' border='0'>";. Cette image en PNG pourra comporter une couleur transparente, mais pas de canal alpha.

-  Tableaux

Les tableaux sont gérés correctement en terme de largeur, avec un algorithme un peu brut qui consiste à réduire la taille de la police tant que la largeur du tableau dépasse la largeur imprimable de la page. Si vous avez beaucoup de tableaux de largeurs différentes dans votre article, le résultat peut ne pas être très esthétique.

Les entêtes de colonne (si elles sont spécifiées avec | {{ titre }} |) sont affichés en gras sur fond jaune (choix qui n’appartient qu’à moi).

-  Listes

Les listes sont gérées correctement, y compris les listes numérotées, avec indentation. On doit même pouvoir relativement facilement modifier le type de puce en fonction de la profondeur.

-   Entités HTML

Il y avait aussi quelques problèmes avec des entités HTML qui ont maintenant été corrigées, grâce à quelques ajouts dans la fonction de filtrage pdf_first_clean.

-  Cas particulier : marqueur SPIP code

Le marqueur SPIP <code> doit être marqué dans le source SPIP avec les marqueurs HTML : &lt;code&gt; et &lt;/code&gt;.

Ils sont donc passés en HTML avec les caractères qui vont bien, et au passage dans le générateur PDF, sont vus comme des marqueurs HTML code. Ce qui nous permet d’injecter dans le PDF le texte qui va bien pour obtenir le résultat voulu (bon OK, c’est une bidouille infâme, mais ça marche ;-).

-  Autre cas particulier : marqueur SPIP cadre

Alors que SPIP fait tout le travail avec le marqueur <code>, il en va différemment avec le marqueur . En effet, SPIP le transforme en bout de formulaire HTML (<TEXTAREA> pour les intimes), et c’est ensuite le navigateur qui fait tout, et en particulier le traitement des retours chariot. Il va donc nous falloir faire quelques petites choses avant de pouvoir utiliser ce qui se trouve entre les marqueurs <TEXTAREA> pour en faire quelque chose.

Tout d’abord, rappelons que la présence d’un caractère retour chariot ou saut de line dans un fichier HTML n’aide pas à la présentation du contenu, mais uniquement du source : ils sont interprétés comme des espaces. Sauf dans quelques cas : au sein de marqueurs <PRE>, <TEXTAREA>, et quelques autres. Dans ces cas-là, et uniquement ceux-là, les caractères en question font passer à la ligne. Et l’on trouve aux environs de la ligne 68 dans lib_pdf_global.php une ligne qui remplace toutes les occurences de saut de ligne (\n) par une espace.

Il est hors de question dans le filtre SPIP pour le PDF (pdf_first_clean) de remplacer - filtre vu avant la ligne 68 pré-citée - tous les \n par des &ltBR>, cela aurait un effet désastreux. D’où l’expression régulière qui permet de trouver toutes les occurences de marqueurs HTML <TEXTAREA>, et de remplacer entre les balises de début et de fin les \n par ce qu’il faut. Gymnastique un peu tordue, mais la moins pire que j’ai pu trouvé.

Ce qui reste à faire...

En 6 mois de développement erratique, cette liste s’est amoindrie (je n’ai plus l’historique, enfin si, regardez plus haut les améliorations apportées). Il reste peu de choses à mon sens à corriger :

  • un léger décalage à droite sur les élements de liste (<LI> quoi) entre la puce et les premiers caractères de la première ligne, les lignes suivantes du même élément se recadrant un pouillème plus à gauche ;
  • il semble y avoir des problèmes avec les liens internes, mais je n’ai pas envie de fouiller (j’utilise SPIP2PDF pour éviter de donner l’accès à tout mon SPIP) ;
  • encore un peu de nettoyage à faire dans le code, histoire d’y mettre les commentaires adéquats.

En enfin une suggestion que je devrais passer sur la liste : abandonner le GIF dans SPIP comme format d’image, et le remplacer par le PNG (sans canal alpha, please).

Annexes

-   Contenu de mes_fonctions.php3

function pdf_first_clean($texte) {
	// $texte = ereg_replace("<p class[^>]*>", "<P>", $texte);
	//Translation des codes iso
	// PB avec l'utilisation de <code>
	$trans = get_html_translation_table(HTML_ENTITIES);
	$trans = array_flip($trans);
	$trans["<br />\n"] = "<BR>";	// Pour éviter que le \n ne se tranforme en espace dans les <DIV class=spip_code> (TT, tag SPIP : code)
	$trans["&#339;"] = "oe";
	$trans["&#8230;"] = "...";
	$trans["'"] = "'";
	$trans["-"] = "-";
	$trans["'"] = "'";
	$trans["""] = "\"";
	$trans["""] = "\"";
	$trans["&ucirc;"] = "û";
	$trans['$'] = '\$';
	$trans['->'] = '-»';
	$trans['<-'] = '«-';
	$texte = strtr($texte, $trans);
  		
	// Echappement des "
  	$texte = ereg_replace("\"", "\\\"", $texte);
 
	// Traitement des Espaces
 	$texte = ereg_replace("(&nbsp;| )+", " ", $texte);

	// Traitement des cadres
	$trans=array("\n" => '<BR>');
	while (preg_match('/(.*<textarea[^>]*>)(.*\n.*)(<\/textarea>.*)/ims', $texte, $textarea)) {
		$rep=strtr($textarea[2], $trans);
		$texte=$textarea[1].$rep.$textarea[3];
	}

 	return $texte;
}

INSTALLATION


-  Installer d’abord les fichiers de Drop Zone city ;
-  Puis installer les fichiers présents dans cet article. Ils vont écraser certains fichiers de DropZone City : c’est normal.

Discussion

31 discussions

  • 4
    Cédric Lang-Roth

    J’ai ce message d’erreur qui s’affiche :

    Warning: fopen(IMG/_article_PDF/article_328.pdf): failed to open stream: Permission denied in /disque2/home/alorsquoi/www/lib/class_pdf/fpdf.php on line 1025
    FPDF error: Unable to create output file: IMG/_article_PDF/article_328.pdf

    Que faire ?

    • Mathieu

      il semble que ce soit une question de permissions sur le répertoire correspondant :

      essaies de faire un chmod 777 sur ce repertoire.

    • Bonjour et merci pour cette contrib,
      J’ai le même problème, et après attribution des droit au répertoire IMG, ce problème persiste.

      Quelqu’un aurait-il une solution ?
      merci encore

    • Bonjour et merci d’avance,
      J’ai bien affecté les droits sur le repértoire IMG, mais c’est l’erreur suivante qui survient :
      FPDF error : Alpha channel not supported : IMG/icones/pdf-dist.png

      quelqu’un aurait-il déja rencontré cette erreur ?
      Je ne sais d’où elle provient et comment la traiter.
      quelqu’un pourait-il m’aider ;
      merci d’avance

    • FPDF ne gère pas le canal alpha, donc pour utiliser ton image tu dois le convertir en JPG.

    Répondre à ce message

  • Bonjour, j’obtiens ce message d’erreur et impossible à la virer.. Pourtant dans le rep qui sert de cache j’ai bien mes fichiers pdf correctement formatés. Que se passe-t-il ??
    Merci par avance

    ++

    Ben

    Warning : Cannot modify header information - headers already sent by (output started at /var/www/html/etablissements/0601882v/mes_fonctions.php3:15) in /var/www/html/etablissements/0601882v/inc-public.php3(60) : eval()’d code on line 127

    Répondre à ce message

  • 2

    très bonne contrib mais y a t il un moyen de le faire foctionner en UTF-8...

    Merci d’avance...

    Quentin

    • Hmm, effectivement, vu l’article 41 de ton site, je vois le problème...
      Tu as plus de détails sur la configuration de la partie AMP (Apache, PHP, MySQL) ? Voire même celle de Linux (locale utilisée, etc) ?

    • Il te suffit de mettre la ligne

      « $texte = utf8_decode($texte) ; »

      avant « return $texte ; » dans ton fichier mes_fonctions.php3 et ça marche... Du moins pour les caractères présents dans la police utilisée par fpdf (occidentale, accentuée & co)... pour une écriture de type japonais, il te faudra installer de nouvelles polices
      (cf. lien).

      Je n’ai pas testé avec cette contrib, mais avec celle-ci
      (http://www.spip-contrib.net/Articles-SPIP-au-format-PDF#forum384265)
      ca marche parfaitement ;)

    Répondre à ce message

  • 1

    SUPER !!!!! C’est une coïncidence heureuse. Je travaillais sur le sujet et je viens sur le site et QUE VOIS-JE ?

    La superbe contrib qui tue :-)))

    Mil merci ;-)

    • Bonjour a tous.
      Je suis nouveau dans l’utilisation de spip. Pouvez-vous me donner le fichier final de mes_fonctions.php3 et aussi le code a ajouter pour acceder a la fonction pdf a partir d’un article.

      Merci d’avance

    Répondre à ce message

  • Salut,
    C’est assez génial cette contrib... J’aimerai essayer de l’adapter pour pouvoir générer un pdf incluant tous les articles d’une rubrique (un chapitre par article). Mon probléme (et ma question) concerne la création d’une table des matiéres... Je n’ai pas vu de fonctions fpdf pour la générer automatiquement. Est-ce qu’il y aurait une solution ?

    Répondre à ce message

  • Bilibu

    Je tenais a féliciter et remercier toutes les personnes qui ont fait cette contrib ! Je suis tout content de pouvoir l’utiliser... Bravo à vous.

    Répondre à ce message

  • L. Marso

    Tout s’affiche bien quand je clique sur le lien PDF.

    Dans le fichier PDF, je clique sur les notes de mon article.
    Oh, à ma grande surprise, ce lien me renvoie à la racine du site.

    Pourquoi ?...

    Y-a-t-il un moyen de remédier à cela ?

    Si non, dites-moi comment désactiver les liens dans le fichier PDF.

    Merci bien

    Répondre à ce message

  • 1

    Bonjour,

    Ton code est excellent mais il reste deux problèmes :
    -  Le caractère "« " est remplacé par & #171 ; dans le titre (dans le reste du texte c’est ok)
    -  J’ai des numéros de notes que je met en exposant (style 1), dans le PDF ils apparaissent en normal (style « 1 ») ce qui fait assez moche. Est il possible que ton code prenne en compte cette balise ?

    Répondre à ce message

  • Cédric Lang-Roth

    Bonjour. Deux problèmes :

    1. Je n’avais pas de fichier mes_fonctions.php3 auparavant. J’en crée un avec le code fourni et il s’affiche sur tout le site la mention suivante : Parse error: parse error in /Users/cedriclangroth/Sites/SPIP-v1-8b2/mes_fonctions.php3 on line 3
    2. Lorsque je charge un fichier article_pdf.php3, ceci s’affiche :
      Erreur(s) dans le squelette
      Erreur : filtre « pdf_first_clean » non défini, _principale
      
      Erreur : filtre « pdf_first_clean » non défini, _principale
      
      Erreur : filtre « pdf_first_clean » non défini, _rubrique_mere
      
      Erreur : filtre « pdf_first_clean » non défini, _principale
      
      Erreur : filtre « pdf_first_clean » non défini, _principale

    Que faire ?

    Répondre à ce message

  • Bonjour tout le monde,

    Je suis débutant en php. J’ai installé spip sur mon ordi et le générateur pdf, tout tourne super bien.

    Seulement voilà, je voudrai ajouter le logo de mon site ( ici rubon0 ) sous le titre principal et la rubrique lorsque le pdf d’un article est généré.

    Après plusieurs essais infructueux avec pleins de messages d’erreurs en retouchant article_pdf et lib_pdf_spip, j’appelle les âmes généreuses pour les codes à insérer dans les fichiers.

    Merci pour votre aide généreuse !
    site de mon association : www.boisleroifc.haisoft.fr

    Répondre à ce message

Ajouter un commentaire

Avant de faire part d’un problème sur un plugin X, merci de lire ce qui suit :

  • Désactiver tous les plugins que vous ne voulez pas tester afin de vous assurer que le bug vient bien du plugin X. Cela vous évitera d’écrire sur le forum d’une contribution qui n’est finalement pas en cause.
  • Cherchez et notez les numéros de version de tout ce qui est en place au moment du test :
    • version de SPIP, en bas de la partie privée
    • version du plugin testé et des éventuels plugins nécessités
    • version de PHP (exec=info en partie privée)
    • version de MySQL / SQLite
  • Si votre problème concerne la partie publique de votre site, donnez une URL où le bug est visible, pour que les gens puissent voir par eux-mêmes.
  • En cas de page blanche, merci d’activer l’affichage des erreurs, et d’indiquer ensuite l’erreur qui apparaît.

Merci d’avance pour les personnes qui vous aideront !

Par ailleurs, n’oubliez pas que les contributeurs et contributrices ont une vie en dehors de SPIP.

Qui êtes-vous ?
[Se connecter]

Pour afficher votre trombine avec votre message, enregistrez-la d’abord sur gravatar.com (gratuit et indolore) et n’oubliez pas d’indiquer votre adresse e-mail ici.

Ajoutez votre commentaire ici

Ce champ accepte les raccourcis SPIP {{gras}} {italique} -*liste [texte->url] <quote> <code> et le code HTML <q> <del> <ins>. Pour créer des paragraphes, laissez simplement des lignes vides.

Ajouter un document

Suivre les commentaires : RSS 2.0 | Atom