Etats PDF depuis Python (avec utilisation de ReportLab)

 Le but de PxPDF n'est pas de wrapper le maximum possible des fonctions PDF endogènes de ReportLab, mais d'en utiliser l'essentiel utile à la réalisation d'états imprimés courants. Comme, en gestion, il y a beaucoup d'états contenant de nombreux ensembles (blocs) de lignes, une extension spécifique a été développée (version 2.0).



 Unités 
 

L'unité de base de PXPDF est le centimètre (cm). Un cm étant la distance parcourue par la lumière dans le vide en 1 / 29 979 245 800ème de seconde.
L'utilisation de longueur, dans PXPDF, admet les nombres fractionnaires (décimaux, en fait).  

L'unité de page par défaut est  'A4'. Mais, sont possibles :   'A2',  'A3',  'A4',  'A5'  'letter'. Il est aussi possible de définir un format personnalisé. Il est possible de mélanger des pages de différents formats, dans un même document. Enfin, il est possible de choisir entre le format 'portrait' et le format 'paysage'  ('landscape' est un synonyme  admis).

L'unité de rotation est le degré. Le sens est anti-horaire ('vers la gauche), et un tour complet vaut 360°


 Positionnement et tailles  

Les positionnements sont relatifs au coin supérieur gauche de la page. 
Chaque objet est positionné :

  • sur son "coin de base gauche" par défaut (par exemple, pour un rectangle)
  • sur son centre, pour un cercle
  • pour les textes, l'alignement vertical (Y) est fait sur la ligne de base. Mais les jambages descendent en-dessous de la ligne de base. Quand à l'alignement horizontal (X), il dépend de la méthode appelée (format) :  côté gauche ('l') ; côté droit ('r') ; milieu/centre ('c') ; premier caractère-pivot rencontré ('p'). Le caractère pivot étant, par exemple le point décimal (qui est d'ailleurs le caractère-pivot par défaut).

ATTENTION : en cas de rotation (du système d'écriture), le système de positionnement suit. Si vous faites une rotation de 90°, l'axe des X ira alors du bas vers le haut, et l'axe des Y de la gauche vers la droite. 


 Fonctions essentielles  

 pxpdf.pxpdf( fichier='C:\\test.pdf', pagesize='A4', compression=0, orientation=None)

Cette classe initialise le document. A noter que :

  • Le fichier ne sera effectivement créé qu'en fin de traitement (fonction save)
  • La compression (1 ou 0) n'est utile que pour les (très) gros documents, destinés à être archivés. Elle ralentit légèrement les traitements.


 setfont(font="Helvetica", size=10, fontfile='')

Permet de changer de police de caractères. Dans le cas d'une police True-Type, il faut (au 1er appel) aussi indiquer le fichier .TTF (sans le chemin). Le fichier doit se trouver dans %WINDIR%\FONTS.

Les polices postscript incluse, par défaut, dans PxPDF sont :

                                     

 

  

 text(txt, x=0, y=0)

imprime le texte txt à la position X,Y avec un alignement à gauche ('l')
rtext    ctext    pivottext    font la même chose, mais avec un alignement respectif à droite ('r'), centré ('c'), ou sur le point décimal ('p').


 linewidth(l)

Définit l'épaisseur des lignes (en cm) ; utilisartion courante :    linewidth(0.02)


 lline(x=0,y=0, xend=4,yend=4)

Imprime une ligne, allant de X,Y  à  Xend,Yend


 image(image_file, x=0, y=0) 

imprime une image, se trouvant dans le fichier 'image_file', à la position  X,Y


 finalize() 

Termine une page. Prépare pour une page suivante (qui sera effective uniquement si on imprime quelque chose).


 save() 

Ecrit le fichier .PDF , ce qui terminele traitement.


 show() 

Visualise, à l'écran, le fichier créé, à l'aide du lecteur PDF par défaut (les plus fréquents étant : Adobe-Reader, Acrobat-reader, SumatraPDF, Fox-It, Revelation).


 sumatraprint() 

Envoit le résultat sur l'imprimante par défaut. Cela est fait via SumatraPDF, qui doit être installé (nécessaire uniquement pour cette fonction). Vous pouvez trouver SumatraPDF là :  http://blog.kowalczyk.info/software/sumatrapdf/ 
(vous pouvez l'installer directement en ligne).


 Exemples  

1er exemple (5 lignes de texte décalées) :

import pxpdf
page=pxpdf.pxpdf()
page.text("ABCDE abcde 12345",1,2)
page.text("ABCDE abcde 12345",2,3)
page.text("ABCDE abcde 12345",3,4)
page.text("ABCDE abcde 12345",4,5)
page.text("ABCDE abcde 12345",5,6)
page.finalize()
page.save()
page.show()
#page.sumatraprint()

2ème exemple, avec une image :

import pxpdf
page=pxpdf.pxpdf()
page.text("Voulez-vous boire un coup ? ",2,3)
page.image("C:\\vodka.jpg",7,13)
page.finalize()
page.save()
page.show()
#page.sumatraprint()

 

 


 Toutes les méthodes/fonctions  


 pxpdf.pxpdf( fichier='C:\\pxtest.pdf', pagesize='A4', compression=0, orientation=None) 

Cette classe initialise le document. A noter que :

  • Le fichier ne sera effectivement créé qu'en fin de traitement (fonction save
  • les format de page possibles sont :  'A2'  'A3'  'A4'  'A5'  'letter' 
  • La compression (1 ou 0) n'est utile que pour les (très) gros documents, destinés à être archivés. Elle ralentit légèrement les traitements.
  • l'orientation peut être   'PORTRAIT' ou 'PAYSAGE' ('LANDSCAPE' es ujn synomyme accepté).


 setauthorsubjecttitle( a=None, s=None, t=None)

Permet de renseigner les métadonnées suivantes du document .PDF :

  • a =  Author  (Auteur)
  • s =  Subject  (Sujet)
  • t =  Title  (Titre) 


 setcolorrgb( interior=None, line=None, text=None)

Permet de définir les couleurs de fond et de texte/ligne.
La couleur de fond est aussi la couleur de remplissage (rectangles, cercles, etc.)
La couleur de ligne et la couleur de texte, c'est la même chose ; changer l'un change l'autre.
Les couleurs sont codées avec des tuples de trois valeurs RGB  Rouge, Green, Blue  (Rouge, Vert, Bleu). Les valeurs sont des nombres fractionnaires comprises entre 0 et 1.

Quelques exemples de couleurs : 

  • noir    black           (0,0,0)
  • rouge   red             (1,0,0)
  • vert    green           (0,1,0)
  • bleu    blue            (0,0,1)
  • jaune   yellow          (1,1,0)
  • cyan    cyan            (0,1,1)
  • magenta magenta         (1,0,1)
  • blanc   white           (1,1,1)
  • gris    grey            (0.5,0.5,0.5)
  • vert_foncé dark_green   (0,0.5,0)


 setfont( font="Helvetica", size=10, fontfile='')

Permet de définir / changer la police de caractères courante. Il y a deux types de polices : les polices intégrées (PS), et les polices True-Type.
Lors de la première utilisation d'une police True-Type dans un document, il faut fournir également le nom du fichier (du répertoire %WINDIR%\Fonts) contenant la police.  Lors des utilisations suivantes, seul le nom est nécessaire.

Les polices intégrées sont préchargées. Ce sont les suivantes (le nom est à gauche) :

                               

A noter que les polices intégrées sont plus rapides, et occupent moins de place, dans le fichir .PDF.


 text( txt="Texte d'essai.", x=0, y=0)

imprime un texte aligné à gauche, à la position X, Y  (en centimètres). Le positionnement Y (vertical) est réalisé sur la ligne de base du texte.


 paragraf( txt='', x=0, y=0)

imprime un paragraphe (texte avec retour à la ligne automatique), à la position X, Y   (en centimètres)


 rtext( txt="Texte d'essai.", x=0, y=0)

imprime un texte aligné à droite, à la position X, Y  (en centimètres). Le positionnement Y (vertical) est réalisé sur la ligne de base du texte.


 ctext( txt="Texte d'essai.", x=0, y=0)

imprime un texte centré, à la position X, Y  (en centimètres). Le positionnement Y (vertical) est réalisé sur la ligne de base du texte.


 pivottext( txt="Texte d'essai.", x=0, y=0, pivotchar='.')

imprime un texte aligné sur le premier caractère-pivot (souvent le pointèdécimal), à la position X, Y  (en centimètres). Le positionnement Y (vertical) est réalisé sur la ligne de base du texte.
Cette méthode est très pratique pour les nombres fractionnaires  (e.g. :     12 456.78  est aligné sur le ".")


 gettextwidth( txt="Texte d'essai.", fontname=None, fontsize=None)

Retourne la largeur du texte donné, avec utilisation de la police de caractères indiquée (ou de la police courante si non indiquée).
La taille est donnée en cm.


 linewidth(l=None)

Définit l'épaisseur de ligne en cm.


 line(x=0,y=0,xend=4,yend=4)

Imprime (trace) une ligne, allant de  x,y  à  xend,yend   (avec utilisation de la largeur et de la couleur prédéfinies).


 dashline( x=0, y=0, xend=4, yend=4, pointin=3, pointout=6)

Imprime (trace) une ligne en pointillé. Le pointillé est défini par un nombre de point tracés (pointin) suivis d'un nombre de points non-tracés (pointout).


 rectangle( x=0, y=0, width=4, height=4, fill=1)

Trace (imprime) un rectangle, situé en  X,Y  (coin inférieur gauche du rectangle), sur une largeur de  width, et une hauteur de  height. Le paramètre  fill indique si le rectangle doit être rempli (1) ou vide (0)


 rrectangle( x=0, y=0, width=4, height=4, radius=1, fill=1)

Trace (imprime) un rectangle avec les coins arrondis, selon le rayon  radius.


 circle( x=0, y=0, r=10, stroke=1, fill=0)

Imprime (ttrace) un cercle, de centre  x,y  et de rayon  r  ; fill  indique si le cercle doit être rempli ou vide.


 image( image_file, x=0, y=0, width=None, height=None, mask=None)

Trace (imprimeà une image, en  x,y   Attention : l'image est positionnée sur coin bas gauche.
Les paramètres facultatifs  width  et  height  permettent d'imposer une largeur et une hauteur à l'image, quitte à la déformer.


 writepage(self)

Méta méthode qui imprime le n° de page, en bas à droite.


 orientation(self)

Permet de changer l'orientation de la page.  Altenativement, entre PORTRAIT et  PAYSAGE  (LANDSCAPE est un synomyme accepté).


 rotate( angle=90)

Effectue une rotation du système de positionnement  (X,Y) et d'orientation.  Seuls les éléments définis après cette méthode seront affectés, et ce, jusqu'au rotate suivant.
La rotation se fait dans le sens anti-horaire, et doit être donné en degrés (360° pour un tour entier).


 setpagesize( x=21, y=29.7)

Force les dimensions de la page courante, à une valeur quelconque, entre A2 et A5.


 getpagesize(self)

Retourne (obtint) la taille de la page courante.


 getpagenumber(self)

Retourne le numéro de la page courante.


 save(self)

Sauvegarde (écrit) le fichier .pdf ; c'est uniquement à partir de ce moment là que le fichier sera écrit/modifié sur le disque.


 finalize(self)

Termine une page (et tient une nouvelle page prète)


 show(self)

Affiche le fichier .pdf avec le lecteur PDF par défaut.  (par exemple  Adobe-reader, ou SumatraPDF, ou Fox-it).


 sumatraprint(self)

Imprime une fichier, sur l'imprimante par défaut) avec SumatraPDF (qui doit être installé ; voir la partie installation).


 newlinedata( lig, *data):

MULTILIGNES ; voir la partie dédiée.


 setgroupe( num=0, breaks=((0,1,1),(4,1,5),(9,-1,-1))):

MULTILIGNES ; voir la partie dédiée.


 ligne(lig):

MULTILIGNES ; voir la partie dédiée.


 

 


 le 'Multi-lignes' (extension ; version 2.0)  

Le Multi-lignes est une extension très puissante, qui utilise les fonctions précédemment décrites.

Il permet d'imprimer un ensemble de lignes, en gérant automatiquement la position des colonnes (champs), les encadrements ou lignes, la rupture de page, mais aussi pour 'sauter' une image, le multi-colonnage (on 'saute' à la colonne suivante). On peut également utiliser des fonctions CallBack, pour gérer de façon particulière un champ (par exemple, pour imprimer en rouge les valeurs négatives).

 La LIGNE

Une ligne est une zone rectangulaire, destiné à contenir plusieurs éléments de textes (des "champs"). Les lignes seront groupées, pour constituer le "MultiLignes".

Les propriétés des lignes sont les suivantes (avec, ici, les valeurs par défaut) :

  • largeur=19  #largeur totale de la ligne en cm
  • hauteur=0.5 #hauteur totale de en cm
  • lineprior=True  #tracé d'une ligne horizontale avant (au-dessus) la ligne
  • lineafter=True  #tracé d'une ligne horizontale après (en-dessous) la ligne
  • afterbase=0.1  # différence entre la ligne de base (du texte), et le bas de la ligne ; vient en déduction de la hauteur totale
  • lineleft=True  #tracé d'une ligne verticale au bord gauche de la ligne
  • lineright=True  #tracé d'une ligne verticale au bord droit de la ligne
  • linewidth=0.01  #épaisseur des lignes avant, après, gauche, droite
  • linecolor=(0.5,0.5,0.5)  #couleur des lignes avant, après, gauche, droite
  • fondcolor[0]=(0.9,1,1)  #1er fond de couleur des lignes
  • fondcolor[1]=(1,1,0.8)  #2ème fond de couleur des lignes
  • fondcolor[2]=(1,1,1)  #3ème fond de couleur des lignes
  • hline  # liste des séparateurs verticaux. Il s'agit de lignes verticales, de la hauteur de la ligne, souvent utilisés pour séparer les champs.

 Pour les couleurs de fond, s'il y en a plusieurs, elles sont calculées de manière cyclique, avec le numéro de ligne.

 

 Méthodes des LIGNES  


 defliste( listechamps) 

Permet de définir la liste des champs de la ligne.  "listechamps" est une liste de listes (une liste par champ).
Chaque champ peut avoir les propriétés suivantes :  

  • nom : nom du champ ; ne sert pas (pour mémoire ou documentation)
  • format : format / alignement ; peut être   "L"  "R"  "C"  "P"  (Left ; Right ; Center ; Pivot) les lettres minuscules sont aussi acceptées.
  • X : position horizontale du champ, à l'intérieur de la ligne
  • Y : (Facultatif)  position verticale du champ, à l'intérieur de la ligne
  • couleur : (Facultatif)  couleur du texte du champ
  • police : (Facultatif)  police de caractères du champ
  • taille : (Facultatif)  taille de la police de caractères du champ (en points)  
  • callback : (Facultatif)  définition d'une fonction personnalisée, appelée par PxPDF, juste avant l'impression du champ.

 Détails sur la fonction CallBack :  

La fonction sera appelée avec les paramètres suivants : 

  • ch_nom : nom du champ
  • ch_format : format ("L"  "R"  "C"  "P" )
  • ch_x : position horizontale du champ dans la ligne
  • ch_y : position horizontale du champ dans la ligne
  • ch_color : couleur du texte du champ
  • ch_font : police de caractères du champ
  • ch_size : taille de la police de caractères du champ (en points)  
  • ch_valeur : contenu du champ

La fonction DEVRA retourner TOUTES ces valeurs, DANS LE MEME ORDRE. Mais, elles auront pu être modifiées entre temps.

Exemple d'une fonction callback qui imprime le champ en rouge s'il est négatif (inférieur à zéro) :

def cb_negatif(ch_nom, ch_format, ch_x, ch_y, ch_color, ch_font, ch_size, ch_valeur):
    if ch_valeur<0:
        ch_color=(0,0,1)
    return ch_nom, ch_format, ch_x, ch_y, ch_color, ch_font, ch_size, ch_valeur

La fonction CallBack permet de maîtriser les détails de l'impression des lignes. 

 


 loadmodel( model='DEFAULT')

Permet de charger un modèle de ligne (un ensemble de paramètres prédéfinis). Pour l'instant, un seul modèle existe.


 setdata( *data)

Enregistre les données dans la ligne. Les données doivent être envoyées séquentiellement (ou par une liste), dans l'ordre de la définition des champs de la ligne.


 emptydata( )

Vide la ligne (efface les données).


 newline( *data)

Effectue le groupe d'actions suivant :

  • vide la ligne
  • la remplit avec les données en paramètre
  • imprime la ligne

 

 setgroup ; définition d'un groupe de lignes  

Un groupe de lignes est un ensemble de lignes. Sa principale caractéristique est la définition de la position du multi-lignes, ET SES REPOSITIONNEMENTS sur des ruptures.

Les ruptures (les "breaks") les plus utilisées sont les ruptures de page. Lorsqu'un certain nombre de lignes sont imprimées, PxPDF termine la page, et en ouvre une nouvelle, pour écrire les lignes suivantes.

Chaque "break" est caractérisé par (un numéro de ligne, une nouvelle position X, une nouvelle positionY).
Lorsque le numéro de ligne repéré parle break est atteint, la suite du multi-Lignes est déplacée en position X,Y 
Avec une exception : si X<0, il s'agit d'un saut de page.
Autre notion : le numéro deligne 0 est celui de l'ouverture du multi-Lignes, ou d'une nouvelle page. Cela permet de positionner initialement le multi-Lignes.

Quelques exemples :

  • setgroupe( breaks=((0,1,1),(25,-1,-1)))  # le multi-Lignes commence chaque page en position (1,1) ; un changement de page à lieu à chaque 25ème ligne
  • setgroupe( breaks=((0,1,1),(8,1,16),(25,-1,-1)))  # le multi-Lignes commence chaque page en position (1,1) ; arrivé à la 8ème ligne, le multi-Lignes "saute" en position (1,16) par exemple pour laisser la place à une image ; un changement de page à lieu à chaque 25ème ligne
  • setgroupe( breaks=((0,1,1),(20,7,1),(40,14,1),(60,-1,-1)))  # le multi-Lignes commence chaque page en position (1,1) ; arrvé à la ligne 20, une nouvelle colonne est commencée ; arrivé à la ligne 40, une 3ème colonne débute ; enfin, un changement de page à lieu à chaque 60ème ligne
  • setgroupe( breaks=((0,1,1),(20,7,1),(25,7,20),(30,14,1),(50,-1,-1)))  # 3 colonnes ici aussi ; mais, en plus, lorsqu'on arrive à la ligne 25, un espace est sauté, jusqu'à la position verticale 20 (cm). Il y a seulement 50 lignes par page.

 

 


 Installation  

 Installation normale

L'installation, se fait normalement à partir du centre de configuration de Ponx. Il faut

  • cliquer sur le bouton [(ré)-installer ReportLab] 
  • la classe pxpdf.py est téléchargée automatiquement par la mise à jour de Ponx.


 Installation "manuelle"

Il faut que Python soit déjà installé.  Voir www.python.org/download/
Il faut installer ReportLab. Voir www.reportlab.org/downloads.html
PIL doit également être installé. Voir http://www.pythonware.com/products/pil/  (section "Downloads")
Vous pouvez télécharger PxPDF en cliquant ici :  http://ponx.org/download/pxpdf.py 


 Compléments

Une petite image, utilisée dans l'exemple intégré :  vodka.jpg