ArrcttacsrjksX commited on
Commit
1f38be2
·
verified ·
1 Parent(s): 269d2c2

Upload app (7).py

Browse files
Files changed (1) hide show
  1. app (7).py +224 -0
app (7).py ADDED
@@ -0,0 +1,224 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import math
3
+ import textwrap
4
+ from io import BytesIO
5
+
6
+ import gradio as gr
7
+ import matplotlib.pyplot as plt
8
+ from PIL import Image, ImageDraw, ImageFont
9
+ from huggingface_hub import hf_hub_download
10
+
11
+ # --- Phần tải về CLI tool từ Hugging Face Hub ---
12
+ # Giả sử tên file CLI trong repo là "Texttoimage" (bạn có thể thay đổi nếu cần)
13
+ CLI_FILENAME = "Texttoimage"
14
+ if not os.path.exists(CLI_FILENAME):
15
+ hf_token = os.environ.get("HF_TOKEN")
16
+ if not hf_token:
17
+ print("Biến môi trường HF_TOKEN chưa được thiết lập!")
18
+ else:
19
+ try:
20
+ # Tải file CLI từ repo ArrcttacsrjksX/Texttoimage
21
+ cli_local_path = hf_hub_download(
22
+ repo_id="ArrcttacsrjksX/Texttoimage",
23
+ filename=CLI_FILENAME,
24
+ token=hf_token
25
+ )
26
+ # Di chuyển (hoặc đổi tên) file tải về nếu cần
27
+ os.rename(cli_local_path, CLI_FILENAME)
28
+ # Cho phép chạy được file CLI
29
+ os.chmod(CLI_FILENAME, 0o755)
30
+ print(f"Đã tải về CLI tool: {CLI_FILENAME}")
31
+ except Exception as e:
32
+ print(f"Lỗi khi tải CLI tool: {e}")
33
+
34
+ # --- Các hàm hỗ trợ render ảnh text ---
35
+
36
+ def parse_color(color: str):
37
+ """
38
+ Chuyển đổi chuỗi màu (hex hoặc RGB dạng "R,G,B") thành tuple RGB.
39
+ Ví dụ: "#FFEEEE" hoặc "255,238,238"
40
+ """
41
+ color = color.strip()
42
+ if color.startswith('#'):
43
+ color = color.lstrip('#')
44
+ if len(color) != 6:
45
+ raise ValueError("Mã hex phải có 6 ký tự.")
46
+ return tuple(int(color[i:i+2], 16) for i in (0, 2, 4))
47
+ else:
48
+ parts = color.split(',')
49
+ if len(parts) != 3:
50
+ raise ValueError("Màu dạng RGB phải có 3 thành phần cách nhau bởi dấu phẩy.")
51
+ return tuple(int(x) for x in parts)
52
+
53
+ def calculate_text_dimensions(text, font, max_width, margin):
54
+ """Tính toán kích thước text cho việc wrap theo chiều rộng cho trước."""
55
+ lines = []
56
+ for line in text.split('\n'):
57
+ # Sử dụng độ rộng ước tính dựa trên kích thước font
58
+ lines.extend(textwrap.wrap(line, width=int(max_width / font.size * 1.8)))
59
+
60
+ bbox = font.getbbox('Ay')
61
+ line_height = bbox[3] - bbox[1]
62
+ total_height = line_height * len(lines)
63
+
64
+ return lines, line_height, total_height
65
+
66
+ def create_text_segment(lines, start_idx, max_lines, width, height, bg_color, text_color, font, align, margin):
67
+ """Tạo một đoạn ảnh chứa một phần các dòng text."""
68
+ img = Image.new("RGB", (width, height), color=bg_color)
69
+ draw = ImageDraw.Draw(img)
70
+
71
+ bbox = font.getbbox('Ay')
72
+ line_height = bbox[3] - bbox[1]
73
+
74
+ y = margin
75
+ end_idx = min(start_idx + max_lines, len(lines))
76
+ segment_lines = lines[start_idx:end_idx]
77
+
78
+ for line in segment_lines:
79
+ bbox = font.getbbox(line)
80
+ line_width = bbox[2] - bbox[0]
81
+
82
+ if align == 'left':
83
+ x = margin
84
+ elif align == 'center':
85
+ x = (width - line_width) // 2
86
+ else: # 'right'
87
+ x = width - line_width - margin
88
+
89
+ draw.text((x, y), line, fill=text_color, font=font)
90
+ y += line_height
91
+
92
+ return img, end_idx
93
+
94
+ def render_plain_text_image(text, font_size, width, height, bg_color, text_color, font_path, align):
95
+ """Render ảnh chứa text dạng thông thường."""
96
+ margin = 10
97
+ try:
98
+ font = ImageFont.truetype(font_path, font_size)
99
+ except Exception:
100
+ print(f"Cảnh báo: Không tải được font {font_path}. Sử dụng font mặc định.")
101
+ font = ImageFont.load_default()
102
+
103
+ max_width = width - 2 * margin
104
+ lines, line_height, total_text_height = calculate_text_dimensions(text, font, max_width, margin)
105
+
106
+ max_lines_per_segment = (height - 2 * margin) // line_height
107
+ num_segments = math.ceil(len(lines) / max_lines_per_segment)
108
+
109
+ segments = []
110
+ current_line = 0
111
+ for _ in range(num_segments):
112
+ segment_img, current_line = create_text_segment(
113
+ lines, current_line, max_lines_per_segment,
114
+ width, height, bg_color, text_color, font, align, margin
115
+ )
116
+ segments.append(segment_img)
117
+
118
+ total_img_height = len(segments) * height
119
+ final_image = Image.new("RGB", (width, total_img_height), color=bg_color)
120
+ for i, segment in enumerate(segments):
121
+ final_image.paste(segment, (0, i * height))
122
+
123
+ return final_image
124
+
125
+ def render_math_image(text, font_size, width, height, bg_color, text_color):
126
+ """Render ảnh chứa biểu thức toán học sử dụng matplotlib."""
127
+ fig, ax = plt.subplots(figsize=(width / 100, height / 100), facecolor=bg_color)
128
+ ax.set_facecolor(bg_color)
129
+ ax.axis('off')
130
+
131
+ # Nếu text chưa được bọc trong dấu $, thêm vào
132
+ if not (text.startswith(r"$") and text.endswith(r"$")):
133
+ text = rf"${text}$"
134
+
135
+ ax.text(0.5, 0.5, text, fontsize=font_size, ha='center', va='center', color=text_color)
136
+
137
+ buf = BytesIO()
138
+ plt.savefig(buf, format='png', bbox_inches='tight', pad_inches=0)
139
+ plt.close(fig)
140
+ buf.seek(0)
141
+ img = Image.open(buf)
142
+ return img
143
+
144
+ # --- Hàm xử lý chính cho giao diện Gradio ---
145
+
146
+ def generate_image(text: str,
147
+ font_size: int,
148
+ width: int,
149
+ height: int,
150
+ bg_color: str,
151
+ text_color: str,
152
+ align: str,
153
+ mode: str,
154
+ font_path: str):
155
+ """
156
+ Hàm tạo ảnh từ text với các tham số đầu vào.
157
+ Nếu mode = "plain" thì render text bình thường,
158
+ nếu mode = "math" thì render biểu thức toán học.
159
+ """
160
+ try:
161
+ bg_color_tuple = parse_color(bg_color)
162
+ text_color_tuple = parse_color(text_color)
163
+ except Exception as e:
164
+ return f"Lỗi khi parse màu: {e}"
165
+
166
+ try:
167
+ if mode == "plain":
168
+ img = render_plain_text_image(
169
+ text, font_size, width, height,
170
+ bg_color_tuple, text_color_tuple, font_path, align
171
+ )
172
+ else:
173
+ img = render_math_image(
174
+ text, font_size, width, height,
175
+ bg_color_tuple, text_color_tuple
176
+ )
177
+ except Exception as e:
178
+ return f"Lỗi khi tạo ảnh: {e}"
179
+
180
+ return img
181
+
182
+ # --- Tạo giao diện Gradio ---
183
+
184
+ # Các widget đầu vào
185
+ text_input = gr.Textbox(label="Text cần chuyển", placeholder="Nhập text của bạn vào đây...", lines=4)
186
+ font_size_input = gr.Slider(10, 100, value=40, step=1, label="Cỡ chữ (font size)")
187
+ width_input = gr.Number(value=1000, label="Chiều rộng ảnh (px)")
188
+ height_input = gr.Number(value=800, label="Chiều cao ảnh (px)")
189
+ bg_color_input = gr.Textbox(value="#FFEEEE", label="Màu nền (hex hoặc R,G,B)")
190
+ text_color_input = gr.Textbox(value="#000066", label="Màu chữ (hex hoặc R,G,B)")
191
+ align_input = gr.Radio(choices=["left", "center", "right"], value="right", label="Căn chỉnh text")
192
+ mode_input = gr.Radio(choices=["plain", "math"], value="plain", label="Chế độ render")
193
+ font_path_input = gr.Textbox(value="/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", label="Đường dẫn font")
194
+
195
+ # Một số CSS tùy chỉnh để làm đẹp giao diện
196
+ custom_css = """
197
+ body {
198
+ background: linear-gradient(135deg, #f6d365 0%, #fda085 100%);
199
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
200
+ }
201
+ .gradio-container {
202
+ border-radius: 15px;
203
+ box-shadow: 0 4px 10px rgba(0,0,0,0.2);
204
+ padding: 20px;
205
+ background-color: rgba(255, 255, 255, 0.9);
206
+ }
207
+ """
208
+
209
+ # Xây dựng giao diện Gradio
210
+ demo = gr.Interface(
211
+ fn=generate_image,
212
+ inputs=[text_input, font_size_input, width_input, height_input,
213
+ bg_color_input, text_color_input, align_input, mode_input, font_path_input],
214
+ outputs=gr.Image(type="pil", label="Ảnh được tạo"),
215
+ title="Text to Image - Texttoimage CLI",
216
+ description=("Giao diện demo chuyển text thành ảnh. "
217
+ "Bạn có thể nhập text, chọn các tham số như kích thước, màu sắc, căn chỉnh, "
218
+ "và xem ảnh được render theo thời gian thực."),
219
+ css=custom_css,
220
+ allow_flagging="never"
221
+ )
222
+
223
+ if __name__ == "__main__":
224
+ demo.launch()