Official links:
Codebase links:
Community links:
| 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() |
Official links:
Codebase links:
Community links: