PyPDFForm 2.5.0__py3-none-any.whl → 3.0.0__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 +22 -6
- PyPDFForm/adapter.py +28 -26
- PyPDFForm/constants.py +29 -34
- PyPDFForm/coordinate.py +23 -399
- PyPDFForm/filler.py +79 -303
- PyPDFForm/font.py +166 -164
- PyPDFForm/hooks.py +109 -69
- PyPDFForm/image.py +72 -22
- PyPDFForm/middleware/base.py +42 -60
- PyPDFForm/middleware/checkbox.py +27 -58
- PyPDFForm/middleware/dropdown.py +41 -30
- PyPDFForm/middleware/image.py +10 -22
- PyPDFForm/middleware/radio.py +30 -31
- PyPDFForm/middleware/signature.py +32 -47
- PyPDFForm/middleware/text.py +54 -48
- PyPDFForm/patterns.py +61 -106
- PyPDFForm/template.py +80 -427
- PyPDFForm/utils.py +142 -128
- PyPDFForm/watermark.py +77 -208
- PyPDFForm/widgets/base.py +57 -76
- PyPDFForm/widgets/checkbox.py +18 -21
- PyPDFForm/widgets/dropdown.py +18 -25
- PyPDFForm/widgets/image.py +11 -9
- PyPDFForm/widgets/radio.py +25 -35
- PyPDFForm/widgets/signature.py +29 -40
- PyPDFForm/widgets/text.py +18 -17
- PyPDFForm/wrapper.py +351 -443
- {pypdfform-2.5.0.dist-info → pypdfform-3.0.0.dist-info}/METADATA +6 -7
- pypdfform-3.0.0.dist-info/RECORD +35 -0
- {pypdfform-2.5.0.dist-info → pypdfform-3.0.0.dist-info}/WHEEL +1 -1
- pypdfform-2.5.0.dist-info/RECORD +0 -35
- {pypdfform-2.5.0.dist-info → pypdfform-3.0.0.dist-info}/licenses/LICENSE +0 -0
- {pypdfform-2.5.0.dist-info → pypdfform-3.0.0.dist-info}/top_level.txt +0 -0
PyPDFForm/middleware/text.py
CHANGED
|
@@ -1,35 +1,34 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
|
-
"""Provides middleware for PDF text field widgets.
|
|
3
|
-
|
|
4
|
-
This module contains the Text class which handles:
|
|
5
|
-
- Text field value management
|
|
6
|
-
- Font properties (family, size, color)
|
|
7
|
-
- Text wrapping and formatting
|
|
8
|
-
- Comb field (fixed character spacing) support
|
|
9
|
-
- Preview mode for form field visualization
|
|
10
2
|
"""
|
|
3
|
+
Module representing a text field widget.
|
|
11
4
|
|
|
12
|
-
|
|
5
|
+
This module defines the Text class, which is a subclass of the
|
|
6
|
+
Widget class. It represents a text field form field in a PDF document,
|
|
7
|
+
allowing users to enter text.
|
|
8
|
+
"""
|
|
13
9
|
|
|
14
10
|
from .base import Widget
|
|
15
11
|
|
|
16
12
|
|
|
17
13
|
class Text(Widget):
|
|
18
|
-
"""
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
Inherits from Widget base class and extends it with text-specific features.
|
|
14
|
+
"""
|
|
15
|
+
Represents a text field widget.
|
|
16
|
+
|
|
17
|
+
The Text class provides a concrete implementation for text field
|
|
18
|
+
form fields. It inherits from the Widget class and implements
|
|
19
|
+
the value, schema_definition, and sample_value properties. It
|
|
20
|
+
also defines a number of attributes that can be used to customize
|
|
21
|
+
the appearance and behavior of the text field, such as font,
|
|
22
|
+
font_size, font_color, comb, alignment, and multiline.
|
|
28
23
|
"""
|
|
29
24
|
|
|
30
25
|
SET_ATTR_TRIGGER_HOOK_MAP = {
|
|
26
|
+
"font": "update_text_field_font",
|
|
31
27
|
"font_size": "update_text_field_font_size",
|
|
32
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",
|
|
33
32
|
}
|
|
34
33
|
|
|
35
34
|
def __init__(
|
|
@@ -37,36 +36,43 @@ class Text(Widget):
|
|
|
37
36
|
name: str,
|
|
38
37
|
value: str = None,
|
|
39
38
|
) -> None:
|
|
40
|
-
"""
|
|
39
|
+
"""
|
|
40
|
+
Initializes a text field widget.
|
|
41
41
|
|
|
42
42
|
Args:
|
|
43
|
-
name:
|
|
44
|
-
value:
|
|
43
|
+
name (str): The name of the text field.
|
|
44
|
+
value (str): The initial value of the text field. Defaults to None.
|
|
45
|
+
|
|
46
|
+
Attributes:
|
|
47
|
+
font (str): The font of the text field. Defaults to None.
|
|
48
|
+
font_size (int): The font size of the text field. Defaults to None.
|
|
49
|
+
font_color (str): The font color of the text field. Defaults to None.
|
|
50
|
+
comb (bool): Whether the text field is a comb field. Defaults to None.
|
|
51
|
+
alignment (str): The alignment of the text field. Defaults to None.
|
|
52
|
+
multiline (bool): Whether the text field is multiline. Defaults to None.
|
|
53
|
+
max_length (int): The maximum length of the text field. Defaults to None.
|
|
45
54
|
"""
|
|
46
|
-
|
|
47
55
|
super().__init__(name, value)
|
|
48
56
|
|
|
49
57
|
self.font = None
|
|
50
58
|
self.font_size = None
|
|
51
59
|
self.font_color = None
|
|
52
|
-
self.text_wrap_length = None
|
|
53
|
-
self.max_length = None
|
|
54
60
|
self.comb = None
|
|
55
|
-
self.
|
|
56
|
-
self.
|
|
57
|
-
|
|
58
|
-
self.
|
|
61
|
+
self.alignment = None
|
|
62
|
+
self.multiline = None
|
|
63
|
+
|
|
64
|
+
self.max_length = None
|
|
59
65
|
|
|
60
66
|
@property
|
|
61
|
-
def value(self) ->
|
|
62
|
-
"""
|
|
67
|
+
def value(self) -> str:
|
|
68
|
+
"""
|
|
69
|
+
Returns the value of the text field.
|
|
63
70
|
|
|
64
|
-
|
|
71
|
+
If the value is an integer or float, it is converted to a string.
|
|
65
72
|
|
|
66
73
|
Returns:
|
|
67
|
-
|
|
74
|
+
str: The value of the text field.
|
|
68
75
|
"""
|
|
69
|
-
|
|
70
76
|
if isinstance(self._value, (int, float)):
|
|
71
77
|
return str(self._value)
|
|
72
78
|
|
|
@@ -74,27 +80,25 @@ class Text(Widget):
|
|
|
74
80
|
|
|
75
81
|
@value.setter
|
|
76
82
|
def value(self, value: str) -> None:
|
|
77
|
-
"""
|
|
83
|
+
"""
|
|
84
|
+
Sets the value of the text field.
|
|
78
85
|
|
|
79
86
|
Args:
|
|
80
|
-
value:
|
|
87
|
+
value (str): The value to set.
|
|
81
88
|
"""
|
|
82
|
-
|
|
83
89
|
self._value = value
|
|
84
90
|
|
|
85
91
|
@property
|
|
86
92
|
def schema_definition(self) -> dict:
|
|
87
|
-
"""
|
|
93
|
+
"""
|
|
94
|
+
Returns the schema definition for the text field.
|
|
88
95
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
- Max length if specified
|
|
92
|
-
- Any inherited schema properties
|
|
96
|
+
The schema definition is a dictionary that describes the
|
|
97
|
+
data type and other constraints for the text field value.
|
|
93
98
|
|
|
94
99
|
Returns:
|
|
95
|
-
dict:
|
|
100
|
+
dict: A dictionary representing the schema definition.
|
|
96
101
|
"""
|
|
97
|
-
|
|
98
102
|
result = {"type": "string"}
|
|
99
103
|
|
|
100
104
|
if self.max_length is not None:
|
|
@@ -104,14 +108,16 @@ class Text(Widget):
|
|
|
104
108
|
|
|
105
109
|
@property
|
|
106
110
|
def sample_value(self) -> str:
|
|
107
|
-
"""
|
|
111
|
+
"""
|
|
112
|
+
Returns a sample value for the text field.
|
|
108
113
|
|
|
109
|
-
|
|
114
|
+
The sample value is used to generate example data for the
|
|
115
|
+
text field. It returns the name of the field, truncated to
|
|
116
|
+
the maximum length if specified.
|
|
110
117
|
|
|
111
118
|
Returns:
|
|
112
|
-
str:
|
|
119
|
+
str: A sample value for the text field.
|
|
113
120
|
"""
|
|
114
|
-
|
|
115
121
|
return (
|
|
116
122
|
self.name[: self.max_length] if self.max_length is not None else self.name
|
|
117
123
|
)
|
PyPDFForm/patterns.py
CHANGED
|
@@ -1,27 +1,19 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
|
-
"""
|
|
3
|
-
|
|
4
|
-
This module provides:
|
|
5
|
-
- Pattern definitions for identifying widget types and properties
|
|
6
|
-
- Functions for updating widget states and appearances
|
|
7
|
-
- Support for common PDF form operations like flattening fields
|
|
8
|
-
|
|
9
|
-
Patterns are used throughout PyPDFForm to:
|
|
10
|
-
- Classify widget types (text, checkbox, radio, etc.)
|
|
11
|
-
- Extract widget properties (alignment, colors, flags)
|
|
12
|
-
- Modify widget states (values, appearances, flags)
|
|
2
|
+
"""
|
|
3
|
+
This module defines patterns and utility functions for interacting with PDF form fields.
|
|
13
4
|
|
|
14
|
-
|
|
15
|
-
|
|
5
|
+
It includes patterns for identifying different types of widgets (e.g., text fields,
|
|
6
|
+
checkboxes, radio buttons, dropdowns, images, and signatures) based on their
|
|
7
|
+
properties in the PDF's annotation dictionary. It also provides utility functions
|
|
8
|
+
for updating and flattening these widgets.
|
|
16
9
|
"""
|
|
17
10
|
|
|
18
11
|
from pypdf.generic import (ArrayObject, DictionaryObject, NameObject,
|
|
19
12
|
NumberObject, TextStringObject)
|
|
20
13
|
|
|
21
|
-
from .constants import (AP, AS,
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
W, Yes)
|
|
14
|
+
from .constants import (AP, AS, DV, FT, IMAGE_FIELD_IDENTIFIER, JS, READ_ONLY,
|
|
15
|
+
TU, A, Btn, Ch, Ff, I, N, Off, Opt, Parent, Sig, T, Tx,
|
|
16
|
+
V, Yes)
|
|
25
17
|
from .middleware.checkbox import Checkbox
|
|
26
18
|
from .middleware.dropdown import Dropdown
|
|
27
19
|
from .middleware.image import Image
|
|
@@ -103,52 +95,18 @@ DROPDOWN_CHOICE_PATTERNS = [
|
|
|
103
95
|
{Parent: {Opt: True}},
|
|
104
96
|
]
|
|
105
97
|
|
|
106
|
-
WIDGET_ALIGNMENT_PATTERNS = [
|
|
107
|
-
{Q: True},
|
|
108
|
-
{Parent: {Q: True}},
|
|
109
|
-
]
|
|
110
|
-
|
|
111
|
-
TEXT_FIELD_FLAG_PATTERNS = [
|
|
112
|
-
{Ff: True},
|
|
113
|
-
{Parent: {Ff: True}},
|
|
114
|
-
]
|
|
115
|
-
|
|
116
|
-
TEXT_FIELD_APPEARANCE_PATTERNS = [
|
|
117
|
-
{DA: True},
|
|
118
|
-
{Parent: {DA: True}},
|
|
119
|
-
]
|
|
120
|
-
|
|
121
|
-
BUTTON_STYLE_PATTERNS = [
|
|
122
|
-
{MK: {CA: True}},
|
|
123
|
-
]
|
|
124
|
-
|
|
125
|
-
BORDER_COLOR_PATTERNS = [
|
|
126
|
-
{MK: {BC: True}},
|
|
127
|
-
]
|
|
128
|
-
|
|
129
|
-
BACKGROUND_COLOR_PATTERNS = [
|
|
130
|
-
{MK: {BG: True}},
|
|
131
|
-
]
|
|
132
|
-
|
|
133
|
-
BORDER_WIDTH_PATTERNS = [{BS: {W: True}}]
|
|
134
|
-
|
|
135
|
-
BORDER_STYLE_PATTERNS = [{BS: {S: True}}]
|
|
136
98
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
def simple_update_checkbox_value(annot: DictionaryObject, check: bool = False) -> None:
|
|
141
|
-
"""Update checkbox annotation values based on check state.
|
|
99
|
+
def update_checkbox_value(annot: DictionaryObject, check: bool = False) -> None:
|
|
100
|
+
"""
|
|
101
|
+
Updates the value of a checkbox annotation, setting it to checked or unchecked.
|
|
142
102
|
|
|
143
|
-
|
|
144
|
-
to reflect the desired
|
|
145
|
-
appearance dictionary (AP/N) to determine valid states.
|
|
103
|
+
This function modifies the appearance state (AS) and value (V) of the checkbox
|
|
104
|
+
annotation to reflect the desired state (checked or unchecked).
|
|
146
105
|
|
|
147
106
|
Args:
|
|
148
|
-
annot:
|
|
149
|
-
check:
|
|
107
|
+
annot (DictionaryObject): The checkbox annotation dictionary.
|
|
108
|
+
check (bool): True to check the checkbox, False to uncheck it. Defaults to False.
|
|
150
109
|
"""
|
|
151
|
-
|
|
152
110
|
for each in annot[AP][N]:
|
|
153
111
|
if (check and str(each) != Off) or (not check and str(each) == Off):
|
|
154
112
|
annot[NameObject(AS)] = NameObject(each)
|
|
@@ -156,18 +114,16 @@ def simple_update_checkbox_value(annot: DictionaryObject, check: bool = False) -
|
|
|
156
114
|
break
|
|
157
115
|
|
|
158
116
|
|
|
159
|
-
def
|
|
160
|
-
"""
|
|
117
|
+
def update_radio_value(annot: DictionaryObject) -> None:
|
|
118
|
+
"""
|
|
119
|
+
Updates the value of a radio button annotation, selecting it.
|
|
161
120
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
from parent dictionary if present. Uses the annotation's appearance
|
|
165
|
-
dictionary (AP/N) to determine valid states.
|
|
121
|
+
This function modifies the appearance state (AS) and value (V) of the radio button's
|
|
122
|
+
parent dictionary to reflect the selected state.
|
|
166
123
|
|
|
167
124
|
Args:
|
|
168
|
-
annot:
|
|
125
|
+
annot (DictionaryObject): The radio button annotation dictionary.
|
|
169
126
|
"""
|
|
170
|
-
|
|
171
127
|
if Opt in annot[Parent]:
|
|
172
128
|
del annot[Parent][Opt]
|
|
173
129
|
|
|
@@ -178,41 +134,41 @@ def simple_update_radio_value(annot: DictionaryObject) -> None:
|
|
|
178
134
|
break
|
|
179
135
|
|
|
180
136
|
|
|
181
|
-
def
|
|
182
|
-
"""
|
|
137
|
+
def update_dropdown_value(annot: DictionaryObject, widget: Dropdown) -> None:
|
|
138
|
+
"""
|
|
139
|
+
Updates the value of a dropdown annotation, selecting an option from the list.
|
|
183
140
|
|
|
184
|
-
|
|
185
|
-
annotation to reflect the
|
|
186
|
-
|
|
141
|
+
This function modifies the value (V) and appearance (AP) of the dropdown
|
|
142
|
+
annotation to reflect the selected option. It also updates the index (I)
|
|
143
|
+
of the selected option.
|
|
187
144
|
|
|
188
145
|
Args:
|
|
189
|
-
annot:
|
|
190
|
-
widget: Dropdown widget containing the selected value
|
|
146
|
+
annot (DictionaryObject): The dropdown annotation dictionary.
|
|
147
|
+
widget (Dropdown): The Dropdown widget object containing the selected value.
|
|
191
148
|
"""
|
|
192
|
-
|
|
149
|
+
choices = widget.choices or []
|
|
193
150
|
if Parent in annot and T not in annot:
|
|
194
151
|
annot[NameObject(Parent)][NameObject(V)] = TextStringObject(
|
|
195
|
-
|
|
152
|
+
choices[widget.value]
|
|
196
153
|
)
|
|
197
|
-
annot[NameObject(AP)] = TextStringObject(
|
|
154
|
+
annot[NameObject(AP)] = TextStringObject(choices[widget.value])
|
|
198
155
|
else:
|
|
199
|
-
annot[NameObject(V)] = TextStringObject(
|
|
200
|
-
annot[NameObject(AP)] = TextStringObject(
|
|
156
|
+
annot[NameObject(V)] = TextStringObject(choices[widget.value])
|
|
157
|
+
annot[NameObject(AP)] = TextStringObject(choices[widget.value])
|
|
201
158
|
annot[NameObject(I)] = ArrayObject([NumberObject(widget.value)])
|
|
202
159
|
|
|
203
160
|
|
|
204
|
-
def
|
|
205
|
-
"""
|
|
161
|
+
def update_text_value(annot: DictionaryObject, widget: Text) -> None:
|
|
162
|
+
"""
|
|
163
|
+
Updates the value of a text annotation, setting the text content.
|
|
206
164
|
|
|
207
|
-
|
|
208
|
-
reflect the
|
|
209
|
-
text fields and those with parent annotations.
|
|
165
|
+
This function modifies the value (V) and appearance (AP) of the text
|
|
166
|
+
annotation to reflect the new text content.
|
|
210
167
|
|
|
211
168
|
Args:
|
|
212
|
-
annot:
|
|
213
|
-
widget: Text widget containing the value
|
|
169
|
+
annot (DictionaryObject): The text annotation dictionary.
|
|
170
|
+
widget (Text): The Text widget object containing the text value.
|
|
214
171
|
"""
|
|
215
|
-
|
|
216
172
|
if Parent in annot and T not in annot:
|
|
217
173
|
annot[NameObject(Parent)][NameObject(V)] = TextStringObject(widget.value)
|
|
218
174
|
annot[NameObject(AP)] = TextStringObject(widget.value)
|
|
@@ -221,33 +177,32 @@ def simple_update_text_value(annot: DictionaryObject, widget: Text) -> None:
|
|
|
221
177
|
annot[NameObject(AP)] = TextStringObject(widget.value)
|
|
222
178
|
|
|
223
179
|
|
|
224
|
-
def
|
|
225
|
-
"""
|
|
180
|
+
def flatten_radio(annot: DictionaryObject) -> None:
|
|
181
|
+
"""
|
|
182
|
+
Flattens a radio button annotation by setting the ReadOnly flag, making it non-editable.
|
|
226
183
|
|
|
227
|
-
|
|
228
|
-
to set the
|
|
229
|
-
|
|
184
|
+
This function modifies the Ff (flags) entry in the radio button's parent
|
|
185
|
+
dictionary to set the ReadOnly flag, preventing the user from changing the
|
|
186
|
+
selected option.
|
|
230
187
|
|
|
231
188
|
Args:
|
|
232
|
-
annot:
|
|
189
|
+
annot (DictionaryObject): The radio button annotation dictionary.
|
|
233
190
|
"""
|
|
234
|
-
|
|
235
191
|
annot[NameObject(Parent)][NameObject(Ff)] = NumberObject(
|
|
236
192
|
int(annot[NameObject(Parent)].get(NameObject(Ff), 0)) | READ_ONLY
|
|
237
193
|
)
|
|
238
194
|
|
|
239
195
|
|
|
240
|
-
def
|
|
241
|
-
"""
|
|
196
|
+
def flatten_generic(annot: DictionaryObject) -> None:
|
|
197
|
+
"""
|
|
198
|
+
Flattens a generic annotation by setting the ReadOnly flag, making it non-editable.
|
|
242
199
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
Handles both standalone annotations and those with parent annotations.
|
|
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.
|
|
246
202
|
|
|
247
203
|
Args:
|
|
248
|
-
annot:
|
|
204
|
+
annot (DictionaryObject): The annotation dictionary.
|
|
249
205
|
"""
|
|
250
|
-
|
|
251
206
|
if Parent in annot and Ff not in annot:
|
|
252
207
|
annot[NameObject(Parent)][NameObject(Ff)] = NumberObject(
|
|
253
208
|
int(annot.get(NameObject(Ff), 0)) | READ_ONLY
|
|
@@ -259,16 +214,16 @@ def simple_flatten_generic(annot: DictionaryObject) -> None:
|
|
|
259
214
|
|
|
260
215
|
|
|
261
216
|
def update_annotation_name(annot: DictionaryObject, val: str) -> None:
|
|
262
|
-
"""
|
|
217
|
+
"""
|
|
218
|
+
Updates the name of an annotation, setting the T (title) entry.
|
|
263
219
|
|
|
264
|
-
|
|
265
|
-
|
|
220
|
+
This function modifies the T (title) entry in the annotation dictionary to
|
|
221
|
+
change the name or title of the annotation.
|
|
266
222
|
|
|
267
223
|
Args:
|
|
268
|
-
annot:
|
|
269
|
-
val:
|
|
224
|
+
annot (DictionaryObject): The annotation dictionary.
|
|
225
|
+
val (str): The new name for the annotation.
|
|
270
226
|
"""
|
|
271
|
-
|
|
272
227
|
if Parent in annot and T not in annot:
|
|
273
228
|
annot[NameObject(Parent)][NameObject(T)] = TextStringObject(val)
|
|
274
229
|
else:
|