I am currently trying to display a PDF form as part of my web page (not like described here: Embed a fillable pdf form on web page, they are using Acrobat for this). The user should be able to edit the PDF fields like he would in a PDF viewer. I’ve tried to use PDF.js for this, but I cannot find any good documentation on how to render the text and form part (See my question here: https://github.com/mozilla/pdf.js/discussions/19183). Also, the react-pdf module (https://www.npmjs.com/package/react-pdf) does not have any documentation for PDF forms. How do I achieve this?
The code I have came up with so far is (see link above):
import { Button, Center, Flex, Input, Paper, Text } from "@mantine/core";
import * as pdfjslib from "pdfjs-dist";
import { useEffect, useRef, useState } from "react";
import { IconAt } from '@tabler/icons-react';
import $ from "jquery";
pdfjslib.GlobalWorkerOptions.workerSrc = new URL(
'pdfjs-dist/build/pdf.worker.min.mjs',
import.meta.url,
).toString();
async function renderCanvasLayer(pdfPage: pdfjslib.PDFPageProxy
, canvas: HTMLCanvasElement
, viewport: pdfjslib.PageViewport) {
const ctx = canvas.getContext("2d")!;
const renderTask = pdfPage.render({
canvasContext: ctx,
viewport,
});
return await renderTask.promise;
}
async function renderTextLayer(pdfPage: pdfjslib.PDFPageProxy
, div: HTMLDivElement
, canvas: HTMLCanvasElement
, viewport: pdfjslib.PageViewport) {
$(div.id)
.css({
left: canvas.offsetLeft + 'px',
top: canvas.offsetTop + 'px',
height: canvas.height + 'px',
width: canvas.width + 'px'
})
.html("");
const textLayer = new pdfjslib.TextLayer({
textContentSource: await pdfPage.getTextContent(),
container: div,
viewport: viewport
});
return await textLayer.render();
}
async function renderXfaLayer(pdfPage: pdfjslib.PDFPageProxy) {
//pdfjslib.XfaLayer.render({
// viewport: new PageViewport,
// div: undefined,
// xfaHtml: undefined,
// linkService: new IPDFLinkService
//});
}
async function loadPDFPage(pdfDocument: pdfjslib.PDFDocumentProxy
, canvas: HTMLCanvasElement
, div: HTMLDivElement
, pageNum: number) {
const pdfPage: pdfjslib.PDFPageProxy = await pdfDocument.getPage(pageNum);
const viewport = pdfPage.getViewport({
scale: 1.5
});
canvas.width = viewport.width;
canvas.height = viewport.height;
await renderCanvasLayer(pdfPage, canvas, viewport);
await renderTextLayer(pdfPage, div, canvas, viewport);
await renderXfaLayer(pdfPage);
};
function Page({ numPage, pdfDocument }: { numPage: number, pdfDocument: pdfjslib.PDFDocumentProxy }) {
console.assert(numPage != null);
const pageCanvas = useRef<HTMLCanvasElement>(null);
const pageDiv = useRef<HTMLDivElement>(null);
useEffect(() => {
if (pageCanvas.current && pageDiv.current) {
loadPDFPage(pdfDocument, pageCanvas.current, pageDiv.current, numPage);
}
}, [pageCanvas]);
return <>
<Paper
shadow="xl"
p="xl">
<Center>
<Flex
mt={10}
mih={10}
gap="sm"
justify="center"
align="center"
direction="column"
wrap="wrap">
<canvas ref={pageCanvas}></canvas>
<div ref={pageDiv} className="select-text"></div>
<Text>Seite {numPage}</Text>
</Flex>
</Center>
</Paper >
</>
}
But I am also open for solutions using approaches other than PDF.js
Thanks!
2