How to Generate a Hero Image using Python.PIL
guides
tutorials
Instructions for Placing Hero Images and Updating Blog Posts
1. Generate the hero image and optionally update the .qmd
file:
python makeheroimage.py "Your Blog Post Title" -o "blog/images/Python-PIL-Generate-Hero-Image.png" -q "blog/Python-PIL-Generate-Hero-Image.qmd"
2. Place the Hero Image:
- The script will automatically place the generated image in the specified output path.
- If the
-q
option is used, the script will also update the front matter of the specified.qmd
file with the image path.
3. Commit and Push the Changes:
Add the new image and updated blog post to git:
git add blog/images/Python-PIL-Generate-Hero-Image.png blog/Python-PIL-Generate-Hero-Image.qmd
Commit the changes with a meaningful message:
git commit -m "Add hero image and new blog post about [topic]"
Push the changes to your GitHub repository:
git push origin main
4. Publish the Blog Post on the Server:
SSH into your server where the blog is hosted.
Navigate to the project directory on the server.
Pull the latest changes from GitHub:
git pull origin main
Render the site with Quarto:
quarto render
5. Verify the Blog Post:
- Open your website in a browser to ensure the new post is live and the hero image is displayed correctly.
Instructions for Using the Script
Save the script below as
makeheroimage.py
.Ensure you have a compatible font installed (DejaVu Sans, Arial, Monaco or similar).
Run the script from the command line:
python makeheroimage.py "Your text here" -o "path/to/hero_image.png" -q "path/to/blog/post.qmd"
# makeheroimage.py """ This script generates a hero image with complementary colors and centered text. It can optionally insert/update the hero image in the .qmd front matter. requirements: Pillow, PyYAML """ import argparse from PIL import Image, ImageDraw, ImageFont import random import os import sys import yaml def generate_complementary_colors(): # Pantone Orange and complementary colors = [ colors 255, 165, 0), (0, 0, 255)), # Orange and Blue ((255, 127, 80), (75, 0, 130)), # Coral and Indigo ((255, 69, 0), (0, 128, 128)), # Red-Orange and Teal ((255, 140, 0), (0, 206, 209)), # Dark Orange and Dark Turquoise (( ]return random.choice(colors) def get_font_path(): # Check for common font paths in different operating systems = [ common_paths "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", # Linux "/System/Library/Fonts/Monaco.ttf", # macOS "C:\\Windows\\Fonts\\Arial.ttf", # Windows ]for path in common_paths: if os.path.exists(path): return path print("Error: Font file not found. Please install DejaVu Sans or Arial font.") 1) sys.exit( def create_hero_image(text, output_path="hero_image.png"): try: # Define image dimensions and background color = 1200, 600 width, height = generate_complementary_colors() background_color, text_color # Create an image = Image.new("RGB", (width, height), color=background_color) image = ImageDraw.Draw(image) draw # Define font = get_font_path() font_path = ImageFont.truetype(font_path, size=60) font # Calculate text size and position using textbbox = draw.textbbox((0, 0), text, font=font) text_bbox = text_bbox[2] - text_bbox[0], text_bbox[3] - text_bbox[1] text_width, text_height while text_width > width - 140: # Adjust font size to fit within image width = ImageFont.truetype(font_path, size=font.size - 2) font = draw.textbbox((0, 0), text, font=font) text_bbox = text_bbox[2] - text_bbox[0], text_bbox[3] - text_bbox[1] text_width, text_height = (width - text_width) / 2 text_x = (height - text_height) / 2 text_y # Draw the text on the image =font, fill=text_color) draw.text((text_x, text_y), text, font # Save the image image.save(output_path)print(f"Image saved at {output_path}") except Exception as e: print(f"An error occurred: {e}") def update_qmd_front_matter(qmd_path, image_path): try: with open(qmd_path, 'r') as file: = file.read() content # Find the front matter section if content.startswith('---'): = content.find('---', 3) + 3 end_index = content[3:end_index-3] front_matter = content[end_index:] body else: = "" front_matter = content body # Parse the front matter = yaml.safe_load(front_matter) if front_matter else {} fm_data # Update the image path to be relative 'image'] = os.path.join("images", os.path.basename(image_path)) fm_data[ # Convert the front matter back to a string = yaml.dump(fm_data) new_front_matter # Write the updated content back to the file with open(qmd_path, 'w') as file: file.write(f"---\n{new_front_matter}---\n{body}") print(f"Updated {qmd_path} with image {fm_data['image']}") except Exception as e: print(f"An error occurred while updating the .qmd file: {e}") if __name__ == "__main__": = argparse.ArgumentParser(description="Generate a hero image with specified text.") parser "text", type=str, help="Text to display on the hero image") parser.add_argument("-o", "--output", type=str, default="hero_image.png", help="Output path for the hero image") parser.add_argument("-q", "--qmd", type=str, help="Path to the .qmd file to update front matter with the image") parser.add_argument(= parser.parse_args() args create_hero_image(args.text, args.output) if args.qmd: update_qmd_front_matter(args.qmd, args.output)
The hero image for this post and Create-Publish-Quarto-Blog-Post were generated with the script above.