Conversation
README.md
Outdated
| // Make modifications... | ||
|
|
||
| // Save with XFA preservation | ||
| const pdfBytes = await pdfDoc.save({ |
There was a problem hiding this comment.
Unless I missed it, this is not yet implemented in this PR
| * @param newScript The new JavaScript code to set | ||
| * @returns True if the script was found and updated, false otherwise | ||
| */ | ||
| setXFAJavaScript( |
There was a problem hiding this comment.
You will probably need to escape xml from newScript.
src/api/PDFDocument.ts
Outdated
|
|
||
| // Find and replace the script | ||
| // Note: XFA uses newlines in closing tags like </script\n> | ||
| const fieldPattern = new RegExp( |
There was a problem hiding this comment.
You should be able to use XML parsing instead of a regex
src/api/PDFDocument.ts
Outdated
| : acroForm; | ||
|
|
||
| const xfa = formDict.get(PDFName.of('XFA')); | ||
| if (!xfa || !(xfa instanceof PDFArray)) { |
There was a problem hiding this comment.
This will return false if xfa is a PDFRef
src/api/PDFDocument.ts
Outdated
|
|
||
| // Create new stream with modified XML | ||
| const newXmlBytes = new TextEncoder().encode(xmlString); | ||
| const newStream = this.context.stream(newXmlBytes); |
There was a problem hiding this comment.
If the stream is compressed, you'll need to call flateStream instead of streal
src/api/PDFDocument.ts
Outdated
| const fieldNameMatch = beforeScript.match( | ||
| /<field[^>]*name="([^"]*)"[^>]*>/gi, | ||
| ); | ||
| const fieldName = fieldNameMatch |
There was a problem hiding this comment.
Returning unknown for multiple field might cause a problem when using setXFAJavaScripts, no?
| * ``` | ||
| * @returns An array of objects containing script names and their JavaScript code. | ||
| */ | ||
| getDocumentJavaScripts(): Array<{ name: string; script: string }> { |
There was a problem hiding this comment.
This doesn't appear in the readme
src/api/PDFJavaScriptAction.ts
Outdated
| ? nameStr.substring(1) | ||
| : nameStr; | ||
| // Decode hex sequences like #28 -> ( | ||
| return withoutSlash.replace(/#([\dA-Fa-f]{2})/g, (_, hex) => |
src/api/PDFDocument.ts
Outdated
| * ``` | ||
| * @returns An array of objects containing field names, events, and JavaScript code. | ||
| */ | ||
| getXFAJavaScripts(): Array<{ field: string; event: string; script: string }> { |
There was a problem hiding this comment.
It is probably possible to share parts of this function with setXFAJavaScripts
src/api/PDFDocument.ts
Outdated
| fieldName: string, | ||
| eventName: string, | ||
| newScript: string, | ||
| ): boolean { |
There was a problem hiding this comment.
I wonder if it would not be better to throw an error with details about why it failed instead of returning false. At least, we should consider logging it
|
thank you for the input, Im not very familiar with pdfs spec |
What?
First attempt at adding support for preserving XFA (XML Forms) forms and extracting/modifying JavaScript embedded in XFA templates.
Why?
pdf-lib strips by default XFA data when loading and saving PDFs, causing these forms to lose all functionality. Additionally, there was no way to programmatically access or modify the JavaScript code embedded in XFA templates
How?
**Preserv XFA forms **
preserveXFAoption toPDFDocument.load()andPDFDocument.save()XFA JavaScript Extraction (
getXFAJavaScripts()){field: string, event: string, script: string}objects</script\n>)XFA JavaScript Modification (
setXFAJavaScript(field, event, script))Technical details:
<script>elements<\/script\s*>instead of<\/script>)decodePDFRawStreamto handle compressed streamsTesting?
Unit Tests (7 tests in
PDFDocumentXFA.spec.ts)assets/pdfs/with_xfa_fields.pdf(included in repo)Integration Testing
New Dependencies?
No new production dependencies. The implementation uses existing dependencies:
pako(already in dependencies) - for stream compression/decompressionScreenshots
Suggested Reading?
Anything Else?
Documentation updates