Webfonts & Background Removal
Two features that require a bit of setup but unlock a lot of creative flexibility: loading fonts directly from URLs and removing image backgrounds with AI.
Webfonts
quickthumb can load fonts from remote URLs at render time. The font file is downloaded once and cached locally.
Basic usage
Pass any .ttf, .otf, or .woff2 URL as the font parameter:
from quickthumb import Canvas
INTER_BOLD_URL = (
"https://fonts.gstatic.com/s/inter/v13/"
"UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuLyfAZ9hiA.woff2"
)
canvas = Canvas(1280, 720).text(
content="Hello from Inter",
font=INTER_BOLD_URL,
size=72,
color="#FFFFFF",
align="center",
)
Finding Google Font URLs
- Open fonts.google.com and pick a font.
- Click Get font → Get embed code → @import.
- The
@importURL points to a CSS file. Open it in your browser. - Inside the CSS, find the
src: url(...)lines — copy the.woff2URL for the weight and style you need.
Common weights (check the CSS file for the exact URLs for your font):
| Weight | Name |
|---|---|
| 400 | Regular |
| 500 | Medium |
| 700 | Bold |
| 900 | Black |
Using bold and italic variants
When font is a URL, bold, italic, and weight are ignored — the URL already points to a specific variant. Download separate URLs for each style you need:
from quickthumb import Canvas, TextPart
REGULAR_URL = "https://fonts.gstatic.com/.../inter-regular.woff2"
BOLD_URL = "https://fonts.gstatic.com/.../inter-bold.woff2"
canvas = Canvas(1280, 720).text(
content=[
TextPart(text="Regular text ", font=REGULAR_URL, color="#AAAAAA"),
TextPart(text="BOLD TEXT", font=BOLD_URL, color="#FFFFFF"),
],
size=64,
position=("50%", "50%"),
align=("center", "middle"),
)
Local font directory
For fonts you already have on disk, set the environment variable instead of URLs:
import os
os.environ["QUICKTHUMB_FONT_DIR"] = "assets/fonts"
os.environ["QUICKTHUMB_DEFAULT_FONT"] = "Roboto"
# Now use the family name directly
canvas.text(content="Hello", font="Roboto", size=64, color="#FFFFFF", align="center")
quickthumb searches QUICKTHUMB_FONT_DIR for files matching the family name, and falls back to QUICKTHUMB_DEFAULT_FONT when font is omitted.
Background removal
remove_background=True on an .image() layer uses AI (via rembg + ONNX) to cut out the subject and remove the background, leaving a clean cutout composited on top of your canvas.
Installation
The ONNX model (~170 MB) is downloaded on first use and cached. Subsequent renders are fast.
Basic usage
from quickthumb import Canvas, Shadow
canvas = Canvas(1280, 720).image(
path="portrait.jpg",
position=("75%", "55%"),
width=430,
height=540,
align=("center", "middle"),
remove_background=True,
effects=[Shadow(offset_x=0, offset_y=14, color="#000000", blur_radius=24)],
)
The shadow is applied after the background is removed, so it follows the subject silhouette rather than the original rectangle.
Works with remote images too
GUEST_URL = "https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=900"
canvas.image(
path=GUEST_URL,
position=(1280, 720),
width=500,
height=660,
fit="cover",
align=("right", "bottom"),
remove_background=True,
)
Combining both features
A podcast promo with a webfont show title and an AI-cutout guest portrait:
from quickthumb import Canvas, Filter, FitMode, LinearGradient, Shadow, Stroke
SHOW_FONT = "https://fonts.gstatic.com/s/pacifico/v22/FwZY7-Qmy14u9lezJ-6H6MmBp0u-.woff2"
GUEST_URL = "https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=900"
BG_URL = "https://images.unsplash.com/photo-1478737270239-2f02b77fc618?w=1600"
canvas = (
Canvas(1280, 720)
.background(
image=BG_URL,
fit=FitMode.COVER,
effects=[Filter(brightness=0.42, saturation=0.75, blur=2)],
)
.background(
gradient=LinearGradient(
angle=0,
stops=[("#07111F", 0.0), ("#07111FE8", 0.45), ("#07111F70", 1.0)],
)
)
# Webfont show title
.text(
content="Signal to Noise",
font=SHOW_FONT,
size=62,
color="#8CE1FF",
position=(60, 80),
effects=[Shadow(offset_x=0, offset_y=6, color="#021018CC", blur_radius=12)],
)
# Episode headline
.text(
content="HOW GREAT TEAMS\nBUILD BETTER\nFEEDBACK LOOPS",
size=70,
color="#FFFFFF",
weight=900,
line_height=1.0,
position=(60, 170),
effects=[
Stroke(width=3, color="#04111A"),
Shadow(offset_x=0, offset_y=10, color="#00000099", blur_radius=18),
],
)
# AI-cutout guest portrait — bottom right, shadow follows silhouette
.image(
path=GUEST_URL,
position=(1095, 698),
width=500,
height=660,
fit=FitMode.COVER,
align=("center", "bottom"),
remove_background=True,
effects=[Shadow(offset_x=16, offset_y=18, color="#000000AA", blur_radius=22)],
)
.outline(width=10, color="#8CE1FF")
.render("podcast_webfont_rembg.png")
)
Tips
- Portrait orientation works best.
rembgis trained on people — headshots and three-quarter shots give the cleanest cutouts. - High contrast helps. Images where the subject is clearly separated from the background produce better results.
- Apply
Filterbeforeremove_background. Adjusting brightness or contrast on the image first can improve segmentation quality. - Cache is automatic. Once the model is downloaded, there's nothing to configure.