Update app.py
Browse files
app.py
CHANGED
@@ -17,10 +17,9 @@ st.set_page_config(layout="wide", initial_sidebar_state="collapsed")
|
|
17 |
def create_pdf_tab(default_markdown):
|
18 |
# Dynamically load all .ttf fonts from the current directory
|
19 |
# Fonts are sourced from: https://fonts.google.com/download/next-steps
|
20 |
-
# We use glob to find all .ttf files, making the font list dynamic instead of hardcoded.
|
21 |
font_files = glob.glob("*.ttf")
|
22 |
if not font_files:
|
23 |
-
st.error("No .ttf font files found in the current directory. Please add some, e.g., NotoColorEmoji-Regular.ttf.")
|
24 |
return
|
25 |
available_fonts = {os.path.splitext(os.path.basename(f))[0]: f for f in font_files}
|
26 |
|
@@ -28,12 +27,11 @@ def create_pdf_tab(default_markdown):
|
|
28 |
with st.sidebar:
|
29 |
selected_font_name = st.selectbox("Select Font", options=list(available_fonts.keys()), index=0 if "NotoColorEmoji-Regular" in available_fonts else 0)
|
30 |
selected_font_path = available_fonts[selected_font_name]
|
31 |
-
base_font_size = st.slider("Font Size (points)", min_value=6, max_value=16, value=9, step=1)
|
32 |
plain_text_mode = st.checkbox("Render as Plain Text (Preserve Bold Only)", value=False)
|
33 |
auto_bold_numbers = st.checkbox("Auto-Bold Numbered Lines", value=False)
|
34 |
-
num_columns = st.selectbox("Number of Columns", options=[1, 2, 3, 4, 5, 6], index=3)
|
35 |
|
36 |
-
# Markdown editor and buttons
|
37 |
if 'markdown_content' not in st.session_state:
|
38 |
st.session_state.markdown_content = default_markdown
|
39 |
|
@@ -44,16 +42,18 @@ def create_pdf_tab(default_markdown):
|
|
44 |
|
45 |
st.download_button(label="Save Markdown", data=st.session_state.markdown_content, file_name="deities_guide.md", mime="text/markdown")
|
46 |
|
47 |
-
# Register the selected font
|
48 |
-
#
|
49 |
-
|
|
|
|
|
|
|
|
|
|
|
50 |
|
51 |
-
# Emoji font application
|
52 |
-
#
|
53 |
-
#
|
54 |
-
# To avoid multi-character emoji issues (e.g., base char + variation selector U+FE0F), we limit to the first character.
|
55 |
-
# Noto Color Emoji (NotoColorEmoji-Regular.ttf) is recommended as it supports a full range of modern emojis,
|
56 |
-
# including color rendering, though ReportLab renders in black-and-white by default.
|
57 |
def apply_emoji_font(text, emoji_font):
|
58 |
emoji_pattern = re.compile(
|
59 |
r"([\U0001F300-\U0001F5FF" # Miscellaneous Symbols and Pictographs
|
@@ -71,16 +71,13 @@ def create_pdf_tab(default_markdown):
|
|
71 |
)
|
72 |
def replace_emoji(match):
|
73 |
emoji = match.group(1)
|
74 |
-
# Limit to first character to avoid
|
75 |
-
# Example: ✝️ (U+271D U+FE0F) becomes just ✝ (U+271D), dropping the variation selector
|
76 |
-
if len(emoji) > 1:
|
77 |
emoji = emoji[0]
|
|
|
78 |
return f'<font face="{emoji_font}">{emoji}</font>'
|
79 |
return emoji_pattern.sub(replace_emoji, text)
|
80 |
|
81 |
-
#
|
82 |
-
# This function processes markdown lines, filtering out headers and applying bolding rules.
|
83 |
-
# If auto_bold_numbers is True, lines starting with "number. " (e.g., "1. ") are bolded.
|
84 |
def markdown_to_pdf_content(markdown_text, plain_text_mode, auto_bold_numbers):
|
85 |
lines = markdown_text.strip().split('\n')
|
86 |
pdf_content = []
|
@@ -111,10 +108,6 @@ def create_pdf_tab(default_markdown):
|
|
111 |
return pdf_content, total_lines
|
112 |
|
113 |
# Create PDF
|
114 |
-
# This function builds a PDF using ReportLab, arranging content in columns.
|
115 |
-
# We use a double A4 landscape layout (A4 width * 2) for wide content.
|
116 |
-
# Spacers are added before numbered sections for visual separation.
|
117 |
-
# Paragraph styles define font sizes and bolding, with emojis rendered via the selected font.
|
118 |
def create_pdf(markdown_text, base_font_size, plain_text_mode, num_columns, auto_bold_numbers):
|
119 |
buffer = io.BytesIO()
|
120 |
page_width = A4[0] * 2
|
@@ -129,6 +122,7 @@ def create_pdf_tab(default_markdown):
|
|
129 |
item_font_size = base_font_size
|
130 |
section_font_size = base_font_size * 1.1
|
131 |
|
|
|
132 |
section_style = ParagraphStyle(
|
133 |
'SectionStyle', parent=styles['Heading2'], fontName="Helvetica-Bold",
|
134 |
textColor=colors.darkblue, fontSize=section_font_size, leading=section_font_size * 1.2, spaceAfter=2
|
@@ -186,8 +180,7 @@ def create_pdf_tab(default_markdown):
|
|
186 |
buffer.seek(0)
|
187 |
return buffer.getvalue()
|
188 |
|
189 |
-
#
|
190 |
-
# Uses PyMuPDF (fitz) to render PDF pages as images for Streamlit display.
|
191 |
def pdf_to_image(pdf_bytes):
|
192 |
try:
|
193 |
doc = fitz.open(stream=pdf_bytes, filetype="pdf")
|
@@ -245,7 +238,7 @@ default_markdown = """# Deities Guide: Mythology and Moral Lessons 🌟
|
|
245 |
|
246 |
5. 🌠 Ascension and Signs
|
247 |
- Paths: Birth, deeds, revelation, as with Jesus and Arjuna.
|
248 |
-
- Signs: Miracles and prophecies, like those in the Quran and Gita
|
249 |
- Morals: Obedience and devotion shape destiny.
|
250 |
|
251 |
6. 🎲 Storytelling and Games
|
|
|
17 |
def create_pdf_tab(default_markdown):
|
18 |
# Dynamically load all .ttf fonts from the current directory
|
19 |
# Fonts are sourced from: https://fonts.google.com/download/next-steps
|
|
|
20 |
font_files = glob.glob("*.ttf")
|
21 |
if not font_files:
|
22 |
+
st.error("No .ttf font files found in the current directory. Please add some, e.g., NotoColorEmoji-Regular.ttf or NotoEmoji-Regular.ttf.")
|
23 |
return
|
24 |
available_fonts = {os.path.splitext(os.path.basename(f))[0]: f for f in font_files}
|
25 |
|
|
|
27 |
with st.sidebar:
|
28 |
selected_font_name = st.selectbox("Select Font", options=list(available_fonts.keys()), index=0 if "NotoColorEmoji-Regular" in available_fonts else 0)
|
29 |
selected_font_path = available_fonts[selected_font_name]
|
30 |
+
base_font_size = st.slider("Font Size (points)", min_value=6, max_value=16, value=9, step=1)
|
31 |
plain_text_mode = st.checkbox("Render as Plain Text (Preserve Bold Only)", value=False)
|
32 |
auto_bold_numbers = st.checkbox("Auto-Bold Numbered Lines", value=False)
|
33 |
+
num_columns = st.selectbox("Number of Columns", options=[1, 2, 3, 4, 5, 6], index=3)
|
34 |
|
|
|
35 |
if 'markdown_content' not in st.session_state:
|
36 |
st.session_state.markdown_content = default_markdown
|
37 |
|
|
|
42 |
|
43 |
st.download_button(label="Save Markdown", data=st.session_state.markdown_content, file_name="deities_guide.md", mime="text/markdown")
|
44 |
|
45 |
+
# Register the selected font
|
46 |
+
# Noto Color Emoji is a color font, which ReportLab may not render correctly (monochrome only).
|
47 |
+
# If emojis don’t show, try a monochrome font like NotoEmoji-Regular.ttf as a fallback.
|
48 |
+
try:
|
49 |
+
pdfmetrics.registerFont(TTFont(selected_font_name, selected_font_path))
|
50 |
+
except Exception as e:
|
51 |
+
st.error(f"Failed to register font {selected_font_name}: {e}")
|
52 |
+
return
|
53 |
|
54 |
+
# Emoji font application
|
55 |
+
# We apply the selected font to emojis, falling back to plain text if the font doesn’t support them.
|
56 |
+
# ReportLab needs explicit font tagging for emojis; Noto Color Emoji may need special handling.
|
|
|
|
|
|
|
57 |
def apply_emoji_font(text, emoji_font):
|
58 |
emoji_pattern = re.compile(
|
59 |
r"([\U0001F300-\U0001F5FF" # Miscellaneous Symbols and Pictographs
|
|
|
71 |
)
|
72 |
def replace_emoji(match):
|
73 |
emoji = match.group(1)
|
74 |
+
if len(emoji) > 1: # Limit to first character to avoid multi-codepoint issues
|
|
|
|
|
75 |
emoji = emoji[0]
|
76 |
+
# Wrap emoji in font tag; if it doesn’t render, it’ll show as text
|
77 |
return f'<font face="{emoji_font}">{emoji}</font>'
|
78 |
return emoji_pattern.sub(replace_emoji, text)
|
79 |
|
80 |
+
# Markdown to PDF content
|
|
|
|
|
81 |
def markdown_to_pdf_content(markdown_text, plain_text_mode, auto_bold_numbers):
|
82 |
lines = markdown_text.strip().split('\n')
|
83 |
pdf_content = []
|
|
|
108 |
return pdf_content, total_lines
|
109 |
|
110 |
# Create PDF
|
|
|
|
|
|
|
|
|
111 |
def create_pdf(markdown_text, base_font_size, plain_text_mode, num_columns, auto_bold_numbers):
|
112 |
buffer = io.BytesIO()
|
113 |
page_width = A4[0] * 2
|
|
|
122 |
item_font_size = base_font_size
|
123 |
section_font_size = base_font_size * 1.1
|
124 |
|
125 |
+
# Use Helvetica as a fallback for text, emoji font for emojis
|
126 |
section_style = ParagraphStyle(
|
127 |
'SectionStyle', parent=styles['Heading2'], fontName="Helvetica-Bold",
|
128 |
textColor=colors.darkblue, fontSize=section_font_size, leading=section_font_size * 1.2, spaceAfter=2
|
|
|
180 |
buffer.seek(0)
|
181 |
return buffer.getvalue()
|
182 |
|
183 |
+
# PDF to image
|
|
|
184 |
def pdf_to_image(pdf_bytes):
|
185 |
try:
|
186 |
doc = fitz.open(stream=pdf_bytes, filetype="pdf")
|
|
|
238 |
|
239 |
5. 🌠 Ascension and Signs
|
240 |
- Paths: Birth, deeds, revelation, as with Jesus and Arjuna.
|
241 |
+
- Signs: Miracles and prophecies, like those in the Quran and Gita.
|
242 |
- Morals: Obedience and devotion shape destiny.
|
243 |
|
244 |
6. 🎲 Storytelling and Games
|