Skip to content

Render via memegen API; Pillow fallback for custom images#21

Merged
brianckeegan merged 1 commit intomainfrom
claude/mystifying-leavitt-08a7e3
Apr 28, 2026
Merged

Render via memegen API; Pillow fallback for custom images#21
brianckeegan merged 1 commit intomainfrom
claude/mystifying-leavitt-08a7e3

Conversation

@brianckeegan
Copy link
Copy Markdown
Owner

Summary

  • Rewires the rendering pipeline around three backends (auto / memegen / pillow / matplotlib). By default meme() now constructs a memegen rendering URL (/images/<id>/<line>/.../<line>.<ext>?style=...&font=...), fetches the composed image, and imshows it.
  • Custom local images and any feature memegen can't express (per-line fontsize, custom outlines, **text_kwargs, per-line overrides) route to a new client-side Pillow renderer. Legacy Axes.text + path-effects rendering is preserved as backend="matplotlib".
  • Adds Meme.line(index, text, *, fontsize=, color=, font=, position=) for per-line overrides and Meme.with_backend(...) chainable setter.
  • New meme() knobs: backend, extension, width, height, layout, background, overlays, template_style. CLI and MCP gain matching arguments.
  • Template now carries lines_count / overlays_count / styles / is_memegen.
  • Documents the memegen URL grammar (escape table, query parameters, fonts/styles/overlays) in a new docs/url_construction.rst, adapted from jacebrowning/memegen#993.
  • Bumps to 0.5.0 with a CHANGELOG migration note. CLAUDE.md and README rewritten for the dual-backend architecture.

Why

The memegen API can compose entire memes server-side, but memeplotlib was only using it to fetch blank backgrounds and re-implementing text composition client-side with matplotlib. That left memegen features (template styles, custom fonts/colours, dimensions, layouts, custom backgrounds, overlay slots) unused. Routing the default path through the API gives users canonical memegen output for free; the Pillow fallback covers the cases the API can't reach (custom local images, explicit fontsize, custom outlines).

Reviewer notes

  • Output appearance changes by default. Existing baselines are unaffected because the autouse fixture in tests/conftest.py pins legacy tests to backend="matplotlib"; new tests for the memegen and pillow paths opt in via @pytest.mark.uses_default_backend. Users who want exact v0.4 visuals can pass backend="matplotlib" or set config["backend"] = "matplotlib".
  • memegen never honours custom outlines or per-line fontsize. Under auto, passing those forces the Pillow backend automatically; under backend="memegen" they are silently ignored. This is documented in the changelog and CLAUDE.md.
  • Sentinel pattern in meme(): outline_color, outline_width, fontsize default to a private _UNSET sentinel so the dispatcher can tell "user passed it" from "user accepted the default". _UNSET is treated as None by every downstream consumer.
  • Template.get_image() now respects config["cache_enabled"]. This was a latent bug surfaced while writing tests — under the old behaviour, disabling caching at the config level didn't actually disable the cache instance, so tests could read stale data from the user's real cache directory.
  • Test mocking for memegen: rendered URLs are dynamic (the path embeds caption text). Use the new memegen_rendered_pattern("buzz") helper in tests/conftest.py for regex matching with responses.

Test plan

  • ruff check .
  • black --check .
  • mypy --strict src/memeplotlib
  • pytest --cov --mpl — 222 passed, 88% coverage (≥ 85% gate)
  • sphinx-build -W docs docs/_build
  • CI matrix on this PR (Python 3.10–3.13 × ubuntu/macos/windows)
  • Manual smoke against the real memegen API once approved (pytest -m integration)

🤖 Generated with Claude Code

…-line styling

Rewires the rendering pipeline around three backends (auto / memegen /
pillow / matplotlib). Memes from the memegen catalogue are now composed
server-side via /images/<id>/<line>.../<line>.<ext>?... URLs and `imshow`n;
custom local images and any feature memegen can't express (per-line
fontsize, custom outlines, **text_kwargs, per-line overrides) route to a
new client-side Pillow renderer. The legacy matplotlib `Axes.text` +
patheffects path is preserved as `backend="matplotlib"`.

References jacebrowning/memegen#993 for the URL grammar and adds a
docs/url_construction.rst guide adapted for memeplotlib users.

- New `_url.py` (build_memegen_url, OverlaySpec, MEMEGEN_FONT_ALIASES) and
  `_pillow.py` (TTF resolution, multiline shrink-to-fit, stroke-aware
  drawing).
- `meme()` uses sentinel detection to know which knobs the caller passed
  so `auto` can route correctly. New params: backend, extension, width,
  height, layout, background, overlays, template_style.
- `Meme.line(index, text, *, fontsize, color, font, position)` for
  per-line overrides; `Meme.with_backend(...)` chainable setter.
- `Template` carries lines_count / overlays_count / styles / is_memegen.
- `Template.get_image()` now respects config["cache_enabled"] (latent bug).
- CLI gains --backend / --ext / --width / --height / --layout /
  --background / --template-style.
- MCP `meme` tool accepts the new knobs.
- Version bumped to 0.5.0 across pyproject.toml, __init__.py, and both
  conda recipes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@brianckeegan brianckeegan merged commit 71b2675 into main Apr 28, 2026
30 checks passed
@brianckeegan brianckeegan deleted the claude/mystifying-leavitt-08a7e3 branch April 28, 2026 20:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant