Minekooooooooooo2's picture
Upload folder using huggingface_hub
f737e2c verified
import gradio as gr
import numpy as np
import requests
from PIL import Image, ImageDraw, ImageFont
import random
import io
import os
from pathlib import Path
# Set up static paths for faster loading
gr.set_static_paths(["assets"])
# Download some fonts if not available
FONT_PATH = "assets/fonts"
os.makedirs(FONT_PATH, exist_ok=True)
# Download Impact font (common meme font)
IMPACT_URL = "https://github.com/google/fonts/raw/main/apache/impact/Impact.ttf"
IMPACT_PATH = os.path.join(FONT_PATH, "Impact.ttf")
if not os.path.exists(IMPACT_PATH):
response = requests.get(IMPACT_URL)
with open(IMPACT_PATH, "wb") as f:
f.write(response.content)
# Download some other fonts
FONT_URLS = {
"Arial": "https://github.com/google/fonts/raw/main/apache/arial/Arial.ttf",
"ComicSans": "https://github.com/google/fonts/raw/main/apache/comicsansms/ComicSansMS.ttf",
"TimesNewRoman": "https://github.com/google/fonts/raw/main/apache/timesnewroman/TimesNewRoman.ttf"
}
for font_name, url in FONT_URLS.items():
font_path = os.path.join(FONT_PATH, f"{font_name}.ttf")
if not os.path.exists(font_path):
try:
response = requests.get(url)
with open(font_path, "wb") as f:
f.write(response.content)
except:
pass # Skip if font download fails
# Load meme templates and quotes
MEME_TEMPLATES = [
{"name": "Distracted Boyfriend", "image": "https://i.imgur.com/5e3qY.jpg", "boxes": [{"x": 0.1, "y": 0.1, "width": 0.3, "height": 0.2}, {"x": 0.6, "y": 0.1, "width": 0.3, "height": 0.2}, {"x": 0.4, "y": 0.6, "width": 0.2, "height": 0.2}]},
{"name": "Drake Hotline Bling", "image": "https://i.imgur.com/5e3qY.jpg", "boxes": [{"x": 0.1, "y": 0.1, "width": 0.8, "height": 0.3}, {"x": 0.1, "y": 0.6, "width": 0.8, "height": 0.3}]},
{"name": "Two Buttons", "image": "https://i.imgur.com/5e3qY.jpg", "boxes": [{"x": 0.1, "y": 0.4, "width": 0.3, "height": 0.2}, {"x": 0.6, "y": 0.4, "width": 0.3, "height": 0.2}]},
{"name": "Expanding Brain", "image": "https://i.imgur.com/5e3qY.jpg", "boxes": [{"x": 0.1, "y": 0.1, "width": 0.2, "height": 0.2}, {"x": 0.4, "y": 0.3, "width": 0.2, "height": 0.2}, {"x": 0.7, "y": 0.5, "width": 0.2, "height": 0.2}]},
{"name": "Woman Yelling at Cat", "image": "https://i.imgur.com/5e3qY.jpg", "boxes": [{"x": 0.1, "y": 0.1, "width": 0.3, "height": 0.2}, {"x": 0.6, "y": 0.6, "width": 0.3, "height": 0.2}]}
]
QUOTES = [
"When you realize you left the oven on",
"Me trying to adult",
"When the WiFi is slow",
"My brain at 3 AM",
"When someone says 'just relax'",
"Me pretending I understand",
"When you find money in your pocket",
"My motivation level",
"When the food is finally ready",
"Me avoiding responsibilities",
"When you hear a funny joke",
"My reaction to Mondays",
"When the weekend is over",
"Me trying to be productive",
"When you see a cute animal",
"My face when I see my bank account",
"When someone cancels plans",
"Me trying to parallel park",
"When you remember an embarrassing moment",
"My reaction to bad news"
]
SHITPOST_PHRASES = [
"This is fine",
"I have no idea what I'm doing",
"Send help",
"Why is this happening?",
"I need adult supervision",
"This is my life now",
"I regret my choices",
"I'm not okay",
"This is the worst",
"I give up",
"Why me?",
"I'm dying inside",
"This is a disaster",
"I'm not ready",
"This is too much",
"I can't even",
"This is ridiculous",
"I'm over it",
"This is insane",
"I'm done"
]
def get_random_font():
"""Get a random font from available fonts"""
font_files = [f for f in os.listdir(FONT_PATH) if f.endswith('.ttf')]
if font_files:
return os.path.join(FONT_PATH, random.choice(font_files))
return IMPACT_PATH
def add_text_to_image(image, text, font_path=IMPACT_PATH, font_size=40, color=(255, 255, 255), stroke_width=2, stroke_color=(0, 0, 0), position="center", max_width=0.8):
"""
Add text to an image with various styling options
"""
# Convert to PIL Image if it's a numpy array
if isinstance(image, np.ndarray):
image = Image.fromarray(image)
# Create a draw object
draw = ImageDraw.Draw(image)
# Load font
try:
font = ImageFont.truetype(font_path, font_size)
except:
font = ImageFont.load_default()
# Calculate text size and position
text_width, text_height = draw.textsize(text, font=font)
# Calculate position based on max_width percentage
img_width, img_height = image.size
max_text_width = int(img_width * max_width)
# Wrap text if needed
if text_width > max_text_width:
# Simple text wrapping
words = text.split()
lines = []
current_line = []
for word in words:
test_line = ' '.join(current_line + [word])
test_width, _ = draw.textsize(test_line, font=font)
if test_width <= max_text_width:
current_line.append(word)
else:
lines.append(' '.join(current_line))
current_line = [word]
if current_line:
lines.append(' '.join(current_line))
text = '\n'.join(lines)
text_width, text_height = draw.textsize(text, font=font)
# Calculate position
if position == "center":
x = (img_width - text_width) // 2
y = (img_height - text_height) // 2
elif position == "top":
x = (img_width - text_width) // 2
y = 20
elif position == "bottom":
x = (img_width - text_width) // 2
y = img_height - text_height - 20
elif position == "left":
x = 20
y = (img_height - text_height) // 2
elif position == "right":
x = img_width - text_width - 20
y = (img_height - text_height) // 2
else:
# Custom position format: "x,y" where x and y are percentages
try:
x_percent, y_percent = map(float, position.split(','))
x = int((img_width * x_percent) - (text_width / 2))
y = int((img_height * y_percent) - (text_height / 2))
except:
x = (img_width - text_width) // 2
y = (img_height - text_height) // 2
# Draw text with stroke
for dx in range(-stroke_width, stroke_width + 1):
for dy in range(-stroke_width, stroke_width + 1):
if dx != 0 or dy != 0:
draw.text((x + dx, y + dy), text, font=font, fill=stroke_color)
# Draw main text
draw.text((x, y), text, font=font, fill=color)
return image
def create_meme(image, meme_type="random", custom_text=None, font_size=40, text_color=(255, 255, 255), stroke_color=(0, 0, 0), stroke_width=2):
"""
Create a meme from an image
"""
# Convert to PIL Image if it's a numpy array
if isinstance(image, np.ndarray):
image = Image.fromarray(image)
# Get meme template
if meme_type == "random":
template = random.choice(MEME_TEMPLATES)
else:
template = next((t for t in MEME_TEMPLATES if t["name"] == meme_type), MEME_TEMPLATES[0])
# Get text for each box
texts = []
if custom_text:
# Split custom text by newlines
texts = custom_text.split('\n')
else:
# Use random quotes
texts = [random.choice(QUOTES) for _ in template["boxes"]]
# Add text to image for each box
for i, box in enumerate(template["boxes"]):
if i < len(texts):
text = texts[i]
# Calculate position from box coordinates
x_percent = box["x"] + box["width"] / 2
y_percent = box["y"] + box["height"] / 2
position = f"{x_percent},{y_percent}"
image = add_text_to_image(
image, text,
font_path=get_random_font(),
font_size=font_size,
color=text_color,
stroke_color=stroke_color,
stroke_width=stroke_width,
position=position,
max_width=box["width"] * 0.9
)
return image
def create_quote_image(image, quote_type="inspirational", custom_text=None, font_size=40, text_color=(255, 255, 255), stroke_color=(0, 0, 0), stroke_width=2, position="center"):
"""
Create a quote image
"""
# Get quote text
if custom_text:
text = custom_text
else:
if quote_type == "inspirational":
text = random.choice([
"Believe you can and you're halfway there",
"The only way to do great work is to love what you do",
"Don't watch the clock; do what it does. Keep going",
"Success is not final, failure is not fatal",
"You are never too old to set another goal",
"The future belongs to those who believe in their dreams",
"Everything you've ever wanted is on the other side of fear",
"Hardships often prepare ordinary people for extraordinary destiny",
"Don't be pushed around by the fears in your mind",
"The only limit to our realization of tomorrow is our doubts of today"
])
elif quote_type == "funny":
text = random.choice([
"I'm not lazy, I'm on energy saving mode",
"I put the 'pro' in procrastination",
"I'm not arguing, I'm just explaining why I'm right",
"I don't need anger management, I need people to stop pissing me off",
"I'm not short, I'm just more down to earth than you",
"I'm not bossy, I just have better ideas",
"I'm not crazy, my reality is just different than yours",
"I'm not a regular mom, I'm a cool mom",
"I'm not a morning person, I'm a coffee person",
"I'm not a shopaholic, I'm helping the economy"
])
elif quote_type == "shitpost":
text = random.choice(SHITPOST_PHRASES)
else:
text = random.choice(QUOTES)
# Add text to image
image = add_text_to_image(
image, text,
font_path=get_random_font(),
font_size=font_size,
color=text_color,
stroke_color=stroke_color,
stroke_width=stroke_width,
position=position
)
return image
def process_image(image, content_type, custom_text=None, font_size=40, text_color=(255, 255, 255), stroke_color=(0, 0, 0), stroke_width=2, position="center", meme_type="random"):
"""
Main processing function
"""
if image is None:
raise gr.Error("Please upload an image first!")
try:
if content_type == "meme":
result = create_meme(image, meme_type=meme_type, custom_text=custom_text, font_size=font_size, text_color=text_color, stroke_color=stroke_color, stroke_width=stroke_width)
else:
result = create_quote_image(image, quote_type=content_type, custom_text=custom_text, font_size=font_size, text_color=text_color, stroke_color=stroke_color, stroke_width=stroke_width, position=position)
return result
except Exception as e:
raise gr.Error(f"Error processing image: {str(e)}")
# Create custom theme
custom_theme = gr.themes.Soft(
primary_hue="blue",
secondary_hue="indigo",
neutral_hue="slate",
font=gr.themes.GoogleFont("Inter"),
text_size="lg",
spacing_size="lg",
radius_size="md"
).set(
button_primary_background_fill="*primary_600",
button_primary_background_fill_hover="*primary_700",
block_title_text_weight="600",
)
# Create the Gradio interface
with gr.Blocks() as demo:
gr.Markdown("""
# 🎨 Neural Network Image Editor
Upload an image and let our neural networks add random quotes, memes, or shitposts to it!
[![Built with anycoder](https://img.shields.io/badge/Built%20with-anycoder-%23FF6B6B.svg?style=for-the-badge)](https://huggingface.co/spaces/akhaliq/anycoder)
""")
with gr.Row():
with gr.Column():
# Image upload
input_image = gr.Image(label="Upload your image", type="numpy", sources=["upload", "webcam", "clipboard"])
# Content type selection
content_type = gr.Radio(
choices=["meme", "inspirational", "funny", "shitpost"],
value="meme",
label="Content Type"
)
# Meme type selection (only shown for memes)
meme_type = gr.Dropdown(
choices=[t["name"] for t in MEME_TEMPLATES],
value="random",
label="Meme Template",
visible=True
)
# Custom text
custom_text = gr.Textbox(
label="Custom Text (optional)",
placeholder="Enter your own text or leave blank for random",
lines=3
)
# Text styling options
with gr.Accordion("Text Styling Options", open=False):
font_size = gr.Slider(
minimum=20,
maximum=100,
value=40,
step=5,
label="Font Size"
)
text_color = gr.ColorPicker(
value="#FFFFFF",
label="Text Color"
)
stroke_color = gr.ColorPicker(
value="#000000",
label="Stroke Color"
)
stroke_width = gr.Slider(
minimum=0,
maximum=10,
value=2,
step=1,
label="Stroke Width"
)
position = gr.Dropdown(
choices=["center", "top", "bottom", "left", "right"],
value="center",
label="Text Position"
)
# Process button
process_btn = gr.Button("Generate Image", variant="primary")
with gr.Column():
# Output
output_image = gr.Image(label="Result", type="pil")
status = gr.Textbox(label="Status", value="Ready to process your image!")
# Examples
gr.Markdown("## Examples")
examples = gr.Examples(
examples=[
["https://i.imgur.com/5e3qY.jpg", "meme", "When you realize you left the oven on"],
["https://i.imgur.com/5e3qY.jpg", "inspirational", None],
["https://i.imgur.com/5e3qY.jpg", "funny", None],
["https://i.imgur.com/5e3qY.jpg", "shitpost", None]
],
inputs=[input_image, content_type, custom_text],
outputs=[output_image],
fn=process_image,
cache_examples=True,
label="Try these examples!"
)
# Update meme type visibility based on content type
def update_meme_visibility(content_type):
return gr.Dropdown(visible=content_type == "meme")
content_type.change(
fn=update_meme_visibility,
inputs=[content_type],
outputs=[meme_type]
)
# Process button click
process_btn.click(
fn=process_image,
inputs=[input_image, content_type, custom_text, font_size, text_color, stroke_color, stroke_width, position, meme_type],
outputs=[output_image, status],
api_visibility="public"
)
# Deep link button
gr.DeepLinkButton()
# Launch the app
demo.launch(
theme=custom_theme,
footer_links=[
{"label": "Built with anycoder", "url": "https://huggingface.co/spaces/akhaliq/anycoder"},
{"label": "GitHub", "url": "https://github.com/akhaliq/anycoder"},
{"label": "Gradio Docs", "url": "https://gradio.app/docs"}
],
css="""
.gradio-container {
max-width: 1200px !important;
}
.gr-button-primary {
background: linear-gradient(90deg, #3b82f6 0%, #8b5cf6 100%) !important;
border: none !important;
}
.gr-button-primary:hover {
background: linear-gradient(90deg, #2563eb 0%, #7c3aed 100%) !important;
}
""",
js="""
console.log("Neural Network Image Editor loaded!");
"""
)