PyPDFForm 3.0.1__py3-none-any.whl → 3.1.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of PyPDFForm might be problematic. Click here for more details.
- PyPDFForm/__init__.py +1 -1
- PyPDFForm/constants.py +3 -0
- PyPDFForm/filler.py +6 -4
- PyPDFForm/hooks.py +75 -4
- PyPDFForm/middleware/base.py +4 -1
- PyPDFForm/middleware/checkbox.py +5 -4
- PyPDFForm/middleware/dropdown.py +6 -5
- PyPDFForm/middleware/radio.py +5 -0
- PyPDFForm/middleware/text.py +10 -9
- PyPDFForm/patterns.py +88 -34
- PyPDFForm/template.py +12 -2
- PyPDFForm/utils.py +5 -1
- {pypdfform-3.0.1.dist-info → pypdfform-3.1.1.dist-info}/METADATA +1 -1
- {pypdfform-3.0.1.dist-info → pypdfform-3.1.1.dist-info}/RECORD +17 -17
- {pypdfform-3.0.1.dist-info → pypdfform-3.1.1.dist-info}/WHEEL +0 -0
- {pypdfform-3.0.1.dist-info → pypdfform-3.1.1.dist-info}/licenses/LICENSE +0 -0
- {pypdfform-3.0.1.dist-info → pypdfform-3.1.1.dist-info}/top_level.txt +0 -0
PyPDFForm/__init__.py
CHANGED
|
@@ -20,7 +20,7 @@ The library supports various PDF form features, including:
|
|
|
20
20
|
PyPDFForm aims to simplify PDF form manipulation, making it accessible to developers of all skill levels.
|
|
21
21
|
"""
|
|
22
22
|
|
|
23
|
-
__version__ = "3.
|
|
23
|
+
__version__ = "3.1.1"
|
|
24
24
|
|
|
25
25
|
from .middleware.text import Text # exposing for setting global font attrs
|
|
26
26
|
from .wrapper import PdfWrapper
|
PyPDFForm/constants.py
CHANGED
|
@@ -67,6 +67,7 @@ Opt = "/Opt"
|
|
|
67
67
|
AS = "/AS"
|
|
68
68
|
Yes = "/Yes"
|
|
69
69
|
Off = "/Off"
|
|
70
|
+
XObject = "/XObject"
|
|
70
71
|
|
|
71
72
|
# Font dict
|
|
72
73
|
Length1 = "/Length1"
|
|
@@ -105,3 +106,5 @@ IMAGE_FIELD_IDENTIFIER = "event.target.buttonImportIcon();"
|
|
|
105
106
|
|
|
106
107
|
COORDINATE_GRID_FONT_SIZE_MARGIN_RATIO = DEFAULT_FONT_SIZE / 100
|
|
107
108
|
UNIQUE_SUFFIX_LENGTH = 20
|
|
109
|
+
|
|
110
|
+
SLASH = "/"
|
PyPDFForm/filler.py
CHANGED
|
@@ -15,6 +15,7 @@ from pypdf import PdfReader, PdfWriter
|
|
|
15
15
|
from pypdf.generic import DictionaryObject
|
|
16
16
|
|
|
17
17
|
from .constants import WIDGET_TYPES, Annots
|
|
18
|
+
from .hooks import flatten_generic, flatten_radio
|
|
18
19
|
from .image import get_draw_image_resolutions, get_image_dimensions
|
|
19
20
|
from .middleware.checkbox import Checkbox
|
|
20
21
|
from .middleware.dropdown import Dropdown
|
|
@@ -22,9 +23,8 @@ from .middleware.image import Image
|
|
|
22
23
|
from .middleware.radio import Radio
|
|
23
24
|
from .middleware.signature import Signature
|
|
24
25
|
from .middleware.text import Text
|
|
25
|
-
from .patterns import (
|
|
26
|
-
|
|
27
|
-
update_text_value)
|
|
26
|
+
from .patterns import (update_checkbox_value, update_dropdown_value,
|
|
27
|
+
update_radio_value, update_text_value)
|
|
28
28
|
from .template import get_widget_key
|
|
29
29
|
from .utils import stream_to_io
|
|
30
30
|
from .watermark import create_watermarks_and_draw, merge_watermarks_with_pdf
|
|
@@ -145,7 +145,9 @@ def fill(
|
|
|
145
145
|
|
|
146
146
|
# flatten all
|
|
147
147
|
if flatten:
|
|
148
|
-
(flatten_radio if isinstance(widget, Radio) else flatten_generic)(
|
|
148
|
+
(flatten_radio if isinstance(widget, Radio) else flatten_generic)(
|
|
149
|
+
annot, True
|
|
150
|
+
)
|
|
149
151
|
if widget.value is None:
|
|
150
152
|
continue
|
|
151
153
|
|
PyPDFForm/hooks.py
CHANGED
|
@@ -4,7 +4,8 @@ This module defines widget hooks that allow for dynamic modification of PDF form
|
|
|
4
4
|
|
|
5
5
|
It provides functions to trigger these hooks, enabling changes to text field properties
|
|
6
6
|
like font, font size, color, alignment, and multiline settings, as well as the size
|
|
7
|
-
of checkbox and radio button widgets.
|
|
7
|
+
of checkbox and radio button widgets. It also provides functions for flattening
|
|
8
|
+
generic and radio button widgets. These hooks are triggered during the PDF form
|
|
8
9
|
filling process, allowing for customization of the form's appearance and behavior.
|
|
9
10
|
"""
|
|
10
11
|
|
|
@@ -17,7 +18,7 @@ from pypdf.generic import (ArrayObject, DictionaryObject, FloatObject,
|
|
|
17
18
|
NameObject, NumberObject, TextStringObject)
|
|
18
19
|
|
|
19
20
|
from .constants import (COMB, DA, FONT_COLOR_IDENTIFIER, FONT_SIZE_IDENTIFIER,
|
|
20
|
-
MULTILINE, Annots, Ff, Opt, Parent, Q, Rect)
|
|
21
|
+
MULTILINE, READ_ONLY, Annots, Ff, Opt, Parent, Q, Rect)
|
|
21
22
|
from .template import get_widget_key
|
|
22
23
|
from .utils import stream_to_io
|
|
23
24
|
|
|
@@ -249,8 +250,78 @@ def update_dropdown_choices(annot: DictionaryObject, val: list) -> None:
|
|
|
249
250
|
|
|
250
251
|
Args:
|
|
251
252
|
annot (DictionaryObject): The annotation dictionary for the dropdown field.
|
|
252
|
-
val (list): A list of strings representing the new choices for the dropdown.
|
|
253
|
+
val (list): A list of strings or tuples representing the new choices for the dropdown.
|
|
253
254
|
"""
|
|
254
255
|
annot[NameObject(Opt)] = ArrayObject(
|
|
255
|
-
[
|
|
256
|
+
[
|
|
257
|
+
(
|
|
258
|
+
ArrayObject([TextStringObject(each[1]), TextStringObject(each[0])])
|
|
259
|
+
if isinstance(each, tuple)
|
|
260
|
+
else ArrayObject([TextStringObject(each), TextStringObject(each)])
|
|
261
|
+
)
|
|
262
|
+
for each in val
|
|
263
|
+
]
|
|
256
264
|
)
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
def flatten_radio(annot: DictionaryObject, val: bool) -> None:
|
|
268
|
+
"""
|
|
269
|
+
Flattens a radio button annotation by setting or unsetting the ReadOnly flag,
|
|
270
|
+
making it non-editable or editable based on the `val` parameter.
|
|
271
|
+
|
|
272
|
+
This function modifies the Ff (flags) entry in the radio button's annotation
|
|
273
|
+
dictionary or its parent dictionary if `Parent` exists in `annot`, to set or
|
|
274
|
+
unset the ReadOnly flag, preventing or allowing the user from changing the
|
|
275
|
+
selected option.
|
|
276
|
+
|
|
277
|
+
Args:
|
|
278
|
+
annot (DictionaryObject): The radio button annotation dictionary.
|
|
279
|
+
val (bool): True to flatten (make read-only), False to unflatten (make editable).
|
|
280
|
+
"""
|
|
281
|
+
if Parent in annot:
|
|
282
|
+
annot[NameObject(Parent)][NameObject(Ff)] = NumberObject(
|
|
283
|
+
(
|
|
284
|
+
int(annot[NameObject(Parent)].get(NameObject(Ff), 0)) | READ_ONLY
|
|
285
|
+
if val
|
|
286
|
+
else int(annot[NameObject(Parent)].get(NameObject(Ff), 0)) & ~READ_ONLY
|
|
287
|
+
)
|
|
288
|
+
)
|
|
289
|
+
else:
|
|
290
|
+
annot[NameObject(Ff)] = NumberObject(
|
|
291
|
+
(
|
|
292
|
+
int(annot.get(NameObject(Ff), 0)) | READ_ONLY
|
|
293
|
+
if val
|
|
294
|
+
else int(annot.get(NameObject(Ff), 0)) & ~READ_ONLY
|
|
295
|
+
)
|
|
296
|
+
)
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
def flatten_generic(annot: DictionaryObject, val: bool) -> None:
|
|
300
|
+
"""
|
|
301
|
+
Flattens a generic annotation by setting or unsetting the ReadOnly flag,
|
|
302
|
+
making it non-editable or editable based on the `val` parameter.
|
|
303
|
+
|
|
304
|
+
This function modifies the Ff (flags) entry in the annotation dictionary to
|
|
305
|
+
set or unset the ReadOnly flag, preventing or allowing the user from
|
|
306
|
+
interacting with the form field.
|
|
307
|
+
|
|
308
|
+
Args:
|
|
309
|
+
annot (DictionaryObject): The annotation dictionary.
|
|
310
|
+
val (bool): True to flatten (make read-only), False to unflatten (make editable).
|
|
311
|
+
"""
|
|
312
|
+
if Parent in annot and Ff not in annot:
|
|
313
|
+
annot[NameObject(Parent)][NameObject(Ff)] = NumberObject(
|
|
314
|
+
(
|
|
315
|
+
int(annot.get(NameObject(Ff), 0)) | READ_ONLY
|
|
316
|
+
if val
|
|
317
|
+
else int(annot.get(NameObject(Ff), 0)) & ~READ_ONLY
|
|
318
|
+
)
|
|
319
|
+
)
|
|
320
|
+
else:
|
|
321
|
+
annot[NameObject(Ff)] = NumberObject(
|
|
322
|
+
(
|
|
323
|
+
int(annot.get(NameObject(Ff), 0)) | READ_ONLY
|
|
324
|
+
if val
|
|
325
|
+
else int(annot.get(NameObject(Ff), 0)) & ~READ_ONLY
|
|
326
|
+
)
|
|
327
|
+
)
|
PyPDFForm/middleware/base.py
CHANGED
|
@@ -21,7 +21,9 @@ class Widget:
|
|
|
21
21
|
as name, value, and schema definition.
|
|
22
22
|
"""
|
|
23
23
|
|
|
24
|
-
SET_ATTR_TRIGGER_HOOK_MAP = {
|
|
24
|
+
SET_ATTR_TRIGGER_HOOK_MAP = {
|
|
25
|
+
"readonly": "flatten_generic",
|
|
26
|
+
}
|
|
25
27
|
|
|
26
28
|
def __init__(
|
|
27
29
|
self,
|
|
@@ -39,6 +41,7 @@ class Widget:
|
|
|
39
41
|
self._name = name
|
|
40
42
|
self._value = value
|
|
41
43
|
self.desc = None
|
|
44
|
+
self.readonly = None
|
|
42
45
|
self.hooks_to_trigger = []
|
|
43
46
|
|
|
44
47
|
def __setattr__(self, name: str, value: Any) -> None:
|
PyPDFForm/middleware/checkbox.py
CHANGED
|
@@ -20,10 +20,6 @@ class Checkbox(Widget):
|
|
|
20
20
|
implements the schema_definition and sample_value properties.
|
|
21
21
|
"""
|
|
22
22
|
|
|
23
|
-
SET_ATTR_TRIGGER_HOOK_MAP = {
|
|
24
|
-
"size": "update_check_radio_size",
|
|
25
|
-
}
|
|
26
|
-
|
|
27
23
|
def __init__(
|
|
28
24
|
self,
|
|
29
25
|
name: str,
|
|
@@ -39,6 +35,11 @@ class Checkbox(Widget):
|
|
|
39
35
|
Attributes:
|
|
40
36
|
size (int): The size of the checkbox. Defaults to None.
|
|
41
37
|
"""
|
|
38
|
+
self.SET_ATTR_TRIGGER_HOOK_MAP.update(
|
|
39
|
+
{
|
|
40
|
+
"size": "update_check_radio_size",
|
|
41
|
+
}
|
|
42
|
+
)
|
|
42
43
|
super().__init__(name, value)
|
|
43
44
|
|
|
44
45
|
self.size = None
|
PyPDFForm/middleware/dropdown.py
CHANGED
|
@@ -26,11 +26,6 @@ class Dropdown(Widget):
|
|
|
26
26
|
sample_value: Returns a sample value for the dropdown.
|
|
27
27
|
"""
|
|
28
28
|
|
|
29
|
-
SET_ATTR_TRIGGER_HOOK_MAP = {
|
|
30
|
-
"font": "update_text_field_font",
|
|
31
|
-
"choices": "update_dropdown_choices",
|
|
32
|
-
}
|
|
33
|
-
|
|
34
29
|
def __init__(
|
|
35
30
|
self,
|
|
36
31
|
name: str,
|
|
@@ -47,6 +42,12 @@ class Dropdown(Widget):
|
|
|
47
42
|
font (str): The font of the dropdown field.
|
|
48
43
|
choices (List[str]): The list of choices for the dropdown.
|
|
49
44
|
"""
|
|
45
|
+
self.SET_ATTR_TRIGGER_HOOK_MAP.update(
|
|
46
|
+
{
|
|
47
|
+
"font": "update_text_field_font",
|
|
48
|
+
"choices": "update_dropdown_choices",
|
|
49
|
+
}
|
|
50
|
+
)
|
|
50
51
|
super().__init__(name, value)
|
|
51
52
|
|
|
52
53
|
self.font = None
|
PyPDFForm/middleware/radio.py
CHANGED
|
@@ -34,6 +34,11 @@ class Radio(Checkbox):
|
|
|
34
34
|
Attributes:
|
|
35
35
|
number_of_options (int): The number of options for the radio button.
|
|
36
36
|
"""
|
|
37
|
+
self.SET_ATTR_TRIGGER_HOOK_MAP.update(
|
|
38
|
+
{
|
|
39
|
+
"readonly": "flatten_radio",
|
|
40
|
+
}
|
|
41
|
+
)
|
|
37
42
|
super().__init__(name, value)
|
|
38
43
|
|
|
39
44
|
self.number_of_options = 0
|
PyPDFForm/middleware/text.py
CHANGED
|
@@ -22,15 +22,6 @@ class Text(Widget):
|
|
|
22
22
|
font_size, font_color, comb, alignment, and multiline.
|
|
23
23
|
"""
|
|
24
24
|
|
|
25
|
-
SET_ATTR_TRIGGER_HOOK_MAP = {
|
|
26
|
-
"font": "update_text_field_font",
|
|
27
|
-
"font_size": "update_text_field_font_size",
|
|
28
|
-
"font_color": "update_text_field_font_color",
|
|
29
|
-
"comb": "update_text_field_comb",
|
|
30
|
-
"alignment": "update_text_field_alignment",
|
|
31
|
-
"multiline": "update_text_field_multiline",
|
|
32
|
-
}
|
|
33
|
-
|
|
34
25
|
def __init__(
|
|
35
26
|
self,
|
|
36
27
|
name: str,
|
|
@@ -52,6 +43,16 @@ class Text(Widget):
|
|
|
52
43
|
multiline (bool): Whether the text field is multiline. Defaults to None.
|
|
53
44
|
max_length (int): The maximum length of the text field. Defaults to None.
|
|
54
45
|
"""
|
|
46
|
+
self.SET_ATTR_TRIGGER_HOOK_MAP.update(
|
|
47
|
+
{
|
|
48
|
+
"font": "update_text_field_font",
|
|
49
|
+
"font_size": "update_text_field_font_size",
|
|
50
|
+
"font_color": "update_text_field_font_color",
|
|
51
|
+
"comb": "update_text_field_comb",
|
|
52
|
+
"alignment": "update_text_field_alignment",
|
|
53
|
+
"multiline": "update_text_field_multiline",
|
|
54
|
+
}
|
|
55
|
+
)
|
|
55
56
|
super().__init__(name, value)
|
|
56
57
|
|
|
57
58
|
self.font = None
|
PyPDFForm/patterns.py
CHANGED
|
@@ -5,15 +5,17 @@ This module defines patterns and utility functions for interacting with PDF form
|
|
|
5
5
|
It includes patterns for identifying different types of widgets (e.g., text fields,
|
|
6
6
|
checkboxes, radio buttons, dropdowns, images, and signatures) based on their
|
|
7
7
|
properties in the PDF's annotation dictionary. It also provides utility functions
|
|
8
|
-
for updating
|
|
8
|
+
for updating these widgets.
|
|
9
9
|
"""
|
|
10
10
|
|
|
11
|
+
from typing import Union
|
|
12
|
+
|
|
11
13
|
from pypdf.generic import (ArrayObject, DictionaryObject, NameObject,
|
|
12
14
|
NumberObject, TextStringObject)
|
|
13
15
|
|
|
14
|
-
from .constants import (AP, AS, DV, FT, IMAGE_FIELD_IDENTIFIER, JS,
|
|
15
|
-
|
|
16
|
-
V, Yes)
|
|
16
|
+
from .constants import (AP, AS, DV, FT, IMAGE_FIELD_IDENTIFIER, JS, SLASH, TU,
|
|
17
|
+
A, Btn, Ch, I, N, Off, Opt, Parent, Resources, Sig, T,
|
|
18
|
+
Tx, V, XObject, Yes)
|
|
17
19
|
from .middleware.checkbox import Checkbox
|
|
18
20
|
from .middleware.dropdown import Dropdown
|
|
19
21
|
from .middleware.image import Image
|
|
@@ -22,6 +24,14 @@ from .middleware.signature import Signature
|
|
|
22
24
|
from .middleware.text import Text
|
|
23
25
|
|
|
24
26
|
WIDGET_TYPE_PATTERNS = [
|
|
27
|
+
# barcode? see pdf_samples/scenario/issues/1087.pdf
|
|
28
|
+
(
|
|
29
|
+
(
|
|
30
|
+
{FT: Tx},
|
|
31
|
+
{AP: {N: {Resources: {XObject: True}}}},
|
|
32
|
+
),
|
|
33
|
+
None,
|
|
34
|
+
),
|
|
25
35
|
(
|
|
26
36
|
({A: {JS: IMAGE_FIELD_IDENTIFIER}},),
|
|
27
37
|
Image,
|
|
@@ -43,7 +53,7 @@ WIDGET_TYPE_PATTERNS = [
|
|
|
43
53
|
(
|
|
44
54
|
{FT: Btn},
|
|
45
55
|
{Parent: {FT: Btn}},
|
|
46
|
-
{AS: (Yes, Off)},
|
|
56
|
+
{AS: (Yes, Off, SLASH)},
|
|
47
57
|
),
|
|
48
58
|
Radio,
|
|
49
59
|
),
|
|
@@ -77,7 +87,7 @@ WIDGET_TYPE_PATTERNS = [
|
|
|
77
87
|
(
|
|
78
88
|
(
|
|
79
89
|
{Parent: {FT: Btn}},
|
|
80
|
-
{AS: (Yes, Off)},
|
|
90
|
+
{AS: (Yes, Off, SLASH)},
|
|
81
91
|
),
|
|
82
92
|
Radio,
|
|
83
93
|
),
|
|
@@ -114,6 +124,23 @@ def update_checkbox_value(annot: DictionaryObject, check: bool = False) -> None:
|
|
|
114
124
|
break
|
|
115
125
|
|
|
116
126
|
|
|
127
|
+
def get_checkbox_value(annot: DictionaryObject) -> Union[bool, None]:
|
|
128
|
+
"""
|
|
129
|
+
Retrieves the boolean value of a checkbox annotation.
|
|
130
|
+
|
|
131
|
+
This function checks the value (V) of the checkbox annotation. If the value
|
|
132
|
+
is not 'Off', it means the checkbox is checked, and True is returned.
|
|
133
|
+
Otherwise, if the value is 'Off' or not present, None is returned.
|
|
134
|
+
|
|
135
|
+
Args:
|
|
136
|
+
annot (DictionaryObject): The checkbox annotation dictionary.
|
|
137
|
+
|
|
138
|
+
Returns:
|
|
139
|
+
Union[bool, None]: True if the checkbox is checked, None otherwise.
|
|
140
|
+
"""
|
|
141
|
+
return True if annot.get(V, Off) != Off else None
|
|
142
|
+
|
|
143
|
+
|
|
117
144
|
def update_radio_value(annot: DictionaryObject) -> None:
|
|
118
145
|
"""
|
|
119
146
|
Updates the value of a radio button annotation, selecting it.
|
|
@@ -134,6 +161,28 @@ def update_radio_value(annot: DictionaryObject) -> None:
|
|
|
134
161
|
break
|
|
135
162
|
|
|
136
163
|
|
|
164
|
+
def get_radio_value(annot: DictionaryObject) -> bool:
|
|
165
|
+
"""
|
|
166
|
+
Retrieves the boolean value of a radio button annotation.
|
|
167
|
+
|
|
168
|
+
This function iterates through the appearance states (AP) of the radio button
|
|
169
|
+
annotation. If the value (V) of the parent dictionary matches any of these
|
|
170
|
+
appearance states, it means the radio button is selected, and True is returned.
|
|
171
|
+
Otherwise, False is returned.
|
|
172
|
+
|
|
173
|
+
Args:
|
|
174
|
+
annot (DictionaryObject): The radio button annotation dictionary.
|
|
175
|
+
|
|
176
|
+
Returns:
|
|
177
|
+
bool: True if the radio button is selected, False otherwise.
|
|
178
|
+
"""
|
|
179
|
+
for each in annot.get(AP, {}).get(N, []):
|
|
180
|
+
if annot.get(Parent, {}).get(V) == each:
|
|
181
|
+
return True
|
|
182
|
+
|
|
183
|
+
return False
|
|
184
|
+
|
|
185
|
+
|
|
137
186
|
def update_dropdown_value(annot: DictionaryObject, widget: Dropdown) -> None:
|
|
138
187
|
"""
|
|
139
188
|
Updates the value of a dropdown annotation, selecting an option from the list.
|
|
@@ -158,6 +207,29 @@ def update_dropdown_value(annot: DictionaryObject, widget: Dropdown) -> None:
|
|
|
158
207
|
annot[NameObject(I)] = ArrayObject([NumberObject(widget.value)])
|
|
159
208
|
|
|
160
209
|
|
|
210
|
+
def get_dropdown_value(annot: DictionaryObject, widget: Dropdown) -> None:
|
|
211
|
+
"""
|
|
212
|
+
Retrieves the selected value of a dropdown annotation and updates the widget.
|
|
213
|
+
|
|
214
|
+
This function determines the current value of the dropdown, considering
|
|
215
|
+
whether it's a child annotation or a top-level one. It then iterates
|
|
216
|
+
through the widget's choices to find a match and sets the widget's
|
|
217
|
+
value to the index of the matched choice.
|
|
218
|
+
|
|
219
|
+
Args:
|
|
220
|
+
annot (DictionaryObject): The dropdown annotation dictionary.
|
|
221
|
+
widget (Dropdown): The Dropdown widget object to update with the retrieved value.
|
|
222
|
+
"""
|
|
223
|
+
if Parent in annot and T not in annot:
|
|
224
|
+
to_compare = annot.get(Parent, {}).get(V)
|
|
225
|
+
else:
|
|
226
|
+
to_compare = annot.get(V)
|
|
227
|
+
|
|
228
|
+
for i, each in enumerate(widget.choices):
|
|
229
|
+
if each == to_compare:
|
|
230
|
+
widget.value = i or None # set None when 0
|
|
231
|
+
|
|
232
|
+
|
|
161
233
|
def update_text_value(annot: DictionaryObject, widget: Text) -> None:
|
|
162
234
|
"""
|
|
163
235
|
Updates the value of a text annotation, setting the text content.
|
|
@@ -177,40 +249,22 @@ def update_text_value(annot: DictionaryObject, widget: Text) -> None:
|
|
|
177
249
|
annot[NameObject(AP)] = TextStringObject(widget.value)
|
|
178
250
|
|
|
179
251
|
|
|
180
|
-
def
|
|
252
|
+
def get_text_value(annot: DictionaryObject, widget: Text) -> None:
|
|
181
253
|
"""
|
|
182
|
-
|
|
254
|
+
Retrieves the text value of a text annotation and updates the widget.
|
|
183
255
|
|
|
184
|
-
This function
|
|
185
|
-
|
|
186
|
-
|
|
256
|
+
This function determines the current text value of the annotation, considering
|
|
257
|
+
whether it's a child annotation or a top-level one, and then sets the
|
|
258
|
+
widget's value accordingly.
|
|
187
259
|
|
|
188
260
|
Args:
|
|
189
|
-
annot (DictionaryObject): The
|
|
190
|
-
|
|
191
|
-
annot[NameObject(Parent)][NameObject(Ff)] = NumberObject(
|
|
192
|
-
int(annot[NameObject(Parent)].get(NameObject(Ff), 0)) | READ_ONLY
|
|
193
|
-
)
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
def flatten_generic(annot: DictionaryObject) -> None:
|
|
197
|
-
"""
|
|
198
|
-
Flattens a generic annotation by setting the ReadOnly flag, making it non-editable.
|
|
199
|
-
|
|
200
|
-
This function modifies the Ff (flags) entry in the annotation dictionary to
|
|
201
|
-
set the ReadOnly flag, preventing the user from interacting with the form field.
|
|
202
|
-
|
|
203
|
-
Args:
|
|
204
|
-
annot (DictionaryObject): The annotation dictionary.
|
|
261
|
+
annot (DictionaryObject): The text annotation dictionary.
|
|
262
|
+
widget (Text): The Text widget object to update with the retrieved value.
|
|
205
263
|
"""
|
|
206
|
-
if Parent in annot and
|
|
207
|
-
annot[
|
|
208
|
-
int(annot.get(NameObject(Ff), 0)) | READ_ONLY
|
|
209
|
-
)
|
|
264
|
+
if Parent in annot and T not in annot:
|
|
265
|
+
widget.value = annot[Parent].get(V)
|
|
210
266
|
else:
|
|
211
|
-
|
|
212
|
-
int(annot.get(NameObject(Ff), 0)) | READ_ONLY
|
|
213
|
-
)
|
|
267
|
+
widget.value = annot.get(V)
|
|
214
268
|
|
|
215
269
|
|
|
216
270
|
def update_annotation_name(annot: DictionaryObject, val: str) -> None:
|
PyPDFForm/template.py
CHANGED
|
@@ -16,12 +16,14 @@ from pypdf import PdfReader, PdfWriter
|
|
|
16
16
|
from pypdf.generic import DictionaryObject
|
|
17
17
|
|
|
18
18
|
from .constants import WIDGET_TYPES, Annots, MaxLen, Parent, T
|
|
19
|
+
from .middleware.checkbox import Checkbox
|
|
19
20
|
from .middleware.dropdown import Dropdown
|
|
20
21
|
from .middleware.radio import Radio
|
|
21
22
|
from .middleware.text import Text
|
|
22
23
|
from .patterns import (DROPDOWN_CHOICE_PATTERNS, WIDGET_DESCRIPTION_PATTERNS,
|
|
23
24
|
WIDGET_KEY_PATTERNS, WIDGET_TYPE_PATTERNS,
|
|
24
|
-
|
|
25
|
+
get_checkbox_value, get_dropdown_value, get_radio_value,
|
|
26
|
+
get_text_value, update_annotation_name)
|
|
25
27
|
from .utils import extract_widget_property, find_pattern_match, stream_to_io
|
|
26
28
|
|
|
27
29
|
|
|
@@ -61,11 +63,16 @@ def build_widgets(
|
|
|
61
63
|
if isinstance(_widget, Text):
|
|
62
64
|
# mostly for schema for now
|
|
63
65
|
_widget.max_length = get_text_field_max_length(widget)
|
|
66
|
+
get_text_value(widget, _widget)
|
|
67
|
+
|
|
68
|
+
if type(_widget) is Checkbox:
|
|
69
|
+
_widget.value = get_checkbox_value(widget)
|
|
64
70
|
|
|
65
71
|
if isinstance(_widget, Dropdown):
|
|
66
72
|
# actually used for filling value
|
|
67
73
|
# doesn't trigger hook
|
|
68
74
|
_widget.__dict__["choices"] = get_dropdown_choices(widget)
|
|
75
|
+
get_dropdown_value(widget, _widget)
|
|
69
76
|
|
|
70
77
|
if isinstance(_widget, Radio):
|
|
71
78
|
if key not in results:
|
|
@@ -73,6 +80,9 @@ def build_widgets(
|
|
|
73
80
|
|
|
74
81
|
# for schema
|
|
75
82
|
results[key].number_of_options += 1
|
|
83
|
+
|
|
84
|
+
if get_radio_value(widget):
|
|
85
|
+
results[key].value = results[key].number_of_options - 1
|
|
76
86
|
continue
|
|
77
87
|
|
|
78
88
|
results[key] = _widget
|
|
@@ -172,7 +182,7 @@ def construct_widget(widget: dict, key: str) -> Union[WIDGET_TYPES, None]:
|
|
|
172
182
|
for pattern in patterns:
|
|
173
183
|
check = check and find_pattern_match(pattern, widget)
|
|
174
184
|
if check:
|
|
175
|
-
result = _type(key)
|
|
185
|
+
result = _type(key) if _type else None
|
|
176
186
|
break
|
|
177
187
|
return result
|
|
178
188
|
|
PyPDFForm/utils.py
CHANGED
|
@@ -23,7 +23,7 @@ from typing import Any, BinaryIO, List, Union
|
|
|
23
23
|
from pypdf import PdfReader, PdfWriter
|
|
24
24
|
from pypdf.generic import ArrayObject, DictionaryObject, NameObject
|
|
25
25
|
|
|
26
|
-
from .constants import UNIQUE_SUFFIX_LENGTH, XFA, AcroForm, Annots, Root
|
|
26
|
+
from .constants import SLASH, UNIQUE_SUFFIX_LENGTH, XFA, AcroForm, Annots, Root
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
@lru_cache
|
|
@@ -220,6 +220,10 @@ def find_pattern_match(pattern: dict, widget: Union[dict, DictionaryObject]) ->
|
|
|
220
220
|
else:
|
|
221
221
|
if isinstance(pattern[key], tuple):
|
|
222
222
|
result = value in pattern[key]
|
|
223
|
+
if not result and SLASH in pattern[key] and value.startswith(SLASH):
|
|
224
|
+
result = True
|
|
225
|
+
elif pattern[key] is True:
|
|
226
|
+
result = True
|
|
223
227
|
else:
|
|
224
228
|
result = pattern[key] == value
|
|
225
229
|
if result:
|
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
PyPDFForm/__init__.py,sha256=
|
|
1
|
+
PyPDFForm/__init__.py,sha256=2jZGE5eQAyNUA-c-ZZWdKF5RufHjKaqaqyFfH2XhNCM,925
|
|
2
2
|
PyPDFForm/adapter.py,sha256=8E_PZlXU1ALWez_pWF_U52cynzowK_NQFYzMJoH9VUk,2428
|
|
3
|
-
PyPDFForm/constants.py,sha256=
|
|
3
|
+
PyPDFForm/constants.py,sha256=6XTmMC-sr6c6K5hG7XZ7qhC44m8RrXvUpakA26MvW9Q,2477
|
|
4
4
|
PyPDFForm/coordinate.py,sha256=VMVkqa-VAGJSGVvetZwOxeMzIgQtQdvtn_DI_qSecCE,3876
|
|
5
|
-
PyPDFForm/filler.py,sha256=
|
|
5
|
+
PyPDFForm/filler.py,sha256=KwStL6YzrNBcDd919ig83MnAxopi8Vnz3QNJzN_CjNM,7272
|
|
6
6
|
PyPDFForm/font.py,sha256=EZSAHnkzaBo96p9XJrQDMcEhjh5BZ8p7WwFC3SbKRMM,8828
|
|
7
|
-
PyPDFForm/hooks.py,sha256=
|
|
7
|
+
PyPDFForm/hooks.py,sha256=A8p67ubWvCvzRt346Q7BjOvbi4_NXBcynXmq6fJTadY,11679
|
|
8
8
|
PyPDFForm/image.py,sha256=CAC69jEfSbWbyNJcjLhjWVSNJuFh7frMI70eaiFayHw,3823
|
|
9
|
-
PyPDFForm/patterns.py,sha256=
|
|
10
|
-
PyPDFForm/template.py,sha256=
|
|
11
|
-
PyPDFForm/utils.py,sha256=
|
|
9
|
+
PyPDFForm/patterns.py,sha256=8wlOma6s9Be0QxE9Fx2nGGWtPs5RlQ2ARIMCD9qIq-4,8940
|
|
10
|
+
PyPDFForm/template.py,sha256=OyMBAZSAuGM7_YZ4tey7YP0UtzCNM3cUghqpudKMfE0,9692
|
|
11
|
+
PyPDFForm/utils.py,sha256=qKBOB-qsQBhqXP1XoqCukpvtwwMaBVX4uljWPV5i6iU,11078
|
|
12
12
|
PyPDFForm/watermark.py,sha256=9p1tjaIqicXngTNai_iOEkCoXRYnR66azB4s7wNsZUw,9349
|
|
13
13
|
PyPDFForm/wrapper.py,sha256=Ysd1mkvE5OfDkjUI6mNFIt16-JUKwj2ifbp1MioWPUo,25257
|
|
14
14
|
PyPDFForm/middleware/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
15
|
-
PyPDFForm/middleware/base.py,sha256=
|
|
16
|
-
PyPDFForm/middleware/checkbox.py,sha256=
|
|
17
|
-
PyPDFForm/middleware/dropdown.py,sha256=
|
|
15
|
+
PyPDFForm/middleware/base.py,sha256=J8mlVIzC0QrljNAjRjGm0ns6w1MJOVp5cRSyqN1Bv_Q,3074
|
|
16
|
+
PyPDFForm/middleware/checkbox.py,sha256=GVYVXRDFQ_nj720Vsol2kkyBf3UqTtKOXDxY0O_2moM,1863
|
|
17
|
+
PyPDFForm/middleware/dropdown.py,sha256=hzXTLwvHob8EyI1ePJgqMoxePfPiE4FpPehvWD6pdvc,2361
|
|
18
18
|
PyPDFForm/middleware/image.py,sha256=oeXaThV9hEpHsTwH7VT4qbreh_5tsS1dwA1E_eHe61o,579
|
|
19
|
-
PyPDFForm/middleware/radio.py,sha256=
|
|
19
|
+
PyPDFForm/middleware/radio.py,sha256=4XQU8zjPzZoEx0v_ukKpHPuUhLHyAKFrAwoMVy3nC8I,2206
|
|
20
20
|
PyPDFForm/middleware/signature.py,sha256=I0ygzfgodREUAEfEA2AzIszAVFg4In_K-l4bAKZiImE,2143
|
|
21
|
-
PyPDFForm/middleware/text.py,sha256=
|
|
21
|
+
PyPDFForm/middleware/text.py,sha256=HAMsLiuX0iQZnsrenlc_QJdJ2R46sxQ0Fn5VTHla9_k,3895
|
|
22
22
|
PyPDFForm/widgets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
23
23
|
PyPDFForm/widgets/base.py,sha256=kOfxV8HSmwXoy0vFYPgJKKDQ7RUNMACWfX6T4HeJeOU,5177
|
|
24
24
|
PyPDFForm/widgets/bedrock.py,sha256=j6beU04kaQzpAIFZHI5VJLaDT5RVAAa6LzkU1luJpN8,137660
|
|
@@ -28,8 +28,8 @@ PyPDFForm/widgets/image.py,sha256=aSD-3MEZFIRL7HYVuO6Os8irfSUOLHA_rHGkqcEIPPA,85
|
|
|
28
28
|
PyPDFForm/widgets/radio.py,sha256=nWSQQp06kRISO7Q7FVFeB3PXYvMOSc0SMhRs1bHTxeQ,2261
|
|
29
29
|
PyPDFForm/widgets/signature.py,sha256=EqIRIuKSQEg8LJZ_Mu859eEvs0dwO-mzkMNuhHG1Vsg,4034
|
|
30
30
|
PyPDFForm/widgets/text.py,sha256=gtheE6_w0vQPRJJ9oj_l9FaMDEGnPtvVR6_axsrmxKI,1540
|
|
31
|
-
pypdfform-3.
|
|
32
|
-
pypdfform-3.
|
|
33
|
-
pypdfform-3.
|
|
34
|
-
pypdfform-3.
|
|
35
|
-
pypdfform-3.
|
|
31
|
+
pypdfform-3.1.1.dist-info/licenses/LICENSE,sha256=43awmYkI6opyTpg19me731iO1WfXZwViqb67oWtCsFY,1065
|
|
32
|
+
pypdfform-3.1.1.dist-info/METADATA,sha256=AV8baYVcYIjI7kUlWQJQ0B0PTn6CBLEcV7WPpTZOVPU,4587
|
|
33
|
+
pypdfform-3.1.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
34
|
+
pypdfform-3.1.1.dist-info/top_level.txt,sha256=GQQKuWqPUjT9YZqwK95NlAQzxjwoQrsxQ8ureM8lWOY,10
|
|
35
|
+
pypdfform-3.1.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|