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

  • Il te faut malheureusement tâtonner dans deux fichiers :
    article_pdf.html pour faire les boucles que tu as besoin et
    lib_pdf_spip.php dans le répertoire lib/class_pdf/ une sorte de feuille de style pour éditer le pdf

    si comme moi tu n’es pas spécialiste du php et autres spécialité du genre... je te souhaite bonne chance... après trois jours de bidouilles j’arrive enfin à obtenir un truc tout simple qui correspond plus ou moins à mes besoins.

    Répondre à ce message

  • comment (et ou) puis je modifier fpdf.php pour inserer dans le pdf l’adresse internet de mon site ?

    Répondre à ce message

  • Grégoire Guzik

    Nous utilisons assez souvent les tableaux SPIP dans notre site en y mettant souvent des textes assez longs dans les cellules. Le traitement actuel rend des tableaux dont le contenu est microscopique dans certains cas (cf. http://www.mgbz-briey.net/article.php3?id_article=420 et http://www.mgbz-briey.net/article_pdf.php3?id_article=420). Quelqu’un s’est-il penché sur la question ? Pour ma part, il ne me parait pas évident d’adapter les scripts trouvés sur http://www.fpdf.org/fr/script/index.php.

    Répondre à ce message

  • 1

    le lien de la note 3 est cassé.
    Ou puis je recuperer le patch pour gerer le probleme des fichiers gif ?
    merci

    • Grégoire Guzik

      Le fichier nécessaire est gif.php qui se trouve dans le package fourni. Mais le résultat obtenu est très moyen.

      J’ai donc modifié le script de fpdf.php pour « transformer » les images gif en png qui sont très bien traitées. J’applique d’ailleurs la même méthode à ces images png pour éviter le problème de canal alpha.

      La modification faite se trouve dans la fonction Image située ligne 902.

      A la ligne 920, je remplace :

      elseif($type=='png')
      $info=$this->_parsepng($file);
      elseif($type=='gif')
      $info=$this->_parsegif($file);

      par :

      elseif($type=='png')
      {
      Header( "Content-type: image/png");
      $image = @imagecreatefromPNG("$file");
      //imagealphablending($image, false);
      //imagesavealpha($image, false);
      imageinterlace($image,0);
      ImagePNG($image,"./IMG/tempo.png");
      ImageDestroy($image);
      $info=$this->_parsepng("./IMG/tempo.png");
      unlink ("./IMG/tempo.png");
      }
      //$info=$this->_parsepng($file);
      
      elseif($type=='gif')
      {
      Header( "Content-type: image/png");
      $image = @imagecreatefromGIF("$file");
      //imagealphablending($image, false);
      //imagesavealpha($image, false);
      imageinterlace($image,0);
      ImagePNG($image,"./IMG/tempo.png");
      ImageDestroy($image);
      $info=$this->_parsepng("./IMG/tempo.png");
      unlink ("./IMG/tempo.png");
      }
      //$info=$this->_parsegif($file);

    Répondre à ce message

  • Mathieu

    Dans le même esprit que mon post précédent, les dates ne s’affichent pas correctement dans les PDF générés... Surement mon install qui n’est pas correcte mais que faut-il modifier pour résoudre ce petit problème.

    Merci encore pour la contrib.

    Répondre à ce message

  • Mathieu

    Très bonne contrib !!!!

    Cela colle à une grande partie de mes besoins,
    cependant je l’utilise sur l’intranet de ma société et j’aurais besoin de ’formatter’ les PDF pour les faire correspondre à la charte graphique de l’entreprise et rajouter éventuellement quelques mentions légales.

    Comment puis-je modifier la mise en forme des fichiers PDF générés ?

    D’avance merci

    Répondre à ce message

  • vincent

    bonjour,

    le lien correspondant a la note 3 est cassé.

    Ou puis je recuperer le patch qui permet de traiter les fichiers gif ?

    merci

    Répondre à ce message

  • 4

    Merci pour ce travail !

    Par contre j’ai un souci pour au niveau des ’ qui apparaissent d’une étrange façon dans le PDF généré.

    une piste ?

    • tu parles des apostrophes typographiques (ie. penchées) de Microsoft, et pas celles de ton clavier dans un Notepad ou sous Linux ?

      Si c’est bien ça, il te suffit d’ajouter dans pdf_first_clean la ligne suivante :

              $trans[""] = "'";
    • je pense qu’il parle plutôt de cela :

      $trans[""] = "'";

      Qui est à rajouté avec ses confrères dans le fichier mes_fonctions.php3.

      Je viens de le corriger dans la version 2.6.3 de BioSPIP / BioSquelettes.

    • En fait, c’est pas apparu à l’écran, mais il faut changer le premier apostrophe (type Krosoft) par son code ASCII, ce qui donne (à regrouper, les caractères sont ici volontairement séparés pour apparaître à l’écran) :

      $trans["& # 8217 ;"] = "'";

      il faut virer tous les espaces qu’il y a ici :
      ["& # 8217 ;"]

    • $trans["&ucirc;"] = "û";
      à rajouter dans mes fonctions après les autres transes

      ça marche même avec du code html ? moi pani compend
      merci mais y’en a marcher

    Répondre à ce message

  • Bonjour

    J’ai besoin d’afficher le carractère ° dans mes articles.

    J’ai compris que je dois ajouter dans mes_fonctions.php3 une ligne :

        $trans["°"] = "?";

    Mon problème est : Que mettre à la place du ? ou autrement dit comment coder ce carractère pour PDF ?

    Si quelqu’un sait ...
    merci d’avance

    Répondre à ce message

  • 2
    Jean-Marc

    Bonjour,

    J’ai installé cette contrib, ça marche parfaitement, sauf qu’il semble qu’une fois que le pdf ait été généré pour un article, il n’y ait pas moyen de lui faire prendre les éventuelles modifs d’article, même en demandant le vidage du cache.
    La seule solution semble consiter à aller faire le ménage à la mano dans le répertoire de génération. Il y a t il une solution pour régler ce petit désagément ?

    Merci en tous cas pour ce superbe script.

    • Arnaud Dupin de Beyssat

      Bonjour,
      Effectivement, je constate le même pb.
      Pas moyen d’obtenir un « nouveau » fichier après modifiications du texte.
      ADB

    • voir mon post ci-dessus

    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