Created
July 8, 2025 09:01
-
-
Save pleabargain/fc2014ff73b7afa3e306f4b1a0013cc9 to your computer and use it in GitHub Desktop.
python random font to image
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from PIL import Image, ImageDraw, ImageFont | |
import os | |
import random | |
import argparse | |
import sys | |
from datetime import datetime | |
def get_system_fonts(): | |
"""Finds all usable TrueType font paths on the system.""" | |
font_paths = [] | |
if os.name == 'nt': # Windows | |
font_dir = "C:\\Windows\\Fonts" | |
for item in os.listdir(font_dir): | |
if item.lower().endswith('.ttf'): | |
font_paths.append(os.path.join(font_dir, item)) | |
elif os.name == 'posix': # Linux, macOS | |
font_dirs = [ | |
"/usr/share/fonts/truetype/", | |
"/System/Library/Fonts/Supplemental/", # macOS | |
"/Library/Fonts/", # macOS | |
] | |
for font_dir in font_dirs: | |
if os.path.exists(font_dir): | |
for root, _, files in os.walk(font_dir): | |
for file in files: | |
if file.lower().endswith('.ttf'): | |
font_paths.append(os.path.join(root, file)) | |
return font_paths | |
def wrap_text(text, font, max_width): | |
"""Wraps text to fit a specific pixel width.""" | |
lines = [] | |
words = text.split(' ') | |
current_line = "" | |
for word in words: | |
if font.getlength(current_line + " " + word) <= max_width: | |
current_line += " " + word | |
else: | |
lines.append(current_line.strip()) | |
current_line = word | |
lines.append(current_line.strip()) | |
return [line for line in lines if line] | |
def draw_random_text(draw, text, fonts, image_size, text_color): | |
"""Draws text with a random font for each character.""" | |
if not fonts: | |
print("Warning: No system fonts found. Cannot use random font feature.") | |
# Fallback to a simple drawing method | |
font = ImageFont.load_default() | |
draw.text((10, 10), text, font=font, fill=text_color) | |
return | |
padding = image_size[0] * 0.1 | |
max_width = image_size[0] - (padding * 2) | |
max_height = image_size[1] - (padding * 2) | |
# --- Simplified text layout for random fonts --- | |
font_size = 100 # Start with a reasonable size | |
# Simple line breaking | |
words = text.split() | |
lines = [] | |
current_line = "" | |
for word in words: | |
# A proper width check is complex here, so we do a simpler split | |
if len(current_line) + len(word) < 30: # Character count based wrapping | |
current_line += word + " " | |
else: | |
lines.append(current_line.strip()) | |
current_line = word + " " | |
lines.append(current_line.strip()) | |
# --- Drawing Logic --- | |
y = (image_size[1] - (len(lines) * font_size)) / 2 # Center vertically | |
for line in lines: | |
# Estimate line width for centering | |
line_width = 0 | |
for char in line: | |
try: | |
font = ImageFont.truetype(random.choice(fonts), font_size) | |
line_width += font.getlength(char) | |
except Exception: | |
line_width += font_size * 0.6 # Estimate for failed fonts | |
x = (image_size[0] - line_width) / 2 | |
for char in line: | |
try: | |
font = ImageFont.truetype(random.choice(fonts), font_size) | |
draw.text((x, y), char, font=font, fill=text_color) | |
x += font.getlength(char) | |
except Exception as e: | |
# If a font fails, skip the character and move on | |
print(f"Skipping character due to font error: {e}") | |
x += font_size * 0.6 # Move cursor by an estimated width | |
y += font_size * 1.2 # Move to the next line | |
def generate_image_with_text(text, output_filename="output_image.png", image_size=(800, 800), text_color=(0, 0, 0), background_color=(255, 255, 255), randomize_fonts=False): | |
""" | |
Generates an image with text. Can use a single font or randomize fonts per character. | |
""" | |
img = Image.new("RGB", image_size, color=background_color) | |
draw = ImageDraw.Draw(img) | |
if randomize_fonts: | |
all_fonts = get_system_fonts() | |
draw_random_text(draw, text, all_fonts, image_size, text_color) | |
else: | |
# --- Original single-font logic --- | |
font_paths = get_system_fonts() | |
font_path = font_paths[0] if font_paths else None | |
if not font_path: | |
print("Warning: Could not find a scalable system font. Falling back to default PIL font.") | |
font = ImageFont.load_default() | |
padding = image_size[0] * 0.1 # 10% padding | |
max_width = image_size[0] - (padding * 2) | |
max_height = image_size[1] - (padding * 2) | |
font_size = 350 | |
font = None | |
wrapped_lines = [] | |
while font_size > 10: | |
if font_path: | |
font = ImageFont.truetype(font_path, font_size) | |
else: | |
font = ImageFont.load_default() | |
wrapped_lines = wrap_text(text, font, max_width) | |
wrapped_text = "\n".join(wrapped_lines) | |
text_bbox = draw.multiline_textbbox((0, 0), wrapped_text, font=font, align="center") | |
text_height = text_bbox[3] - text_bbox[1] | |
if text_height <= max_height: | |
break | |
font_size -= 5 | |
if font_size <= 10: | |
print("Warning: Text might be too long to fit properly.") | |
final_bbox = draw.multiline_textbbox((0, 0), "\n".join(wrapped_lines), font=font, align="center") | |
text_block_width = final_bbox[2] - final_bbox[0] | |
text_block_height = final_bbox[3] - final_bbox[1] | |
x = (image_size[0] - text_block_width) / 2 - final_bbox[0] | |
y = (image_size[1] - text_block_height) / 2 - final_bbox[1] | |
draw.multiline_text((x, y), "\n".join(wrapped_lines), font=font, fill=text_color, align="center") | |
img.save(output_filename) | |
print(f"Image saved as {output_filename}") | |
if __name__ == "__main__": | |
# Simplified argument handling | |
if len(sys.argv) < 2: | |
user_text = input("Enter text for the image: ") | |
if not user_text: | |
user_text = "Hello, world!" | |
print("No text provided. Using default 'Hello, world!'") | |
randomize_fonts = "--random-fonts" in sys.argv | |
else: | |
user_text = sys.argv[1] | |
randomize_fonts = "--random-fonts" in sys.argv[2:] | |
base_filename = user_text[:20].replace(" ", "_") | |
safe_filename = "".join(c for c in base_filename if c.isalnum() or c in ('_', '-')).rstrip() | |
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") | |
output_filename = f"{safe_filename}_{timestamp}.png" | |
generate_image_with_text(user_text, output_filename=output_filename, randomize_fonts=randomize_fonts) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment