Skip to content

Commit

Permalink
Continue on 260140b / c2d4a17 (CC #191)
Browse files Browse the repository at this point in the history
This is an API-breaking change.
  • Loading branch information
mara004 committed Mar 14, 2023
1 parent c2d4a17 commit 0de6e3c
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 10 deletions.
2 changes: 2 additions & 0 deletions docs/devel/changelog_staging.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@
<!-- List character: dash (-) -->

# Changelog for next release
- On multi-page rendering, `PdfDocument` objects constructed in parallel jobs now correctly initialize a form env if the triggering `PdfDocument` has an active one. (In versions 4.1 and 4.2, a form env would never be initialized and thus forms never rendered. In v4.0, a form env would always be initialized for documents with forms.)
- API-breaking change on `PdfDocument.init_forms()`: `config` (`FPDF_FORMFILLINFO`) parameter changed to `config_maker` (`Callable` -> `FPDF_FORMFILLINFO`), on behalf of the multi-page renderer.
33 changes: 23 additions & 10 deletions src/pypdfium2/_helpers/document.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ def __init__(
self._data_holder = []
self._data_closer = []
self.formenv = None
self._form_config_maker = None

if isinstance(self._input, pdfium_c.FPDF_DOCUMENT):
self.raw = self._input
Expand Down Expand Up @@ -133,7 +134,12 @@ def new(cls):
return cls(new_pdf)


def init_forms(self, config=None):
@staticmethod
def _default_form_config_maker():
return pdfium_c.FPDF_FORMFILLINFO(version=2)


def init_forms(self, config_maker=None):
"""
Initialize a form env, if the document has forms. If already initialized, nothing will be done.
See the :attr:`formenv` attribute.
Expand All @@ -143,16 +149,23 @@ def init_forms(self, config=None):
before getting any page handles (due to PDFium's API).
Parameters:
config (FPDF_FORMFILLINFO):
Caller-provided form config interface to use. Optional for default builds.
Must be given if using V8 enabled PDFium (:data:`.V_PDFIUM_IS_V8`), with all required fields implemented.
config_maker (typing.Callable | None):
Callback returning a custom form config interface. Optional for default builds.
Must be given if using V8 enabled PDFium (:data:`.V_PDFIUM_IS_V8`), and the returned config must implement all required fields.
"""

if (self.get_formtype() == pdfium_c.FORMTYPE_NONE) or self.formenv:
return
if not config:

if config_maker:
self._form_config_maker = config_maker
else:
if V_PDFIUM_IS_V8:
raise RuntimeError("A caller-provided form config is required with V8 enabled PDFium.")
config = pdfium_c.FPDF_FORMFILLINFO(version=2)
raise RuntimeError("A caller-provided form config maker is required with V8 enabled PDFium.")
else:
config_maker = PdfDocument._default_form_config_maker

config = config_maker()
raw = pdfium_c.FPDFDOC_InitFormFillEnvironment(self, config)
self.formenv = PdfFormEnv(raw, config, self)

Expand Down Expand Up @@ -540,15 +553,14 @@ def get_toc(


@classmethod
def _process_page(cls, index, input_data, password, renderer, converter, pass_info, need_formenv, **kwargs):
def _process_page(cls, index, input_data, password, renderer, converter, pass_info, need_formenv, form_config_maker, **kwargs):

pdf = cls(
input_data,
password = password,
)
if need_formenv:
# TODO handle custom form config - as ctypes objects can't be pickled, we can't directly pass in a form config (which recursively consists of ctypes objects), so we'll need some different mechanism, likely a callback to create the form config.
pdf.init_forms()
pdf.init_forms(config_maker=form_config_maker)
page = pdf[index]

bitmap = renderer(page, **kwargs)
Expand Down Expand Up @@ -617,6 +629,7 @@ def render(
converter = converter,
pass_info = pass_info,
need_formenv = bool(self.formenv),
form_config_maker = self._form_config_maker,
**kwargs
)

Expand Down

0 comments on commit 0de6e3c

Please sign in to comment.