Skip to main content

Pillow-based emoji rendering with HTTP and local sources

Project description

Parmoji

PyPI PyPI - Python Version Runs on Linux | macOS | Windows Arch x86-64 | ARM | AppleSilicon PyPI - Downloads PyPI - License

Build codecov Release Publish (PyPI) Publish (TestPyPI) TestPyPI

Description

Parmoji is a Pillow-based emoji rendering library (unicode + Discord custom emoji) with pluggable image sources (HTTP CDN and local font), LRU in-memory caching, and optional on-disk caching using XDG locations. It’s extracted from the par-term-emu project and packaged as a standalone library for reuse.

Buy Me A Coffee

Technology

  • Python 3.11+
  • Pillow
  • httpx / requests (optional fallback)

Prerequisites

  • Python 3.11 or higher
  • uv package manager (recommended)

Features

  • Unicode and Discord emoji
  • Multi-line rendering with alignment and anchors
  • Fine control over emoji size/position per draw call
  • Multiple built-in emoji sources (Twemoji, Apple, Google, etc.)
  • LRU in-memory cache and optional disk cache (XDG)

Installation

uv add parmoji

Update

uv add parmoji -U

Quickstart

from parmoji import Parmoji
from parmoji.source import TwitterEmojiSource
from PIL import Image, ImageFont

text = "Hello 👋  from Parmoji 😎"

img = Image.new("RGBA", (480, 120), (255, 255, 255, 255))
font = ImageFont.load_default()

with Parmoji(img, source=TwitterEmojiSource, cache=True) as p:
    p.text((10, 20), text, fill=(0, 0, 0), font=font)

img.save("parmoji_example.png")

Emoji Sources and Caching

  • Default source is Twemoji (Twitter-style). Swap via Parmoji(image, source=AppleEmojiSource).
  • Disk cache: construct sources with disk_cache=True to persist assets.
  • Cache location: $XDG_CACHE_HOME/par-term/parmoji/<SourceClass>/ (or ~/.cache/par-term/parmoji/<SourceClass>/).
  • Clear failed CDN retries: source.clear_failed_cache().

Tight Cropping (remove Twemoji safe-zone)

Some emoji sets (notably Twemoji) include transparent padding around glyphs. To have the visible emoji fill the cell area (useful for multi-cell flags), request a tightly cropped asset directly from the source:

from parmoji.source import TwitterEmojiSource

src = TwitterEmojiSource(disk_cache=True)
stream = src.get_emoji("🇺🇸", tight=True, margin=1)  # crop to alpha bbox + 1px margin
  • Cropped variants are cached on disk with a derived key, so subsequent calls don’t repeat work.
  • You can enable tight cropping by default via environment:
    • PARMOJI_TIGHT=1 to enable
    • PARMOJI_TIGHT_MARGIN=2 to set a default margin

Architecture

For a high-level system design, components, rendering flow, and caching details, see the Architecture overview:

Development

make setup          # uv lock + uv sync
make checkall       # format + lint + typecheck + test
make test           # run tests
make package-all    # build wheel + sdist
  • Pre-commit: pre-commit install (then pre-commit run --all-files)
  • Type checking: uv run pyright
  • Lint/format: uv run ruff check --fix src/ tests and uv run ruff format src/ tests

CI / Releases

  • Build & test on push: .github/workflows/build.yml
  • Publish to TestPyPI (manual): .github/workflows/publish-dev.yml
  • Publish to PyPI (manual): .github/workflows/publish.yml (trusted publishing)
  • GitHub Release (manual): .github/workflows/release.yml

What’s New

  • 2.0.7 — Tight-cropping support for CDN sources (Twemoji, etc.):
    • get_emoji(..., tight=True, margin=1) trims Twemoji’s transparent safe‑zone.
    • Cropped variants are cached with a derived key.
    • Env toggles: PARMOJI_TIGHT=1, PARMOJI_TIGHT_MARGIN=2.

License

MIT — see LICENSE.

Acknowledgements

Originally based on the Pilmoji project by jay3332; heavily refactored and optimized.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

parmoji-2.0.7.tar.gz (22.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

parmoji-2.0.7-py3-none-any.whl (24.8 kB view details)

Uploaded Python 3

File details

Details for the file parmoji-2.0.7.tar.gz.

File metadata

  • Download URL: parmoji-2.0.7.tar.gz
  • Upload date:
  • Size: 22.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for parmoji-2.0.7.tar.gz
Algorithm Hash digest
SHA256 5138629f1010f9eb883c141177d4c2ac7744ae6ebaecf6435bb6cf8722eb9221
MD5 d9ccc830c915198510c60a5c29a68b4f
BLAKE2b-256 3dd4f09ad6037e08716b9afe20e78e1782a5bbbf074981b2d653bfcbf323a8ad

See more details on using hashes here.

Provenance

The following attestation bundles were made for parmoji-2.0.7.tar.gz:

Publisher: publish.yml on paulrobello/parmoji

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file parmoji-2.0.7-py3-none-any.whl.

File metadata

  • Download URL: parmoji-2.0.7-py3-none-any.whl
  • Upload date:
  • Size: 24.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for parmoji-2.0.7-py3-none-any.whl
Algorithm Hash digest
SHA256 203d2ddc1221469fb08ed7a58a4bfdd3af58c1a19c42639a71ef04ab2b8a3ffd
MD5 76b5aa7c72806c47dc0715f8c3bd31f9
BLAKE2b-256 cd746ec5f9a38e4234960bc5bcf12177dd5c40e32a4072c47886dce1f5e6319d

See more details on using hashes here.

Provenance

The following attestation bundles were made for parmoji-2.0.7-py3-none-any.whl:

Publisher: publish.yml on paulrobello/parmoji

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page