File size: 7,596 Bytes
6b64a10
 
 
 
 
 
 
 
 
 
69751c5
 
 
 
 
 
2764dca
6b64a10
 
 
 
bd9441c
6b64a10
 
 
 
bd9441c
6b64a10
 
7496d06
bd9441c
 
6b64a10
 
 
 
 
 
 
 
 
2764dca
69751c5
6b64a10
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2764dca
 
 
69751c5
 
2764dca
 
 
 
 
 
69751c5
6b64a10
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38e901b
 
6b64a10
 
 
 
 
 
 
 
 
2764dca
 
6b64a10
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2764dca
69751c5
6b64a10
 
 
 
 
 
 
 
bd9441c
 
 
 
 
6b64a10
2764dca
69751c5
3db52e5
 
 
 
 
 
 
 
2764dca
69751c5
3db52e5
 
 
 
 
 
 
 
2764dca
69751c5
3db52e5
6b64a10
 
 
 
 
 
 
 
2764dca
69751c5
f9b4b79
 
 
 
6b64a10
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
144ab4f
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
import gradio as gr
from PIL import Image, ImageDraw, ImageFont
import numpy as np
import os
from PIL import Image
from gradio_client import Client, handle_file
import uuid

client = Client("ysharma/BiRefNet_for_text_writing")

def add_text_with_stroke(draw, text, x, y, font, text_color, stroke_width):
    """Helper function to draw text with stroke"""
    # Draw the stroke/outline
    for adj_x in range(-stroke_width, stroke_width + 1):
        for adj_y in range(-stroke_width, stroke_width + 1):
            draw.text((x + adj_x, y + adj_y), text, font=font, fill=text_color)

def remove_background(image):
    # Save the image to a specific location
    filename = f"image_{uuid.uuid4()}.png"  # Generates a universally unique identifier (UUID) for the filename
    image.save(filename)
    # Call gradio client for background removal
    result = client.predict(images=handle_file(filename), api_name="/image")
    return Image.open(result[0])

def superimpose(image_with_text, overlay_image):
    # Open image as RGBA to handle transparency
    overlay_image = overlay_image.convert("RGBA")
    # Paste overlay on the background
    image_with_text.paste(overlay_image, (0, 0), overlay_image)
    # Save the final image
    # image_with_text.save("output_image.png")
    return image_with_text

def add_text_to_image(
    input_image,
    text,
    font_size,
    color,
    opacity,
    x_position,
    y_position,
    thickness
):
    """
    Add text to an image with customizable properties
    """
    # Convert gradio image (numpy array) to PIL Image
    if input_image is None:
        return None
    
    image = Image.fromarray(input_image)
    # remove background 
    overlay_image = remove_background(image)

    # Create a transparent overlay for the text
    txt_overlay = Image.new('RGBA', image.size, (255, 255, 255, 0))
    draw = ImageDraw.Draw(txt_overlay)
    
    # Create a font with specified size
    try:
        font = ImageFont.truetype("DejaVuSans.ttf", int(font_size))
    except:
        # If DejaVu font is not found, try to use Arial or default
        try:
            font = ImageFont.truetype("arial.ttf", int(font_size))
        except:
            print("Using default font as system fonts not found")
            font = ImageFont.load_default()
    
    # Convert color name to RGB
    color_map = {
        'White': (255, 255, 255),
        'Black': (0, 0, 0),
        'Red': (255, 0, 0),
        'Green': (0, 255, 0),
        'Blue': (0, 0, 255),
        'Yellow': (255, 255, 0),
        'Purple': (128, 0, 128)
    }
    rgb_color = color_map.get(color, (255, 255, 255))
    
    # Get text size for positioning
    text_bbox = draw.textbbox((0, 0), text, font=font)
    text_width = text_bbox[2] - text_bbox[0]
    text_height = text_bbox[3] - text_bbox[1]

    # Calculate actual x and y positions based on percentages
    actual_x = int((image.width - text_width) * (x_position / 100))
    actual_y = int((image.height - text_height) * (y_position / 100))

    # Create final color with opacity
    text_color = (*rgb_color, int(opacity))
    
    # Draw the text with stroke for thickness
    add_text_with_stroke(
        draw, 
        text, 
        actual_x, 
        actual_y, 
        font, 
        text_color, 
        int(thickness)
    )

    # Combine the original image with the text overlay
    if image.mode != 'RGBA':
        image = image.convert('RGBA')
    output_image = Image.alpha_composite(image, txt_overlay)
    
    # Convert back to RGB for display
    output_image = output_image.convert('RGB')

    # superimpose images
    output_image = superimpose(output_image, overlay_image)
    
    # Convert PIL image back to numpy array for Gradio
    return np.array(output_image)

# Create the Gradio interface
def create_interface():
    with gr.Blocks() as app:
        gr.Markdown("# Add Text Behind Image")
        gr.Markdown("Upload an image and customize text properties to add text overlay.")
        
        with gr.Row():
            with gr.Column():
                # Input components
                input_image = gr.Image(label="Upload Image", type="numpy")
                text_input = gr.Textbox(label="Enter Text", placeholder="Type your text here...")
                font_size = gr.Slider(minimum=10, maximum=800, value=400, step=10, 
                                    label="Font Size")
                thickness = gr.Slider(minimum=0, maximum=20, value=0, step=1,
                                    label="Text Thickness")
                color_dropdown = gr.Dropdown(
                    choices=["White", "Black", "Red", "Green", "Blue", "Yellow", "Purple"],
                    value="White",
                    label="Text Color"
                )
                opacity_slider = gr.Slider(minimum=0, maximum=255, value=255, step=1, 
                                         label="Opacity")
                x_position = gr.Slider(minimum=0, maximum=100, value=50, step=1, 
                                     label="X Position (%)")
                y_position = gr.Slider(minimum=0, maximum=100, value=50, step=1, 
                                     label="Y Position (%)")
                
            with gr.Column():
                # Output image
                output_image = gr.Image(label="Output Image")
        
        # Process button
        process_btn = gr.Button("Add Text to Image")
        
        # Connect the input components to the processing function
        process_btn.click(
            fn=add_text_to_image,
            inputs=[
                input_image,
                text_input,
                font_size,
                color_dropdown,
                opacity_slider,
                x_position,
                y_position,
                thickness
            ],
            outputs=output_image
        )
        
        # Add example inputs
        gr.Examples(
            examples=[
                [
                    "pink_convertible.webp",
                    "EPIC",
                    420,
                    "Purple",
                    150,
                    50,
                    21,
                    9
                ],
                [
                    "pear.jpg",
                    "PEAR",
                    350,
                    "Black",
                    100,
                    50,
                    2,
                    5
                ],
                [
                    "sample_text_image.jpeg",
                    "LIFE",
                    400,
                    "Black",
                    150,
                    50,
                    2,
                    8
                ],
            ],
            inputs=[
                input_image,
                text_input,
                font_size,
                color_dropdown,
                opacity_slider,
                x_position,
                y_position,
                thickness
            ],
            outputs=output_image,
            fn=add_text_to_image,
            cache_examples=True,
        )

    return app

# Launch the app
if __name__ == "__main__":
    # Try to install required font
    try:
        import subprocess
        subprocess.run(['apt-get', 'update'])
        subprocess.run(['apt-get', 'install', '-y', 'fonts-dejavu'])
        print("Font installed successfully")
    except:
        print("Could not install font automatically. Please install DejaVu font manually.")
    
    # Create and launch the interface
    app = create_interface()
    app.launch(ssr_mode = False)