web-dev-qa-db-fra.com

Génération de pdf-latex avec le script python

Je suis un gars de collège, et dans mon collège, pour présenter tout type de devoirs, il doit avoir une page de couverture standard (avec le logo du collège, le nom du cours, le nom du professeur, mon nom et bla bla bla).

Donc, j'ai un document .tex, qui génère mes pdfs de pages de garde standard. Cela va quelque chose comme:

...
\begin{document}
%% College logo
\vspace{5cm}
\begin{center}
\textbf{\huge "School and Program Name" \\}
\vspace{1cm}
\textbf{\Large "Homework Title" \\}
\vspace{1cm}
\textbf{\Large "Course Name" \\}
\end{center}
\vspace{2.5cm}
\begin{flushright}
{\large "My name" }
\end{flushright}
...

Donc, je me demandais s'il y avait un moyen de créer un script Python qui me demande le titre de mes devoirs, le nom du cours et le reste des chaînes et les utiliser pour générer la page de couverture. Après cela, il devrait compiler le .tex et générer le pdf avec les informations fournies.

Tout avis, conseil, extrait, bibliothèque, est accepté.

29
juliomalegria

Vous pouvez commencer par définir le fichier tex modèle comme une chaîne:

content = r'''\documentclass{article}
\begin{document}
...
\textbf{\huge %(school)s \\}
\vspace{1cm}
\textbf{\Large %(title)s \\}
...
\end{document}
'''

Ensuite, utilisez argparse pour accepter les valeurs du cours, du titre, du nom et de l'école:

parser = argparse.ArgumentParser()
parser.add_argument('-c', '--course')
parser.add_argument('-t', '--title')
parser.add_argument('-n', '--name',) 
parser.add_argument('-s', '--school', default='My U')

Un peu de formatage de chaîne suffit pour coller les arguments dans content:

args = parser.parse_args()
content%args.__dict__

Après avoir écrit le contenu dans un fichier, cover.tex,

with open('cover.tex','w') as f:
    f.write(content%args.__dict__)

vous pouvez utiliser subprocess pour appeler pdflatex cover.tex.

proc = subprocess.Popen(['pdflatex', 'cover.tex'])
proc.communicate()

Vous pouvez également ajouter une commande lpr ici pour ajouter l'impression au flux de travail.

Supprimez les fichiers inutiles:

os.unlink('cover.tex')
os.unlink('cover.log')

Le script pourrait alors être appelé comme ceci:

make_cover.py -c "Hardest Class Ever" -t "Theoretical Theory" -n Me

Mettre tous ensemble,

import argparse
import os
import subprocess

content = r'''\documentclass{article}
\begin{document}
... P \& B 
\textbf{\huge %(school)s \\}
\vspace{1cm}
\textbf{\Large %(title)s \\}
...
\end{document}
'''

parser = argparse.ArgumentParser()
parser.add_argument('-c', '--course')
parser.add_argument('-t', '--title')
parser.add_argument('-n', '--name',) 
parser.add_argument('-s', '--school', default='My U')

args = parser.parse_args()

with open('cover.tex','w') as f:
    f.write(content%args.__dict__)

cmd = ['pdflatex', '-interaction', 'nonstopmode', 'cover.tex']
proc = subprocess.Popen(cmd)
proc.communicate()

retcode = proc.returncode
if not retcode == 0:
    os.unlink('cover.pdf')
    raise ValueError('Error {} executing command: {}'.format(retcode, ' '.join(cmd))) 

os.unlink('cover.tex')
os.unlink('cover.log')
59
unutbu

Il existe bien sûr des systèmes de modèles comme Jinja, mais ils sont probablement exagérés pour ce que vous demandez. Vous pouvez également formater la page en utilisant RST et l'utiliser pour générer LaTeX, mais là encore, c'est probablement exagéré. Heck, la génération automatique de la page est probablement exagérée pour le nombre de champs que vous devez définir, mais depuis quand la surpuissance nous a-t-elle arrêtés! :)

J'ai fait quelque chose de similaire avec le formatage des chaînes de Python. Prenez votre document LaTeX ci-dessus et "tokenize" le fichier en plaçant des jetons %(placeholder_name1)s dans le document. Par exemple, où vous voulez que votre nom de classe aille, utilisez %(course_name)s

\textbf{\Large "%(homework_title)s" \\}
\vspace{1cm}
\textbf{\Large "%(course_name)s" \\}

Ensuite, à partir de Python, vous pouvez charger dans ce modèle et le formater comme:

template = file('template.tex', 'r').read()
page = template % {'course_name' : 'Computer Science 500', 
                   'homework_title' : 'NP-Complete'}
file('result.tex', 'w').write(page)

Si vous souhaitez trouver ces jetons automatiquement, les opérations suivantes devraient plutôt bien fonctionner:

import sys
import re
import subprocess

template = file('template.tex', 'r').read()
pattern = re.compile('%\(([^}]+)\)[bcdeEfFgGnosxX%]')
tokens = pattern.findall(template)

token_values = dict()
for token in tokens:
    sys.stdout.write('Enter value for ' + token + ': ')
    token_values[token] = sys.stdin.readline().strip()

page = template % token_values
file('result.tex', 'w').write(page)

subprocess.call('pdflatex result.tex')

Le code parcourra les jetons et imprimera une invite dans la console vous demandant une entrée pour chaque jeton. Dans l'exemple ci-dessus, vous obtiendrez deux invites (avec des exemples de réponses):

Enter value for homework_title: NP-Complete
Enter value for course_name: Computer Science 500

La dernière ligne appelle pdflatex sur le fichier résultant et génère un PDF à partir de celui-ci. Si vous voulez aller plus loin, vous pouvez également demander à l'utilisateur un nom de fichier de sortie ou prendre comme une option de ligne de commande.

5
Nathan

Il existe également une classe Template (depuis 2.4) permettant d'utiliser le jeton $that Au lieu de %(thi)s one.

3
Jill-Jênn Vie