(pdfFile)
| 1 | import { PDFDocument } from "pdf-lib"; |
| 2 | |
| 3 | export const clearAcroFields = async (pdfFile) => { |
| 4 | const pdfDoc = await PDFDocument.load(pdfFile, { ignoreEncryption: true }); |
| 5 | |
| 6 | try { |
| 7 | const acroFormEntry = pdfDoc.catalog.get(PDFName.of("AcroForm")); |
| 8 | const acroForm = pdfDoc.context.lookupMaybe |
| 9 | ? pdfDoc.context.lookupMaybe(acroFormEntry) |
| 10 | : pdfDoc.context.lookup(acroFormEntry); |
| 11 | |
| 12 | if (acroForm && typeof acroForm.set === "function") { |
| 13 | // Avoid pdf-lib form APIs here; some malformed PDFs crash while |
| 14 | // iterating/removing fields. Clearing /Fields directly is safer. |
| 15 | acroForm.set(PDFName.of("Fields"), pdfDoc.context.obj([])); |
| 16 | acroForm.delete(PDFName.of("XFA")); |
| 17 | acroForm.delete(PDFName.of("SigFlags")); |
| 18 | } |
| 19 | } catch { |
| 20 | // If AcroForm is malformed, continue with page annotation cleanup. |
| 21 | } |
| 22 | |
| 23 | for (const page of pdfDoc.getPages()) { |
| 24 | try { |
| 25 | const annotationsRef = page.node.get(PDFName.of("Annots")); |
| 26 | if (!annotationsRef) continue; |
| 27 | |
| 28 | const annotations = pdfDoc.context.lookup(annotationsRef); |
| 29 | if (!annotations || !annotations.asArray) continue; |
| 30 | |
| 31 | const filtered = annotations.asArray().filter((annotRef) => { |
| 32 | try { |
| 33 | const annot = pdfDoc.context.lookup(annotRef); |
| 34 | const subtype = annot?.get(PDFName.of("Subtype")); |
| 35 | return subtype?.toString() !== "/Widget"; |
| 36 | } catch { |
| 37 | return true; |
| 38 | } |
| 39 | }); |
| 40 | |
| 41 | if (filtered.length === 0) { |
| 42 | page.node.delete(PDFName.of("Annots")); |
| 43 | } else { |
| 44 | page.node.set(PDFName.of("Annots"), pdfDoc.context.obj(filtered)); |
| 45 | } |
| 46 | } catch { |
| 47 | // best effort cleanup |
| 48 | } |
| 49 | } |
| 50 | |
| 51 | try { |
| 52 | pdfDoc.catalog.delete(PDFName.of("AcroForm")); |
| 53 | } catch { |
| 54 | // best effort cleanup |
| 55 | } |
| 56 | |
| 57 | return await pdfDoc.save({ useObjectStreams: false }); |
| 58 | }; |
| 59 | |
| 60 | export async function isPdfPasswordProtected(pdfBytes) { |
no test coverage detected