#!/usr/bin/env python3 """ Explore PIL text options and test if we can match them. """ import numpy as np from PIL import Image, ImageDraw, ImageFont def load_font(font_name=None, font_size=32): """Load a font.""" candidates = [ font_name, '/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf', '/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf', '/usr/share/fonts/truetype/dejavu/DejaVuSans-Oblique.ttf', ] for path in candidates: if path is None: continue try: return ImageFont.truetype(path, font_size) except (IOError, OSError): continue return ImageFont.load_default() def test_pil_options(): """Test various PIL text options.""" # Create a test frame frame_size = (600, 400) font = load_font(None, 36) font_bold = load_font('/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf', 36) font_italic = load_font('/usr/share/fonts/truetype/dejavu/DejaVuSans-Oblique.ttf', 36) tests = [] # Test 1: Basic text def basic_text(): img = Image.new('RGBA', frame_size, (0, 0, 0, 0)) draw = ImageDraw.Draw(img) draw.text((20, 20), "Basic Text", fill=(255, 255, 255, 255), font=font) return img, "basic" tests.append(basic_text) # Test 2: Stroke/outline def stroke_text(): img = Image.new('RGBA', frame_size, (0, 0, 0, 0)) draw = ImageDraw.Draw(img) draw.text((20, 20), "Stroke Text", fill=(255, 255, 255, 255), font=font, stroke_width=2, stroke_fill=(255, 0, 0, 255)) return img, "stroke" tests.append(stroke_text) # Test 3: Bold font def bold_text(): img = Image.new('RGBA', frame_size, (0, 0, 0, 0)) draw = ImageDraw.Draw(img) draw.text((20, 20), "Bold Text", fill=(255, 255, 255, 255), font=font_bold) return img, "bold" tests.append(bold_text) # Test 4: Italic font def italic_text(): img = Image.new('RGBA', frame_size, (0, 0, 0, 0)) draw = ImageDraw.Draw(img) draw.text((20, 20), "Italic Text", fill=(255, 255, 255, 255), font=font_italic) return img, "italic" tests.append(italic_text) # Test 5: Different anchors def anchor_text(): img = Image.new('RGBA', frame_size, (0, 0, 0, 0)) draw = ImageDraw.Draw(img) # Draw crosshairs at anchor points for x in [100, 300, 500]: draw.line([(x-10, 50), (x+10, 50)], fill=(100, 100, 100, 255)) draw.line([(x, 40), (x, 60)], fill=(100, 100, 100, 255)) draw.text((100, 50), "Left", fill=(255, 255, 255, 255), font=font, anchor="lm") draw.text((300, 50), "Center", fill=(255, 255, 255, 255), font=font, anchor="mm") draw.text((500, 50), "Right", fill=(255, 255, 255, 255), font=font, anchor="rm") return img, "anchor" tests.append(anchor_text) # Test 6: Multiline text def multiline_text(): img = Image.new('RGBA', frame_size, (0, 0, 0, 0)) draw = ImageDraw.Draw(img) draw.multiline_text((20, 20), "Line One\nLine Two\nLine Three", fill=(255, 255, 255, 255), font=font, spacing=10) return img, "multiline" tests.append(multiline_text) # Test 7: Semi-transparent text def alpha_text(): img = Image.new('RGBA', frame_size, (0, 0, 0, 0)) draw = ImageDraw.Draw(img) draw.text((20, 20), "Alpha 100%", fill=(255, 255, 255, 255), font=font) draw.text((20, 60), "Alpha 50%", fill=(255, 255, 255, 128), font=font) draw.text((20, 100), "Alpha 25%", fill=(255, 255, 255, 64), font=font) return img, "alpha" tests.append(alpha_text) # Test 8: Colored text def colored_text(): img = Image.new('RGBA', frame_size, (0, 0, 0, 0)) draw = ImageDraw.Draw(img) draw.text((20, 20), "Red", fill=(255, 0, 0, 255), font=font) draw.text((20, 60), "Green", fill=(0, 255, 0, 255), font=font) draw.text((20, 100), "Blue", fill=(0, 0, 255, 255), font=font) draw.text((20, 140), "Yellow", fill=(255, 255, 0, 255), font=font) return img, "colored" tests.append(colored_text) # Test 9: Large stroke def large_stroke(): img = Image.new('RGBA', frame_size, (0, 0, 0, 0)) draw = ImageDraw.Draw(img) draw.text((20, 20), "Big Stroke", fill=(255, 255, 255, 255), font=font, stroke_width=5, stroke_fill=(0, 0, 0, 255)) return img, "large_stroke" tests.append(large_stroke) # Test 10: Emoji (if supported) def emoji_text(): img = Image.new('RGBA', frame_size, (0, 0, 0, 0)) draw = ImageDraw.Draw(img) try: # Try to find an emoji font emoji_font = None emoji_paths = [ '/usr/share/fonts/truetype/noto/NotoColorEmoji.ttf', '/usr/share/fonts/truetype/ancient-scripts/Symbola_hint.ttf', ] for p in emoji_paths: try: emoji_font = ImageFont.truetype(p, 36) break except: pass if emoji_font: draw.text((20, 20), "Hello 🎵 World 🎸", fill=(255, 255, 255, 255), font=emoji_font) else: draw.text((20, 20), "No emoji font found", fill=(255, 255, 255, 255), font=font) except Exception as e: draw.text((20, 20), f"Emoji error: {e}", fill=(255, 255, 255, 255), font=font) return img, "emoji" tests.append(emoji_text) # Run all tests print("PIL Text Options Test") print("=" * 60) for test_fn in tests: img, name = test_fn() fname = f"/tmp/pil_test_{name}.png" img.save(fname) print(f"Saved: {fname}") print("\nCheck /tmp/pil_test_*.png for results") # Print available parameters print("\n" + "=" * 60) print("PIL draw.text() parameters:") print(" - xy: position tuple") print(" - text: string to draw") print(" - fill: color (R,G,B) or (R,G,B,A)") print(" - font: ImageFont object") print(" - anchor: 2-char code (la=left-ascender, mm=middle-middle, etc.)") print(" - spacing: line spacing for multiline") print(" - align: 'left', 'center', 'right' for multiline") print(" - direction: 'rtl', 'ltr', 'ttb' (requires libraqm)") print(" - features: OpenType features list") print(" - language: language code for shaping") print(" - stroke_width: outline width in pixels") print(" - stroke_fill: outline color") print(" - embedded_color: use embedded color glyphs (emoji)") if __name__ == "__main__": test_pil_options()