Skip to content

Commit

Permalink
Attempts multipage document display with React example. (#136)
Browse files Browse the repository at this point in the history
* Attempts multipage document display with React example.

* Adds more catching and reporting.

* Replaces wrapper mupdfjs with mupdf in mupdf worker.

* Ensures to work with mupdf NPM release 1.3.0.
  • Loading branch information
jamie-lemon authored Feb 5, 2025
1 parent 681b2d2 commit 013a842
Show file tree
Hide file tree
Showing 7 changed files with 95 additions and 27 deletions.
8 changes: 4 additions & 4 deletions examples/react/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion examples/react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
},
"dependencies": {
"comlink": "^4.4.2",
"mupdf": "^1.1.0",
"mupdf": "^1.3.0",
"react": "^18.3.1",
"react-dom": "^18.3.1"
},
Expand Down
Binary file modified examples/react/public/test.pdf
Binary file not shown.
17 changes: 17 additions & 0 deletions examples/react/src/App.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,21 @@
#root {
display: flex;
justify-content: center;
}

#pages {
width:90%;
margin:0 auto;
}

#pages div {
position: relative;
width:inherit;
background-color: white;
margin: 16px auto;
box-shadow: 0px 2px 8px #0004;
}

#pages div img {
width:100%;
}
58 changes: 44 additions & 14 deletions examples/react/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,62 @@ import { useMupdf } from "@/hooks/useMupdf.hook";
import { useEffect, useState } from "react";

function App() {
const { isWorkerInitialized, renderPage, loadDocument, currentPage } =

const [docLoaded, setDocLoaded] = useState(false);

const { isWorkerInitialized, renderPage, loadDocument, currentPage, countPages } =
useMupdf();
const [pageImgUrl, setPageImgUrl] = useState<string | null>(null);
const [pageImages, setPageImages] = useState<any>([]);

// ===> This is a demo effect which uses hooks <===
// ===> from useMupdf to load and display the first page <===
// ===> of the pdf as an image. <===
useEffect(() => {

if (!isWorkerInitialized) {
return;
}

const loadAndRender = async () => {
const response = await fetch("/test.pdf");
const arrayBuffer = await response.arrayBuffer();
await loadDocument(arrayBuffer);
const pngData = await renderPage(currentPage);
setPageImgUrl(
URL.createObjectURL(new Blob([pngData], { type: "image/png" }))
);
};
// load the document and then load the pages
const init = async () => {
const response = await fetch("/test.pdf");
const arrayBuffer = await response.arrayBuffer();
await loadDocument(arrayBuffer)
setDocLoaded(true);
await loadPages().catch(console.error);
}


const loadPages = async () => {

let pageStack = new Array();
const totalPages: number | void = await countPages().catch(console.error);

if (totalPages) {
for (let i:number = 0; i < totalPages; ++i) {
let pngData = await renderPage(i).catch(console.error);

if (pngData) {
pageStack.push(URL.createObjectURL(new Blob([pngData], { type: "image/png" })));

if (pageStack.length == totalPages) {
setPageImages(pageStack);
}
}
}
}
}

init();

}, [isWorkerInitialized, loadDocument, renderPage]);

loadAndRender().catch(console.error);
}, [currentPage, isWorkerInitialized, loadDocument, renderPage]);
return <div id="pages">
{ pageImages.map((item:any, i) => {
return <div key={i}><img src={item} /></div>;
}) }
</div>

return <>{pageImgUrl && <img src={pageImgUrl} />}</>;
}

export default App;
11 changes: 11 additions & 0 deletions examples/react/src/hooks/useMupdf.hook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,21 @@ export function useMupdf() {
);
}, []);

const countPages = useCallback(() => {
if (!document.current) {
throw new Error("Document not loaded");
}

return mupdfWorker.current!.getPageCount();
}, []);



return {
isWorkerInitialized,
loadDocument,
renderPage,
currentPage,
countPages,
};
}
26 changes: 18 additions & 8 deletions examples/react/src/workers/mupdf.worker.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
/// <reference lib="webworker" />
import * as Comlink from "comlink";
import * as mupdfjs from "mupdf/mupdfjs";
import * as mupdfjs from "mupdf/mupdfjs"
import { PDFDocument } from "mupdf/mupdfjs";

export const MUPDF_LOADED = "MUPDF_LOADED";

export class MupdfWorker {
private document?: PDFDocument;
private pdfdocument?: PDFDocument;

constructor() {
this.initializeMupdf();
Expand All @@ -25,24 +25,34 @@ export class MupdfWorker {
// ===> from mupdfjs which wraps ./node_modules/mupdf/dist/mupdf.js <===

loadDocument(document: ArrayBuffer): boolean {
this.document = mupdfjs.PDFDocument.openDocument(

this.pdfdocument = mupdfjs.PDFDocument.openDocument(
document,
"application/pdf"
);
) as PDFDocument;

return true;
}

renderPageAsImage(pageIndex = 0, scale = 1): Uint8Array {
if (!this.document) throw new Error("Document not loaded");
renderPageAsImage(pageIndex:number = 0, scale:number = 1): Uint8Array {
if (!this.pdfdocument) throw new Error("Document not loaded");

const page = new mupdfjs.PDFPage(this.pdfdocument, pageIndex);

const page = this.document.loadPage(pageIndex);
const pixmap = page.toPixmap(
[scale, 0, 0, scale, 0, 0],
mupdfjs.ColorSpace.DeviceRGB
);

return pixmap.asPNG();
let png = pixmap.asPNG();
pixmap.destroy();
return png;
}

getPageCount(): number {
if (!this.pdfdocument) throw new Error("Document not loaded");

return this.pdfdocument.countPages();
}
}

Expand Down

0 comments on commit 013a842

Please sign in to comment.