File size: 8,504 Bytes
6b64a10
 
 
 
 
 
 
 
 
 
cd3441f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2764dca
6b64a10
 
 
 
bd9441c
6b64a10
 
 
 
bd9441c
6b64a10
 
7496d06
bd9441c
 
6b64a10
 
 
 
 
 
 
 
 
2764dca
e795b64
 
6b64a10
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2764dca
 
 
e795b64
 
 
 
 
2764dca
 
 
 
 
 
e795b64
 
 
6b64a10
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38e901b
 
6b64a10
 
 
 
 
 
 
 
 
2764dca
 
6b64a10
 
 
 
 
 
 
 
 
 
 
e795b64
6b64a10
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2764dca
e795b64
 
6b64a10
 
 
 
 
 
 
 
bd9441c
 
 
 
 
6b64a10
2764dca
e795b64
 
3db52e5
 
 
 
 
 
 
 
2764dca
e795b64
 
3db52e5
 
 
 
 
 
 
 
2764dca
e795b64
 
3db52e5
6b64a10
 
 
 
 
 
 
 
2764dca
e795b64
cd3441f
f9b4b79
 
 
 
6b64a10
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
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_effects(draw, text, x, y, font, text_color, stroke_width, shadow=False, shadow_offset=(5, 5)):
    """Helper function to draw text with stroke and optional shadow"""
    # Draw shadow first if enabled
    if shadow:
        # Create shadow color (darker version of text color or black)
        shadow_color = (0, 0, 0, text_color[3])  # Black with same opacity as text
        
        # Draw the shadow text with stroke effect
        shadow_x = x + shadow_offset[0]
        shadow_y = y + shadow_offset[1]
        
        for adj_x in range(-stroke_width, stroke_width + 1):
            for adj_y in range(-stroke_width, stroke_width + 1):
                draw.text(
                    (shadow_x + adj_x, shadow_y + adj_y),
                    text,
                    font=font,
                    fill=shadow_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,
    use_shadow
):
    """
    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))
    
    # Calculate shadow offset based on font size
    shadow_offset = (int(font_size * 0.05), int(font_size * 0.05))
    
    # Draw the text with effects
    add_text_with_effects(
        draw, 
        text, 
        actual_x, 
        actual_y, 
        font, 
        text_color, 
        int(thickness),
        shadow=use_shadow,
        shadow_offset=shadow_offset
    )

    # 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 (%)")
                shadow_checkbox = gr.Checkbox(label="Add Shadow Effect", value=False)
                
            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,
                shadow_checkbox
            ],
            outputs=output_image
        )
        
        # Add example inputs
        gr.Examples(
            examples=[
                [
                    "pink_convertible.webp",
                    "EPIC",
                    420,
                    "Purple",
                    150,
                    50,
                    21,
                    9,
                    True
                ],
                [
                    "pear.jpg",
                    "PEAR",
                    350,
                    "Black",
                    100,
                    50,
                    2,
                    5,
                    True
                ],
                [
                    "sample_text_image.jpeg",
                    "LIFE",
                    400,
                    "Black",
                    150,
                    50,
                    2,
                    8,
                    True
                ],
            ],
            inputs=[
                input_image,
                text_input,
                font_size,
                color_dropdown,
                opacity_slider,
                x_position,
                y_position,
                thickness,
                shadow_checkbox,
            ],
            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()