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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +69 -201
app.py CHANGED
@@ -1,15 +1,9 @@
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")
@@ -17,208 +11,82 @@ if not os.path.exists(CLI_FILENAME):
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
- 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()
 
1
  import os
2
+ import subprocess
 
 
 
3
  import gradio as gr
 
 
4
  from huggingface_hub import hf_hub_download
5
 
6
+ # --- Tải về CLI tool từ Hugging Face Hub ---
 
7
  CLI_FILENAME = "Texttoimage"
8
  if not os.path.exists(CLI_FILENAME):
9
  hf_token = os.environ.get("HF_TOKEN")
 
11
  print("Biến môi trường HF_TOKEN chưa được thiết lập!")
12
  else:
13
  try:
 
14
  cli_local_path = hf_hub_download(
15
  repo_id="ArrcttacsrjksX/Texttoimage",
16
  filename=CLI_FILENAME,
17
  token=hf_token
18
  )
 
19
  os.rename(cli_local_path, CLI_FILENAME)
 
20
  os.chmod(CLI_FILENAME, 0o755)
21
  print(f"Đã tải về CLI tool: {CLI_FILENAME}")
22
  except Exception as e:
23
  print(f"Lỗi khi tải CLI tool: {e}")
24
 
25
+ # --- Cấu hình giao diện Gradio ---
26
+ font_list = ["Arial", "Times New Roman", "Courier New", "Comic Sans MS", "Verdana"]
27
+ default_font = "Arial"
28
+
29
+ def text_to_image(text, font_size, width, height, bg_color, text_color, mode, font_name, align, image_format):
30
+ if not os.path.exists(CLI_FILENAME):
31
+ return "Lỗi: Không tìm thấy Texttoimage. Vui lòng kiểm tra lại."
32
+
33
+ command = [
34
+ f"./{CLI_FILENAME}",
35
+ "--text", text,
36
+ "--font-size", str(font_size),
37
+ "--width", str(width),
38
+ "--height", str(height),
39
+ "--bg-color", bg_color,
40
+ "--text-color", text_color,
41
+ "--mode", mode.lower(),
42
+ "--font", font_name,
43
+ "--align", align.lower(),
44
+ "--format", image_format.lower()
45
+ ]
46
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
  try:
48
+ output_path = "output_image.png" if image_format == "PNG" else "output_image.jpg"
49
+ command.extend(["--output", output_path])
50
+
51
+ subprocess.run(command, check=True)
52
+ return output_path
53
+ except subprocess.CalledProcessError as e:
54
+ return f"Lỗi khi chạy Texttoimage: {e}"
55
+
56
+ with gr.Blocks() as demo:
57
+ gr.Markdown("# 🖼️ Text to Image Converter")
58
+
59
+ with gr.Row():
60
+ input_text = gr.Textbox(label="Enter Text", placeholder="Type or paste text here...", lines=5)
61
+ file_input = gr.File(label="Upload a Text File", type="filepath")
62
+
63
+ with gr.Row():
64
+ font_size = gr.Slider(10, 100, value=30, label="Font Size")
65
+ font_name = gr.Dropdown(choices=font_list, value=default_font, label="Font")
66
+ align = gr.Radio(["Left", "Center", "Right"], label="Text Alignment", value="Center")
67
+
68
+ with gr.Row():
69
+ width = gr.Slider(200, 2000, value=800, label="Image Width")
70
+ height = gr.Slider(200, 2000, value=600, label="Base Height")
71
+
72
+ with gr.Row():
73
+ bg_color = gr.ColorPicker(label="Background Color", value="#FFFFFF")
74
+ text_color = gr.ColorPicker(label="Text Color", value="#000000")
75
+
76
+ with gr.Row():
77
+ mode = gr.Radio(["Plain Text", "LaTeX Math"], label="Rendering Mode", value="Plain Text")
78
+ image_format = gr.Radio(["PNG", "JPEG"], label="Image Format", value="PNG")
79
+
80
+ output_image = gr.Image(label="Generated Image")
81
+
82
+ with gr.Row():
83
+ convert_button = gr.Button("Convert Text to Image")
84
+ file_convert_button = gr.Button("Convert File to Image")
85
+
86
+ convert_button.click(
87
+ text_to_image,
88
+ inputs=[input_text, font_size, width, height, bg_color, text_color, mode, font_name, align, image_format],
89
+ outputs=output_image
90
+ )
91
+
92
+ demo.launch()