Skip to Content
FeaturesModulesOG ImagesOG Image Module

OG Image Module

On-the-fly Open Graph image generation for django-cfg. Renders PNG images using PicTex, caches them in MEDIA_ROOT/ogimage/.

No database, no models, no migrations — pure library.

How it works

GET /og/<b64params>/ → decode base64 → OGImageParams → check MEDIA_ROOT/ogimage/<key[:2]>/<key[2:4]>/<key>.png → HIT → FileResponse (instant) → MISS → render(params) → save → FileResponse

The cache key is a SHA256[:40] of the stable params (everything except page_url). Same params always produce the same file — no redundant renders. Files are stored in a two-level sharded layout (like Git objects) to avoid inode limits on large deployments.

Setup

URLs

URLs are registered automatically via add_django_cfg_urls():

# project/urls.py from django_cfg import add_django_cfg_urls urlpatterns = add_django_cfg_urls(urlpatterns) # exposes: GET /og/<b64params>/ (name: og-render)

Media serving is also handled automatically — no extra configuration needed.

Renderer

Uses PicTex (pictex>=2.1.0) — available in djangocfg[full]. PicTex supports gradients, RTL text shaping (Arabic, Hebrew), and CJK fonts.

Quick start

With a preset

from django_cfg.modules.django_ogimage import get_or_create_og_url, DARK_BLUE # Returns /media/ogimage/.../....png — renders on first call, instant on subsequent url = get_or_create_og_url(DARK_BLUE.to_params(title="My Page", description="...")) # Absolute URL url = get_or_create_og_url(DARK_BLUE.to_params(title="My Page"), request=request)

By preset name

from django_cfg.modules.django_ogimage import get_or_create_og_url, get_preset url = get_or_create_og_url(get_preset("dark_blue").to_params(title="My Page"))

With branding — logo / site name / layout

from django_cfg.modules.django_ogimage import get_branded_og_url, DARK_BLUE, HERO params = DARK_BLUE.to_params(title="My Page", description="Subtitle") # Site name only url = get_branded_og_url(params, site_name="Acme Corp") # Built-in Material icon + site name url = get_branded_og_url(params, icon="dashboard", site_name="Acme Corp") # External logo file + custom layout + absolute URL url = get_branded_og_url( params, logo_url="/path/to/logo.png", site_name="Acme Corp", layout=HERO, request=request, )

get_branded_og_url has its own combined cache key — identical inputs never re-render.

In a DRF serializer

from django_cfg.modules.django_ogimage import get_branded_og_url, get_preset class ArticleSerializer(serializers.ModelSerializer): og_image_url = serializers.SerializerMethodField() def get_og_image_url(self, obj): params = get_preset("dark_blue").to_params( title=obj.title, description=obj.excerpt, ) return get_branded_og_url( params, site_name="My Site", request=self.context.get("request"), )

Typed utility function

from django_cfg.modules.django_ogimage import get_or_create_og_url, get_preset, OGImagePreset def render_og(title: str, preset: str | OGImagePreset = "dark_blue") -> str: if isinstance(preset, str): preset = get_preset(preset) # raises ValueError for unknown names return get_or_create_og_url(preset.to_params(title=title)) render_og("Hello") # uses dark_blue render_og("Hello", "light_warm") # by name render_og("Hello", DARK_BLUE) # by object

Build a shareable render URL

Instead of returning the media file path directly, you can build a URL pointing to the render endpoint. The browser will hit /og/<b64params>/ and get the PNG:

from django_cfg.modules.django_ogimage import OGImageParams, build_og_url params = OGImageParams(title="My Page", description="...", style="dark") url = build_og_url(params, request=request) # → https://example.com/og/eyJ0aXRsZSI6...

Render PNG directly (no HTTP)

from django_cfg.modules.django_ogimage import render, OGImageParams png_bytes = render(OGImageParams(title="Hello", style="light"))

OGImageParams fields

FieldDefaultDescription
titlerequiredMain heading text (max 300 chars)
description""Subtitle / body text (max 600 chars)
locale"en"BCP 47 locale — selects font
style"dark"dark or light
bg_color"#1a1a2e"Background color (hex)
bg_color2"#16213e"Gradient / secondary background (hex)
text_color"#ffffff"Text color (hex)
accent_color"#3b82f6"Accent / highlight color (hex)
size"1200x630"Output dimensions
page_url""Source URL — excluded from cache key

Supported sizes

1200x630 (default) · 1200x600 · 800x418 · 1200x1200

Supported locales

Fonts are not bundled with the package — they are downloaded on first use and cached in ~/.cache/django_cfg/fonts/. At Django startup all fonts begin downloading in background threads so they’re ready before the first request.

LocaleFontDownload size
en, *Inter (variable TTF)~350 KB
koNoto Sans KR~3.5 MB
jaNoto Sans JP~4.2 MB
zhNoto Sans SC~6.5 MB
arNoto Sans Arabic (RTL)~300 KB
heNoto Sans Hebrew (RTL)~200 KB

If a font download fails the module falls back to a system font silently — no exception is raised. Override the cache directory with DJANGO_CFG_FONTS_DIR.

  • Presets — built-in color schemes and build_preset()
  • Layouts — layout presets (DEFAULT, HERO, ARTICLE, MINIMAL)
  • Branding & Iconsget_branded_og_url, logo, built-in icons
  • Configuration — environment variables
Last updated on