Install any skill in seconds. Free to start, no credit card required.
Get Started Free →PDF generation toolkit. Create invoices, reports, certificates, forms, charts, tables, barcodes, QR codes, Canvas/Platypus APIs, for professional document automation.
.claude/skills/microck-reportlab/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 55% | 0% |
| case-04 | ✗→✓ | ▲ Improved | 205% | 0% |
| case-11 | ✗→✓ | ▲ Improved | 48% | 0% |
| case-15 | ✗→✓ | ▲ Improved | 4% | 0% |
| case-19 | ✗→✓ | ▲ Improved | 369% | 0% |
ReportLab is a powerful Python library for programmatic PDF generation. Create anything from simple documents to complex reports with tables, charts, images, and interactive forms.
Two main approaches:
Core capabilities:
onPage callback with Canvas)pythonfrom reportlab.pdfgen import canvas from reportlab.lib.pagesizes import letter from reportlab.lib.units import inch c = canvas.Canvas("output.pdf", pagesize=letter) width, height = letter # Draw text c.setFont("Helvetica-Bold", 24) c.drawString(inch, height - inch, "Hello ReportLab!") # Draw a rectangle c.setFillColorRGB(0.2, 0.4, 0.8) c.rect(inch, 5*inch, 4*inch, 2*inch, fill=1) # Save c.showPage() c.save()
pythonfrom reportlab.lib.pagesizes import letter from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer from reportlab.lib.styles import getSampleStyleSheet from reportlab.lib.units import inch doc = SimpleDocTemplate("output.pdf", pagesize=letter) story = [] styles = getSampleStyleSheet() # Add content story.append(Paragraph("Document Title", styles['Title'])) story.append(Spacer(1, 0.2*inch)) story.append(Paragraph("This is body text with <b>bold</b> and <i>italic</i>.", styles['BodyText'])) # Build PDF doc.build(story)
Tables work with both Canvas (via Drawing) and Platypus (as Flowables):
pythonfrom reportlab.platypus import Table, TableStyle from reportlab.lib import colors from reportlab.lib.units import inch # Define data data = [ ['Product', 'Q1', 'Q2', 'Q3', 'Q4'], ['Widget A', '100', '150', '130', '180'], ['Widget B', '80', '120', '110', '160'], ] # Create table table = Table(data, colWidths=[2*inch, 1*inch, 1*inch, 1*inch, 1*inch]) # Apply styling style = TableStyle([ # Header row ('BACKGROUND', (0, 0), (-1, 0), colors.darkblue), ('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke), ('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'), ('ALIGN', (0, 0), (-1, -1), 'CENTER'), # Data rows ('ROWBACKGROUNDS', (0, 1), (-1, -1), [colors.white, colors.lightgrey]), ('GRID', (0, 0), (-1, -1), 1, colors.black), ]) table.setStyle(style) # Add to Platypus story story.append(table) # Or draw on Canvas table.wrapOn(c, width, height) table.drawOn(c, x, y)
Detailed table reference: See references/tables_reference.md for cell spanning, borders, alignment, and advanced styling.
Charts use the graphics framework and can be added to both Canvas and Platypus:
pythonfrom reportlab.graphics.shapes import Drawing from reportlab.graphics.charts.barcharts import VerticalBarChart from reportlab.lib import colors # Create drawing drawing = Drawing(400, 200) # Create chart chart = VerticalBarChart() chart.x = 50 chart.y = 50 chart.width = 300 chart.height = 125 # Set data chart.data = [[100, 150, 130, 180, 140]] chart.categoryAxis.categoryNames = ['Q1', 'Q2', 'Q3', 'Q4', 'Q5'] # Style chart.bars[0].fillColor = colors.blue chart.valueAxis.valueMin = 0 chart.valueAxis.valueMax = 200 # Add to drawing drawing.add(chart) # Use in Platypus story.append(drawing) # Or render directly to PDF from reportlab.graphics import renderPDF renderPDF.drawToFile(drawing, 'chart.pdf', 'Chart Title')
Available chart types: Bar (vertical/horizontal), Line, Pie, Area, Scatter Detailed charts reference: See references/charts_reference.md for all chart types, styling, legends, and customization.
pythonfrom reportlab.graphics.barcode import code128 from reportlab.graphics.barcode.qr import QrCodeWidget from reportlab.graphics.shapes import Drawing from reportlab.graphics import renderPDF # Code128 barcode (general purpose) barcode = code128.Code128("ABC123456789", barHeight=0.5*inch) # On Canvas barcode.drawOn(c, x, y) # QR Code qr = QrCodeWidget("https://example.com") qr.barWidth = 2*inch qr.barHeight = 2*inch # Wrap in Drawing for Platypus d = Drawing() d.add(qr) story.append(d)
Supported formats: Code128, Code39, EAN-13, EAN-8, UPC-A, ISBN, QR, Data Matrix, and 20+ more Detailed barcode reference: See references/barcodes_reference.md for all formats and usage examples.
pythonfrom reportlab.platypus import Paragraph from reportlab.lib.styles import ParagraphStyle from reportlab.lib.enums import TA_JUSTIFY # Create custom style custom_style = ParagraphStyle( 'CustomStyle', fontSize=12, leading=14, # Line spacing alignment=TA_JUSTIFY, spaceAfter=10, textColor=colors.black, ) # Paragraph with inline formatting text = """ This paragraph has <b>bold</b>, <i>italic</i>, and <u>underlined</u> text. You can also use <font color="blue">colors</font> and <font size="14">different sizes</font>. Chemical formula: H<sub>2</sub>O, Einstein: E=mc<sup>2</sup> """ para = Paragraph(text, custom_style) story.append(para)
Using custom fonts:
pythonfrom reportlab.pdfbase import pdfmetrics from reportlab.pdfbase.ttfonts import TTFont # Register TrueType font pdfmetrics.registerFont(TTFont('CustomFont', 'CustomFont.ttf')) # Use in Canvas c.setFont('CustomFont', 12) # Use in Paragraph style style = ParagraphStyle('Custom', fontName='CustomFont', fontSize=12)
Detailed text reference: See references/text_and_fonts.md for paragraph styles, font families, Asian languages, Greek letters, and formatting.
pythonfrom reportlab.platypus import Image from reportlab.lib.units import inch # In Platypus img = Image('photo.jpg', width=4*inch, height=3*inch) story.append(img) # Maintain aspect ratio img = Image('photo.jpg', width=4*inch, height=3*inch, kind='proportional') # In Canvas c.drawImage('photo.jpg', x, y, width=4*inch, height=3*inch) # With transparency (mask white background) c.drawImage('logo.png', x, y, mask=[255,255,255,255,255,255])
pythonfrom reportlab.pdfgen import canvas from reportlab.lib.colors import black, white, lightgrey c = canvas.Canvas("form.pdf") # Text field c.acroForm.textfield( name="name", tooltip="Enter your name", x=100, y=700, width=200, height=20, borderColor=black, fillColor=lightgrey, forceBorder=True ) # Checkbox c.acroForm.checkbox( name="agree", x=100, y=650, size=20, buttonStyle='check', checked=False ) # Dropdown c.acroForm.choice( name="country", x=100, y=600, width=150, height=20, options=[("United States", "US"), ("Canada", "CA")], forceBorder=True ) c.save()
Detailed PDF features reference: See references/pdf_features.md for forms, links, bookmarks, encryption, and metadata.
For Platypus documents, use page callbacks:
pythonfrom reportlab.platypus import BaseDocTemplate, PageTemplate, Frame def add_header_footer(canvas, doc): """Called on each page""" canvas.saveState() # Header canvas.setFont('Helvetica', 9) canvas.drawString(inch, height - 0.5*inch, "Document Title") # Footer canvas.drawRightString(width - inch, 0.5*inch, f"Page {doc.page}") canvas.restoreState() # Set up document doc = BaseDocTemplate("output.pdf") frame = Frame(doc.leftMargin, doc.bottomMargin, doc.width, doc.height, id='normal') template = PageTemplate(id='normal', frames=[frame], onPage=add_header_footer) doc.addPageTemplates([template]) # Build with story doc.build(story)
This skill includes helper scripts for common tasks:
Use scripts/quick_document.py for rapid document creation:
pythonfrom scripts.quick_document import create_simple_document, create_styled_table # Simple document from content blocks content = [ {'type': 'heading', 'content': 'Introduction'}, {'type': 'paragraph', 'content': 'Your text here...'}, {'type': 'bullet', 'content': 'Bullet point'}, ] create_simple_document("output.pdf", "My Document", content_blocks=content) # Styled tables with presets data = [['Header1', 'Header2'], ['Data1', 'Data2']] table = create_styled_table(data, style_name='striped') # 'default', 'striped', 'minimal', 'report'
Complete working examples in assets/:
assets/invoice_template.py - Professional invoice with:
pythonfrom assets.invoice_template import create_invoice create_invoice( filename="invoice.pdf", invoice_number="INV-2024-001", invoice_date="January 15, 2024", due_date="February 15, 2024", company_info={'name': 'Acme Corp', 'address': '...', 'phone': '...', 'email': '...'}, client_info={'name': 'Client Name', ...}, items=[ {'description': 'Service', 'quantity': 1, 'unit_price': 500.00}, ... ], tax_rate=0.08, notes="Thank you for your business!", )
assets/report_template.py - Multi-page business report with:
pythonfrom assets.report_template import create_report report_data = { 'title': 'Quarterly Report', 'subtitle': 'Q4 2023', 'author': 'Analytics Team', 'sections': [ { 'title': 'Executive Summary', 'content': 'Report content...', 'table_data': {...}, 'chart_data': {...} }, ... ] } create_report("report.pdf", report_data)
Comprehensive API references organized by feature:
references/canvas_api.md - Low-level Canvas: drawing primitives, coordinates, transformations, state management, images, pathsreferences/platypus_guide.md - High-level Platypus: document templates, frames, flowables, page layouts, TOCreferences/text_and_fonts.md - Text formatting: paragraph styles, inline markup, custom fonts, Asian languages, bullets, sequencesreferences/tables_reference.md - Tables: creation, styling, cell spanning, borders, alignment, colors, gradientsreferences/charts_reference.md - Charts: all chart types, data handling, axes, legends, colors, renderingreferences/barcodes_reference.md - Barcodes: Code128, QR codes, EAN, UPC, postal codes, and 20+ formatsreferences/pdf_features.md - PDF features: links, bookmarks, forms, encryption, metadata, page transitionspythonfrom reportlab.lib.pagesizes import letter from reportlab.lib.units import inch width, height = letter margin = inch # Top of page y_top = height - margin # Bottom of page y_bottom = margin
pythonfrom reportlab.lib.pagesizes import letter, A4, landscape # US Letter (8.5" x 11") pagesize=letter # ISO A4 (210mm x 297mm) pagesize=A4 # Landscape pagesize=landscape(letter) # Custom pagesize=(6*inch, 9*inch)
drawImage() over drawInlineImage() - caches images for reusecanvas.Canvas("file.pdf", pageCompression=1)Centering text on Canvas:
pythontext = "Centered Text" text_width = c.stringWidth(text, "Helvetica", 12) x = (width - text_width) / 2 c.drawString(x, y, text) # Or use built-in c.drawCentredString(width/2, y, text)
Page breaks in Platypus:
pythonfrom reportlab.platypus import PageBreak story.append(PageBreak())
Keep content together (no split):
pythonfrom reportlab.platypus import KeepTogether story.append(KeepTogether([ heading, paragraph1, paragraph2, ]))
Alternate row colors:
pythonstyle = TableStyle([ ('ROWBACKGROUNDS', (0, 1), (-1, -1), [colors.white, colors.lightgrey]), ])
Text overlaps or disappears:
leading (line spacing) is greater than fontSizeTable doesn't fit on page:
repeatRowsBarcode not scanning:
barHeight (try 0.5 inch minimum)quiet=1 for quiet zonesFont not found:
pdfmetrics.registerFont()Images have white background:
mask parameter to make white transparentmask=[255,255,255,255,255,255]assets/invoice_template.pyassets/report_template.pycreate_styled_table()doc.multiBuild(story) for TOCshowPage() between labels or gridsbashuv pip install reportlab # For image support uv pip install pillow # For charts uv pip install reportlab[renderPM] # For barcode support (included in reportlab) # QR codes require: uv pip install qrcode
This skill should be used when:
This skill provides comprehensive guidance for all ReportLab capabilities, from simple documents to complex multi-page reports with charts, tables, and interactive elements.
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-02 | pass→pass | 15,987 | 12,126 | -24% | 1 | 1 | 0% | 3,264 | 7,008 | +115% | 0 | 0 | — |
case-07 | pass→pass | 6,490 | 5,007 | -23% | 1 | 1 | 0% | 1,321 | 5,714 | +333% | 0 | 0 | — |
case-01 | fail→pass | 31,505 | 24,828 | -21% | 1 | 1 | 0% | 6,189 | 9,595 | +55% | 0 | 0 | — |
case-03 | pass→pass | 6,095 | 3,398 | -44% | 1 | 1 | 0% | 1,158 | 5,352 | +362% | 0 | 0 | — |
case-04 | fail→pass | 10,305 | 8,600 | -17% | 1 | 1 | 0% | 1,931 | 5,894 | +205% | 0 | 0 | — |
case-05 | pass→pass | 15,324 | 10,879 | -29% | 1 | 1 | 0% | 2,889 | 6,865 | +138% | 0 | 0 | — |
case-06 | pass→pass | 7,883 | 7,003 | -11% | 1 | 1 | 0% | 1,316 | 5,940 | +351% | 0 | 0 | — |
case-08 | pass→pass | 3,929 | 2,627 | -33% | 1 | 1 | 0% | 730 | 5,155 | +606% | 0 | 0 | — |
case-09 | pass→pass | 3,726 | 2,590 | -30% | 1 | 1 | 0% | 602 | 5,164 | +758% | 0 | 0 | — |
case-10 | pass→pass | 8,936 | 4,770 | -47% | 1 | 1 | 0% | 1,568 | 5,631 | +259% | 0 | 0 | — |
case-11 | fail→pass | 21,300 | 8,962 | -58% | 1 | 1 | 0% | 4,531 | 6,698 | +48% | 0 | 0 | — |
case-17 | pass→pass | 11,302 | 14,710 | +30% | 1 | 1 | 0% | 2,188 | 7,704 | +252% | 0 | 0 | — |
case-12 | fail→fail | 15,894 | 13,458 | -15% | 1 | 1 | 0% | 3,172 | 7,625 | +140% | 0 | 0 | — |
case-13 | pass→pass | 2,691 | 2,966 | +10% | 1 | 1 | 0% | 419 | 5,232 | +1149% | 0 | 0 | — |
case-14 | pass→pass | 6,682 | 3,951 | -41% | 1 | 1 | 0% | 1,205 | 5,404 | +348% | 0 | 0 | — |
case-15 | fail→pass | 28,058 | 8,098 | -71% | 1 | 1 | 0% | 6,168 | 6,427 | +4% | 0 | 0 | — |
case-16 | pass→pass | 11,564 | 9,307 | -20% | 1 | 1 | 0% | 2,017 | 6,447 | +220% | 0 | 0 | — |
case-18 | pass→pass | 5,544 | 5,023 | -9% | 1 | 1 | 0% | 1,085 | 5,585 | +415% | 0 | 0 | — |
case-19 | fail→pass | 6,459 | 4,488 | -31% | 1 | 1 | 0% | 1,175 | 5,505 | +369% | 0 | 0 | — |
case-20 | pass→pass | 18,776 | 9,561 | -49% | 1 | 1 | 0% | 2,137 | 6,482 | +203% | 0 | 0 | — |
case-21 | pass→pass | 10,324 | 9,685 | -6% | 1 | 1 | 0% | 1,637 | 6,380 | +290% | 0 | 0 | — |
case-22 | pass→pass | 8,359 | 7,647 | -9% | 1 | 1 | 0% | 1,459 | 6,163 | +322% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +23 percentage points is the difference between those two pass rates over the 22 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.