Install
openclaw skills install @mina-atef-00/pdf-creationopenclaw skills install @mina-atef-00/pdf-creationUse when reportlab is unavailable (PIL dependency conflict in alternate venvs, uv-managed Python), or when you need a lighter-weight path to Unicode-aware searchable-text PDFs.
| Situation | Pick |
|---|---|
| Complex multi-page styled docs with tables, headers, footers | reportlab (Platypus) |
| PIL/Imaging not available or version conflict | fpdf2 |
| Need Unicode without configuring custom fonts | fpdf2 (register a TTF font) |
| Simple docs, fast iteration | fpdf2 |
pip install fpdf2
Also install a Unicode-capable TTF font (fpdf2's built-in Helvetica/Times/Courier
only cover Latin-1 — they raise FPDFUnicodeEncodingException on any character
outside that range). Available on most Linux:
/usr/share/fonts/dejavu-sans-fonts/ or /usr/share/fonts/truetype/dejavu/.
from fpdf import FPDF
FONT_DIR = "/usr/share/fonts/dejavu-sans-fonts"
pdf = FPDF("P", "mm", "A4")
pdf.add_font("DJS", "", f"{FONT_DIR}/DejaVuSans.ttf")
pdf.add_font("DJS", "B", f"{FONT_DIR}/DejaVuSans-Bold.ttf")
pdf.add_font("DJS", "I", f"{FONT_DIR}/DejaVuSans-Oblique.ttf")
pdf.set_auto_page_break(auto=True, margin=20)
pdf.add_page()
pdf.set_font("DJS", "B", 26)
pdf.cell(0, 10, "Title", align="C")
pdf.ln(12)
pdf.set_font("DJS", "", 9.5)
pdf.multi_cell(0, 5, "Unicode-safe text with em-dashes and arrows.")
pdf.output("output.pdf")
Uses context manager + FontFace for styling.
Key API points:
| Parameter | Notes |
|---|---|
| first_row_as_headings=True | NOT first_row_as_header (was renamed) |
| headings_style=FontFace(...) | FontFace with family, emphasis, size_pt, color, fill_color |
| cell_fill_mode="ROWS" | Alternating row background |
| cell_fill_color=(R,G,B) | RGB tuple for alternating rows |
| width= | Must be <= pdf.epw (effective page width) |
from fpdf import FPDF, FontFace
FONT_DIR = "/usr/share/fonts/dejavu-sans-fonts"
pdf = FPDF("P", "mm", "A4")
pdf.add_font("DJS", "", f"{FONT_DIR}/DejaVuSans.ttf")
pdf.add_font("DJS", "B", f"{FONT_DIR}/DejaVuSans-Bold.ttf")
pdf.set_margins(20, 18, 20)
pdf.add_page()
hdr = FontFace(family="DJS", emphasis="BOLD", size_pt=8,
color=(255,255,255), fill_color=(26,39,68))
cell = FontFace(family="DJS", emphasis="", size_pt=7.5, color=(26,32,44))
with pdf.table(col_widths=[42,50,84], text_align="LEFT",
first_row_as_headings=True, headings_style=hdr, width=170,
borders_layout="MINIMAL", cell_fill_color=(247,250,252),
cell_fill_mode="ROWS", line_height=4.5) as tbl:
for row in [["Module","Function","Returns"],["os.path","join","str"]]:
r = tbl.row()
for t in row:
r.cell(t, style=cell)
pdf.output("table.pdf")