Social cards¶
Every talk gets an auto-generated social card: a 1920x1080 image built from a per-event template, the talk title, speaker avatars, the speaker names, and the Pretalx code. The card is what shows up as the talk's image on the list, schedule, and detail pages, and as the preview when a talk link is shared.
Source:
talks/management/commands/_pretalx/images.py
(rendering) and
talks/management/commands/_pretalx/avatars.py
(avatar download and cache). Cards are produced as part of the Pretalx sync; see
Pretalx sync.
What a card contains¶
The generator (TalkImageGenerator) assembles each card on top of a randomly chosen template PNG
for the event:
- Speaker avatars: up to four circular avatars laid out in the upper-left. One avatar fills a large square; two sit side by side; three or four form a 2x2 grid. Each photo is cropped square, flattened onto white (so avatars with transparency do not get black edges), and masked into a circle with supersampled anti-aliasing for a clean edge.
- Title: word-wrapped to fit the card width, up to five lines, anchored to the bottom of the safe area. Rendering goes through Pilmoji, so emoji in a title are drawn correctly.
- Speaker names: the formatted
speaker_namesstring near the bottom. - Pretalx code: the submission code in small text at the very bottom.
Layout constants are authored at a 1920-wide design resolution and scaled proportionally, so a larger template renders an identical-looking card and is downscaled to 1920x1080 with Lanczos resampling at the end.
Templates and color schemes¶
Card templates are PNG files stored per event under media/social_card_templates/<event-slug>/. The
generator picks one at random per talk, so a set of talks gets visual variety.
The template filename encodes a color scheme. A file named social-card-<key>.png maps to a palette
that sets the title, speaker-name, and code text colors. The recognized keys are blue, darkblue,
green, darkgreen, orange, yellow, and grey; an unrecognized name falls back to all-white
text.
The shipped templates for the default event live in
media/social_card_templates/pyconde-pydata-2026/ and cover all seven color keys. An event with a
template directory but no matching social-card-* name (for example a single talk_template.png)
still renders, using the default white palette.
An event needs at least one template PNG
Card generation raises FileNotFoundError when the event's template directory has no .png files.
The Pretalx importer absorbs per-talk errors, so a missing template directory means cards are simply
not produced for that event rather than the import failing.
Fonts¶
Text is drawn with Noto Sans, resolved by _resolve_font_path in this order:
settings.TALK_CARD_FONT, an explicit path to a.ttfor.otffile, if it exists.- Otherwise
settings.TALK_CARD_FONT_NAME(defaultNoto Sans), looked up through matplotlib's font manager.
If neither resolves, generation raises a FileNotFoundError telling the operator to install the
font or set TALK_CARD_FONT.
For local development the setup script downloads Noto Sans automatically. When DOWNLOAD_FONT is
true (the default),
scripts/dev-setup.sh
fetches the variable Noto Sans TTF into assets/fonts/NotoSans.ttf. Noto Sans is chosen for its
broad script and emoji coverage, so speaker names and titles in many languages render without
missing glyphs.
Avatars: download, cap, and cache¶
Speaker avatar URLs come from Pretalx profile uploads, so the download is treated as semi-trusted and bounded on two axes:
- Byte cap: each download is streamed and aborted past 10 MiB (
_MAX_AVATAR_BYTES), and a response that advertises a largerContent-Lengthis rejected before the body is read. A failed or oversized download simply yields no avatar. - Decode cap: Pillow's
MAX_IMAGE_PIXELSis set to 50 megapixels, so a small file that decompresses to a huge bitmap raises rather than exhausting memory. That error is absorbed by the per-talk import error handling.
Avatars are cached in two tiers to avoid re-downloading the same photo for every card: an in-memory
dict keyed by URL, and on-disk files under media/avatars/ named by the SHA-256 of the URL. Before
generation begins, the importer prefetches every unique avatar URL for accepted and confirmed
submissions concurrently (bounded to eight connections) to warm both caches.
The --no-avatars flag on the import command skips avatar rendering entirely, producing cards with
just the title, speaker names, and code.
Output formats¶
Cards are saved to the talk's image field. The format is chosen by the importer's --image-format
option, normalized by _resolve_image_format:
webp(the default): saved at quality 82 with maximum compression effort.jpeg(also acceptsjpg): saved at quality 88, optimized and progressive.
Any other value logs a warning and falls back to WebP. The saved file is named talk_<id>.<ext>.
When cards are generated and regenerated¶
Cards are produced during the Pretalx sync. A new talk always gets a card (unless --skip-images is
set). For an existing talk, the card is regenerated when any of these holds:
- The talk's title changed.
--force-imageswas passed.- A still-attached speaker's name or avatar changed earlier in the same run.
- The current image file is missing, or a template PNG for the event was touched on disk after the image's modification time (handy when you swap a template and want every card re-rendered).
The full set of triggers and the relevant import flags are documented in Pretalx sync.