./serve.sh in this directory.
npm install @pdfcora/web
The .wasm ships inside the package and must be served from the same origin.
import { configureEngine, PdfDocument } from '@pdfcora/web';
// Where your app serves the two engine files from the package's vendor/ folder.
configureEngine({
factory: async (options) => (await import('/pdfcora/pdfium.esm.js')).default(options),
locateFile: (path) => (path.endsWith('.wasm') ? '/pdfcora/pdfium.esm.wasm' : path),
});
const doc = await PdfDocument.open(bytes);
const page = await doc.page(0);
const image = await page.render({ width: 1024, annotations: true, forms: true });
A malformed page can hang PDFium in native code, where it cannot be cancelled. Run it in a worker so the page can recover by terminating it:
import { PdfWorker } from '@pdfcora/web';
const worker = new PdfWorker({
workerUrl: '/pdfcora/worker/host.js', // the @pdfcora/web/worker file, dist/worker/host.js
glueUrl: '/pdfcora/pdfium.esm.js',
wasmUrl: '/pdfcora/pdfium.esm.wasm',
});
const doc = await worker.open(bytes); // the same API as PdfDocument
// A call that hangs rejects with engineUnresponsive; worker.terminate() ends it by hand.
for (const signature of await doc.signatures()) {
if (!signature.coversWholeDocument) {
// Valid, but content was appended after signing and is not protected.
}
}
const verdict = await doc.verify(signature, { trustAnchors: roots });
if (verdict.kind === 'digestMismatch') { // the bytes changed after signing
} else if (verdict.kind === 'untrusted') { // intact, but the issuer is unknown
} else if (verdict.kind === 'valid') { // both
}
const report = await doc.redact([
{ kind: 'region', rect, pageIndex: 0 },
{ kind: 'textMatches', query: 'account number' },
]);
const clean = await doc.toBytes('full'); // full, always
The browser has no CMS API — WebCrypto provides the primitives but not the container — so signing takes an implementation you supply. iOS, Android and Java sign natively and need nothing extra.
const signed = await doc.sign({
// Return a CAdES-BES CMS, or pass subFilter: 'adbe.pkcs7.detached' for plain PKCS#7.
signer: { async sign(data) { /* ... */ } },
reason: 'Approved',
});
const t = PdfViewTransform.fittingWidth(await page.size(), canvas.clientWidth);
for (const field of await page.formFields()) { const box = t.toViewRect(field.rect); }