mirror of
https://github.com/shadoll/moma.git
synced 2026-08-28 19:43:28 +00:00
81 lines
2.8 KiB
Python
81 lines
2.8 KiB
Python
"""ASCII art poster renderer."""
|
|
|
|
from .base import PosterRenderer
|
|
|
|
|
|
class AsciiPosterRenderer(PosterRenderer):
|
|
"""Render posters as ASCII art using PIL."""
|
|
|
|
def render(self, image_path: str, width: int = 35) -> str:
|
|
"""Render poster as ASCII art.
|
|
|
|
Args:
|
|
image_path: Path to the poster image
|
|
width: Width in characters (default: 35)
|
|
|
|
Returns:
|
|
ASCII art representation of the poster
|
|
"""
|
|
is_valid, error_msg = self.validate_image(image_path)
|
|
if not is_valid:
|
|
return error_msg
|
|
|
|
is_available, msg = self.is_available()
|
|
if not is_available:
|
|
return msg
|
|
|
|
try:
|
|
from PIL import Image, ImageEnhance
|
|
|
|
# Open image
|
|
img = Image.open(image_path)
|
|
|
|
# Enhance contrast for better detail
|
|
enhancer = ImageEnhance.Contrast(img)
|
|
img = enhancer.enhance(1.3)
|
|
|
|
# Convert to grayscale and resize
|
|
# Using provided width, height calculated to maintain aspect ratio
|
|
img = img.convert('L').resize((width, width), Image.Resampling.LANCZOS)
|
|
|
|
# Extended ASCII characters from darkest to lightest (more gradient levels)
|
|
# Using characters with different visual density for better detail
|
|
ascii_chars = '$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\\|()1{}[]?-_+~<>i!lI;:,"^`\'. '
|
|
|
|
# Convert to ASCII
|
|
pixels = img.getdata()
|
|
img_width, height = img.size
|
|
|
|
ascii_art = []
|
|
for y in range(0, height, 2): # Skip every other row for aspect ratio correction
|
|
row = []
|
|
for x in range(img_width):
|
|
# Average of two rows for better aspect ratio
|
|
pixel1 = pixels[y * img_width + x] if y < height else 255
|
|
pixel2 = pixels[(y + 1) * img_width + x] if y + 1 < height else 255
|
|
avg = (pixel1 + pixel2) // 2
|
|
|
|
# Map pixel brightness to character
|
|
# Invert: 0 (black) -> dark char, 255 (white) -> light char
|
|
char_index = (255 - avg) * (len(ascii_chars) - 1) // 255
|
|
char = ascii_chars[char_index]
|
|
row.append(char)
|
|
ascii_art.append(''.join(row))
|
|
|
|
return '\n'.join(ascii_art)
|
|
|
|
except Exception as e:
|
|
return f"Failed to display image: {e}\nPoster at: {image_path}"
|
|
|
|
def is_available(self) -> tuple[bool, str]:
|
|
"""Check if PIL is available.
|
|
|
|
Returns:
|
|
Tuple of (is_available, message)
|
|
"""
|
|
try:
|
|
import PIL
|
|
return True, ""
|
|
except ImportError:
|
|
return False, "PIL not available for ASCII art rendering\nInstall with: pip install Pillow"
|