From bcf957cabd33a3e32ea288fb21629c881d45016e Mon Sep 17 00:00:00 2001 From: jbranchaud Date: Fri, 21 Aug 2026 10:58:37 -0500 Subject: [PATCH] Add Generate Sample PDFs With ReportLab as a Python TIL --- README.md | 3 +- python/generate-sample-pdfs-with-reportlab.md | 44 +++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 python/generate-sample-pdfs-with-reportlab.md diff --git a/README.md b/README.md index 4b93d6f..c9ff5f8 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ working across different projects via [VisualMode](https://www.visualmode.dev/). For a steady stream of TILs, [sign up for my newsletter](https://visualmode.kit.com/newsletter). -_1869 TILs and counting..._ +_1870 TILs and counting..._ See some of the other learning resources I work on: @@ -1105,6 +1105,7 @@ If you've learned something here, support my efforts writing daily TILs by - [Escape Curly Braces Within Formatted String](python/escape-curly-braces-within-formatted-string.md) - [Experiment With SQLite Queries In Memory](python/experiment-with-sqlite-queries-in-memory.md) - [Force Remaining Arguments To Be Named](python/force-remaining-arguments-to-be-named.md) +- [Generate Sample PDFs With ReportLab](python/generate-sample-pdfs-with-reportlab.md) - [Get Absolute Seconds From `timedelta` Object](python/get-absolute-seconds-from-timedelta-object.md) - [Get Quotient And Remainder In One Operation](python/get-quotient-and-remainder-in-one-operation.md) - [Globally Install CLI Tool With UV](python/globally-install-cli-tool-with-uv.md) diff --git a/python/generate-sample-pdfs-with-reportlab.md b/python/generate-sample-pdfs-with-reportlab.md new file mode 100644 index 0000000..b85fe86 --- /dev/null +++ b/python/generate-sample-pdfs-with-reportlab.md @@ -0,0 +1,44 @@ +# Generate Sample PDFs With ReportLab + +The `reportlab` package has a `pdfgen` module that provides a `Canvas` API for +programmatically constructing a PDF. + +I recently needed the most basic use of this to quickly construct a sample PDF +that I could use as I experimented with [different `qpdf` +commands](/workflow/remove-pages-from-a-pdf.md). I wanted to generate a 10-page +PDF where each page included a large font number in the center. This way I could +clearly see what was the first, second, third, and so on pages. Then I could +quickly verify that the `qpdf` manipulations I was doing were working as +expected. + +I was able to do this without any setup or install. Using a `uv` one-liner (does +a 10-line heredoc count as a one-liner?), I generated a PDF with some basic +canvas rendering on each page. + +```python +❯ uv run --with reportlab python - <<'EOF' +from reportlab.pdfgen import canvas +N, W, H = 10, 612, 792 +c = canvas.Canvas("test.pdf", pagesize=(W, H)) +for i in range(1, N + 1): + c.setFont("Helvetica-Bold", 220) + c.drawCentredString(W / 2, H / 2 - 80, str(i)) + c.setFont("Helvetica", 28) + c.drawCentredString(W / 2, 100, f"page {i} of {N}") + c.showPage() +c.save() +EOF +``` + +The `--with` makes the `reportlab` package available to the command being run. +The command being run is `python` which evaluates that block of heredoc text. + +Within the heredoc, I import `canvas` from the `reportlab` package that has been +made available. I then create an in-memory PDF of a standard size. Then for-loop +10 times to build each page of the PDF with a big number in the middle and a +smaller `page x of N` lower down on the page. Finally, I save the PDF which +writes it to the directory I executed this whole command from. + +I had Claude help with the `canvas` API, however there are some decent +[`reportlab.pdfgen` docs +here](https://docs.reportlab.com/reportlab/userguide/ch2_graphics/).