PyPDFForm 2.0.1__py3-none-any.whl → 2.2.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 +6 -2
- PyPDFForm/adapter.py +37 -3
- PyPDFForm/constants.py +12 -1
- PyPDFForm/coordinate.py +218 -59
- PyPDFForm/filler.py +104 -9
- PyPDFForm/font.py +80 -16
- PyPDFForm/image.py +32 -3
- PyPDFForm/middleware/base.py +57 -8
- PyPDFForm/middleware/checkbox.py +49 -7
- PyPDFForm/middleware/dropdown.py +41 -5
- PyPDFForm/middleware/image.py +26 -2
- PyPDFForm/middleware/radio.py +41 -5
- PyPDFForm/middleware/signature.py +49 -6
- PyPDFForm/middleware/text.py +55 -7
- PyPDFForm/patterns.py +108 -10
- PyPDFForm/template.py +181 -29
- PyPDFForm/utils.py +108 -12
- PyPDFForm/watermark.py +163 -11
- PyPDFForm/widgets/base.py +65 -9
- PyPDFForm/widgets/bedrock.py +3 -0
- PyPDFForm/widgets/checkbox.py +22 -2
- PyPDFForm/widgets/dropdown.py +31 -3
- PyPDFForm/widgets/image.py +24 -0
- PyPDFForm/widgets/radio.py +78 -0
- PyPDFForm/widgets/signature.py +133 -0
- PyPDFForm/widgets/text.py +19 -2
- PyPDFForm/wrapper.py +351 -27
- {pypdfform-2.0.1.dist-info → pypdfform-2.2.0.dist-info}/METADATA +2 -2
- pypdfform-2.2.0.dist-info/RECORD +34 -0
- pypdfform-2.0.1.dist-info/RECORD +0 -30
- {pypdfform-2.0.1.dist-info → pypdfform-2.2.0.dist-info}/WHEEL +0 -0
- {pypdfform-2.0.1.dist-info → pypdfform-2.2.0.dist-info}/licenses/LICENSE +0 -0
- {pypdfform-2.0.1.dist-info → pypdfform-2.2.0.dist-info}/top_level.txt +0 -0
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
|
-
"""
|
|
2
|
+
"""Provides middleware for PDF signature field widgets.
|
|
3
|
+
|
|
4
|
+
This module contains the Signature class which handles:
|
|
5
|
+
- Signature image processing
|
|
6
|
+
- Aspect ratio preservation
|
|
7
|
+
- File path resolution
|
|
8
|
+
- PDF form field integration
|
|
9
|
+
"""
|
|
3
10
|
|
|
4
11
|
from os.path import expanduser
|
|
5
12
|
from typing import BinaryIO, Union
|
|
@@ -9,34 +16,70 @@ from .base import Widget
|
|
|
9
16
|
|
|
10
17
|
|
|
11
18
|
class Signature(Widget):
|
|
12
|
-
"""
|
|
19
|
+
"""Middleware for PDF signature field widgets.
|
|
20
|
+
|
|
21
|
+
Handles all aspects of signature field processing including:
|
|
22
|
+
- Signature image handling
|
|
23
|
+
- Aspect ratio control
|
|
24
|
+
- File path resolution
|
|
25
|
+
- PDF form field integration
|
|
26
|
+
|
|
27
|
+
Inherits from Widget base class and extends it with signature-specific features.
|
|
28
|
+
"""
|
|
13
29
|
|
|
14
30
|
preserve_aspect_ratio = True
|
|
31
|
+
"""Whether to preserve the original image's aspect ratio when scaling."""
|
|
15
32
|
|
|
16
33
|
def __init__(
|
|
17
34
|
self,
|
|
18
35
|
name: str,
|
|
19
36
|
value: Union[bytes, str, BinaryIO] = None,
|
|
20
37
|
) -> None:
|
|
21
|
-
"""
|
|
38
|
+
"""Initializes a new signature field widget.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
name: Field name/key for the signature
|
|
42
|
+
value: Signature image as bytes, file path, or file object (default: None)
|
|
43
|
+
"""
|
|
22
44
|
|
|
23
45
|
super().__init__(name, value)
|
|
24
46
|
|
|
25
47
|
@property
|
|
26
48
|
def schema_definition(self) -> dict:
|
|
27
|
-
"""
|
|
49
|
+
"""Generates a JSON schema definition for the signature field.
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
dict: Schema properties including:
|
|
53
|
+
- type: string (file path)
|
|
54
|
+
- description (if available from base class)
|
|
55
|
+
"""
|
|
28
56
|
|
|
29
57
|
return {"type": "string"}
|
|
30
58
|
|
|
31
59
|
@property
|
|
32
60
|
def sample_value(self) -> str:
|
|
33
|
-
"""
|
|
61
|
+
"""Generates a sample value for the signature field.
|
|
62
|
+
|
|
63
|
+
Returns a default sample image path from the user's Downloads folder.
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
str: Path to sample image file
|
|
67
|
+
"""
|
|
34
68
|
|
|
35
69
|
return expanduser("~/Downloads/sample_image.jpg")
|
|
36
70
|
|
|
37
71
|
@property
|
|
38
72
|
def stream(self) -> Union[bytes, None]:
|
|
39
|
-
"""Converts the
|
|
73
|
+
"""Converts the signature image to a byte stream.
|
|
74
|
+
|
|
75
|
+
Handles conversion of:
|
|
76
|
+
- Raw image bytes
|
|
77
|
+
- File paths
|
|
78
|
+
- File-like objects
|
|
79
|
+
|
|
80
|
+
Returns:
|
|
81
|
+
Union[bytes, None]: Image data as bytes, or None if no value set
|
|
82
|
+
"""
|
|
40
83
|
|
|
41
84
|
return (
|
|
42
85
|
fp_or_f_obj_or_stream_to_stream(self.value)
|
PyPDFForm/middleware/text.py
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
|
-
"""
|
|
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
|
+
"""
|
|
3
11
|
|
|
4
12
|
from typing import Any
|
|
5
13
|
|
|
@@ -7,14 +15,29 @@ from .base import Widget
|
|
|
7
15
|
|
|
8
16
|
|
|
9
17
|
class Text(Widget):
|
|
10
|
-
"""
|
|
18
|
+
"""Middleware for PDF text field widgets.
|
|
19
|
+
|
|
20
|
+
Handles all aspects of text field processing including:
|
|
21
|
+
- Value conversion and validation
|
|
22
|
+
- Font styling and formatting
|
|
23
|
+
- Multiline text wrapping
|
|
24
|
+
- Comb field character spacing
|
|
25
|
+
- Preview mode rendering
|
|
26
|
+
|
|
27
|
+
Inherits from Widget base class and extends it with text-specific features.
|
|
28
|
+
"""
|
|
11
29
|
|
|
12
30
|
def __init__(
|
|
13
31
|
self,
|
|
14
32
|
name: str,
|
|
15
33
|
value: str = None,
|
|
16
34
|
) -> None:
|
|
17
|
-
"""
|
|
35
|
+
"""Initializes a new text field widget.
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
name: Field name/key for the text field
|
|
39
|
+
value: Initial text value (default: None)
|
|
40
|
+
"""
|
|
18
41
|
|
|
19
42
|
super().__init__(name, value)
|
|
20
43
|
|
|
@@ -31,7 +54,13 @@ class Text(Widget):
|
|
|
31
54
|
|
|
32
55
|
@property
|
|
33
56
|
def value(self) -> Any:
|
|
34
|
-
"""
|
|
57
|
+
"""Gets the text field's current value with type conversion.
|
|
58
|
+
|
|
59
|
+
Converts numeric values to strings automatically.
|
|
60
|
+
|
|
61
|
+
Returns:
|
|
62
|
+
Any: The text value as a string (converted if numeric)
|
|
63
|
+
"""
|
|
35
64
|
|
|
36
65
|
if isinstance(self._value, (int, float)):
|
|
37
66
|
return str(self._value)
|
|
@@ -40,13 +69,26 @@ class Text(Widget):
|
|
|
40
69
|
|
|
41
70
|
@value.setter
|
|
42
71
|
def value(self, value: str) -> None:
|
|
43
|
-
"""Sets
|
|
72
|
+
"""Sets the text field's value.
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
value: New text value (will be converted to string if numeric)
|
|
76
|
+
"""
|
|
44
77
|
|
|
45
78
|
self._value = value
|
|
46
79
|
|
|
47
80
|
@property
|
|
48
81
|
def schema_definition(self) -> dict:
|
|
49
|
-
"""
|
|
82
|
+
"""Generates a JSON schema definition for the text field.
|
|
83
|
+
|
|
84
|
+
Includes:
|
|
85
|
+
- Type constraint (string)
|
|
86
|
+
- Max length if specified
|
|
87
|
+
- Any inherited schema properties
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
dict: Complete JSON schema definition
|
|
91
|
+
"""
|
|
50
92
|
|
|
51
93
|
result = {"type": "string"}
|
|
52
94
|
|
|
@@ -57,7 +99,13 @@ class Text(Widget):
|
|
|
57
99
|
|
|
58
100
|
@property
|
|
59
101
|
def sample_value(self) -> str:
|
|
60
|
-
"""
|
|
102
|
+
"""Generates a sample value demonstrating the text field's capacity.
|
|
103
|
+
|
|
104
|
+
Uses the field name as the sample value, truncated to max_length if specified.
|
|
105
|
+
|
|
106
|
+
Returns:
|
|
107
|
+
str: Sample text value for demonstration purposes
|
|
108
|
+
"""
|
|
61
109
|
|
|
62
110
|
return (
|
|
63
111
|
self.name[: self.max_length] if self.max_length is not None else self.name
|
PyPDFForm/patterns.py
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
|
-
"""
|
|
2
|
+
"""Pattern matching utilities for PDF form widgets.
|
|
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)
|
|
13
|
+
|
|
14
|
+
The module also contains utility functions for common PDF form operations
|
|
15
|
+
like updating field values and flattening form fields.
|
|
16
|
+
"""
|
|
3
17
|
|
|
4
18
|
from pypdf.generic import (DictionaryObject, NameObject, NumberObject,
|
|
5
19
|
TextStringObject)
|
|
@@ -32,6 +46,15 @@ WIDGET_TYPE_PATTERNS = [
|
|
|
32
46
|
({FT: Tx},),
|
|
33
47
|
Text,
|
|
34
48
|
),
|
|
49
|
+
(
|
|
50
|
+
# reportlab creation pattern
|
|
51
|
+
(
|
|
52
|
+
{FT: Btn},
|
|
53
|
+
{Parent: {FT: Btn}},
|
|
54
|
+
{AS: (Yes, Off)},
|
|
55
|
+
),
|
|
56
|
+
Radio,
|
|
57
|
+
),
|
|
35
58
|
(
|
|
36
59
|
(
|
|
37
60
|
{FT: Btn},
|
|
@@ -115,7 +138,16 @@ BORDER_DASH_ARRAY_PATTERNS = [{BS: {D: True}}]
|
|
|
115
138
|
|
|
116
139
|
|
|
117
140
|
def simple_update_checkbox_value(annot: DictionaryObject, check: bool = False) -> None:
|
|
118
|
-
"""
|
|
141
|
+
"""Update checkbox annotation values based on check state.
|
|
142
|
+
|
|
143
|
+
Modifies the appearance state (AS) and value (V) of a checkbox annotation
|
|
144
|
+
to reflect the desired checked/unchecked state. Uses the annotation's
|
|
145
|
+
appearance dictionary (AP/N) to determine valid states.
|
|
146
|
+
|
|
147
|
+
Args:
|
|
148
|
+
annot: PDF annotation dictionary to modify
|
|
149
|
+
check: Whether the checkbox should be checked (True) or unchecked (False)
|
|
150
|
+
"""
|
|
119
151
|
|
|
120
152
|
for each in annot[AP][N]: # noqa
|
|
121
153
|
if (check and str(each) != Off) or (not check and str(each) == Off):
|
|
@@ -125,7 +157,15 @@ def simple_update_checkbox_value(annot: DictionaryObject, check: bool = False) -
|
|
|
125
157
|
|
|
126
158
|
|
|
127
159
|
def simple_update_radio_value(annot: DictionaryObject) -> None:
|
|
128
|
-
"""
|
|
160
|
+
"""Update radio button annotation values to selected state.
|
|
161
|
+
|
|
162
|
+
Modifies the appearance state (AS) of a radio button annotation and updates
|
|
163
|
+
the parent's value (V) to reflect the selected state. Uses the annotation's
|
|
164
|
+
appearance dictionary (AP/N) to determine valid states.
|
|
165
|
+
|
|
166
|
+
Args:
|
|
167
|
+
annot: PDF radio button annotation dictionary to modify
|
|
168
|
+
"""
|
|
129
169
|
|
|
130
170
|
for each in annot[AP][N]: # noqa
|
|
131
171
|
if str(each) != Off:
|
|
@@ -135,7 +175,16 @@ def simple_update_radio_value(annot: DictionaryObject) -> None:
|
|
|
135
175
|
|
|
136
176
|
|
|
137
177
|
def simple_update_dropdown_value(annot: DictionaryObject, widget: Dropdown) -> None:
|
|
138
|
-
"""
|
|
178
|
+
"""Update dropdown annotation values based on widget selection.
|
|
179
|
+
|
|
180
|
+
Modifies the value (V) and appearance (AP) of a dropdown annotation to
|
|
181
|
+
reflect the currently selected choice from the widget. Handles both
|
|
182
|
+
standalone dropdowns and those with parent annotations.
|
|
183
|
+
|
|
184
|
+
Args:
|
|
185
|
+
annot: PDF dropdown annotation dictionary to modify
|
|
186
|
+
widget: Dropdown widget containing the selected value
|
|
187
|
+
"""
|
|
139
188
|
|
|
140
189
|
if Parent in annot and T not in annot:
|
|
141
190
|
annot[NameObject(Parent)][NameObject(V)] = TextStringObject( # noqa
|
|
@@ -148,7 +197,16 @@ def simple_update_dropdown_value(annot: DictionaryObject, widget: Dropdown) -> N
|
|
|
148
197
|
|
|
149
198
|
|
|
150
199
|
def simple_update_text_value(annot: DictionaryObject, widget: Text) -> None:
|
|
151
|
-
"""
|
|
200
|
+
"""Update text field annotation values based on widget content.
|
|
201
|
+
|
|
202
|
+
Modifies the value (V) and appearance (AP) of a text field annotation to
|
|
203
|
+
reflect the current value from the text widget. Handles both standalone
|
|
204
|
+
text fields and those with parent annotations.
|
|
205
|
+
|
|
206
|
+
Args:
|
|
207
|
+
annot: PDF text field annotation dictionary to modify
|
|
208
|
+
widget: Text widget containing the value to set
|
|
209
|
+
"""
|
|
152
210
|
|
|
153
211
|
if Parent in annot and T not in annot:
|
|
154
212
|
annot[NameObject(Parent)][NameObject(V)] = TextStringObject( # noqa
|
|
@@ -161,7 +219,15 @@ def simple_update_text_value(annot: DictionaryObject, widget: Text) -> None:
|
|
|
161
219
|
|
|
162
220
|
|
|
163
221
|
def simple_flatten_radio(annot: DictionaryObject) -> None:
|
|
164
|
-
"""
|
|
222
|
+
"""Flatten radio button annotation by making it read-only.
|
|
223
|
+
|
|
224
|
+
Modifies the field flags (Ff) of a radio button's parent annotation
|
|
225
|
+
to set the read-only flag, effectively flattening the field and
|
|
226
|
+
preventing further user interaction.
|
|
227
|
+
|
|
228
|
+
Args:
|
|
229
|
+
annot: PDF radio button annotation dictionary to flatten
|
|
230
|
+
"""
|
|
165
231
|
|
|
166
232
|
annot[NameObject(Parent)][NameObject(Ff)] = NumberObject( # noqa
|
|
167
233
|
int(annot[NameObject(Parent)].get(NameObject(Ff), 0)) | READ_ONLY # noqa
|
|
@@ -169,7 +235,15 @@ def simple_flatten_radio(annot: DictionaryObject) -> None:
|
|
|
169
235
|
|
|
170
236
|
|
|
171
237
|
def simple_flatten_generic(annot: DictionaryObject) -> None:
|
|
172
|
-
"""
|
|
238
|
+
"""Flatten generic annotation by making it read-only.
|
|
239
|
+
|
|
240
|
+
Modifies the field flags (Ff) of an annotation to set the read-only flag,
|
|
241
|
+
effectively flattening the field and preventing further user interaction.
|
|
242
|
+
Handles both standalone annotations and those with parent annotations.
|
|
243
|
+
|
|
244
|
+
Args:
|
|
245
|
+
annot: PDF annotation dictionary to flatten
|
|
246
|
+
"""
|
|
173
247
|
|
|
174
248
|
if Parent in annot and Ff not in annot:
|
|
175
249
|
annot[NameObject(Parent)][NameObject(Ff)] = NumberObject( # noqa
|
|
@@ -182,7 +256,15 @@ def simple_flatten_generic(annot: DictionaryObject) -> None:
|
|
|
182
256
|
|
|
183
257
|
|
|
184
258
|
def update_annotation_name(annot: DictionaryObject, val: str) -> None:
|
|
185
|
-
"""
|
|
259
|
+
"""Update the name/title of a PDF annotation.
|
|
260
|
+
|
|
261
|
+
Modifies the title (T) field of an annotation to set a new name.
|
|
262
|
+
Handles both standalone annotations and those with parent annotations.
|
|
263
|
+
|
|
264
|
+
Args:
|
|
265
|
+
annot: PDF annotation dictionary to modify
|
|
266
|
+
val: New name/title to set for the annotation
|
|
267
|
+
"""
|
|
186
268
|
|
|
187
269
|
if Parent in annot and T not in annot:
|
|
188
270
|
annot[NameObject(Parent)][NameObject(T)] = TextStringObject(val) # noqa
|
|
@@ -191,13 +273,29 @@ def update_annotation_name(annot: DictionaryObject, val: str) -> None:
|
|
|
191
273
|
|
|
192
274
|
|
|
193
275
|
def update_created_text_field_alignment(annot: DictionaryObject, val: int) -> None:
|
|
194
|
-
"""
|
|
276
|
+
"""Update text alignment for created text field annotations.
|
|
277
|
+
|
|
278
|
+
Modifies the alignment (Q) field of a text field annotation created
|
|
279
|
+
by the library to set the specified text alignment.
|
|
280
|
+
|
|
281
|
+
Args:
|
|
282
|
+
annot: PDF text field annotation dictionary to modify
|
|
283
|
+
val: Alignment value to set (typically 0=left, 1=center, 2=right)
|
|
284
|
+
"""
|
|
195
285
|
|
|
196
286
|
annot[NameObject(Q)] = NumberObject(val)
|
|
197
287
|
|
|
198
288
|
|
|
199
289
|
def update_created_text_field_multiline(annot: DictionaryObject, val: bool) -> None:
|
|
200
|
-
"""
|
|
290
|
+
"""Update multiline flag for created text field annotations.
|
|
291
|
+
|
|
292
|
+
Modifies the field flags (Ff) of a text field annotation created by
|
|
293
|
+
the library to set or clear the multiline flag based on the input value.
|
|
294
|
+
|
|
295
|
+
Args:
|
|
296
|
+
annot: PDF text field annotation dictionary to modify
|
|
297
|
+
val: Whether to enable multiline (True) or disable (False)
|
|
298
|
+
"""
|
|
201
299
|
|
|
202
300
|
if val:
|
|
203
301
|
annot[NameObject(Ff)] = NumberObject(
|