TextToImage / app.py
ArrcttacsrjksX's picture
Create app.py
f6dcb1f verified
raw
history blame
5.64 kB
import gradio as gr
import re
import textwrap
from io import BytesIO
# Các thư viện cho việc tạo ảnh từ văn bản
from PIL import Image, ImageDraw, ImageFont
import matplotlib.pyplot as plt
def render_plain_text_image(text, font_size, width, height, bg_color, text_color):
"""
Render văn bản thông thường (không chứa LaTeX) thành ảnh bằng Pillow.
Nếu chiều cao (height) do người dùng nhập vào không đủ để chứa text,
chương trình sẽ tự động điều chỉnh lại (với căn giữa theo chiều dọc).
"""
# Thử load font TrueType; nếu không có, dùng font mặc định
try:
font = ImageFont.truetype("arial.ttf", font_size)
except Exception:
font = ImageFont.load_default()
# Tạo ảnh tạm để đo kích thước của text
temp_img = Image.new("RGB", (width, 100), color=bg_color)
draw = ImageDraw.Draw(temp_img)
# Ước tính chiều rộng của một ký tự (giả sử "A")
char_width, _ = draw.textsize("A", font=font)
# Số ký tự tối đa trên 1 dòng ước tính từ chiều rộng ảnh
max_chars = max(1, width // char_width)
# Tự động ngắt dòng theo số ký tự
lines = textwrap.wrap(text, width=max_chars)
# Tính tổng chiều cao cần dùng cho các dòng text
line_heights = []
for line in lines:
_, lh = draw.textsize(line, font=font)
line_heights.append(lh)
total_text_height = sum(line_heights)
# Nếu chiều cao được truyền vào không đủ, ta dùng chiều cao tối thiểu
if height is None or height < total_text_height + 20:
height = total_text_height + 20
# Tạo ảnh nền với kích thước (width x height)
img = Image.new("RGB", (width, height), color=bg_color)
draw = ImageDraw.Draw(img)
# Căn giữa theo chiều dọc: tính lề trên
y_text = (height - total_text_height) // 2
for line in lines:
line_width, line_height = draw.textsize(line, font=font)
# Căn giữa theo chiều ngang
x_text = (width - line_width) // 2
draw.text((x_text, y_text), line, font=font, fill=text_color)
y_text += line_height
return img
def render_math_image(text, font_size, width, height, bg_color, text_color):
"""
Render văn bản chứa LaTeX (có dấu $ … $) thành ảnh bằng matplotlib.
Chúng ta dùng matplotlib để hiển thị công thức (mathtext) theo kiểu toán học.
"""
dpi = 100
# Chuyển kích thước từ pixel sang inch (1 inch = dpi pixel)
fig_width = width / dpi
fig_height = height / dpi
fig = plt.figure(figsize=(fig_width, fig_height), dpi=dpi)
ax = plt.axes([0, 0, 1, 1])
ax.axis('off')
fig.patch.set_facecolor(bg_color)
# Dùng hàm text() với thuộc tính wrap=True và căn giữa
ax.text(0.5, 0.5, text, color=text_color, fontsize=font_size,
ha='center', va='center', wrap=True)
buf = BytesIO()
# Lưu figure vào bộ nhớ với một chút padding
plt.savefig(buf, format='png', bbox_inches='tight', pad_inches=0.1)
plt.close(fig)
buf.seek(0)
from PIL import Image
img = Image.open(buf)
return img
def text_to_image(file, text, font_size, width, height, bg_color, text_color):
"""
Hàm chính: nếu người dùng upload file thì đọc text từ file; nếu không thì dùng nội dung
nhập trực tiếp. Nếu văn bản có chứa định dạng LaTeX (dấu $ … $) thì dùng hàm render_math_image,
ngược lại dùng render_plain_text_image.
"""
# Nếu file được upload, ưu tiên sử dụng nội dung file
if file is not None:
try:
# Trong Gradio, file đầu vào có thể là dict chứa key "name"
if isinstance(file, dict):
file_path = file["name"]
else:
file_path = file
with open(file_path, 'r', encoding='utf-8') as f:
text = f.read()
except Exception as e:
return f"Error reading file: {e}"
if not text:
return "Chưa có nội dung text được nhập!"
# Nếu phát hiện chuỗi LaTeX (có dấu $ … $) thì dùng mode math
if re.search(r'\$(.*?)\$', text):
return render_math_image(text, font_size, width, height, bg_color, text_color)
else:
return render_plain_text_image(text, font_size, width, height, bg_color, text_color)
# Xây dựng giao diện Gradio
iface = gr.Interface(
fn=text_to_image,
inputs=[
gr.File(label="Upload file chứa text (tùy chọn)"),
gr.Textbox(label="Nhập text", lines=10, placeholder="Nhập text của bạn tại đây..."),
gr.Slider(10, 100, step=1, value=20, label="Font Size"),
gr.Slider(200, 2000, step=10, value=800, label="Chiều rộng ảnh (pixel)"),
gr.Slider(100, 2000, step=10, value=600, label="Chiều cao ảnh (pixel)"),
gr.ColorPicker(value="#ffffff", label="Màu nền"),
gr.ColorPicker(value="#000000", label="Màu chữ")
],
outputs=gr.Image(type="pil"),
title="Text-to-Image Converter",
description=(
"Upload một file chứa text hoặc nhập trực tiếp text. "
"Nếu text có chứa biểu thức LaTeX (ví dụ: $\\int_a^b f(x)dx$) "
"thì nó sẽ được render theo kiểu toán (math). "
"Các tuỳ chọn bên dưới cho phép bạn điều chỉnh đầu ra."
)
)
if __name__ == "__main__":
iface.launch()