class-directory / class-directory.py
nicoaspra
change top and bottom boarder
0034a45
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