ArrcttacsrjksX commited on
Commit
f6dcb1f
·
verified ·
1 Parent(s): ef68089

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +135 -0
app.py ADDED
@@ -0,0 +1,135 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import re
3
+ import textwrap
4
+ from io import BytesIO
5
+
6
+ # Các thư viện cho việc tạo ảnh từ văn bản
7
+ from PIL import Image, ImageDraw, ImageFont
8
+ import matplotlib.pyplot as plt
9
+
10
+
11
+ def render_plain_text_image(text, font_size, width, height, bg_color, text_color):
12
+ """
13
+ Render văn bản thông thường (không chứa LaTeX) thành ảnh bằng Pillow.
14
+ Nếu chiều cao (height) do người dùng nhập vào không đủ để chứa text,
15
+ chương trình sẽ tự động điều chỉnh lại (với căn giữa theo chiều dọc).
16
+ """
17
+ # Thử load font TrueType; nếu không có, dùng font mặc định
18
+ try:
19
+ font = ImageFont.truetype("arial.ttf", font_size)
20
+ except Exception:
21
+ font = ImageFont.load_default()
22
+
23
+ # Tạo ảnh tạm để đo kích thước của text
24
+ temp_img = Image.new("RGB", (width, 100), color=bg_color)
25
+ draw = ImageDraw.Draw(temp_img)
26
+ # Ước tính chiều rộng của một ký tự (giả sử "A")
27
+ char_width, _ = draw.textsize("A", font=font)
28
+ # Số ký tự tối đa trên 1 dòng ước tính từ chiều rộng ảnh
29
+ max_chars = max(1, width // char_width)
30
+ # Tự động ngắt dòng theo số ký tự
31
+ lines = textwrap.wrap(text, width=max_chars)
32
+
33
+ # Tính tổng chiều cao cần dùng cho các dòng text
34
+ line_heights = []
35
+ for line in lines:
36
+ _, lh = draw.textsize(line, font=font)
37
+ line_heights.append(lh)
38
+ total_text_height = sum(line_heights)
39
+
40
+ # Nếu chiều cao được truyền vào không đủ, ta dùng chiều cao tối thiểu
41
+ if height is None or height < total_text_height + 20:
42
+ height = total_text_height + 20
43
+
44
+ # Tạo ảnh nền với kích thước (width x height)
45
+ img = Image.new("RGB", (width, height), color=bg_color)
46
+ draw = ImageDraw.Draw(img)
47
+ # Căn giữa theo chiều dọc: tính lề trên
48
+ y_text = (height - total_text_height) // 2
49
+ for line in lines:
50
+ line_width, line_height = draw.textsize(line, font=font)
51
+ # Căn giữa theo chiều ngang
52
+ x_text = (width - line_width) // 2
53
+ draw.text((x_text, y_text), line, font=font, fill=text_color)
54
+ y_text += line_height
55
+ return img
56
+
57
+
58
+ def render_math_image(text, font_size, width, height, bg_color, text_color):
59
+ """
60
+ Render văn bản chứa LaTeX (có dấu $ … $) thành ảnh bằng matplotlib.
61
+ Chúng ta dùng matplotlib để hiển thị công thức (mathtext) theo kiểu toán học.
62
+ """
63
+ dpi = 100
64
+ # Chuyển kích thước từ pixel sang inch (1 inch = dpi pixel)
65
+ fig_width = width / dpi
66
+ fig_height = height / dpi
67
+ fig = plt.figure(figsize=(fig_width, fig_height), dpi=dpi)
68
+ ax = plt.axes([0, 0, 1, 1])
69
+ ax.axis('off')
70
+ fig.patch.set_facecolor(bg_color)
71
+ # Dùng hàm text() với thuộc tính wrap=True và căn giữa
72
+ ax.text(0.5, 0.5, text, color=text_color, fontsize=font_size,
73
+ ha='center', va='center', wrap=True)
74
+ buf = BytesIO()
75
+ # Lưu figure vào bộ nhớ với một chút padding
76
+ plt.savefig(buf, format='png', bbox_inches='tight', pad_inches=0.1)
77
+ plt.close(fig)
78
+ buf.seek(0)
79
+ from PIL import Image
80
+ img = Image.open(buf)
81
+ return img
82
+
83
+
84
+ def text_to_image(file, text, font_size, width, height, bg_color, text_color):
85
+ """
86
+ 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
87
+ 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,
88
+ ngược lại dùng render_plain_text_image.
89
+ """
90
+ # Nếu file được upload, ưu tiên sử dụng nội dung file
91
+ if file is not None:
92
+ try:
93
+ # Trong Gradio, file đầu vào có thể là dict chứa key "name"
94
+ if isinstance(file, dict):
95
+ file_path = file["name"]
96
+ else:
97
+ file_path = file
98
+ with open(file_path, 'r', encoding='utf-8') as f:
99
+ text = f.read()
100
+ except Exception as e:
101
+ return f"Error reading file: {e}"
102
+ if not text:
103
+ return "Chưa có nội dung text được nhập!"
104
+
105
+ # Nếu phát hiện chuỗi LaTeX (có dấu $ … $) thì dùng mode math
106
+ if re.search(r'\$(.*?)\$', text):
107
+ return render_math_image(text, font_size, width, height, bg_color, text_color)
108
+ else:
109
+ return render_plain_text_image(text, font_size, width, height, bg_color, text_color)
110
+
111
+
112
+ # Xây dựng giao diện Gradio
113
+ iface = gr.Interface(
114
+ fn=text_to_image,
115
+ inputs=[
116
+ gr.File(label="Upload file chứa text (tùy chọn)"),
117
+ gr.Textbox(label="Nhập text", lines=10, placeholder="Nhập text của bạn tại đây..."),
118
+ gr.Slider(10, 100, step=1, value=20, label="Font Size"),
119
+ gr.Slider(200, 2000, step=10, value=800, label="Chiều rộng ảnh (pixel)"),
120
+ gr.Slider(100, 2000, step=10, value=600, label="Chiều cao ảnh (pixel)"),
121
+ gr.ColorPicker(value="#ffffff", label="Màu nền"),
122
+ gr.ColorPicker(value="#000000", label="Màu chữ")
123
+ ],
124
+ outputs=gr.Image(type="pil"),
125
+ title="Text-to-Image Converter",
126
+ description=(
127
+ "Upload một file chứa text hoặc nhập trực tiếp text. "
128
+ "Nếu text có chứa biểu thức LaTeX (ví dụ: $\\int_a^b f(x)dx$) "
129
+ "thì nó sẽ được render theo kiểu toán (math). "
130
+ "Các tuỳ chọn bên dưới cho phép bạn điều chỉnh đầu ra."
131
+ )
132
+ )
133
+
134
+ if __name__ == "__main__":
135
+ iface.launch()