Skip to content

Commit

Permalink
Allow arbitrary ON values for CheckBoxes
Browse files Browse the repository at this point in the history
We previously insisted that the ON-values for CheckBoxes are defined as "Yes" in the PDF (the published recommended value).

This fix introduces lifts this restriction and supports arbitrary values as ON for  check boxes.

So a check box turns to OFF if setting its field value to `False` or "Off".
It is set to ON if the field value is set to any of 'True`, "Yes" or the respective value coded in the PDF.

When checking a check box's value, the return values invariably are either "Off" or the ON-value in the PDF. Which value this is, can be checked via method `on_state()`.
  • Loading branch information
JorjMcKie committed Jan 15, 2025
1 parent 63a3a08 commit 00040fa
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 8 deletions.
14 changes: 6 additions & 8 deletions src/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7269,8 +7269,6 @@ def on_state(self):
"""
if self.field_type not in (2, 5):
return None # no checkbox or radio button
if self.field_type == 2:
return "Yes"
bstate = self.button_states()
if bstate is None:
bstate = dict()
Expand Down Expand Up @@ -17681,13 +17679,13 @@ def GETATTR(name):
mupdf.pdf_dict_put_name(annot_obj, PDF_NAME('AS'), on)
elif text:
mupdf.pdf_dict_put_name(annot_obj, PDF_NAME('AS'), text)
elif field_type == mupdf.PDF_WIDGET_TYPE_CHECKBOX: # will always be "Yes" or "Off"
if value is True or text == 'Yes':
onstate = mupdf.pdf_button_field_on_state(annot_obj)
on = mupdf.pdf_to_name(onstate)
elif field_type == mupdf.PDF_WIDGET_TYPE_CHECKBOX:
onstate = mupdf.pdf_button_field_on_state(annot_obj)
on = onstate.pdf_to_name()
if value in (True, on) or text == 'Yes':
mupdf.pdf_set_field_value(pdf, annot_obj, on, 1)
mupdf.pdf_dict_put_name(annot_obj, PDF_NAME('AS'), 'Yes')
mupdf.pdf_dict_put_name(annot_obj, PDF_NAME('V'), 'Yes')
mupdf.pdf_dict_put_name(annot_obj, PDF_NAME('AS'), on)
mupdf.pdf_dict_put_name(annot_obj, PDF_NAME('V'), on)
else:
mupdf.pdf_dict_put_name( annot_obj, PDF_NAME('AS'), 'Off')
mupdf.pdf_dict_put_name( annot_obj, PDF_NAME('V'), 'Off')
Expand Down
Binary file added tests/resources/test-4055.pdf
Binary file not shown.
55 changes: 55 additions & 0 deletions tests/test_widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
scriptdir = os.path.abspath(os.path.dirname(__file__))
filename = os.path.join(scriptdir, "resources", "widgettest.pdf")
file_2333 = os.path.join(scriptdir, "resources", "test-2333.pdf")
file_4055 = os.path.join(scriptdir, "resources", "test-4055.pdf")


doc = pymupdf.open()
Expand Down Expand Up @@ -379,3 +380,57 @@ def get_widgets_by_name(doc):
assert str(e) == 'Annot is not bound to a page'

doc.close()


def test_4055():
"""Check correct setting of CheckBox "Yes" values.
Test scope:
* setting on with any of 'True' / 'Yes' / built-in values works
* setting off with any of 'False' or 'Off' works
"""

# this PDF has digits as "Yes" values.
doc = pymupdf.open(file_4055)
page = doc[0]

# Round 1: confirm all check boxes are off
for w in page.widgets(types=[2]):
# check that this file doesn't use the "Yes" standard
assert w.on_state() != "Yes"
assert w.field_value == "Off" # all check boxes are off
w.field_value = w.on_state()
w.update()

page = doc.reload_page(page) # reload page to make sure we start fresh

# Round 2: confirm that fields contain the PDF's own on values
for w in page.widgets(types=[2]):
# confirm each value coincides with the "Yes" value
assert w.field_value == w.on_state()
w.field_value = False # switch to "Off" using False
w.update()

page = doc.reload_page(page)

# Round 3: confirm that 'False' achieved "Off" values
for w in page.widgets(types=[2]):
assert w.field_value == "Off"
w.field_value = True # use True for the next round
w.update()

page = doc.reload_page(page)

# Round 4: confirm that setting to True also worked
for w in page.widgets(types=[2]):
assert w.field_value == w.on_state()
w.field_value = "Off" # set off again
w.update()
w.field_value = "Yes"
w.update()

page = doc.reload_page(page)

# Round 5: final check: setting to "Yes" also does work
for w in page.widgets(types=[2]):
assert w.field_value == w.on_state()

0 comments on commit 00040fa

Please sign in to comment.