Spaces:
Sleeping
Sleeping
File size: 4,912 Bytes
c2f1543 6bf5b4d c2f1543 6bf5b4d c2f1543 6bf5b4d c2f1543 6bf5b4d c2f1543 6bf5b4d c2f1543 6bf5b4d c2f1543 6bf5b4d c2f1543 6bf5b4d 1540ae9 1eaced3 c2f1543 6bf5b4d c2f1543 b7401f0 c2f1543 ef4e15e 6bf5b4d c5779e9 ef4e15e c714c5f ef4e15e 9797ea5 6bf5b4d c2f1543 6bf5b4d f3c0137 7bb3833 6bf5b4d c2f1543 6bf5b4d 9797ea5 6bf5b4d c2f1543 6bf5b4d c2f1543 9797ea5 1540ae9 9797ea5 c2f1543 00f4b6e 4528c96 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
import fitz # PyMuPDF
from PIL import Image
import gradio as gr
import tempfile
import os
import glob
from gradio import SelectData
PDF_PATH = "presentation.pdf"
MOVIE_PATHS = glob.glob("presentation_movies/*.mp4")
class PDFBrowser:
def __init__(self):
self.doc = None
self.current_page = 0
self.video_dir = None
self.link_map = {}
def load_all_inputs(self, pdf_file, video_files):
# pdf_file might be a gr.File (has .name) or a str path
pdf_path = pdf_file.name if hasattr(pdf_file, "name") else pdf_file
self.doc = fitz.open(pdf_path)
self.current_page = 0
# Prepare videos
self.video_dir = tempfile.mkdtemp()
self.video_map = {}
for vf in video_files or []:
src = vf.name if hasattr(vf, "name") else vf
dst = os.path.join(self.video_dir, os.path.basename(src))
with open(src, "rb") as in_f, open(dst, "wb") as out_f:
out_f.write(in_f.read())
self.video_map[os.path.basename(src)] = dst
# Scan pages for .mp4 links
self.link_map = {}
for i, page in enumerate(self.doc):
links = []
for link in page.get_links():
rect = link.get("from")
path = link.get("file") or link.get("uri") or ""
if path.lower().endswith(".mp4"):
name = os.path.basename(path.replace("run:", ""))
full = self.video_map.get(name)
if full:
links.append((fitz.Rect(rect), full))
self.link_map[i] = links
return self.render_page()
def render_page(self):
if not self.doc:
return None
page = self.doc[self.current_page]
pix = page.get_pixmap(dpi=150)
img = Image.frombytes("RGB", [pix.width, pix.height], pix.samples)
return img
def next_page(self):
if self.doc and self.current_page < len(self.doc) - 1:
self.current_page += 1
return self.render_page()
def prev_page(self):
if self.doc and self.current_page > 0:
self.current_page -= 1
return self.render_page()
def handle_click(self, evt: SelectData):
x_click, y_click = evt.index
page = self.doc[self.current_page]
pdf_w, pdf_h = page.rect.width, page.rect.height
scale = 1024 / pdf_w
x_pdf = x_click/scale
y_pdf = pdf_h - (y_click/scale)
pt = fitz.Point(x_pdf, y_pdf)
links = self.link_map.get(self.current_page, [])
if not links:
return None
# 1) try exact hit
for rect, full in links:
if rect.contains(pt):
return full
# 2) fallback: pick the nearest link‐center
# compute (distance, video_path) pairs
distances = []
for rect, full in links:
cx = (rect.x0 + rect.x1) / 2
cy = (rect.y0 + rect.y1) / 2
center = fitz.Point(cx, cy)
distances.append((pt.distance_to(center), full))
# sort by increasing distance
distances.sort(key=lambda x: x[0])
best_dist, best_full = distances[0]
# set a PDF‐unit threshold: e.g. half the diagonal of the link rect,
# or a fixed value like 50 pts.
# Here we take half the diagonal of the first rect as a guide:
sample_rect = links[0][0]
diag = ((sample_rect.x1 - sample_rect.x0)**2 + (sample_rect.y1 - sample_rect.y0)**2)**0.5
max_dist = diag * 0.5
if best_dist <= max_dist:
return best_full
# still nothing close enough
return None
# build Gradio UI
pdfb = PDFBrowser()
with gr.Blocks() as demo:
image_output = gr.Image(label="PDF Page", interactive=False, width=1024)
video_output = gr.Video(label="Linked Video", interactive=False)
prev_btn = gr.Button("◀ Previous Page", elem_id="prev_btn")
next_btn = gr.Button("Next Page ▶", elem_id="next_btn")
# load on startup
demo.load(
fn=lambda: pdfb.load_all_inputs(PDF_PATH, MOVIE_PATHS),
outputs=image_output
)
prev_btn.click(pdfb.prev_page, outputs=image_output)
next_btn.click(pdfb.next_page, outputs=image_output)
# **IMPORTANT**: bind the image as an input here
image_output.select(
fn=pdfb.handle_click,
inputs=None, # <-- explicitly list your image
outputs=[video_output] # <-- video_output will get updated
)
gr.HTML("""
<script>
document.addEventListener('keydown', function(e) {
if (e.key === 'ArrowRight') {
document.getElementById('next_btn').click();
} else if (e.key === 'ArrowLeft') {
document.getElementById('prev_btn').click();
}
});
</script>
""")
demo.launch() |