【问题标题】:Generating pdf-latex with python script使用 python 脚本生成 pdf-latex
【发布时间】:2011-12-26 11:56:00
【问题描述】:

我是一名大学生,在我的大学里,要提交任何类型的作业,都必须有一个标准的封面(带有大学徽标、课程名称、教授姓名、我的名字和 bla bla bla)。

所以,我有一个 .tex 文档,它生成我的标准封面 pdf。它是这样的:

...
\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}
...

所以,我想知道是否有办法制作一个 Python 脚本,询问我作业的标题、课程名称和其他字符串,并使用它们来生成封面。之后,它应该编译 .tex 并使用给定的信息生成 pdf。

接受任何意见、建议、sn-p、图书馆。

【问题讨论】:

  • 文本编辑器更快恕我直言。每次打印封面时,您仍然需要输入标题、课程名称等。我会将该 PDF 转换为 word 模板。试试看:pdftoword.com
  • 您可以在文本编辑器中使用 sn-p 管理器/模板系统。
  • 这是个好主意!但我正在寻找更多自制/极客的东西。

标签: python latex pdflatex


【解决方案1】:

您可以从将模板 tex 文件定义为字符串开始:

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

接下来,使用argparse 接受课程、标题、姓名和学校的值:

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 粘贴到 content:

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

将内容写入文件cover.tex后,

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

您可以使用subprocess 呼叫pdflatex cover.tex

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

您也可以在此处添加 lpr 命令以将打印添加到工作流程中。

删除不需要的文件:

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

然后可以像这样调用脚本:

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

把它们放在一起,

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')

【讨论】:

  • 很好的解决方案,而且简单!现在我有一个自动封面生成器:)
  • 有没有办法检查pdf是否生成成功?我发现如果我在文本中有一个“&”或“%”,它会破坏 pdf。
  • @Johan:脚本显示了对pdlatex 的调用的输出。如果处理 LaTeX 时出现错误,这些错误消息将显示 pdf 未成功生成。 & 不是 Python 中的特殊字符,但它在 TeX 中,所以如果你想要一个文字 & 符号,你需要反斜杠:\&% 是 Python 和 TeX 中的特殊字符。根据% 所在的位置,可能需要将其更改为\%%%
  • 感谢 Unutbu。我实际上想在远程服务器上运行它,所以我将无法查看输出。我现在正在做的只是检查是否生成了 pdf。如果它是生成的,我假设一切正常并发送 pdf,如果不是,服务器会返回一条错误消息。或者你有更好的建议吗?
  • @Johan:如果pdflatex 命令失败,我修改了上面的脚本以引发 ValueError。如果没有-interaction nonstopmode,Python 进程可能会挂起等待用户输入。请注意pdflatex 即使发生错误仍会生成 pdf 文件。您必须检查 ValueError 以了解生成的 pdf 文件是否是由于运行错误造成的。
【解决方案2】:

当然有像 Jinja 这样的模板系统,但它们对于您的要求可能有点矫枉过正。您还可以使用 RST 格式化页面并使用它来生成 LaTeX,但这可能又是矫枉过正。哎呀,对于您必须定义的字段数量来说,自动生成页面可能是矫枉过正的,但是从什么时候开始矫枉过正了! :)

我对 Python 的字符串格式做了类似的事情。将您的 LaTeX 文档放在上面并通过将 %(placeholder_name1)s 标记放入文档中来“标记”该文件。例如,你希望你的类名放在哪里,使用%(course_name)s

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

然后,您可以从 Python 中加载该模板并将其格式化为:

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

如果您想自动找到这些标记,以下应该做得很好:

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')

代码将遍历令牌并向控制台打印提示,要求您输入每个令牌。在上面的示例中,您将收到两个提示(带有示例答案):

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

最后一行在结果文件上调用pdflatex 并从中生成PDF。如果您想更进一步,您还可以向用户询问输出文件名或将其作为命令行选项。

【讨论】:

  • 我需要在子进程调用中添加shell=True
  • 既然我们喜欢矫枉过正,我想看看Jinja的答案!
【解决方案3】:

还有一个 Template 类(自 2.4 起)允许使用 $that 令牌而不是 %(thi)s 一个。

【讨论】:

    【解决方案4】:

    正好有一个 Python 库:PyLaTeX。以下代码为taken directly from the documentation

    from pylatex import Document, Section, Subsection, Command
    from pylatex.utils import italic, NoEscape
    
    
    def fill_document(doc):
        """Add a section, a subsection and some text to the document.
    
        :param doc: the document
        :type doc: :class:`pylatex.document.Document` instance
        """
        with doc.create(Section('A section')):
            doc.append('Some regular text and some ')
            doc.append(italic('italic text. '))
    
            with doc.create(Subsection('A subsection')):
                doc.append('Also some crazy characters: $&#{}')
    
    
    if __name__ == '__main__':
        # Basic document
        doc = Document('basic')
        fill_document(doc)
    
        doc.generate_pdf(clean_tex=False)
        doc.generate_tex()
    
        # Document with `\maketitle` command activated
        doc = Document()
    
        doc.preamble.append(Command('title', 'Awesome Title'))
        doc.preamble.append(Command('author', 'Anonymous author'))
        doc.preamble.append(Command('date', NoEscape(r'\today')))
        doc.append(NoEscape(r'\maketitle'))
    
        fill_document(doc)
    
        doc.generate_pdf('basic_maketitle', clean_tex=False)
    
        # Add stuff to the document
        with doc.create(Section('A second section')):
            doc.append('Some text.')
    
        doc.generate_pdf('basic_maketitle2', clean_tex=False)
        tex = doc.dumps()  # The document as string in LaTeX syntax
    

    它对于生成自动报告或幻灯片特别有用。

    【讨论】:

    • 请注意,generate_pdf 之类的东西需要安装 pdflatex 或类似的东西(我认为这又取决于 Perl?)。我最终在PythonAnywhere 使用了PyLaTeX,因为它是免费的,而且几乎默认情况下它都可以正常工作。
    猜你喜欢
    • 1970-01-01
    • 2023-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多