kavehtaheri's picture
Create app.py
734b530 verified
import gradio as gr
import requests
import io
import os
from PIL import Image, ImageDraw, ImageFont
from pathlib import Path
import gdown
# Create fonts directory if it doesn't exist
os.makedirs("fonts", exist_ok=True)
# Dictionary of fonts to download - add Persian fonts here
fonts = {
"Arial Bold": "https://github.com/matomo-org/travis-scripts/raw/master/fonts/Arial.ttf",
"Vazir": "https://github.com/rastikerdar/vazir-font/raw/master/dist/Vazir.ttf",
"Sahel": "https://github.com/rastikerdar/sahel-font/raw/master/dist/Sahel.ttf",
"Samim": "https://github.com/rastikerdar/samim-font/raw/master/dist/Samim.ttf"
}
# Download fonts
for font_name, font_url in fonts.items():
font_filename = font_name.replace(" ", "-") + ".ttf"
font_path = Path(f"fonts/{font_filename}")
if not font_path.exists():
try:
font_data = requests.get(font_url).content
with open(font_path, "wb") as f:
f.write(font_data)
print(f"Downloaded font: {font_name}")
except Exception as e:
print(f"Error downloading font {font_name}: {e}")
# Fallback to system fonts if needed
system_fonts = [
"/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf",
"/usr/share/fonts/TTF/DejaVuSans-Bold.ttf",
"/usr/share/fonts/truetype/liberation/LiberationSans-Bold.ttf"
]
def download_image_from_gdrive(url):
"""Download image from Google Drive"""
try:
# Extract file ID from Google Drive URL
file_id = url.split("/d/")[1].split("/view")[0]
output = "background_image.jpg"
# Download the file
gdown.download(f"https://drive.google.com/uc?id={file_id}", output, quiet=False)
# Open the image
img = Image.open(output)
return img
except Exception as e:
print(f"Error downloading image: {e}")
# Return a default image if download fails
return Image.new('RGB', (1200, 800), (255, 239, 188))
def wrap_text(text, font, max_width):
"""Wrap text to fit within a given width"""
lines = []
paragraphs = text.split('\n')
for paragraph in paragraphs:
words = paragraph.split()
current_line = []
current_width = 0
for word in words:
word_width = font.getbbox(f"{word} ")[2]
if current_width + word_width <= max_width:
current_line.append(word)
current_width += word_width
else:
if current_line:
lines.append(' '.join(current_line))
current_line = [word]
current_width = font.getbbox(f"{word} ")[2]
if current_line:
lines.append(' '.join(current_line))
return lines
def create_quote_image(image_url, quote_text, title_text="", username="",
font_type="Vazir", quote_font_size=60, title_font_size=70,
username_font_size=40, text_color="#333333",
text_position="center", title_position="top",
username_position="bottom"):
"""Create an image with text overlays"""
# Download image from Google Drive
img = download_image_from_gdrive(image_url)
width, height = img.size
draw = ImageDraw.Draw(img)
# Parse text color
try:
if text_color.startswith("#"):
r = int(text_color[1:3], 16)
g = int(text_color[3:5], 16)
b = int(text_color[5:7], 16)
text_color = (r, g, b)
except:
text_color = (51, 51, 51) # Default to dark gray
# Load fonts
try:
font_filename = font_type.replace(" ", "-") + ".ttf"
font_path = f"fonts/{font_filename}"
quote_font = ImageFont.truetype(font_path, quote_font_size)
title_font = ImageFont.truetype(font_path, title_font_size)
username_font = ImageFont.truetype(font_path, username_font_size)
except Exception as e:
print(f"Error loading font: {e}")
# Try system fonts as fallback
for system_font in system_fonts:
if os.path.exists(system_font):
quote_font = ImageFont.truetype(system_font, quote_font_size)
title_font = ImageFont.truetype(system_font, title_font_size)
username_font = ImageFont.truetype(system_font, username_font_size)
break
else:
quote_font = ImageFont.load_default()
title_font = ImageFont.load_default()
username_font = ImageFont.load_default()
# Add title if provided
if title_text:
max_title_width = width * 0.9
title_lines = wrap_text(title_text, title_font, max_title_width)
title_height = len(title_lines) * (title_font_size * 1.2)
if title_position == "top":
title_y = height * 0.05 # 5% from top
else:
title_y = (height - title_height) / 2 # Center
for i, line in enumerate(title_lines):
line_width = title_font.getbbox(line)[2]
x = (width - line_width) / 2
y = title_y + i * (title_font_size * 1.2)
draw.text((x, y), line, fill=text_color, font=title_font)
# Add main quote text
max_text_width = width * 0.8
quote_lines = wrap_text(quote_text, quote_font, max_text_width)
quote_height = len(quote_lines) * (quote_font_size * 1.2)
if text_position == "center":
quote_y = (height - quote_height) / 2
elif text_position == "top":
quote_y = height * 0.05
if title_text and title_position == "top":
quote_y += title_height + height * 0.05 # Add space after title
else: # bottom
quote_y = height - quote_height - height * 0.15
for i, line in enumerate(quote_lines):
line_width = quote_font.getbbox(line)[2]
x = (width - line_width) / 2
y = quote_y + i * (quote_font_size * 1.2)
draw.text((x, y), line, fill=text_color, font=quote_font)
# Add username/author if provided
if username:
if username_position == "bottom":
username_y = height - username_font_size * 2
elif username_position == "top":
username_y = height * 0.05
if title_text and title_position == "top":
username_y += title_height + height * 0.03
else: # After quote
username_y = quote_y + quote_height + username_font_size
username_width = username_font.getbbox(username)[2]
username_x = (width - username_width) / 2
draw.text((username_x, username_y), username, fill=text_color, font=username_font)
return img
def generate_quote_image(image_url, quote_text, title_text, username,
font_type, quote_font_size, title_font_size,
username_font_size, text_color, text_position,
title_position, username_position):
"""Generate a quote image with all customizations"""
print("Start processing")
# Validate inputs
if not image_url or image_url.strip() == "":
return None, "Please provide a valid Google Drive image URL"
if not quote_text or quote_text.strip() == "":
quote_text = "Please enter a quote to generate an image."
# Create image
try:
image = create_quote_image(
image_url=image_url,
quote_text=quote_text,
title_text=title_text,
username=username,
font_type=font_type,
quote_font_size=quote_font_size,
title_font_size=title_font_size,
username_font_size=username_font_size,
text_color=text_color,
text_position=text_position,
title_position=title_position,
username_position=username_position
)
print("Processing complete")
return image, "Image generated successfully!"
except Exception as e:
print(f"Error generating image: {e}")
return None, f"Error: {str(e)}"
# Create Gradio interface
with gr.Blocks() as demo:
gr.Markdown("# Custom Quote Image Generator")
gr.Markdown("""
This tool generates beautiful quote images using your own background image from Google Drive.
Enter your quote, customize the text properties, and click 'Generate Image'.
""")
with gr.Row():
with gr.Column():
image_url = gr.Textbox(
label="Google Drive Image URL",
placeholder="https://drive.google.com/file/d/12QImAkg9A5_yRr-YwjJiFNznYF9ymybS/view?usp=drive_link"
)
with gr.Tabs():
with gr.TabItem("Main Quote"):
quote_input = gr.Textbox(
label="Enter your quote",
placeholder="May the tears you cried in 2024 water the seeds you plant for 2025.",
lines=3
)
quote_font_size = gr.Slider(
label="Quote Font Size",
minimum=20,
maximum=120,
value=60,
step=1
)
text_position = gr.Radio(
label="Quote Position",
choices=["center", "top", "bottom"],
value="center"
)
with gr.TabItem("Title"):
title_input = gr.Textbox(
label="Title (optional)",
placeholder="Inspirational Quote",
lines=1
)
title_font_size = gr.Slider(
label="Title Font Size",
minimum=20,
maximum=120,
value=70,
step=1
)
title_position = gr.Radio(
label="Title Position",
choices=["top", "center"],
value="top"
)
with gr.TabItem("Author/Username"):
username_input = gr.Textbox(
label="Author/Username (optional)",
placeholder="@aestheticdailyquote"
)
username_font_size = gr.Slider(
label="Author Font Size",
minimum=10,
maximum=80,
value=40,
step=1
)
username_position = gr.Radio(
label="Author Position",
choices=["bottom", "top"],
value="bottom"
)
font_type = gr.Dropdown(
label="Font Type",
choices=list(fonts.keys()),
value="Vazir"
)
text_color = gr.ColorPicker(
label="Text Color",
value="#333333"
)
generate_btn = gr.Button("Generate Image", variant="primary")
with gr.Column():
image_output = gr.Image(type="pil", label="Generated Quote Image")
status_output = gr.Textbox(label="Status")
generate_btn.click(
fn=generate_quote_image,
inputs=[
image_url, quote_input, title_input, username_input,
font_type, quote_font_size, title_font_size,
username_font_size, text_color, text_position,
title_position, username_position
],
outputs=[image_output, status_output]
)
# Example for demonstration
gr.Examples(
examples=[
[
"https://drive.google.com/file/d/12QImAkg9A5_yRr-YwjJiFNznYF9ymybS/view?usp=drive_link",
"May the tears you cried in 2024 water the seeds you plant for 2025.",
"Inspirational Quote",
"@aestheticdailyquote",
"Vazir",
60, 70, 40,
"#333333",
"center",
"top",
"bottom"
]
],
inputs=[
image_url, quote_input, title_input, username_input,
font_type, quote_font_size, title_font_size,
username_font_size, text_color, text_position,
title_position, username_position
],
outputs=[image_output, status_output],
fn=generate_quote_image
)
gr.Markdown("""
## How to Use
1. Paste a Google Drive image URL (make sure it's publicly accessible)
2. Enter your quote, title, and author information
3. Customize font type, size, color, and positions
4. Click 'Generate Image'
## Supported Persian Fonts
- Vazir
- Sahel
- Samim
""")
# Launch the app
demo.launch()