CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-pilmoji

Emoji renderer for Pillow with Discord emoji support and multiple emoji sources

Pending
Overview
Eval results
Files

emoji-sources.mddocs/

Emoji Sources

Comprehensive system for fetching emoji images from various providers. The source system supports multiple emoji styles (Twitter, Apple, Microsoft, etc.), Discord custom emojis, HTTP optimization with requests library, and extensibility through custom source implementations.

Capabilities

Base Source Interface

Abstract base class defining the interface for all emoji sources, with methods for retrieving both Unicode emojis and Discord custom emojis.

class BaseSource(ABC):
    """Base class for emoji image sources."""
    
    @abstractmethod
    def get_emoji(self, emoji: str, /) -> Optional[BytesIO]:
        """
        Retrieves emoji image as BytesIO stream.
        
        Parameters:
        - emoji: str - Unicode emoji to retrieve
        
        Returns:
        - BytesIO - Image stream, or None if not found
        """
    
    @abstractmethod
    def get_discord_emoji(self, id: int, /) -> Optional[BytesIO]:
        """
        Retrieves Discord emoji image as BytesIO stream.
        
        Parameters:
        - id: int - Discord emoji snowflake ID
        
        Returns:
        - BytesIO - Image stream, or None if not found
        """

HTTP-Based Source

Base class for sources that fetch emojis via HTTP, with automatic fallback from requests library to urllib and configurable request parameters.

class HTTPBasedSource(BaseSource):
    """Base class for HTTP-based emoji sources."""
    
    REQUEST_KWARGS: ClassVar[Dict[str, Any]] = {
        'headers': {'User-Agent': 'Mozilla/5.0'}
    }
    
    def request(self, url: str) -> bytes:
        """
        Makes GET request to URL using requests library or urllib fallback.
        
        Parameters:
        - url: str - URL to request
        
        Returns:
        - bytes - Response content
        
        Raises:
        - HTTPError - Request failed
        """

Discord Emoji Mixin

Mixin class that adds Discord emoji functionality to other sources, fetching from Discord's CDN.

class DiscordEmojiSourceMixin(HTTPBasedSource):
    """Mixin adding Discord emoji functionality."""
    
    BASE_DISCORD_EMOJI_URL: ClassVar[str] = 'https://cdn.discordapp.com/emojis/'
    
    def get_discord_emoji(self, id: int, /) -> Optional[BytesIO]:
        """
        Fetches Discord emoji from Discord CDN.
        
        Parameters:
        - id: int - Discord emoji ID
        
        Returns:
        - BytesIO - Emoji image stream
        """

EmojiCDN Source

Base class for sources using the emojicdn.elk.sh service, supporting multiple emoji styles through style parameter.

class EmojiCDNSource(DiscordEmojiSourceMixin):
    """Base source for emojicdn.elk.sh service."""
    
    BASE_EMOJI_CDN_URL: ClassVar[str] = 'https://emojicdn.elk.sh/'
    STYLE: ClassVar[str] = None  # Must be overridden in subclasses
    
    def get_emoji(self, emoji: str, /) -> Optional[BytesIO]:
        """
        Fetches emoji from EmojiCDN with configured style.
        
        Parameters:
        - emoji: str - Unicode emoji
        
        Returns:
        - BytesIO - Emoji image stream
        """

Built-in Emoji Providers

Ready-to-use emoji sources for major emoji providers, each with distinct visual styles and characteristics.

# Primary providers
class Twemoji(EmojiCDNSource):
    """Twitter-style emojis (default source, also used by Discord)."""
    STYLE = 'twitter'

class AppleEmojiSource(EmojiCDNSource):
    """Apple-style emojis with iOS aesthetic."""
    STYLE = 'apple'

class MicrosoftEmojiSource(EmojiCDNSource):
    """Microsoft-style emojis with Windows aesthetic."""
    STYLE = 'microsoft'

class GoogleEmojiSource(EmojiCDNSource):
    """Google-style Noto emojis."""
    STYLE = 'google'

# Additional providers
class SamsungEmojiSource(EmojiCDNSource):
    """Samsung-style emojis."""
    STYLE = 'samsung'

class WhatsAppEmojiSource(EmojiCDNSource):
    """WhatsApp-style emojis."""
    STYLE = 'whatsapp'

class FacebookEmojiSource(EmojiCDNSource):
    """Facebook-style emojis."""
    STYLE = 'facebook'

class MessengerEmojiSource(EmojiCDNSource):
    """Facebook Messenger-style emojis."""
    STYLE = 'messenger'

class JoyPixelsEmojiSource(EmojiCDNSource):
    """JoyPixels (formerly EmojiOne) emojis."""
    STYLE = 'joypixels'

class OpenmojiEmojiSource(EmojiCDNSource):
    """Open-source Openmoji emojis."""
    STYLE = 'openmoji'

class EmojidexEmojiSource(EmojiCDNSource):
    """Emojidex-style emojis."""
    STYLE = 'emojidex'

class MozillaEmojiSource(EmojiCDNSource):
    """Mozilla-style emojis."""
    STYLE = 'mozilla'

# Convenience aliases  
TwemojiEmojiSource = Twemoji = TwitterEmojiSource
Openmoji = OpenmojiEmojiSource
FacebookMessengerEmojiSource = MessengerEmojiSource

Usage Examples

from pilmoji import Pilmoji
from pilmoji.source import (
    MicrosoftEmojiSource, AppleEmojiSource, 
    OpenmojiEmojiSource, JoyPixelsEmojiSource
)
from PIL import Image

image = Image.new('RGB', (300, 200), 'white')

# Use different emoji sources
sources = [
    ('Microsoft', MicrosoftEmojiSource),
    ('Apple', AppleEmojiSource),
    ('Openmoji', OpenmojiEmojiSource),
    ('JoyPixels', JoyPixelsEmojiSource)
]

y_pos = 10
for name, source_class in sources:
    with Pilmoji(image, source=source_class) as pilmoji:
        pilmoji.text((10, y_pos), f"{name}: 😊 🎉 🌟 ❤️", (0, 0, 0))
        y_pos += 40

Custom Source Implementation

Guide for implementing custom emoji sources by subclassing BaseSource or HTTPBasedSource.

Custom HTTP Source Example

class CustomEmojiSource(HTTPBasedSource):
    """Custom emoji source from your own CDN."""
    
    def __init__(self, base_url: str):
        super().__init__()
        self.base_url = base_url.rstrip('/')
    
    def get_emoji(self, emoji: str) -> Optional[BytesIO]:
        # Convert emoji to custom URL format
        emoji_code = hex(ord(emoji))[2:].upper()
        url = f"{self.base_url}/emoji_{emoji_code}.png"
        
        try:
            return BytesIO(self.request(url))
        except HTTPError:
            return None
    
    def get_discord_emoji(self, id: int) -> Optional[BytesIO]:
        # Custom Discord emoji handling
        url = f"{self.base_url}/discord/{id}.png"
        
        try:
            return BytesIO(self.request(url))
        except HTTPError:
            return None

# Usage
custom_source = CustomEmojiSource("https://my-emoji-cdn.com")
with Pilmoji(image, source=custom_source) as pilmoji:
    pilmoji.text((10, 10), "Custom emojis! 🎨", (0, 0, 0))

Local File Source Example

import os
from pathlib import Path

class LocalEmojiSource(BaseSource):
    """Source that loads emojis from local filesystem."""
    
    def __init__(self, emoji_dir: str):
        self.emoji_dir = Path(emoji_dir)
    
    def get_emoji(self, emoji: str) -> Optional[BytesIO]:
        # Convert emoji to filename
        emoji_code = f"U+{ord(emoji):04X}"
        emoji_file = self.emoji_dir / f"{emoji_code}.png"
        
        if emoji_file.exists():
            with open(emoji_file, 'rb') as f:
                return BytesIO(f.read())
        return None
    
    def get_discord_emoji(self, id: int) -> Optional[BytesIO]:
        emoji_file = self.emoji_dir / "discord" / f"{id}.png"
        
        if emoji_file.exists():
            with open(emoji_file, 'rb') as f:
                return BytesIO(f.read())
        return None

# Usage
local_source = LocalEmojiSource("/path/to/emoji/files")
with Pilmoji(image, source=local_source) as pilmoji:
    pilmoji.text((10, 10), "Local emojis! 📁", (0, 0, 0))

Install with Tessl CLI

npx tessl i tessl/pypi-pilmoji

docs

core-rendering.md

emoji-sources.md

index.md

text-processing.md

tile.json