Python Guide
This guide covers using printwell with Python.
Installation
pip install printwell
Or with uv:
uv pip install printwell
Basic Usage
from printwell import Converter
converter = Converter()
result = converter.html_to_pdf("<h1>Hello, World!</h1>")
result.write_to_file("output.pdf")
Converting Documents
HTML String to PDF
from printwell import Converter
converter = Converter()
html = """
<!DOCTYPE html>
<html>
<head>
<style>
body { font-family: Arial; padding: 40px; }
h1 { color: #333; }
</style>
</head>
<body>
<h1>My Document</h1>
<p>This is a PDF generated from HTML.</p>
</body>
</html>
"""
result = converter.html_to_pdf(html)
# Get as bytes
pdf_bytes = result.data()
# Write to file
result.write_to_file("output.pdf")
# Get page count
print(f"Pages: {result.page_count}")
URL to PDF
result = converter.url_to_pdf("https://example.com")
result.write_to_file("example.pdf")
File to PDF
with open("input.html") as f:
html = f.read()
result = converter.html_to_pdf(html)
result.write_to_file("output.pdf")
Configuration Options
PDF Options
from printwell import (
Converter, PdfOptions, PageSize, Orientation,
Margins, PdfMetadata
)
converter = Converter()
options = PdfOptions(
# Page size
page_size=PageSize.A4,
# Or custom size in mm
page_width_mm=210.0,
page_height_mm=297.0,
# Orientation
orientation=Orientation.Portrait,
# Margins in mm
margins=Margins(top=20, right=15, bottom=20, left=15),
# Or uniform margins
margins=Margins.uniform(10),
# Scale factor (0.1 to 2.0)
scale=1.0,
# Print background graphics
print_background=True,
# Page ranges
page_ranges="1-5,8,10-12",
# Headers and footers
header_template='<div style="font-size:10px">Header</div>',
footer_template='<div style="font-size:10px">Page <span class="pageNumber"></span></div>',
# Metadata
metadata=PdfMetadata(
title="My Document",
author="Author Name",
subject="Document Subject",
keywords="pdf, python"
)
)
result = converter.html_to_pdf(html, pdf_options=options)
Render Options
from printwell import RenderOptions, ResourceOptions, Viewport
options = RenderOptions(
# Base URL for relative resources
base_url="https://example.com/",
# Viewport
viewport=Viewport(
width=1920,
height=1080,
device_scale_factor=2.0
),
# Resource loading
resources=ResourceOptions(
allow_remote=True,
timeout_ms=30000,
blocked_domains=["ads.example.com"],
user_agent="Custom User Agent"
),
# Custom CSS
user_stylesheets=[
'body { font-family: "Custom Font"; }'
]
)
result = converter.html_to_pdf(html, render_options=options)
Batch Processing
Converter Pool
For high-throughput scenarios:
from printwell import ConverterPool
# Create pool with 4 concurrent converters
pool = ConverterPool(4)
# Convert multiple documents
html_docs = [
"<h1>Document 1</h1>",
"<h1>Document 2</h1>",
"<h1>Document 3</h1>"
]
results = pool.convert_batch(html_docs)
for i, result in enumerate(results):
result.write_to_file(f"output_{i}.pdf")
Parallel Conversion with Threading
from concurrent.futures import ThreadPoolExecutor
from printwell import Converter
converter = Converter()
urls = [
"https://example.com/page1",
"https://example.com/page2",
"https://example.com/page3"
]
def convert_url(url):
return converter.url_to_pdf(url)
with ThreadPoolExecutor(max_workers=4) as executor:
results = list(executor.map(convert_url, urls))
PDF Post-Processing
Watermarks
from printwell import (
add_watermark, add_watermarks, Watermark,
WatermarkPosition, WatermarkColor
)
with open("input.pdf", "rb") as f:
pdf_data = f.read()
# Text watermark
watermark = Watermark.text_watermark(
text="CONFIDENTIAL",
position=WatermarkPosition.Center,
rotation=45,
opacity=0.3,
font_size=72,
color=WatermarkColor(r=128, g=128, b=128)
)
result = add_watermark(pdf_data, watermark)
with open("watermarked.pdf", "wb") as f:
f.write(result)
# Multiple watermarks
result = add_watermarks(pdf_data, [
Watermark(text="DRAFT", opacity=0.2),
Watermark(text="Page header", position=WatermarkPosition.TopCenter, font_size=12)
])
Bookmarks
from printwell import add_bookmarks, extract_bookmarks, Bookmark
with open("input.pdf", "rb") as f:
pdf_data = f.read()
# Add bookmarks
bookmarks = [
Bookmark("Chapter 1", page=1),
Bookmark("Chapter 2", page=5),
Bookmark("Chapter 3", page=12),
]
result = add_bookmarks(pdf_data, bookmarks)
# Extract existing bookmarks
existing = extract_bookmarks(pdf_data)
for bm in existing:
print(f"{bm.title} -> Page {bm.page}")
Annotations
from printwell import (
add_annotations, list_annotations, remove_annotations,
Annotation, AnnotationType, AnnotationRect, AnnotationColor
)
# Add highlight annotation
result = add_annotations(pdf_data, [
Annotation(
annotation_type=AnnotationType.Highlight,
page=1,
rect=AnnotationRect(x=100, y=700, width=200, height=20),
color=AnnotationColor.yellow(),
opacity=0.5
),
Annotation.sticky_note(
page=1,
x=50,
y=600,
contents="Review this section",
author="Reviewer"
)
])
# List annotations
annotations = list_annotations(pdf_data)
for ann in annotations:
print(f"Page {ann.page}: {ann.annotation_type}")
# Remove annotations
cleaned = remove_annotations(pdf_data, annotation_types=[AnnotationType.Highlight])
Encryption
from printwell import (
encrypt_pdf, decrypt_pdf, EncryptionOptions,
Permissions, EncryptionAlgorithm
)
# Encrypt PDF
options = EncryptionOptions(
owner_password="admin123",
user_password="user123",
permissions=Permissions(
print=True,
copy=False,
modify=False,
annotate=True
),
algorithm=EncryptionAlgorithm.Aes256
)
encrypted = encrypt_pdf(pdf_data, options)
with open("encrypted.pdf", "wb") as f:
f.write(encrypted)
# Decrypt PDF
decrypted = decrypt_pdf(encrypted, "admin123")
Digital Signatures
from printwell import (
sign_pdf, sign_pdf_visible, verify_signatures,
SigningOptions, SignatureAppearance, SignatureLevel
)
with open("document.pdf", "rb") as f:
pdf_data = f.read()
with open("certificate.p12", "rb") as f:
cert_data = f.read()
# Invisible signature
options = SigningOptions(
reason="Approved",
location="New York",
signature_level=SignatureLevel.PadesB
)
signed = sign_pdf(pdf_data, cert_data, "certificate_password", options)
# Visible signature
appearance = SignatureAppearance(
page=1,
x=400,
y=50,
width=200,
height=75,
show_name=True,
show_date=True
)
signed_visible = sign_pdf_visible(
pdf_data, cert_data, "password", options, appearance
)
# Verify signatures
verifications = verify_signatures(signed_data)
for v in verifications:
print(f"Signer: {v.signer_name}, Valid: {v.is_valid}")
Form Fields
from printwell import (
add_form_fields, validate_form_fields,
TextField, FormCheckbox, FormDropdown, FormRect,
ValidationRule, FormElementInput
)
# Add form fields
rect = FormRect(x=100, y=700, width=200, height=20)
result = add_form_fields(
pdf_data,
text_fields=[
TextField(
name="full_name",
page=1,
rect=rect,
required=True
)
],
checkboxes=[
FormCheckbox(
name="agree_terms",
page=1,
rect=FormRect(x=100, y=650, width=15, height=15)
)
],
dropdowns=[
FormDropdown(
name="country",
page=1,
rect=FormRect(x=100, y=600, width=150, height=20),
options=["USA", "Canada", "UK", "Other"]
)
]
)
# Validate form fields
elements = [
FormElementInput(name="full_name", default_value="John Doe"),
FormElementInput(name="email", default_value="invalid-email")
]
rules = [
ValidationRule(field_name="full_name", required=True, min_length=2),
ValidationRule(field_name="email", required=True, pattern=r"^[^@]+@[^@]+$")
]
validation = validate_form_fields(elements, rules)
print(f"All valid: {validation.all_valid}")
for result in validation.results:
if not result.is_valid:
print(f"{result.field_name}: {result.errors}")
PDF/A Compliance
from printwell import validate_pdfa, add_pdfa_metadata, PdfALevel
# Validate PDF/A compliance
result = validate_pdfa(pdf_data, PdfALevel.PdfA2b)
print(f"Compliant: {result.is_compliant}")
for issue in result.issues:
print(f"{issue.severity}: {issue.message}")
# Add PDF/A metadata
pdfa_doc = add_pdfa_metadata(
pdf_data,
PdfALevel.PdfA2b,
title="Archived Document",
author="Author Name"
)
PDF/UA Accessibility
from printwell import (
validate_pdfua, add_pdfua_metadata,
PdfUALevel, AccessibilityOptions
)
# Validate accessibility
result = validate_pdfua(pdf_data, PdfUALevel.PdfUA1)
print(f"Accessible: {result.is_compliant}")
# Add accessibility metadata
options = AccessibilityOptions(
language="en",
title="Accessible Document",
generate_outline=True
)
accessible_doc = add_pdfua_metadata(pdf_data, PdfUALevel.PdfUA1, options)
Error Handling
from printwell import Converter
try:
converter = Converter()
result = converter.html_to_pdf(html)
result.write_to_file("output.pdf")
except RuntimeError as e:
if "conversion" in str(e).lower():
print(f"Conversion failed: {e}")
elif "resource" in str(e).lower():
print(f"Resource loading failed: {e}")
else:
raise
Flask Integration
from flask import Flask, send_file
from printwell import Converter
from io import BytesIO
app = Flask(__name__)
converter = Converter()
@app.route('/generate-pdf')
def generate_pdf():
html = f"<h1>Generated at {datetime.now().isoformat()}</h1>"
result = converter.html_to_pdf(html)
buffer = BytesIO(result.data())
buffer.seek(0)
return send_file(
buffer,
mimetype='application/pdf',
as_attachment=True,
download_name='document.pdf'
)
if __name__ == '__main__':
app.run()
FastAPI Integration
from fastapi import FastAPI
from fastapi.responses import Response
from printwell import Converter
app = FastAPI()
converter = Converter()
@app.get("/generate-pdf")
async def generate_pdf():
html = "<h1>Hello from FastAPI!</h1>"
result = converter.html_to_pdf(html)
return Response(
content=result.data(),
media_type="application/pdf",
headers={
"Content-Disposition": "attachment; filename=document.pdf"
}
)
Django Integration
from django.http import HttpResponse
from printwell import Converter
converter = Converter()
def generate_pdf(request):
html = "<h1>Hello from Django!</h1>"
result = converter.html_to_pdf(html)
response = HttpResponse(result.data(), content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename="document.pdf"'
return response