9.2 KiB
9.2 KiB
Text and Fonts Reference
Comprehensive guide to text formatting, paragraph styles, and font handling in ReportLab.
Text Encoding
IMPORTANT: All text input should be UTF-8 encoded or Python Unicode objects (since ReportLab 2.0).
# Correct - UTF-8 strings
text = "Hello 世界 مرحبا"
para = Paragraph(text, style)
# For legacy data, convert first
import codecs
decoded_text = codecs.decode(legacy_bytes, 'latin-1')
Paragraph Styles
Creating Styles
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_LEFT, TA_CENTER, TA_RIGHT, TA_JUSTIFY
from reportlab.lib.colors import black, blue, red
from reportlab.lib.units import inch
# Get default styles
styles = getSampleStyleSheet()
normal = styles['Normal']
heading = styles['Heading1']
# Create custom style
custom_style = ParagraphStyle(
'CustomStyle',
parent=normal, # Inherit from another style
# Font properties
fontName='Helvetica',
fontSize=12,
leading=14, # Line spacing (should be > fontSize)
# Indentation (in points)
leftIndent=0,
rightIndent=0,
firstLineIndent=0, # Positive = indent, negative = outdent
# Spacing
spaceBefore=0,
spaceAfter=0,
# Alignment
alignment=TA_LEFT, # TA_LEFT, TA_CENTER, TA_RIGHT, TA_JUSTIFY
# Colors
textColor=black,
backColor=None, # Background color
# Borders
borderWidth=0,
borderColor=None,
borderPadding=0,
borderRadius=None,
# Bullets
bulletFontName='Helvetica',
bulletFontSize=12,
bulletIndent=0,
bulletText=None, # Text for bullets (e.g., '•')
# Advanced
wordWrap=None, # 'CJK' for Asian languages
allowWidows=1, # Allow widow lines
allowOrphans=0, # Prevent orphan lines
endDots=None, # Trailing dots for TOC entries
splitLongWords=1,
hyphenationLang=None, # 'en_US', etc. (requires pyphen)
)
# Add to stylesheet
styles.add(custom_style)
Built-in Styles
styles = getSampleStyleSheet()
# Common styles
styles['Normal'] # Body text
styles['BodyText'] # Similar to Normal
styles['Heading1'] # Top-level heading
styles['Heading2'] # Second-level heading
styles['Heading3'] # Third-level heading
styles['Title'] # Document title
styles['Bullet'] # Bulleted list items
styles['Definition'] # Definition text
styles['Code'] # Code samples
Paragraph Formatting
Basic Paragraph
from reportlab.platypus import Paragraph
para = Paragraph("This is a paragraph.", style)
story.append(para)
Inline Formatting Tags
text = """
<b>Bold text</b>
<i>Italic text</i>
<u>Underlined text</u>
<strike>Strikethrough text</strike>
<strong>Strong (bold) text</strong>
"""
para = Paragraph(text, normal_style)
Font Control
text = """
<font face="Courier" size="14" color="blue">
Custom font, size, and color
</font>
<font color="#FF0000">Hex color codes work too</font>
"""
para = Paragraph(text, normal_style)
Superscripts and Subscripts
text = """
H<sub>2</sub>O is water.
E=mc<super>2</super> or E=mc<sup>2</sup>
X<sub><i>i</i></sub> for subscripted variables
"""
para = Paragraph(text, normal_style)
Greek Letters
text = """
<greek>alpha</greek>, <greek>beta</greek>, <greek>gamma</greek>
<greek>epsilon</greek>, <greek>pi</greek>, <greek>omega</greek>
"""
para = Paragraph(text, normal_style)
Links
# External link
text = '<link href="https://example.com" color="blue">Click here</link>'
# Internal link (to bookmark)
text = '<link href="#section1" color="blue">Go to Section 1</link>'
# Anchor for internal links
text = '<a name="section1"/>Section 1 Heading'
para = Paragraph(text, normal_style)
Inline Images
text = """
Here is an inline image: <img src="icon.png" width="12" height="12" valign="middle"/>
"""
para = Paragraph(text, normal_style)
Line Breaks
text = """
First line<br/>
Second line<br/>
Third line
"""
para = Paragraph(text, normal_style)
Font Handling
Standard Fonts
ReportLab includes 14 standard PDF fonts (no embedding needed):
# Helvetica family
'Helvetica'
'Helvetica-Bold'
'Helvetica-Oblique'
'Helvetica-BoldOblique'
# Times family
'Times-Roman'
'Times-Bold'
'Times-Italic'
'Times-BoldItalic'
# Courier family
'Courier'
'Courier-Bold'
'Courier-Oblique'
'Courier-BoldOblique'
# Symbol and Dingbats
'Symbol'
'ZapfDingbats'
TrueType Fonts
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
# Register single font
pdfmetrics.registerFont(TTFont('CustomFont', 'CustomFont.ttf'))
# Use in Canvas
canvas.setFont('CustomFont', 12)
# Use in Paragraph style
style = ParagraphStyle('Custom', fontName='CustomFont', fontSize=12)
Font Families
Register related fonts as a family for bold/italic support:
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.lib.fonts import addMapping
# Register fonts
pdfmetrics.registerFont(TTFont('Vera', 'Vera.ttf'))
pdfmetrics.registerFont(TTFont('VeraBd', 'VeraBd.ttf'))
pdfmetrics.registerFont(TTFont('VeraIt', 'VeraIt.ttf'))
pdfmetrics.registerFont(TTFont('VeraBI', 'VeraBI.ttf'))
# Map family (normal, bold, italic, bold-italic)
addMapping('Vera', 0, 0, 'Vera') # normal
addMapping('Vera', 1, 0, 'VeraBd') # bold
addMapping('Vera', 0, 1, 'VeraIt') # italic
addMapping('Vera', 1, 1, 'VeraBI') # bold-italic
# Now <b> and <i> tags work with this family
style = ParagraphStyle('VeraStyle', fontName='Vera', fontSize=12)
para = Paragraph("Normal <b>Bold</b> <i>Italic</i> <b><i>Both</i></b>", style)
Font Search Paths
from reportlab.pdfbase.ttfonts import TTFSearchPath
# Add custom font directory
TTFSearchPath.append('/path/to/fonts/')
# Now fonts in this directory can be found by name
pdfmetrics.registerFont(TTFont('MyFont', 'MyFont.ttf'))
Asian Language Support
Using Adobe Language Packs (no embedding)
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.cidfonts import UnicodeCIDFont
# Register CID fonts
pdfmetrics.registerFont(UnicodeCIDFont('HeiseiMin-W3')) # Japanese
pdfmetrics.registerFont(UnicodeCIDFont('STSong-Light')) # Chinese (Simplified)
pdfmetrics.registerFont(UnicodeCIDFont('MSung-Light')) # Chinese (Traditional)
pdfmetrics.registerFont(UnicodeCIDFont('HYSMyeongJo-Medium')) # Korean
# Use in styles
style = ParagraphStyle('Japanese', fontName='HeiseiMin-W3', fontSize=12)
para = Paragraph("日本語テキスト", style)
Using TrueType Fonts with Asian Characters
# Register TrueType font with full Unicode support
pdfmetrics.registerFont(TTFont('SimSun', 'simsun.ttc'))
style = ParagraphStyle('Chinese', fontName='SimSun', fontSize=12, wordWrap='CJK')
para = Paragraph("中文文本", style)
Note: Set wordWrap='CJK' for proper line breaking in Asian languages.
Numbering and Sequences
Auto-numbering using <seq> tags:
# Simple numbering
text = "<seq id='chapter'/> Introduction" # Outputs: 1 Introduction
text = "<seq id='chapter'/> Methods" # Outputs: 2 Methods
# Reset counter
text = "<seq id='figure' reset='yes'/>"
# Formatting templates
text = "Figure <seq template='%(chapter)s-%(figure+)s' id='figure'/>"
# Outputs: Figure 1-1, Figure 1-2, etc.
# Multi-level numbering
text = "Section <seq template='%(chapter)s.%(section+)s' id='section'/>"
Bullets and Lists
Using Bullet Style
bullet_style = ParagraphStyle(
'Bullet',
parent=normal_style,
leftIndent=20,
bulletIndent=10,
bulletText='•', # Unicode bullet
bulletFontName='Helvetica',
)
story.append(Paragraph("First item", bullet_style))
story.append(Paragraph("Second item", bullet_style))
story.append(Paragraph("Third item", bullet_style))
Custom Bullet Characters
# Different bullet styles
bulletText='•' # Filled circle
bulletText='◦' # Open circle
bulletText='▪' # Square
bulletText='▸' # Triangle
bulletText='→' # Arrow
bulletText='1.' # Numbers
bulletText='a)' # Letters
Text Measurement
from reportlab.pdfbase.pdfmetrics import stringWidth
# Measure string width
width = stringWidth("Hello World", "Helvetica", 12)
# Check if text fits in available width
max_width = 200
if stringWidth(text, font_name, font_size) > max_width:
# Text is too wide
pass
Best Practices
- Always use UTF-8 for text input
- Set leading > fontSize for readability (typically fontSize + 2)
- Register font families for proper bold/italic support
- Escape HTML if displaying user content: use
<for < and>for > - Use getSampleStyleSheet() as a starting point, don't create all styles from scratch
- Test Asian fonts early if supporting multi-language content
- Set wordWrap='CJK' for Chinese/Japanese/Korean text
- Use stringWidth() to check if text fits before rendering
- Define styles once at document start, reuse throughout
- Enable hyphenation for justified text:
hyphenationLang='en_US'(requires pyphen package)