ArrcttacsrjksX commited on
Commit
3778796
·
verified ·
1 Parent(s): cff3d37

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +92 -113
app.py CHANGED
@@ -1,135 +1,114 @@
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 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 ( 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 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()
 
1
  import gradio as gr
2
+ import matplotlib.pyplot as plt
 
3
  from io import BytesIO
 
 
4
  from PIL import Image, ImageDraw, ImageFont
 
5
 
6
+ # Function to parse color
7
+ def parse_color(color):
8
+ """Convert RGBA string to RGB tuple if necessary."""
9
+ if isinstance(color, str) and color.startswith('rgba'):
10
+ color = color.replace('rgba', '').strip('()').split(',')
11
+ return tuple(int(float(c)) for c in color[:3]) # Convert to (R, G, B)
12
+ return color # If already valid, return as is
13
 
14
+ # Function to render plain text as an image
15
  def render_plain_text_image(text, font_size, width, height, bg_color, text_color):
16
+ """Convert plain text to an image with the given parameters."""
17
+ bg_color = parse_color(bg_color)
18
+ text_color = parse_color(text_color)
19
+
20
+ # Create blank image
21
+ img = Image.new("RGB", (width, height), color=bg_color)
22
+ draw = ImageDraw.Draw(img)
23
+
24
+ # Load font (default system font)
25
  try:
26
  font = ImageFont.truetype("arial.ttf", font_size)
27
+ except:
28
  font = ImageFont.load_default()
29
 
30
+ # Get text size
31
+ text_width, text_height = draw.textsize(text, font=font)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
 
33
+ # Position text in center
34
+ x = (width - text_width) // 2
35
+ y = (height - text_height) // 2
36
 
37
+ draw.text((x, y), text, fill=text_color, font=font)
38
+
39
+ return img
40
+
41
+ # Function to render math (LaTeX) as an image
42
  def render_math_image(text, font_size, width, height, bg_color, text_color):
43
+ """Convert LaTeX-formatted text to an image."""
44
+ fig, ax = plt.subplots(figsize=(width / 100, height / 100))
45
+ ax.set_axis_off()
46
+
47
+ # Ensure LaTeX formatting is correct
48
+ if "$" in text:
49
+ text = rf"{text}"
50
+
51
+ ax.text(0.5, 0.5, text, fontsize=font_size, ha='center', va='center', color=text_color)
52
+
 
 
 
 
 
53
  buf = BytesIO()
 
54
  plt.savefig(buf, format='png', bbox_inches='tight', pad_inches=0.1)
55
  plt.close(fig)
56
+
57
  buf.seek(0)
58
+ return Image.open(buf)
 
 
59
 
60
+ # Main function to handle input
61
+ def text_to_image(input_text, font_size, width, height, bg_color, text_color, mode):
62
+ """Determine whether to use plain text or LaTeX rendering."""
63
+ if mode == "Plain Text":
64
+ return render_plain_text_image(input_text, font_size, width, height, bg_color, text_color)
65
+ elif mode == "LaTeX Math":
66
+ return render_math_image(input_text, font_size, width, height, bg_color, text_color)
67
+ else:
68
+ return "Invalid mode selected!"
69
 
70
+ # Function to handle file upload
71
+ def handle_file_upload(file, font_size, width, height, bg_color, text_color, mode):
72
+ """Extract text from file and convert to an image."""
 
 
 
 
73
  if file is not None:
74
+ text = file.read().decode("utf-8") # Read and decode text file
75
+ return text_to_image(text, font_size, width, height, bg_color, text_color, mode)
76
+ return "No file uploaded!"
77
+
78
+ # Gradio Interface
79
+ with gr.Blocks() as demo:
80
+ gr.Markdown("# 🖼️ Text to Image Converter")
81
+
82
+ with gr.Row():
83
+ input_text = gr.Textbox(label="Enter Text", placeholder="Type or paste text here...")
84
+ file_input = gr.File(label="Upload a Text File", type="file")
85
+
86
+ with gr.Row():
87
+ font_size = gr.Slider(10, 100, value=30, label="Font Size")
88
+ width = gr.Slider(200, 1000, value=500, label="Image Width")
89
+ height = gr.Slider(200, 1000, value=300, label="Image Height")
90
+
91
+ with gr.Row():
92
+ bg_color = gr.ColorPicker(label="Background Color", value="#FFFFFF")
93
+ text_color = gr.ColorPicker(label="Text Color", value="#000000")
94
+
95
+ mode = gr.Radio(["Plain Text", "LaTeX Math"], label="Rendering Mode", value="Plain Text")
96
+
97
+ output_image = gr.Image(label="Generated Image")
98
+
99
+ convert_button = gr.Button("Convert Text to Image")
100
+ file_convert_button = gr.Button("Convert File to Image")
101
+
102
+ convert_button.click(
103
+ text_to_image,
104
+ inputs=[input_text, font_size, width, height, bg_color, text_color, mode],
105
+ outputs=output_image
106
+ )
107
+
108
+ file_convert_button.click(
109
+ handle_file_upload,
110
+ inputs=[file_input, font_size, width, height, bg_color, text_color, mode],
111
+ outputs=output_image
 
112
  )
 
113
 
114
+ demo.launch()