Initial commit
This commit is contained in:
241
skills/reportlab/references/canvas_api.md
Normal file
241
skills/reportlab/references/canvas_api.md
Normal file
@@ -0,0 +1,241 @@
|
||||
# Canvas API Reference
|
||||
|
||||
The Canvas API provides low-level, precise control over PDF generation using coordinate-based drawing.
|
||||
|
||||
## Coordinate System
|
||||
|
||||
- Origin (0, 0) is at the **lower-left corner** (not top-left like web graphics)
|
||||
- X-axis points right, Y-axis points upward
|
||||
- Units are in points (72 points = 1 inch)
|
||||
- Default page size is A4; explicitly specify page size for consistency
|
||||
|
||||
## Basic Setup
|
||||
|
||||
```python
|
||||
from reportlab.pdfgen import canvas
|
||||
from reportlab.lib.pagesizes import letter, A4
|
||||
from reportlab.lib.units import inch
|
||||
|
||||
# Create canvas
|
||||
c = canvas.Canvas("output.pdf", pagesize=letter)
|
||||
|
||||
# Get page dimensions
|
||||
width, height = letter
|
||||
|
||||
# Draw content
|
||||
c.drawString(100, 100, "Hello World")
|
||||
|
||||
# Finish page and save
|
||||
c.showPage() # Complete current page
|
||||
c.save() # Write PDF to disk
|
||||
```
|
||||
|
||||
## Text Drawing
|
||||
|
||||
### Basic String Methods
|
||||
```python
|
||||
# Basic text placement
|
||||
c.drawString(x, y, text) # Left-aligned at x, y
|
||||
c.drawRightString(x, y, text) # Right-aligned at x, y
|
||||
c.drawCentredString(x, y, text) # Center-aligned at x, y
|
||||
|
||||
# Font control
|
||||
c.setFont(fontname, size) # e.g., "Helvetica", 12
|
||||
c.setFillColor(color) # Text color
|
||||
```
|
||||
|
||||
### Text Objects (Advanced)
|
||||
For complex text operations with multiple lines and precise control:
|
||||
|
||||
```python
|
||||
t = c.beginText(x, y)
|
||||
t.setFont("Times-Roman", 14)
|
||||
t.textLine("First line")
|
||||
t.textLine("Second line")
|
||||
t.setTextOrigin(x, y) # Reset position
|
||||
c.drawText(t)
|
||||
```
|
||||
|
||||
## Drawing Primitives
|
||||
|
||||
### Lines
|
||||
```python
|
||||
c.line(x1, y1, x2, y2) # Single line
|
||||
c.lines([(x1,y1,x2,y2), (x3,y3,x4,y4)]) # Multiple lines
|
||||
c.grid(xlist, ylist) # Grid from coordinate lists
|
||||
```
|
||||
|
||||
### Shapes
|
||||
```python
|
||||
c.rect(x, y, width, height, stroke=1, fill=0)
|
||||
c.roundRect(x, y, width, height, radius, stroke=1, fill=0)
|
||||
c.circle(x_ctr, y_ctr, r, stroke=1, fill=0)
|
||||
c.ellipse(x1, y1, x2, y2, stroke=1, fill=0)
|
||||
c.wedge(x, y, radius, startAng, extent, stroke=1, fill=0)
|
||||
```
|
||||
|
||||
### Bezier Curves
|
||||
```python
|
||||
c.bezier(x1, y1, x2, y2, x3, y3, x4, y4)
|
||||
```
|
||||
|
||||
## Path Objects
|
||||
|
||||
For complex shapes, use path objects:
|
||||
|
||||
```python
|
||||
p = c.beginPath()
|
||||
p.moveTo(x, y) # Move without drawing
|
||||
p.lineTo(x, y) # Draw line to point
|
||||
p.curveTo(x1, y1, x2, y2, x3, y3) # Bezier curve
|
||||
p.arc(x1, y1, x2, y2, startAng, extent)
|
||||
p.arcTo(x1, y1, x2, y2, startAng, extent)
|
||||
p.close() # Close path to start point
|
||||
|
||||
# Draw the path
|
||||
c.drawPath(p, stroke=1, fill=0)
|
||||
```
|
||||
|
||||
## Colors
|
||||
|
||||
### RGB (Screen Display)
|
||||
```python
|
||||
from reportlab.lib.colors import red, blue, Color
|
||||
|
||||
c.setFillColorRGB(r, g, b) # r, g, b are 0-1
|
||||
c.setStrokeColorRGB(r, g, b)
|
||||
c.setFillColor(red) # Named colors
|
||||
c.setStrokeColor(blue)
|
||||
|
||||
# Custom with alpha transparency
|
||||
c.setFillColor(Color(0.5, 0, 0, alpha=0.5))
|
||||
```
|
||||
|
||||
### CMYK (Professional Printing)
|
||||
```python
|
||||
from reportlab.lib.colors import CMYKColor, PCMYKColor
|
||||
|
||||
c.setFillColorCMYK(c, m, y, k) # 0-1 range
|
||||
c.setStrokeColorCMYK(c, m, y, k)
|
||||
|
||||
# Integer percentages (0-100)
|
||||
c.setFillColor(PCMYKColor(100, 50, 0, 0))
|
||||
```
|
||||
|
||||
## Line Styling
|
||||
|
||||
```python
|
||||
c.setLineWidth(width) # Thickness in points
|
||||
c.setLineCap(mode) # 0=butt, 1=round, 2=square
|
||||
c.setLineJoin(mode) # 0=miter, 1=round, 2=bevel
|
||||
c.setDash(array, phase) # e.g., [3, 3] for dotted line
|
||||
```
|
||||
|
||||
## Coordinate Transformations
|
||||
|
||||
**IMPORTANT:** Transformations are incremental and cumulative.
|
||||
|
||||
```python
|
||||
# Translation (move origin)
|
||||
c.translate(dx, dy)
|
||||
|
||||
# Rotation (in degrees, counterclockwise)
|
||||
c.rotate(theta)
|
||||
|
||||
# Scaling
|
||||
c.scale(xscale, yscale)
|
||||
|
||||
# Skewing
|
||||
c.skew(alpha, beta)
|
||||
```
|
||||
|
||||
### State Management
|
||||
```python
|
||||
# Save current graphics state
|
||||
c.saveState()
|
||||
|
||||
# ... apply transformations and draw ...
|
||||
|
||||
# Restore previous state
|
||||
c.restoreState()
|
||||
```
|
||||
|
||||
**Note:** State cannot be preserved across `showPage()` calls.
|
||||
|
||||
## Images
|
||||
|
||||
```python
|
||||
from reportlab.lib.utils import ImageReader
|
||||
|
||||
# Preferred method (with caching)
|
||||
c.drawImage(image_source, x, y, width=None, height=None,
|
||||
mask=None, preserveAspectRatio=False)
|
||||
|
||||
# image_source can be:
|
||||
# - Filename string
|
||||
# - PIL Image object
|
||||
# - ImageReader object
|
||||
|
||||
# For transparency, specify RGB mask range
|
||||
c.drawImage("logo.png", 100, 500, mask=[255, 255, 255, 255, 255, 255])
|
||||
|
||||
# Inline (inefficient, no caching)
|
||||
c.drawInlineImage(image_source, x, y, width=None, height=None)
|
||||
```
|
||||
|
||||
## Page Management
|
||||
|
||||
```python
|
||||
# Complete current page
|
||||
c.showPage()
|
||||
|
||||
# Set page size for next page
|
||||
c.setPageSize(size) # e.g., letter, A4
|
||||
|
||||
# Page compression (smaller files, slower generation)
|
||||
c = canvas.Canvas("output.pdf", pageCompression=1)
|
||||
```
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Margins and Layout
|
||||
```python
|
||||
from reportlab.lib.units import inch
|
||||
from reportlab.lib.pagesizes import letter
|
||||
|
||||
width, height = letter
|
||||
margin = inch
|
||||
|
||||
# Draw within margins
|
||||
content_width = width - 2*margin
|
||||
content_height = height - 2*margin
|
||||
|
||||
# Text at top margin
|
||||
c.drawString(margin, height - margin, "Header")
|
||||
|
||||
# Text at bottom margin
|
||||
c.drawString(margin, margin, "Footer")
|
||||
```
|
||||
|
||||
### Headers and Footers
|
||||
```python
|
||||
def draw_header_footer(c, width, height):
|
||||
c.saveState()
|
||||
c.setFont("Helvetica", 9)
|
||||
c.drawString(inch, height - 0.5*inch, "Company Name")
|
||||
c.drawRightString(width - inch, 0.5*inch, f"Page {c.getPageNumber()}")
|
||||
c.restoreState()
|
||||
|
||||
# Call on each page
|
||||
draw_header_footer(c, width, height)
|
||||
c.showPage()
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Always specify page size** - Different platforms have different defaults
|
||||
2. **Use variables for measurements** - `margin = inch` instead of hardcoded values
|
||||
3. **Match saveState/restoreState** - Always balance these calls
|
||||
4. **Apply transformations externally** for engineering drawings to prevent line width scaling
|
||||
5. **Use drawImage over drawInlineImage** for better performance with repeated images
|
||||
6. **Draw from bottom-up** - Remember Y-axis points upward
|
||||
Reference in New Issue
Block a user