8

我有一个报告实验室SimpleDocTemplate并将其作为动态 PDF 返回。我正在根据一些 Django 模型元数据生成它的内容。这是我的模板设置:

buff = StringIO()
doc = SimpleDocTemplate(buff, pagesize=letter,
                        rightMargin=72,leftMargin=72,
                        topMargin=72,bottomMargin=18)
Story = []

我可以轻松地将Entry模型中的文本元数据添加Story到稍后要构建的列表中:

    ptext = '<font size=20>%s</font>' % entry.title.title()
    paragraph = Paragraph(ptext, custom_styles["Custom"])
    Story.append(paragraph)

build然后通过调用以下命令生成要在响应中返回的 PDF SimpleDocTemplate

doc.build(Story, onFirstPage=entry_page_template, onLaterPages=entry_page_template)

pdf = buff.getvalue()
resp = HttpResponse(mimetype='application/x-download')    
resp['Content-Disposition'] = 'attachment;filename=logbook.pdf'
resp.write(pdf)
return resp

模型上的一个元数据字段是文件附件。当这些文件附件是 PDF 时,我想将它们合并到我正在生成的故事中;IE 表示reportlab“可流动”类型的PDF。

我正在尝试使用pdfrw,但没有任何运气。理想情况下,我很想打电话:

from pdfrw import PdfReader
pdf = pPdfReader(entry.document.file.path)
Story.append(pdf)

并将 pdf 附加到现有的故事列表中,以包含在最终文档的生成中,如上所述。

有人有想法么?我尝试使用 pagexobj 进行类似的操作来创建 pdf,并尝试遵循以下示例:

http://code.google.com/p/pdfrw/source/browse/trunk/examples/rl1/subset.py

from pdfrw.buildxobj import pagexobj
from pdfrw.toreportlab import makerl

pdf = pagexobj(PdfReader(entry.document.file.path))

但也没有运气。有人可以向我解释将现有PDF文件合并到reportlab flowable的最佳方法吗?我对这些东西并不擅长,并且几天来一直在研究 pdf 生成。:) 任何方向都非常感谢!

4

4 回答 4

3

我刚刚在一个项目中有一个类似的任务。我使用reportlab(开源版本)生成pdf文件和pyPDF以方便合并。我的要求略有不同,因为我只需要每个附件中的一页,但我相信这可能足以让您了解总体思路。

from pyPdf import PdfFileReader, PdfFileWriter

def create_merged_pdf(user):
    basepath = settings.MEDIA_ROOT + "/"
    # following block calls the function that uses reportlab to generate a pdf
    coversheet_path = basepath + "%s_%s_cover_%s.pdf" %(user.first_name, user.last_name, datetime.now().strftime("%f"))
    create_cover_sheet(coversheet_path, user, user.performancereview_set.all())

    # now user the cover sheet and all of the performance reviews to create a merged pdf
    merged_path = basepath + "%s_%s_merged_%s.pdf" %(user.first_name, user.last_name, datetime.now().strftime("%f"))

    # for merged file result
    output = PdfFileWriter()

    # for each pdf file to add, open in a PdfFileReader object and add page to output
    cover_pdf = PdfFileReader(file( coversheet_path, "rb"))
    output.addPage(cover_pdf.getPage(0))

    # iterate through attached files and merge.  I only needed the first page, YMMV
    for review in user.performancereview_set.all():
        review_pdf = PdfFileReader(file(review.pdf_file.file.name, "rb"))
        output.addPage(review_pdf.getPage(0)) # only first page of attachment

    # write out the merged file
    outputStream = file(merged_path, "wb")
    output.write(outputStream)
    outputStream.close()
于 2013-02-06T20:02:01.340 回答
2

我使用以下课程来解决我的问题。它将 PDF 作为矢量 PDF 图像插入。它很好用,因为我需要一个目录。可流动的对象允许内置的 TOC 功能像魅力一样工作。

ReportLab 是否有可流动的 matplotlib?

注意:如果文件中有多个页面,则必须稍微修改类。示例类旨在仅阅读 PDF 的第一页。

于 2014-01-27T01:06:29.020 回答
1

我知道这个问题有点老了,但我想使用最新的PyPDF2.

您现在可以访问PdfFileMerger,它可以做您想做的事,将 PDF 附加到现有文件。您甚至可以将它们合并到不同的位置并选择一个子集或所有页面!

官方文档在这里:https ://pythonhosted.org/PyPDF2/PdfFileMerger.html

您问题中的代码示例:

import tempfile
import PyPDF2
from django.core.files import File

# Using a temporary file rather than a buffer in memory is probably better
temp_base = tempfile.TemporaryFile()
temp_final = tempfile.TemporaryFile()

# Create document, add what you want to the story, then build
doc = SimpleDocTemplate(temp_base, pagesize=letter, ...)
...
doc.build(...)

# Now, this is the fancy part. Create merger, add extra pages and save
merger = PyPDF2.PdfFileMerger()
merger.append(temp_base)
# Add any extra document, you can choose a subset of pages and add bookmarks
merger.append(entry.document.file, bookmark='Attachment')
merger.write(temp_final)

# Write the final file in the HTTP response
django_file = File(temp_final)
resp = HttpResponse(django_file, content_type='application/pdf')
resp['Content-Disposition'] = 'attachment;filename=logbook.pdf'
if django_file.size is not None:
    resp['Content-Length'] = django_file.size
return resp
于 2020-08-27T15:36:26.507 回答
0

使用这个自定义流动:

class PDF_Flowable(Flowable):
#----------------------------------------------------------------------
def __init__(self,P,page_no):
    Flowable.__init__(self)
    self.P = P
    self.page_no = page_no
#----------------------------------------------------------------------
def draw(self):
    """
    draw the line
    """
    canv = self.canv
    pages = self.P
    page_no = self.page_no
    canv.translate(x, y)  
    canv.doForm(makerl(canv, pages[page_no]))
    canv.restoreState()

然后在打开现有的 pdf 即

    pages = PdfReader(BASE_DIR + "/out3.pdf").pages
    pages = [pagexobj(x) for x in pages]
    for i in range(0, len(pages)):
        F = PDF_Flowable(pages,i)
        elements.append(F)
        elements.append(PageBreak())

使用此代码在元素 [] 中添加此自定义流动。

于 2019-10-22T07:38:39.030 回答