Skip to content

fix: render form widgets and signature appearances via FPDF_FFLDraw#6

Open
NadeemIqbal wants to merge 1 commit into
NucleusFramework:masterfrom
NadeemIqbal:fix/issue-5-signature-rendering
Open

fix: render form widgets and signature appearances via FPDF_FFLDraw#6
NadeemIqbal wants to merge 1 commit into
NucleusFramework:masterfrom
NadeemIqbal:fix/issue-5-signature-rendering

Conversation

@NadeemIqbal
Copy link
Copy Markdown

PDFium requires a two-pass render for pages with form widgets: FPDF_RenderPageBitmap draws static content, then FPDF_FFLDraw overlays interactive widget annotations (fillable form fields and digital signature appearances). ComposePdfReader only ran the first pass, so signed PDFs showed blank rectangles where signature widgets should be. The FPDF_ANNOT flag (already passed for RenderQuality.FULL) is insufficient on its own — per PDFium's API contract, widget annotations are always rendered via FPDF_FFLDraw regardless of that flag.

Per-platform changes follow the same pattern: initialize a FPDF_FORMHANDLE once at openPdfDocument(), keep it for the document's lifetime, call the form-fill overlay sequence (FORM_OnAfterLoadPage → FPDF_FFLDraw → FORM_OnBeforeClosePage) after each FPDF_RenderPageBitmap when quality is FULL, and tear it down with FPDFDOC_ExitFormFillEnvironment before FPDF_CloseDocument in close(). PREVIEW renders (used for thumbnails) skip the extra pass to keep them cheap.

The FPDF_FORMFILLINFO struct is zero-initialised with version=2 and null callbacks — sufficient for read-only static rendering. No interactive form-fill behaviour (mouse, keyboard, JavaScript actions) is wired up, matching the existing read-only display contract of the library.

Implementation surface area:

  • JVM/Android: new nInitFormEnv/nCloseFormEnv JNI exports; render JNI functions take an extra form-handle parameter (0 = skip overlay).
  • iOS: cinterop .def now includes fpdf_formfill.h; the actual class stores FPDF_FORMHANDLE + the backing FPDF_FORMFILLINFO allocation in nativeHeap and frees both in close().
  • Web: pdfium_worker.mjs keeps a per-document form handle in formByDoc/formInfoByDoc maps; renderPage gates FPDF_FFLDraw on the FPDF_ANNOT flag so PREVIEW thumbnails don't pay the cost.

bblanchon's prebuilt PDFium binaries already export the form-fill symbols (verified via nm/grep on linux .so, mac .dylib, and pdfium.wasm glue), so no native-binary rebuild is needed.

Verified:

  • :pdfium:smokeTest passes on a non-form PDF (64-parallel render+text+size stress) — form-fill init/teardown is correct for documents with no widgets.
  • All target Kotlin compilations succeed (jvm, android, iosArm64, iosSimulatorArm64, wasmJs, js).
  • Native builds succeed: JNI .dylib for darwin-aarch64/x86_64; Android NDK .so for arm64-v8a/armeabi-v7a/x86/x86_64.

Closes #5.

PDFium requires a two-pass render for pages with form widgets:
FPDF_RenderPageBitmap draws static content, then FPDF_FFLDraw overlays
interactive widget annotations (fillable form fields and digital signature
appearances). ComposePdfReader only ran the first pass, so signed PDFs
showed blank rectangles where signature widgets should be. The FPDF_ANNOT
flag (already passed for RenderQuality.FULL) is insufficient on its own —
per PDFium's API contract, widget annotations are *always* rendered via
FPDF_FFLDraw regardless of that flag.

Per-platform changes follow the same pattern: initialize a
FPDF_FORMHANDLE once at openPdfDocument(), keep it for the document's
lifetime, call the form-fill overlay sequence (FORM_OnAfterLoadPage →
FPDF_FFLDraw → FORM_OnBeforeClosePage) after each FPDF_RenderPageBitmap
when quality is FULL, and tear it down with FPDFDOC_ExitFormFillEnvironment
before FPDF_CloseDocument in close(). PREVIEW renders (used for thumbnails)
skip the extra pass to keep them cheap.

The FPDF_FORMFILLINFO struct is zero-initialised with version=2 and
null callbacks — sufficient for read-only static rendering. No interactive
form-fill behaviour (mouse, keyboard, JavaScript actions) is wired up,
matching the existing read-only display contract of the library.

Implementation surface area:
- JVM/Android: new nInitFormEnv/nCloseFormEnv JNI exports; render JNI
  functions take an extra form-handle parameter (0 = skip overlay).
- iOS: cinterop .def now includes fpdf_formfill.h; the actual class
  stores FPDF_FORMHANDLE + the backing FPDF_FORMFILLINFO allocation in
  nativeHeap and frees both in close().
- Web: pdfium_worker.mjs keeps a per-document form handle in
  formByDoc/formInfoByDoc maps; renderPage gates FPDF_FFLDraw on the
  FPDF_ANNOT flag so PREVIEW thumbnails don't pay the cost.

bblanchon's prebuilt PDFium binaries already export the form-fill
symbols (verified via nm/grep on linux .so, mac .dylib, and pdfium.wasm
glue), so no native-binary rebuild is needed.

Verified:
- :pdfium:smokeTest passes on a non-form PDF (64-parallel render+text+size
  stress) — form-fill init/teardown is correct for documents with no
  widgets.
- All target Kotlin compilations succeed (jvm, android, iosArm64,
  iosSimulatorArm64, wasmJs, js).
- Native builds succeed: JNI .dylib for darwin-aarch64/x86_64; Android
  NDK .so for arm64-v8a/armeabi-v7a/x86/x86_64.

Closes NucleusFramework#5.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support displaying digital signature appearance in PDF

1 participant