canismarko / dungeon-sheets

A tool to create character sheets and GM session notes for Dungeons and Dragons fifth edition (D&D 5e).
https://dungeon-sheets.readthedocs.io/en/latest/
GNU General Public License v3.0
161 stars 66 forks source link

Remove external dependcy on pdftk #75

Open canismarko opened 4 years ago

canismarko commented 4 years ago

Currently, filling in the PDF forms is done using pdftk. It would be nice if we could remove this dependency and use only pypi packages. This issue in the PyPDF2 package my help with this: https://github.com/mstamy2/PyPDF2/issues/355#issuecomment-644629188

ale-rt commented 3 years ago

LOL I had the same issue, this is what I came up with:

#!/usr/bin/env python3
from PyPDF4.generic import NameObject
from PyPDF4.generic import TextStringObject
from PyPDF4.pdf import PdfFileReader
from PyPDF4.pdf import PdfFileWriter

import random
import sys

reader = PdfFileReader(sys.argv[1])

writer = PdfFileWriter()
# Try to "clone" the original one (note the library has cloneDocumentFromReader)
# but the render pdf is blank
writer.appendPagesFromReader(reader)
writer._info = reader.trailer["/Info"]
reader_trailer = reader.trailer["/Root"]
writer._root_object.update(
    {
        key: reader_trailer[key]
        for key in reader_trailer
        if key in ("/AcroForm", "/Lang", "/MarkInfo")
    }
)

page = writer.getPage(0)

params = {"Foo": "Bar"}

# Inspired by updatePageFormFieldValues but also handle checkboxes
for annot in page["/Annots"]:
    writer_annot = annot.getObject()
    field = writer_annot["/T"]
    if writer_annot["/FT"] == "/Btn":
        value = params.get(field, random.getrandbits(1))
        if value:
            writer_annot.update(
                {
                    NameObject("/AS"): NameObject("/On"),
                    NameObject("/V"): NameObject("/On"),
                }
            )
    elif writer_annot["/FT"] == "/Tx":
        value = params.get(field, field)
        writer_annot.update(
            {
                NameObject("/V"): TextStringObject(value),
            }
        )

with open(sys.argv[2], "wb") as f:
    writer.write(f)

https://stackoverflow.com/a/66388344/646005

canismarko commented 3 years ago

Thanks. Unfortunately, I don't have the bandwidth to work on this right now but hopefully that SO post will be useful when I (or someone else) do.

bw-mutley commented 3 years ago

I've just made a PR to use @matsavage latex package, take a look when you can.