Skip to content

Instantly share code, notes, and snippets.

@huangsam
Last active July 5, 2019 21:30
Show Gist options
  • Save huangsam/d4d77a79acb80b406f455a623c7ebd15 to your computer and use it in GitHub Desktop.
Save huangsam/d4d77a79acb80b406f455a623c7ebd15 to your computer and use it in GitHub Desktop.
Testing out PDF generation
from io import BytesIO
from reportlab.lib.enums import TA_JUSTIFY
from reportlab.lib.pagesizes import letter
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.platypus import BaseDocTemplate, Paragraph, Spacer, PageTemplate, Frame
# Common text
LOREM = (
"Lorem Ipsum is simply dummy text of the printing and typesetting industry. "
"Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, "
"when an unknown printer took a galley of type and scrambled it to make a type "
"specimen book. It has survived not only five centuries, but also the leap into "
"electronic typesetting, remaining essentially unchanged. It was popularised in "
"the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, "
"and more recently with desktop publishing software like Aldus PageMaker including "
"versions of Lorem Ipsum."
)
HELLO = "Hello World is another language"
HELLO_MULTI = ". ".join([HELLO for _ in range(40)]) + "."
# Common styles
STYLES = getSampleStyleSheet()
STYLES.add(ParagraphStyle(name="Justify", alignment=TA_JUSTIFY))
NORM_STYLE = STYLES["Normal"]
H1_STYLE = STYLES["Heading1"]
def context(canvas, doc):
"""Establish header and footer contexts."""
canvas.saveState()
# Establish header
P = build_p("This is a multi-line header. It goes on every page. " * 5, font_size=6)
w, h = P.wrap(doc.width, doc.topMargin)
P.drawOn(canvas, doc.leftMargin, doc.height + doc.topMargin)
# Establish footer
P = build_p("This is a multi-line footer. It goes on every page. " * 5, font_size=6)
w, h = P.wrap(doc.width, doc.bottomMargin)
P.drawOn(canvas, doc.leftMargin, h)
canvas.restoreState()
def build_text(content: str, font_size: int = 8):
"""Build text with certain font."""
pre = f"<font size={font_size}>"
post = "</font>"
return pre + content + post
def build_p(content: str, font_size: int = 8):
"""Build <p> paragraph."""
return Paragraph(build_text(content, font_size=font_size), NORM_STYLE)
def build_h1(content: str, font_size: int = 8):
"""Build <h1> paragraph."""
return Paragraph(build_text(content, font_size=font_size), H1_STYLE)
def build_space():
return Spacer(1, 12)
def main():
"""Main logic of the program."""
output = BytesIO()
doc = BaseDocTemplate(
output,
pagesize=letter,
rightMargin=72,
leftMargin=72,
topMargin=72,
bottomMargin=72,
)
# Define a page template
frame = Frame(
doc.leftMargin, doc.bottomMargin, doc.width, doc.height - 20, id="normal"
)
template = PageTemplate(id="tbase", frames=frame, onPage=context)
doc.addPageTemplates([template])
# Generate content
Story = []
for i in range(10):
Story.append(build_p(LOREM))
Story.append(build_space())
Story.append(build_p(HELLO_MULTI))
Story.append(build_space())
# Save file contents
doc.build(Story)
# Pass bytes into open file
with open("demo_doc.pdf", "wb") as f:
f.write(output.getvalue())
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment