将文档嵌入PDF文件中

时间:2015-05-15 10:41:01

标签: pdf reportlab pypdf

我们希望在我们创建的PDF文档中存储一些特定于应用程序的元数据(JSON对象)。

我们尝试使用canvas.setKeyword和PdfFileReader.documentInfo [“/ Keywords”]

这适用于100 KB文件,但挂起1 MB文件(documentInfo实际返回但需要很长时间> 1分钟)

是否有另一种方法可以使用reportlab将文件嵌入到PDF文档中? 还有另一种方法可以用PyPDF2读回来吗?

2 个答案:

答案 0 :(得分:0)

(这可能是也可能不是一个足够好的答案,但我还没有能够发表评论的声誉......)

长延迟的一个可能原因可能是字符串的编码过程。如果您不介意重新阅读PDF,添加数据并将其写回,您可以尝试pdfrw。 (免责声明:我是pdfrw作者。)执行此操作的代码如下所示:

    from pdfrw import PdfReader, PdfWriter
    trailer = PdfReader('source.pdf')
    trailer.Info.Keywords = my_json_string
    PdfWriter().write('dest.pdf', trailer)

如果由于字符串编码而不够快,您实际上可以将数据存储在文件中其他位置的流中(如果需要,甚至可以压缩它)。

答案 1 :(得分:0)

有点晚了,但我需要将数据嵌入到reportlab创建的PDF中,并最终提出以下内容。它将数据存储为 PDF中的EmbeddedFile流。为了以后查找数据,它存储了 PDF对象引用作为关键字(这不是"标准",PDF规范定义了定位/命名EmbeddedFile流的其他方法,但它有效)。使用PyPDF2提取数据。

# embeds data in the given reportlab.pdfgen.canvas, addressed by key.
# returns a string that must be added to canvas as a keyword
#
def canvas_embed(canvas, key, data):
    from reportlab.pdfbase import pdfdoc
    # create a stream object to hold the embedded data
    s = pdfdoc.PDFStream(
        content=data,
        filters=[pdfdoc.PDFBase85Encode, pdfdoc.PDFZCompress])
    s.dictionary['Type'] = '/EmbeddedFile'
    # add it to the pdf
    r = canvas._doc.Reference(s)
    # return a string representing the object reference.
    # we just use the two reference components concatenated with
    # the given key name:
    return '{}:{:d}:{:d}'.format(key,
        *canvas._doc.idToObjectNumberAndVersion[r.name])

# extract the embedded file identified by key from
# the given PyPDF2.pdf.PdfFileReader
#
def reader_extract(pdfreader, key):
    from PyPDF2.generic import IndirectObject
    # find the key in the pdf's keywords (reportlab canvas
    # separates keywords with ', '), and split it to get
    # the object reference
    for k in pdfreader.documentInfo['/Keywords'].split(', '):
        if k.startswith(key + ':'):
            refn, refv = [int(x) for x in k.split(':')[1:]]
            break
    # fetch the stream data
    return IndirectObject(refn, refv, pdfreader).getObject().getData()

# a quick test
#
if __name__ == '__main__':
    import StringIO
    from reportlab.pdfgen import canvas
    from PyPDF2.pdf import PdfFileReader

    pdfbuf = StringIO.StringIO()

    # create pdf with embedded data
    c = canvas.Canvas(pdfbuf)
    c.drawString(72.0, 72.0, 'embedded file test')

    embedkey = canvas_embed(
        canvas=c,
        key='myembeddeddata',
        data='some embedded data.')

    c.setKeywords(['SomeOtherKeyword', embedkey])

    c.showPage()
    c.save()
    pdfbuf.seek(0)

    # read embedded data from the pdf
    r = PdfFileReader(stream=pdfbuf)
    data = reader_extract(pdfreader=r, key='myembeddeddata')

    print 'Found: {}'.format(data)