Spaces:
Sleeping
Sleeping
| import math | |
| import os | |
| import hashlib | |
| import streamlit as st | |
| import fitz # PyMuPDF | |
| st.set_page_config(page_title="PDF Tiler", layout="centered") | |
| st.title("PDF Tiler") | |
| uploaded = st.file_uploader("Upload a PDF", type=["pdf"]) | |
| debug_borders = st.checkbox("Show debug borders", value=False) | |
| # ---- Fixed layout ---- | |
| inch = 72 | |
| page_w, page_h = 13.0 * inch, 8.5 * inch # 8.5x13 landscape | |
| cols, rows = 10, 5 | |
| tiles_per_sheet = cols * rows | |
| margin_lr = 0.25 * inch | |
| margin_top = 0.70 * inch | |
| margin_bottom = 0.3 * inch # your updated bottom margin | |
| content_w = page_w - 2 * margin_lr | |
| content_h = page_h - margin_top - margin_bottom | |
| cell_w = content_w / cols | |
| cell_h = content_h / rows | |
| title_font = "cour" | |
| title_fontsize = 10 | |
| title_baseline_from_bottom = 0.2 * inch | |
| def tile_pdf(src_bytes: bytes, title_text: str, debug: bool) -> bytes: | |
| src = fitz.open(stream=src_bytes, filetype="pdf") | |
| out = fitz.open() | |
| total_pages = src.page_count | |
| out_pages = math.ceil(total_pages / tiles_per_sheet) | |
| for sheet_idx in range(out_pages): | |
| dst_page = out.new_page(width=page_w, height=page_h) | |
| start = sheet_idx * tiles_per_sheet | |
| end = min(start + tiles_per_sheet, total_pages) | |
| for j, pno in enumerate(range(start, end)): | |
| r = j // cols | |
| c = j % cols | |
| x0 = margin_lr + c * cell_w | |
| y0 = margin_top + r * cell_h | |
| rect = fitz.Rect(x0, y0, x0 + cell_w, y0 + cell_h) | |
| dst_page.show_pdf_page(rect, src, pno, keep_proportion=True, overlay=True) | |
| if debug: | |
| dst_page.draw_rect(rect, color=(0, 0, 0), width=0.3, overlay=True) | |
| # Title baseline 0.2 in above bottom | |
| y = page_h - title_baseline_from_bottom | |
| # text_w = fitz.get_text_length(title_text, fontname=title_font, fontsize=title_fontsize) | |
| # x = (page_w - text_w) / 2 | |
| # x = max(margin_lr, min(x, page_w - margin_lr - text_w)) | |
| x = margin_lr # left-aligned at the left margin | |
| dst_page.insert_text( | |
| fitz.Point(x, y), | |
| title_text, | |
| fontsize=title_fontsize, | |
| fontname=title_font, | |
| color=(0, 0, 0), | |
| overlay=True, | |
| ) | |
| out_bytes = out.tobytes() | |
| out.close() | |
| src.close() | |
| return out_bytes | |
| # ---- Session state storage ---- | |
| if "job_key" not in st.session_state: | |
| st.session_state.job_key = None | |
| st.session_state.out_bytes = None | |
| st.session_state.out_name = None | |
| if uploaded: | |
| src_bytes = uploaded.getvalue() | |
| filename = uploaded.name | |
| title_text = os.path.splitext(os.path.basename(filename))[0] | |
| out_name = f"{title_text}_tiled_5x10_8.5x13_landscape.pdf" | |
| # Key changes whenever file or debug_borders changes (add other params if you tweak them) | |
| h = hashlib.sha256() | |
| h.update(src_bytes) | |
| h.update(b"|debug=" + (b"1" if debug_borders else b"0")) | |
| job_key = h.hexdigest() | |
| # Generate only when something changed | |
| if st.session_state.job_key != job_key: | |
| with st.spinner("Preparing output..."): | |
| st.session_state.out_bytes = tile_pdf(src_bytes, title_text, debug_borders) | |
| st.session_state.out_name = out_name | |
| st.session_state.job_key = job_key | |
| # Only ONE button shown | |
| st.download_button( | |
| "Generate & Download", | |
| data=st.session_state.out_bytes, | |
| file_name=st.session_state.out_name, | |
| mime="application/pdf", | |
| type="primary", | |
| ) | |
| else: | |
| st.info("Upload a PDF to enable the Generate & Download button.") | |
| ## streamlit run 260215_class-directory/class-directory.py | |
| ## streamlit run class-directory.py |