| | import solara, ipyreact |
| | from pathlib import Path |
| | import base64 |
| | import requests |
| |
|
| | def pdf_url_to_base64(url): |
| | response = requests.get(url) |
| | if response.status_code == 200: |
| | pdf_bytes = response.content |
| | base64_encoded = base64.b64encode(pdf_bytes).decode("utf-8") |
| | return base64_encoded |
| | else: |
| | print("Failed to fetch PDF from URL:", url) |
| | return None |
| |
|
| |
|
| | ipyreact.define_module("ts-pdf", "./tp.mjs") |
| | ipyreact.define_import_map({ |
| | "pdfjs-dist": "https://esm.sh/pdfjs-dist@2.16.105/build/pdf.worker.js", |
| | }) |
| |
|
| | @solara.component |
| | def PDFViewer(type,pdf): |
| | if type=="bytes": |
| | pdf_bytes=pdf |
| | else: |
| | pdf_bytes=pdf_url_to_base64(pdf) |
| | |
| | app = ipyreact.ValueWidget(_esm= |
| | """ |
| | import React, { useEffect } from 'react'; |
| | import { AnnotEventDetail, CustomStampEventDetail, TsPdfViewer, TsPdfViewerOptions } from 'ts-pdf'; |
| | |
| | const PdfViewerComponent = () => { |
| | useEffect(() => { |
| | const mobileVhHack = () => { |
| | const vh = window.innerHeight * 0.01; |
| | document.documentElement.style.setProperty('--vh', `${vh}px`); |
| | }; |
| | |
| | mobileVhHack(); |
| | window.addEventListener("resize", mobileVhHack); |
| | |
| | return () => { |
| | window.removeEventListener("resize", mobileVhHack); |
| | }; |
| | }, []); |
| | |
| | var arrayBuffer = base64ToArrayBuffer('"""+pdf_bytes+"""'); |
| | |
| | function base64ToArrayBuffer(base64) { |
| | var binaryString = window.atob(base64); |
| | var binaryLen = binaryString.length; |
| | var bytes = new Uint8Array(binaryLen); |
| | for (var i = 0; i < binaryLen; i++) { |
| | var ascii = binaryString.charCodeAt(i); |
| | bytes[i] = ascii; |
| | } |
| | return bytes; |
| | } |
| | var blob = new Blob([arrayBuffer], {type: "application/pdf"}); |
| | var link = window.URL.createObjectURL(blob); |
| | |
| | useEffect(() => { |
| | const run = async () => { |
| | const options: TsPdfViewerOptions = { |
| | containerSelector: "#pdf-main-container", |
| | workerSource: "https://cdn.jsdelivr.net/npm/pdfjs-dist@2.16.105/build/pdf.worker.js", |
| | userName: "corran", |
| | fileButtons: ["close", "save"], |
| | comparableFileButtons: ["open", "close"], |
| | annotChangeCallback: (detail: AnnotEventDetail) => { |
| | if (detail.type === "focus" || detail.type === "select" || detail.type === "render") { |
| | return; |
| | } |
| | console.log(detail); |
| | }, |
| | customStampChangeCallback: (detail: CustomStampEventDetail) => { |
| | // console.log(JSON.stringify(detail.stamp)); |
| | }, |
| | }; |
| | const viewer = new TsPdfViewer(options); |
| | // viewer.importAnnotationsFromJson(dtos); |
| | // }, 5000); |
| | // for debug |
| | window["pdfViewer"] = viewer; |
| | await viewer.openPdfAsync(link); |
| | }; |
| | |
| | run(); |
| | |
| | // Clean up function |
| | return () => { |
| | // Perform any cleanup of the effect here |
| | }; |
| | }, []); |
| | |
| | return ( |
| | <div style={{ |
| | position: "relative", |
| | minWidth: "320px", |
| | width: "100vw", |
| | height: "calc(var(--vh, 1vh) * 100)", |
| | margin: "0", |
| | backgroundColor: "var(--tspdf-color-bg)", |
| | transition: "height .25s ease" |
| | }}> |
| | <style> |
| | {` |
| | .abs-stretch { |
| | position: absolute; |
| | top: 0; |
| | left: 0; |
| | width: 100%; |
| | height: 100%; |
| | } |
| | `} |
| | </style> |
| | <div className="test-container abs-stretch"> |
| | <div id="pdf-main-container" className="abs-stretch"> |
| | {/* Your PDF content will be rendered here */} |
| | </div> |
| | </div> |
| | </div> |
| | ); |
| | }; |
| | |
| | export default PdfViewerComponent; |
| | """) |
| | solara.display(app) |
| |
|
| |
|
| | @solara.component |
| | def Reader(): |
| | solara.Style(""" |
| | #app > div > div:nth-child(2) > |
| | div:nth-child(2){ |
| | display: none; |
| | } |
| | """) |
| | router = solara.use_router() |
| | path = router.path |
| | if "bytes=" in path: |
| | data=path.split("bytes=")[-1] |
| | PDFViewer("bytes",data) |
| | elif "url=" in path: |
| | data=path.split("url=")[-1] |
| | PDFViewer("url",data) |
| | else: |
| | solara.Markdown("Invalid PDF") |
| | solara.Markdown(path) |
| |
|
| | routes = [ |
| | solara.Route( |
| | "reader", |
| | component=Reader, |
| | ), |
| | ] |
| | Reader() |
| |
|