Un de mes programmes fabrique plusieurs centaines de courriers sous forme de fichiers pdf, et je veux créer un fichier pdf qui regroupe tous ces courriers. Pourquoi? En particulier pour pouvoir les imprimer (mailing papier): si j'ai 1000 courriers à imprimer pour un mailing papier, je me vois mal lancer 1000 fois l'impression!!!
Avec le module PyPdf, c'est assez facile de faire des regroupements de fichiers pdf (http://pybrary.net/pyPdf/). Mais, car il y a un mais, pypdf impose que tous les fichiers à regrouper soient ouverts en même temps, et le système d'exploitation limite le nombre de fichiers ouverts en même temps (pour Windows, c'est environ 500).
Pour dépasser cette limite, j'ai donc développé le code ci-dessous!
Voilà le code proposé:
# Python 2.7 import sys, os from pyPdf import PdfFileWriter, PdfFileReader ############################################################################# def _addpdf(listepdf, pdfresult): """fonction utilitaire: voir addpdf""" pdftous = PdfFileWriter() ft = [] for nf in listepdf: ft.append(open(nf, "rb")) pdf = PdfFileReader(ft[-1]) for i in xrange(0, pdf.getNumPages()): pdftous.addPage(pdf.getPage(i)) f = open(pdfresult, "wb") pdftous.write(f) f.close() # fermeture de tous les fichiers "ft" ouverts for k in xrange(0, len(ft)): ft[k].close() #============================================================================ def addpdf(listepdf, pdfresult, temprep=None, imax=100): """fabrique le fichier pdf pdfresult = addition des fichiers pdf de listepdf listepdf = liste des noms de fichiers pdf à regrouper pdfresult = nom du fichier résultat à créer temprep = répertoire des fichiers temporaires si = None: fichiers temporaires dans le 'home' de l'utilisateur imax = nb maxi de fichiers ouverts en même temps """ if len(listepdf)<=imax: # on ne dépasse pas le nb de fichiers maxi ouverts: on y va directement _addpdf(listepdf, pdfresult) else: # il faut s'y reprendre à plusieurs fois pour éviter d'avoir # trop de fichiers ouverts en même temps! # répertoire des fichiers temporaires if temprep==None: temprep = os.path.expanduser("~") # temprep dans le home utilisateur # init. de la liste des fichiers temporaires temp = [] i1 = 0 while True: i2 = min(i1+imax, len(listepdf)) if i2<=i1: break # création d'un fichier temporaire supplémentaire temp.append(os.path.join(temprep, "temp%d.pdf" % len(temp))) _addpdf(listepdf[i1:i2], temp[-1]) i1 = i2 # addition de tous les fichiers temporaires ensemble _addpdf(temp, pdfresult) # destruction des fichiers temporaires for nf in temp: os.remove(nf)
Le principe est simple: si on dépasse le nombre maxi de fichiers ouverts en même temps (ici fixé à 100), on segmente la liste en autant de listes de 100 fichiers, et on crée des fichiers temporaires de regroupement. A la fin, il suffit de regrouper les fichiers temporaires en un seul fichier, et c'est fini! Pour faire propre, on détruit les fichiers temporaires.
import glob listefic = glob.glob(os.path.join("auteurs", "*.pdf")) listefic.sort() addpdf(listefic, "pdftous.pdf", ".")
Ici, on a tous les fichiers pdf à regrouper dans le sous-répertoire 'auteurs'.
Chacun de ces fichiers peut avoir un nombre quelconque de pages: elles seront toutes ajoutées dans le bon ordre.
On peut trier cette liste: cela déterminera dans quel ordre ces fichiers se placeront dans le pdf résultat.
Et on appelle la fonction de regroupement addpdf, en donnant comme répertoire temporaire le répertoire courant. Si on ne donne pas un répertoire temporaire, les fichiers temporaires seront placés dans le 'home' de l'utilisateur.
Le pdf résultat sera “pdftous.pdf”.
Les performances sont satisfaisantes: on regroupe 1000 courriers pdf d'une page en un seul pdf en une minute environ.
Amusez-vous bien!