Spaces:
Build error
Build error
import gradio as gr | |
import numpy as np | |
import PIL.Image as Image | |
from rembg import remove | |
from PIL import ImageDraw, ImageFont | |
import textwrap | |
# Function to remove background and place text behind person | |
def text_behind_image(input_image, text, text_color, font_size, text_opacity): | |
if input_image is None or text.strip() == "": | |
return input_image | |
# Convert color hex to RGB | |
try: | |
r = int(text_color[1:3], 16) | |
g = int(text_color[3:5], 16) | |
b = int(text_color[5:7], 16) | |
text_color_rgb = (r, g, b) | |
except: | |
text_color_rgb = (0, 0, 0) # Default to black | |
try: | |
# Open the image | |
img = Image.fromarray(input_image) | |
# Get dimensions | |
width, height = img.size | |
# Step 1: Extract the person from the image | |
try: | |
# Try to use the human segmentation model first | |
person_only = remove(img, model_name="u2net_human_seg") | |
except: | |
# Fallback to default model if human_seg not available | |
person_only = remove(img) | |
# Step 2: Create a mask from the person cutout | |
person_mask = Image.new('RGBA', (width, height), (0, 0, 0, 0)) | |
person_mask.paste(person_only, (0, 0), person_only) | |
# Step 3: Extract the background (original image without the person) | |
# Create inverted mask (where the person is black, background is white) | |
inverted_mask = Image.new('L', (width, height), 255) | |
inverted_mask.paste(0, (0, 0), person_only) | |
# Extract just the background | |
background = img.copy() | |
background.putalpha(inverted_mask) | |
# Step 4: Create the text layer | |
text_layer = Image.new('RGBA', (width, height), (0, 0, 0, 0)) | |
draw = ImageDraw.Draw(text_layer) | |
# Prepare the text | |
text = text.strip().upper() | |
if not text: | |
text = "SAMPLE TEXT" | |
# Set up the font size - make it larger since we're just placing it once | |
font_size = max(20, int(min(width, height) * (font_size / 100))) | |
# Try several fonts | |
font = None | |
try: | |
font_paths = [ | |
"arial.ttf", | |
"/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", | |
"/usr/share/fonts/truetype/liberation/LiberationSans-Bold.ttf", | |
"/usr/share/fonts/truetype/freefont/FreeSansBold.ttf" | |
] | |
for font_path in font_paths: | |
try: | |
font = ImageFont.truetype(font_path, font_size) | |
break | |
except: | |
continue | |
except: | |
pass | |
if font is None: | |
font = ImageFont.load_default() | |
# Get text dimensions | |
# Try to use getbbox first for newer PIL versions | |
try: | |
text_width = font.getbbox(text)[2] - font.getbbox(text)[0] | |
text_height = font.getbbox(text)[3] - font.getbbox(text)[1] | |
except: | |
# Fallback for older PIL versions | |
try: | |
text_width = font.getsize(text)[0] | |
text_height = font.getsize(text)[1] | |
except: | |
# Second fallback - estimate size | |
text_width = len(text) * (font_size * 0.6) | |
text_height = font_size * 1.2 | |
# Position in the upper middle section | |
# Divide the image into a 3x3 grid and put the text in the top-center cell | |
grid_width = width // 3 | |
grid_height = height // 3 | |
# Center horizontally in the middle third | |
x_center = width // 2 - text_width // 2 | |
# Position vertically in the top third | |
y_top = grid_height // 2 - text_height // 2 | |
# Draw the text with specified opacity and color | |
draw.text((x_center, y_top), text, font=font, fill=text_color_rgb + (int(text_opacity * 255),)) | |
# Step 5: Composite all layers together | |
# First, composite the text on top of the background | |
background_with_text = Image.alpha_composite(background, text_layer) | |
# Then, composite the person on top | |
final_image = Image.alpha_composite(background_with_text, person_mask) | |
# Convert to RGB for display | |
return np.array(final_image.convert('RGB')) | |
except Exception as e: | |
print(f"Error processing image: {e}") | |
return input_image # Return original image on error | |
# Create Gradio interface | |
with gr.Blocks(title="Text Behind Image") as demo: | |
gr.Markdown("# Text Behind Image") | |
gr.Markdown("Upload an image with a person and add text behind them") | |
with gr.Row(): | |
with gr.Column(): | |
input_image = gr.Image(label="Upload Image", type="numpy") | |
text_input = gr.Textbox(label="Text to place behind", placeholder="Enter text here...") | |
with gr.Row(): | |
text_color = gr.ColorPicker(label="Text Color", value="#000000") | |
font_size = gr.Slider(label="Font Size (%)", minimum=1, maximum=30, value=10, step=1) | |
text_opacity = gr.Slider(label="Text Opacity", minimum=0.1, maximum=1.0, value=0.8, step=0.1) | |
submit_btn = gr.Button("Generate", variant="primary") | |
with gr.Column(): | |
output_image = gr.Image(label="Result", type="numpy") | |
submit_btn.click( | |
fn=text_behind_image, | |
inputs=[input_image, text_input, text_color, font_size, text_opacity], | |
outputs=output_image | |
) | |
gr.Markdown("## How it works") | |
gr.Markdown("1. Upload an image with a person") | |
gr.Markdown("2. Enter the text you want to place behind the person") | |
gr.Markdown("3. Customize text color, size, and opacity") | |
gr.Markdown("4. Click 'Generate' to create your image") | |
# Launch the app | |
demo.launch() |