File size: 6,109 Bytes
f6dcb1f
3778796
f6dcb1f
 
71e45d9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3778796
 
 
 
 
 
 
71e45d9
f6dcb1f
71e45d9
 
 
f6dcb1f
 
71e45d9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3778796
 
 
71e45d9
f6dcb1f
71e45d9
 
 
3778796
71e45d9
 
 
 
 
 
 
3778796
71e45d9
3778796
f6dcb1f
71e45d9
f6dcb1f
3778796
f6dcb1f
3778796
f6dcb1f
71e45d9
 
 
 
 
 
 
3778796
71e45d9
f6dcb1f
71e45d9
 
 
 
 
3778796
df27c04
71e45d9
 
 
df27c04
 
 
 
71e45d9
 
 
 
 
 
 
 
3778796
71e45d9
3778796
 
71e45d9
df27c04
3778796
 
71e45d9
 
 
 
 
 
 
3778796
 
 
 
 
71e45d9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3778796
71e45d9
 
 
 
 
 
3778796
f6dcb1f
 
3778796
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
import gradio as gr
import matplotlib.pyplot as plt
from io import BytesIO
from PIL import Image, ImageDraw, ImageFont
import textwrap
import os
import matplotlib

# Function to get available system fonts
def get_system_fonts():
    fonts = []
    for font in matplotlib.font_manager.findSystemFonts(fontpaths=None, fontext='ttf'):
        font_name = os.path.basename(font)
        fonts.append(font_name)
    return sorted(set(fonts))

# Function to parse color
def parse_color(color):
    """Convert RGBA string to RGB tuple if necessary."""
    if isinstance(color, str) and color.startswith('rgba'):
        color = color.replace('rgba', '').strip('()').split(',')
        return tuple(int(float(c.strip())) for c in color[:3])  # Convert to (R, G, B)
    return color  # If already valid, return as is

# Function to render plain text as an image
def render_plain_text_image(text, font_size, width, height, bg_color, text_color, font_name, align):
    """Convert plain text to an image with the given parameters."""
    bg_color = parse_color(bg_color)
    text_color = parse_color(text_color)

    # Create blank image
    img = Image.new("RGB", (width, height), color=bg_color)
    draw = ImageDraw.Draw(img)

    # Load font
    try:
        font_path = matplotlib.font_manager.findfont(font_name)
        font = ImageFont.truetype(font_path, font_size)
    except Exception:
        font = ImageFont.load_default()

    # Text wrapping
    margin = 10
    max_width = width - 2 * margin
    lines = []
    for line in text.split('\n'):
        lines.extend(textwrap.wrap(line, width=int(max_width / font_size * 1.8)))

    # Calculate total text height
    line_height = font.getsize('Ay')[1]
    total_text_height = line_height * len(lines)

    # Starting position
    y = (height - total_text_height) // 2

    for line in lines:
        line_width = font.getsize(line)[0]
        if align == 'Left':
            x = margin
        elif align == 'Center':
            x = (width - line_width) // 2
        else:  # Right alignment
            x = width - line_width - margin
        draw.text((x, y), line, fill=text_color, font=font)
        y += line_height

    return img

# Function to render math (LaTeX) as an image
def render_math_image(text, font_size, width, height, bg_color, text_color):
    """Convert LaTeX-formatted text to an image."""
    bg_color = parse_color(bg_color)
    text_color = parse_color(text_color)

    fig, ax = plt.subplots(figsize=(width / 100, height / 100), facecolor=bg_color)
    ax.set_facecolor(bg_color)
    ax.axis('off')

    # Ensure LaTeX formatting is correct
    if not (text.startswith(r"$") and text.endswith(r"$")):
        text = rf"${text}$"

    ax.text(0.5, 0.5, text, fontsize=font_size, ha='center', va='center', color=text_color)

    buf = BytesIO()
    plt.savefig(buf, format='png', bbox_inches='tight', pad_inches=0)
    plt.close(fig)

    buf.seek(0)
    return Image.open(buf)

# Main function to handle input
def text_to_image(input_text, font_size, width, height, bg_color, text_color, mode, font_name, align, image_format):
    """Determine whether to use plain text or LaTeX rendering."""
    if mode == "Plain Text":
        img = render_plain_text_image(input_text, font_size, width, height, bg_color, text_color, font_name, align)
    elif mode == "LaTeX Math":
        img = render_math_image(input_text, font_size, width, height, bg_color, text_color)
    else:
        return "Invalid mode selected!"

    # Save image to buffer
    buf = BytesIO()
    img.save(buf, format=image_format)
    buf.seek(0)
    return buf

# Function to handle file upload using file path
def handle_file_upload(file, font_size, width, height, bg_color, text_color, mode, font_name, align, image_format):
    """Extract text from file and convert to an image."""
    if file is not None:
        # 'file' is a list of file paths; use the first file path.
        file_path = file[0]
        with open(file_path, "r", encoding="utf-8") as f:
            text = f.read()
        return text_to_image(text, font_size, width, height, bg_color, text_color, mode, font_name, align, image_format)
    return "No file uploaded!"

# Get list of system fonts
font_list = get_system_fonts()
default_font = "DejaVuSans.ttf" if "DejaVuSans.ttf" in font_list else font_list[0]

# Gradio Interface
with gr.Blocks() as demo:
    gr.Markdown("# 🖼️ Text to Image Converter")

    with gr.Row():
        input_text = gr.Textbox(label="Enter Text", placeholder="Type or paste text here...")
        file_input = gr.File(label="Upload a Text File", type="filepath")

    with gr.Row():
        font_size = gr.Slider(10, 100, value=30, label="Font Size")
        font_name = gr.Dropdown(choices=font_list, value=default_font, label="Font")
        align = gr.Radio(["Left", "Center", "Right"], label="Text Alignment", value="Center")

    with gr.Row():
        width = gr.Slider(200, 2000, value=800, label="Image Width")
        height = gr.Slider(200, 2000, value=600, label="Image Height")

    with gr.Row():
        bg_color = gr.ColorPicker(label="Background Color", value="#FFFFFF")
        text_color = gr.ColorPicker(label="Text Color", value="#000000")

    with gr.Row():
        mode = gr.Radio(["Plain Text", "LaTeX Math"], label="Rendering Mode", value="Plain Text")
        image_format = gr.Radio(["PNG", "JPEG"], label="Image Format", value="PNG")

    output_image = gr.Image(label="Generated Image")

    with gr.Row():
        convert_button = gr.Button("Convert Text to Image")
        file_convert_button = gr.Button("Convert File to Image")

    convert_button.click(
        text_to_image,
        inputs=[
            input_text, font_size, width, height, bg_color, text_color,
            mode, font_name, align, image_format
        ],
        outputs=output_image
    )

    file_convert_button.click(
        handle_file_upload,
        inputs=[
            file_input, font_size, width, height, bg_color, text_color,
            mode, font_name, align, image_format
        ],
        outputs=output_image
    )

demo.launch()