Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -1,6 +1,5 @@
|
|
1 |
import os
|
2 |
import gradio as gr
|
3 |
-
import tempfile
|
4 |
from PIL import Image, ImageDraw, ImageFont
|
5 |
|
6 |
# --- Image Generation Logic (from coverter.py) ---
|
@@ -28,8 +27,8 @@ def draw_lattice_grid(draw, width, height, spacing=100, color=(235, 235, 235)):
|
|
28 |
|
29 |
def text_to_images_generator(text_content, style='lines', font_path=None):
|
30 |
"""
|
31 |
-
Converts a given string of text into a series of images and returns
|
32 |
-
|
33 |
|
34 |
Args:
|
35 |
text_content (str): The text to be converted.
|
@@ -37,7 +36,7 @@ def text_to_images_generator(text_content, style='lines', font_path=None):
|
|
37 |
font_path (str, optional): The path to a .ttf font file.
|
38 |
|
39 |
Returns:
|
40 |
-
list: A list of
|
41 |
"""
|
42 |
if not text_content or not text_content.strip():
|
43 |
# Return empty list and show a warning if there is no text
|
@@ -57,17 +56,12 @@ def text_to_images_generator(text_content, style='lines', font_path=None):
|
|
57 |
FONT_SIZE = 48
|
58 |
LINE_SPACING = 20
|
59 |
|
60 |
-
# Create a temporary directory to save images for the Gradio gallery
|
61 |
-
output_dir = tempfile.mkdtemp()
|
62 |
-
|
63 |
# --- Font Loading ---
|
64 |
font = None
|
65 |
try:
|
66 |
-
# Prioritize provided font path if it exists
|
67 |
if font_path and os.path.exists(font_path):
|
68 |
font = ImageFont.truetype(font_path, FONT_SIZE)
|
69 |
else:
|
70 |
-
# Otherwise, search for common system fonts
|
71 |
font_paths_to_try = [
|
72 |
"Arial.ttf", "arial.ttf", "DejaVuSans.ttf",
|
73 |
"/System/Library/Fonts/Supplemental/Arial.ttf",
|
@@ -80,9 +74,8 @@ def text_to_images_generator(text_content, style='lines', font_path=None):
|
|
80 |
break
|
81 |
except IOError:
|
82 |
continue
|
83 |
-
# Fallback to default if no font is found
|
84 |
if not font:
|
85 |
-
gr.Warning("Could not find a standard .ttf font. Falling back to the basic default font.
|
86 |
font = ImageFont.load_default()
|
87 |
except Exception as e:
|
88 |
print(f"An unexpected error occurred during font loading: {e}")
|
@@ -97,7 +90,6 @@ def text_to_images_generator(text_content, style='lines', font_path=None):
|
|
97 |
words = paragraph.split()
|
98 |
current_line = ""
|
99 |
for word in words:
|
100 |
-
# Handle very long words by breaking them up
|
101 |
if font.getlength(word) > drawable_width:
|
102 |
temp_word = ""
|
103 |
for char in word:
|
@@ -115,31 +107,26 @@ def text_to_images_generator(text_content, style='lines', font_path=None):
|
|
115 |
current_line = word
|
116 |
all_lines_and_breaks.append(current_line.strip())
|
117 |
|
118 |
-
# Add a placeholder for paragraph breaks
|
119 |
if i < len(paragraphs) - 1:
|
120 |
all_lines_and_breaks.append(None)
|
121 |
|
122 |
# --- Image Generation ---
|
123 |
-
|
124 |
-
img_count = 0
|
125 |
page_content = []
|
126 |
y_text = PADDING_Y
|
127 |
|
128 |
try:
|
129 |
-
# Get line height from font metrics if possible
|
130 |
line_height = font.getbbox("A")[3] - font.getbbox("A")[1]
|
131 |
except AttributeError:
|
132 |
-
# Fallback for default font
|
133 |
line_height = 12
|
134 |
|
135 |
PARAGRAPH_SPACING = line_height
|
136 |
|
137 |
-
def create_image_page(content
|
138 |
-
"""Helper function to create
|
139 |
img = Image.new('RGB', (IMG_WIDTH, IMG_HEIGHT), color=BACKGROUND_COLOR)
|
140 |
draw = ImageDraw.Draw(img)
|
141 |
|
142 |
-
# Draw the selected background style first
|
143 |
if style == 'lines':
|
144 |
line_style_spacing = line_height + LINE_SPACING
|
145 |
draw_horizontal_lines(draw, IMG_WIDTH, IMG_HEIGHT, spacing=line_style_spacing, color=STYLE_COLOR)
|
@@ -148,50 +135,39 @@ def text_to_images_generator(text_content, style='lines', font_path=None):
|
|
148 |
elif style == 'grid':
|
149 |
draw_lattice_grid(draw, IMG_WIDTH, IMG_HEIGHT, color=STYLE_COLOR)
|
150 |
|
151 |
-
# Draw the text on top of the background
|
152 |
current_y = PADDING_Y
|
153 |
for page_item in content:
|
154 |
if page_item is not None:
|
155 |
draw.text((PADDING_X, current_y), page_item, font=font, fill=TEXT_COLOR)
|
156 |
current_y += line_height + LINE_SPACING
|
157 |
-
else:
|
158 |
current_y += PARAGRAPH_SPACING
|
159 |
|
160 |
-
|
161 |
-
img.save(filename)
|
162 |
-
generated_files.append(filename)
|
163 |
|
164 |
-
# Iterate through all lines and create pages
|
165 |
for item in all_lines_and_breaks:
|
166 |
is_break = item is None
|
167 |
item_height = PARAGRAPH_SPACING if is_break else line_height
|
168 |
|
169 |
-
# If adding the next line/break exceeds page height, create the current page
|
170 |
if y_text + item_height > IMG_HEIGHT - PADDING_Y:
|
171 |
-
|
172 |
-
create_image_page(page_content, img_count)
|
173 |
-
# Start a new page
|
174 |
page_content = [item]
|
175 |
y_text = PADDING_Y + item_height + (0 if is_break else LINE_SPACING)
|
176 |
else:
|
177 |
page_content.append(item)
|
178 |
y_text += item_height + (0 if is_break else LINE_SPACING)
|
179 |
|
180 |
-
# Save the last page if it has content
|
181 |
if page_content:
|
182 |
-
|
183 |
-
create_image_page(page_content, img_count)
|
184 |
|
185 |
-
return
|
186 |
|
187 |
# --- Gradio Interface ---
|
188 |
|
189 |
-
# Example text to pre-fill the textbox
|
190 |
example_text = """In the heart of a bustling city, there lived a clockmaker named Alistair. His shop, a quaint corner of tranquility amidst the urban chaos, was filled with the gentle ticking of countless timepieces. Each clock was a masterpiece, a testament to his dedication and skill.
|
191 |
|
192 |
One day, a young girl with eyes as curious as a cat's wandered into his shop. She wasn't interested in the shiny new watches but was drawn to the grandfather clock in the corner. "What's its story?" she asked, her voice soft. Alistair smiled, for he knew he had found the next guardian of the stories. The legacy of the whispering clock would live on."""
|
193 |
|
194 |
-
# Define the Gradio interface
|
195 |
demo = gr.Interface(
|
196 |
fn=text_to_images_generator,
|
197 |
inputs=[
|
@@ -206,6 +182,4 @@ demo = gr.Interface(
|
|
206 |
|
207 |
# --- Main Execution ---
|
208 |
if __name__ == "__main__":
|
209 |
-
# Launch the Gradio app as an MCP server
|
210 |
-
# The MCP server allows other applications to call this Gradio app as an API
|
211 |
demo.launch(mcp_server=True)
|
|
|
1 |
import os
|
2 |
import gradio as gr
|
|
|
3 |
from PIL import Image, ImageDraw, ImageFont
|
4 |
|
5 |
# --- Image Generation Logic (from coverter.py) ---
|
|
|
27 |
|
28 |
def text_to_images_generator(text_content, style='lines', font_path=None):
|
29 |
"""
|
30 |
+
Converts a given string of text into a series of images and returns them
|
31 |
+
as a list of PIL Image objects. This is compatible with both UI and MCP.
|
32 |
|
33 |
Args:
|
34 |
text_content (str): The text to be converted.
|
|
|
36 |
font_path (str, optional): The path to a .ttf font file.
|
37 |
|
38 |
Returns:
|
39 |
+
list: A list of PIL.Image.Image objects.
|
40 |
"""
|
41 |
if not text_content or not text_content.strip():
|
42 |
# Return empty list and show a warning if there is no text
|
|
|
56 |
FONT_SIZE = 48
|
57 |
LINE_SPACING = 20
|
58 |
|
|
|
|
|
|
|
59 |
# --- Font Loading ---
|
60 |
font = None
|
61 |
try:
|
|
|
62 |
if font_path and os.path.exists(font_path):
|
63 |
font = ImageFont.truetype(font_path, FONT_SIZE)
|
64 |
else:
|
|
|
65 |
font_paths_to_try = [
|
66 |
"Arial.ttf", "arial.ttf", "DejaVuSans.ttf",
|
67 |
"/System/Library/Fonts/Supplemental/Arial.ttf",
|
|
|
74 |
break
|
75 |
except IOError:
|
76 |
continue
|
|
|
77 |
if not font:
|
78 |
+
gr.Warning("Could not find a standard .ttf font. Falling back to the basic default font.")
|
79 |
font = ImageFont.load_default()
|
80 |
except Exception as e:
|
81 |
print(f"An unexpected error occurred during font loading: {e}")
|
|
|
90 |
words = paragraph.split()
|
91 |
current_line = ""
|
92 |
for word in words:
|
|
|
93 |
if font.getlength(word) > drawable_width:
|
94 |
temp_word = ""
|
95 |
for char in word:
|
|
|
107 |
current_line = word
|
108 |
all_lines_and_breaks.append(current_line.strip())
|
109 |
|
|
|
110 |
if i < len(paragraphs) - 1:
|
111 |
all_lines_and_breaks.append(None)
|
112 |
|
113 |
# --- Image Generation ---
|
114 |
+
generated_images = [] # Store PIL Image objects directly
|
|
|
115 |
page_content = []
|
116 |
y_text = PADDING_Y
|
117 |
|
118 |
try:
|
|
|
119 |
line_height = font.getbbox("A")[3] - font.getbbox("A")[1]
|
120 |
except AttributeError:
|
|
|
121 |
line_height = 12
|
122 |
|
123 |
PARAGRAPH_SPACING = line_height
|
124 |
|
125 |
+
def create_image_page(content):
|
126 |
+
"""Helper function to create a single image page and return it."""
|
127 |
img = Image.new('RGB', (IMG_WIDTH, IMG_HEIGHT), color=BACKGROUND_COLOR)
|
128 |
draw = ImageDraw.Draw(img)
|
129 |
|
|
|
130 |
if style == 'lines':
|
131 |
line_style_spacing = line_height + LINE_SPACING
|
132 |
draw_horizontal_lines(draw, IMG_WIDTH, IMG_HEIGHT, spacing=line_style_spacing, color=STYLE_COLOR)
|
|
|
135 |
elif style == 'grid':
|
136 |
draw_lattice_grid(draw, IMG_WIDTH, IMG_HEIGHT, color=STYLE_COLOR)
|
137 |
|
|
|
138 |
current_y = PADDING_Y
|
139 |
for page_item in content:
|
140 |
if page_item is not None:
|
141 |
draw.text((PADDING_X, current_y), page_item, font=font, fill=TEXT_COLOR)
|
142 |
current_y += line_height + LINE_SPACING
|
143 |
+
else:
|
144 |
current_y += PARAGRAPH_SPACING
|
145 |
|
146 |
+
generated_images.append(img) # Add the PIL image to our list
|
|
|
|
|
147 |
|
|
|
148 |
for item in all_lines_and_breaks:
|
149 |
is_break = item is None
|
150 |
item_height = PARAGRAPH_SPACING if is_break else line_height
|
151 |
|
|
|
152 |
if y_text + item_height > IMG_HEIGHT - PADDING_Y:
|
153 |
+
create_image_page(page_content)
|
|
|
|
|
154 |
page_content = [item]
|
155 |
y_text = PADDING_Y + item_height + (0 if is_break else LINE_SPACING)
|
156 |
else:
|
157 |
page_content.append(item)
|
158 |
y_text += item_height + (0 if is_break else LINE_SPACING)
|
159 |
|
|
|
160 |
if page_content:
|
161 |
+
create_image_page(page_content)
|
|
|
162 |
|
163 |
+
return generated_images
|
164 |
|
165 |
# --- Gradio Interface ---
|
166 |
|
|
|
167 |
example_text = """In the heart of a bustling city, there lived a clockmaker named Alistair. His shop, a quaint corner of tranquility amidst the urban chaos, was filled with the gentle ticking of countless timepieces. Each clock was a masterpiece, a testament to his dedication and skill.
|
168 |
|
169 |
One day, a young girl with eyes as curious as a cat's wandered into his shop. She wasn't interested in the shiny new watches but was drawn to the grandfather clock in the corner. "What's its story?" she asked, her voice soft. Alistair smiled, for he knew he had found the next guardian of the stories. The legacy of the whispering clock would live on."""
|
170 |
|
|
|
171 |
demo = gr.Interface(
|
172 |
fn=text_to_images_generator,
|
173 |
inputs=[
|
|
|
182 |
|
183 |
# --- Main Execution ---
|
184 |
if __name__ == "__main__":
|
|
|
|
|
185 |
demo.launch(mcp_server=True)
|