Update app.py
Browse files
app.py
CHANGED
@@ -472,6 +472,65 @@ def create_selflinking_pdf(pdf_file="SelfLinking.pdf"):
|
|
472 |
|
473 |
return pdf_file
|
474 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
475 |
# Streamlit UI
|
476 |
md_files = [f for f in glob.glob("*.md") if os.path.basename(f) != "README.md"]
|
477 |
md_options = [os.path.splitext(os.path.basename(f))[0] for f in md_files]
|
@@ -600,11 +659,33 @@ with st.sidebar:
|
|
600 |
mime="audio/mpeg"
|
601 |
)
|
602 |
|
603 |
-
|
604 |
-
|
605 |
-
|
606 |
-
st.
|
607 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
608 |
with open(pdf_file, "rb") as f:
|
609 |
st.download_button(
|
610 |
label=f"๐พ Download {pdf_file}",
|
@@ -612,23 +693,21 @@ with st.sidebar:
|
|
612 |
file_name=pdf_file,
|
613 |
mime="application/pdf"
|
614 |
)
|
615 |
-
|
616 |
-
if st.button("
|
617 |
-
with st.spinner("Generating
|
618 |
-
|
619 |
-
|
620 |
-
|
621 |
-
|
622 |
-
|
623 |
-
|
624 |
-
|
625 |
-
|
626 |
-
st.image(img, caption=f"{pdf_file} Page {i+1}", use_container_width=True)
|
627 |
-
with open(pdf_file, "rb") as f:
|
628 |
st.download_button(
|
629 |
-
label=
|
630 |
-
data=
|
631 |
-
file_name=
|
632 |
mime="application/pdf"
|
633 |
)
|
634 |
|
|
|
472 |
|
473 |
return pdf_file
|
474 |
|
475 |
+
def create_pdf_with_images(source_pdf_bytes, output_pdf="ImageLinked.pdf"):
|
476 |
+
"""Create a PDF with links to images on numbered items 1-12."""
|
477 |
+
# Get all PNG files in the project directory, sorted by name
|
478 |
+
image_files = sorted(glob.glob("*.png"))
|
479 |
+
|
480 |
+
if not source_pdf_bytes:
|
481 |
+
st.error("No source PDF provided.")
|
482 |
+
return None
|
483 |
+
|
484 |
+
# Read the source PDF
|
485 |
+
reader = PdfReader(io.BytesIO(source_pdf_bytes))
|
486 |
+
writer = PdfWriter()
|
487 |
+
|
488 |
+
# Copy all pages from source PDF
|
489 |
+
for page in reader.pages:
|
490 |
+
writer.add_page(page)
|
491 |
+
|
492 |
+
# Only process the first page for links
|
493 |
+
page = writer.pages[0]
|
494 |
+
number_pattern = re.compile(r'^\d+\.\s')
|
495 |
+
|
496 |
+
# Find numbered items 1-12 on the page
|
497 |
+
y_positions = []
|
498 |
+
# Assuming the PDF was generated with numbered items at predictable y-coordinates
|
499 |
+
for i in range(1, 13): # 1 to 12
|
500 |
+
y = 800 - (i * 20) # Adjust based on create_pdf layout
|
501 |
+
y_positions.append(y)
|
502 |
+
|
503 |
+
# Add links to images
|
504 |
+
for idx, (y, image_file) in enumerate(zip(y_positions, image_files[:12])):
|
505 |
+
if os.path.exists(image_file):
|
506 |
+
# Add "link" text next to numbered item
|
507 |
+
buffer = io.BytesIO()
|
508 |
+
c = canvas.Canvas(buffer)
|
509 |
+
c.setFont("Helvetica", 8)
|
510 |
+
c.drawString(90, y - 5, "link")
|
511 |
+
c.showPage()
|
512 |
+
c.save()
|
513 |
+
buffer.seek(0)
|
514 |
+
text_pdf = PdfReader(buffer)
|
515 |
+
page.merge_page(text_pdf.pages[0])
|
516 |
+
|
517 |
+
# Add link annotation
|
518 |
+
link = Link(
|
519 |
+
rect=(90, y - 10, 150, y + 10),
|
520 |
+
url=f"file://{os.path.abspath(image_file)}"
|
521 |
+
)
|
522 |
+
writer.add_annotation(page_number=0, annotation=link)
|
523 |
+
buffer.close()
|
524 |
+
|
525 |
+
# Save the modified PDF
|
526 |
+
output_buffer = io.BytesIO()
|
527 |
+
writer.write(output_buffer)
|
528 |
+
output_buffer.seek(0)
|
529 |
+
with open(output_pdf, "wb") as f:
|
530 |
+
f.write(output_buffer.getvalue())
|
531 |
+
|
532 |
+
return output_buffer.getvalue()
|
533 |
+
|
534 |
# Streamlit UI
|
535 |
md_files = [f for f in glob.glob("*.md") if os.path.basename(f) != "README.md"]
|
536 |
md_options = [os.path.splitext(os.path.basename(f))[0] for f in md_files]
|
|
|
659 |
mime="audio/mpeg"
|
660 |
)
|
661 |
|
662 |
+
col1, col2 = st.columns(2)
|
663 |
+
with col1:
|
664 |
+
if st.button("๐ Create CrossFile PDFs"):
|
665 |
+
with st.spinner("Creating cross-file linked PDFs..."):
|
666 |
+
source_pdf, target_pdf = create_crossfile_pdfs()
|
667 |
+
st.success(f"Created {source_pdf} and {target_pdf}")
|
668 |
+
for pdf_file in [source_pdf, target_pdf]:
|
669 |
+
with open(pdf_file, "rb") as f:
|
670 |
+
st.download_button(
|
671 |
+
label=f"๐พ Download {pdf_file}",
|
672 |
+
data=f.read(),
|
673 |
+
file_name=pdf_file,
|
674 |
+
mime="application/pdf"
|
675 |
+
)
|
676 |
+
|
677 |
+
with col2:
|
678 |
+
if st.button("๐งช Create SelfLinking PDF"):
|
679 |
+
with st.spinner("Generating self-linking PDF with TOC..."):
|
680 |
+
pdf_file = create_selflinking_pdf()
|
681 |
+
st.success(f"Generated {pdf_file}")
|
682 |
+
with open(pdf_file, "rb") as f:
|
683 |
+
pdf_bytes = f.read()
|
684 |
+
images = pdf_to_image(pdf_bytes)
|
685 |
+
if images:
|
686 |
+
st.subheader(f"Preview of {pdf_file}")
|
687 |
+
for i, img in enumerate(images):
|
688 |
+
st.image(img, caption=f"{pdf_file} Page {i+1}", use_container_width=True)
|
689 |
with open(pdf_file, "rb") as f:
|
690 |
st.download_button(
|
691 |
label=f"๐พ Download {pdf_file}",
|
|
|
693 |
file_name=pdf_file,
|
694 |
mime="application/pdf"
|
695 |
)
|
696 |
+
|
697 |
+
if st.button("๐ผ๏ธ Generate PDF With Images"):
|
698 |
+
with st.spinner("Generating PDF with image links..."):
|
699 |
+
linked_pdf_bytes = create_pdf_with_images(pdf_bytes)
|
700 |
+
if linked_pdf_bytes:
|
701 |
+
st.success("Generated PDF with image links")
|
702 |
+
images = pdf_to_image(linked_pdf_bytes)
|
703 |
+
if images:
|
704 |
+
st.subheader("Preview of Image-Linked PDF")
|
705 |
+
for i, img in enumerate(images):
|
706 |
+
st.image(img, caption=f"Image-Linked PDF Page {i+1}", use_container_width=True)
|
|
|
|
|
707 |
st.download_button(
|
708 |
+
label="๐พ Download Image-Linked PDF",
|
709 |
+
data=linked_pdf_bytes,
|
710 |
+
file_name=f"{prefix} {selected_md}_image_linked.pdf" if selected_md else f"{prefix} image_linked.pdf",
|
711 |
mime="application/pdf"
|
712 |
)
|
713 |
|