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/filler.py
CHANGED
|
@@ -1,106 +1,60 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
|
-
"""
|
|
3
|
-
|
|
4
|
-
This module handles:
|
|
5
|
-
- Drawing text, images, borders and other elements onto PDF forms
|
|
6
|
-
- Managing widget states and appearances
|
|
7
|
-
- Supporting different filling modes (simple vs watermark-based)
|
|
8
|
-
- Handling special cases like checkboxes, radio buttons and signatures
|
|
2
|
+
"""
|
|
3
|
+
Module containing functions to fill PDF forms.
|
|
9
4
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
5
|
+
This module provides the core functionality for filling PDF forms programmatically.
|
|
6
|
+
It includes functions for handling various form field types, such as text fields,
|
|
7
|
+
checkboxes, radio buttons, dropdowns, images, and signatures. The module also
|
|
8
|
+
supports flattening the filled form to prevent further modifications.
|
|
13
9
|
"""
|
|
14
10
|
|
|
15
11
|
from io import BytesIO
|
|
16
|
-
from typing import Dict,
|
|
12
|
+
from typing import Dict, Union, cast
|
|
17
13
|
|
|
18
14
|
from pypdf import PdfReader, PdfWriter
|
|
19
|
-
from pypdf.generic import
|
|
20
|
-
IndirectObject, NameObject)
|
|
15
|
+
from pypdf.generic import DictionaryObject
|
|
21
16
|
|
|
22
|
-
from .constants import
|
|
23
|
-
|
|
24
|
-
from .coordinate import (get_draw_border_coordinates,
|
|
25
|
-
get_draw_checkbox_radio_coordinates,
|
|
26
|
-
get_draw_image_coordinates_resolutions,
|
|
27
|
-
get_draw_text_coordinates,
|
|
28
|
-
get_text_line_x_coordinates)
|
|
29
|
-
from .font import checkbox_radio_font_size
|
|
30
|
-
from .image import get_image_dimensions
|
|
17
|
+
from .constants import WIDGET_TYPES, Annots
|
|
18
|
+
from .image import get_draw_image_resolutions, get_image_dimensions
|
|
31
19
|
from .middleware.checkbox import Checkbox
|
|
32
20
|
from .middleware.dropdown import Dropdown
|
|
33
21
|
from .middleware.image import Image
|
|
34
22
|
from .middleware.radio import Radio
|
|
35
23
|
from .middleware.signature import Signature
|
|
36
24
|
from .middleware.text import Text
|
|
37
|
-
from .patterns import (
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
from .
|
|
42
|
-
from .utils import checkbox_radio_to_draw, stream_to_io
|
|
25
|
+
from .patterns import (flatten_generic, flatten_radio, update_checkbox_value,
|
|
26
|
+
update_dropdown_value, update_radio_value,
|
|
27
|
+
update_text_value)
|
|
28
|
+
from .template import get_widget_key
|
|
29
|
+
from .utils import stream_to_io
|
|
43
30
|
from .watermark import create_watermarks_and_draw, merge_watermarks_with_pdf
|
|
44
31
|
|
|
45
32
|
|
|
46
|
-
def check_radio_handler(
|
|
47
|
-
widget: dict, middleware: Union[Checkbox, Radio], radio_button_tracker: dict
|
|
48
|
-
) -> Tuple[Text, Union[float, int], Union[float, int], bool]:
|
|
49
|
-
"""Calculates drawing parameters for checkbox and radio button widgets.
|
|
50
|
-
|
|
51
|
-
Args:
|
|
52
|
-
widget: PDF form widget dictionary containing Rect coordinates
|
|
53
|
-
middleware: Checkbox or Radio middleware instance
|
|
54
|
-
radio_button_tracker: Dictionary tracking radio button group states
|
|
55
|
-
|
|
56
|
-
Returns:
|
|
57
|
-
Tuple containing:
|
|
58
|
-
- Text: Prepared text object for drawing the symbol
|
|
59
|
-
- float/int: x coordinate for drawing
|
|
60
|
-
- float/int: y coordinate for drawing
|
|
61
|
-
- bool: Whether the symbol needs to be drawn
|
|
62
|
-
"""
|
|
63
|
-
|
|
64
|
-
font_size = (
|
|
65
|
-
checkbox_radio_font_size(widget) if middleware.size is None else middleware.size
|
|
66
|
-
)
|
|
67
|
-
to_draw = checkbox_radio_to_draw(middleware, font_size)
|
|
68
|
-
x, y = get_draw_checkbox_radio_coordinates(
|
|
69
|
-
widget, to_draw, border_width=middleware.border_width
|
|
70
|
-
)
|
|
71
|
-
text_needs_to_be_drawn = False
|
|
72
|
-
if type(middleware) is Checkbox and middleware.value:
|
|
73
|
-
text_needs_to_be_drawn = True
|
|
74
|
-
elif isinstance(middleware, Radio):
|
|
75
|
-
if middleware.name not in radio_button_tracker:
|
|
76
|
-
radio_button_tracker[middleware.name] = 0
|
|
77
|
-
radio_button_tracker[middleware.name] += 1
|
|
78
|
-
if middleware.value == radio_button_tracker[middleware.name] - 1:
|
|
79
|
-
text_needs_to_be_drawn = True
|
|
80
|
-
|
|
81
|
-
return to_draw, x, y, text_needs_to_be_drawn
|
|
82
|
-
|
|
83
|
-
|
|
84
33
|
def signature_image_handler(
|
|
85
34
|
widget: dict, middleware: Union[Signature, Image], images_to_draw: list
|
|
86
35
|
) -> bool:
|
|
87
|
-
"""
|
|
36
|
+
"""Handles signature and image widgets by extracting image data and preparing it for drawing.
|
|
37
|
+
|
|
38
|
+
This function processes signature and image widgets found in a PDF form. It extracts the
|
|
39
|
+
image data from the widget's middleware and prepares it for drawing on the form. The
|
|
40
|
+
function calculates the position and dimensions of the image based on the widget's
|
|
41
|
+
properties and the `preserve_aspect_ratio` setting. The image data is then stored in a
|
|
42
|
+
list for later drawing.
|
|
88
43
|
|
|
89
44
|
Args:
|
|
90
|
-
widget:
|
|
91
|
-
middleware
|
|
92
|
-
images_to_draw:
|
|
45
|
+
widget (dict): The widget dictionary representing the signature or image field.
|
|
46
|
+
middleware (Union[Signature, Image]): The middleware object containing the image data and properties.
|
|
47
|
+
images_to_draw (list): A list to store image data for drawing.
|
|
93
48
|
|
|
94
49
|
Returns:
|
|
95
|
-
bool: True if
|
|
50
|
+
bool: True if any image is to be drawn, False otherwise.
|
|
96
51
|
"""
|
|
97
|
-
|
|
98
52
|
stream = middleware.stream
|
|
99
53
|
any_image_to_draw = False
|
|
100
54
|
if stream is not None:
|
|
101
55
|
any_image_to_draw = True
|
|
102
56
|
image_width, image_height = get_image_dimensions(stream)
|
|
103
|
-
x, y, width, height =
|
|
57
|
+
x, y, width, height = get_draw_image_resolutions(
|
|
104
58
|
widget, middleware.preserve_aspect_ratio, image_width, image_height
|
|
105
59
|
)
|
|
106
60
|
images_to_draw.append(
|
|
@@ -116,95 +70,23 @@ def signature_image_handler(
|
|
|
116
70
|
return any_image_to_draw
|
|
117
71
|
|
|
118
72
|
|
|
119
|
-
def text_handler(
|
|
120
|
-
widget: dict, middleware: Text
|
|
121
|
-
) -> Tuple[Text, Union[float, int], Union[float, int], bool]:
|
|
122
|
-
"""Prepares text field drawing parameters.
|
|
123
|
-
|
|
124
|
-
Args:
|
|
125
|
-
widget: PDF form widget dictionary containing Rect and properties
|
|
126
|
-
middleware: Text middleware instance with text properties
|
|
127
|
-
|
|
128
|
-
Returns:
|
|
129
|
-
Tuple containing:
|
|
130
|
-
- Text: The text middleware to draw
|
|
131
|
-
- float/int: x coordinate for drawing
|
|
132
|
-
- float/int: y coordinate for drawing
|
|
133
|
-
- bool: Always True for text fields (they always need drawing)
|
|
134
|
-
"""
|
|
135
|
-
|
|
136
|
-
middleware.text_line_x_coordinates = get_text_line_x_coordinates(widget, middleware)
|
|
137
|
-
x, y = get_draw_text_coordinates(widget, middleware)
|
|
138
|
-
to_draw = middleware
|
|
139
|
-
text_needs_to_be_drawn = True
|
|
140
|
-
|
|
141
|
-
return to_draw, x, y, text_needs_to_be_drawn
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
def border_handler(
|
|
145
|
-
widget: dict,
|
|
146
|
-
middleware: WIDGET_TYPES,
|
|
147
|
-
rect_borders_to_draw: list,
|
|
148
|
-
ellipse_borders_to_draw: list,
|
|
149
|
-
line_borders_to_draw: list,
|
|
150
|
-
) -> None:
|
|
151
|
-
"""Prepares border drawing parameters for widgets.
|
|
152
|
-
|
|
153
|
-
Args:
|
|
154
|
-
widget: PDF form widget dictionary containing Rect coordinates
|
|
155
|
-
middleware: Any widget middleware instance
|
|
156
|
-
rect_borders_to_draw: List to append rectangle border parameters to
|
|
157
|
-
ellipse_borders_to_draw: List to append ellipse border parameters to
|
|
158
|
-
line_borders_to_draw: List to append line border parameters to
|
|
159
|
-
"""
|
|
160
|
-
|
|
161
|
-
if (
|
|
162
|
-
isinstance(middleware, Radio)
|
|
163
|
-
and BUTTON_STYLES.get(middleware.button_style) == DEFAULT_RADIO_STYLE
|
|
164
|
-
):
|
|
165
|
-
list_to_append = ellipse_borders_to_draw
|
|
166
|
-
shape = "ellipse"
|
|
167
|
-
elif middleware.border_style == U:
|
|
168
|
-
list_to_append = line_borders_to_draw
|
|
169
|
-
shape = "line"
|
|
170
|
-
else:
|
|
171
|
-
list_to_append = rect_borders_to_draw
|
|
172
|
-
shape = "rect"
|
|
173
|
-
|
|
174
|
-
list_to_append.append(
|
|
175
|
-
{
|
|
176
|
-
**get_draw_border_coordinates(widget, shape),
|
|
177
|
-
"border_color": middleware.border_color,
|
|
178
|
-
"background_color": middleware.background_color,
|
|
179
|
-
"border_width": middleware.border_width,
|
|
180
|
-
"dash_array": middleware.dash_array,
|
|
181
|
-
}
|
|
182
|
-
)
|
|
183
|
-
|
|
184
|
-
if shape == "line":
|
|
185
|
-
rect_borders_to_draw.append(
|
|
186
|
-
{
|
|
187
|
-
**get_draw_border_coordinates(widget, "rect"),
|
|
188
|
-
"border_color": None,
|
|
189
|
-
"background_color": middleware.background_color,
|
|
190
|
-
"border_width": 0,
|
|
191
|
-
"dash_array": None,
|
|
192
|
-
}
|
|
193
|
-
)
|
|
194
|
-
|
|
195
|
-
|
|
196
73
|
def get_drawn_stream(to_draw: dict, stream: bytes, action: str) -> bytes:
|
|
197
|
-
"""Applies
|
|
74
|
+
"""Applies watermarks to specific pages of a PDF based on the provided drawing instructions.
|
|
75
|
+
|
|
76
|
+
This function takes a dictionary of drawing instructions and applies watermarks to the
|
|
77
|
+
specified pages of a PDF. It iterates through the drawing instructions, creates watermarks
|
|
78
|
+
for each page, and merges the watermarks with the original PDF content. The function
|
|
79
|
+
supports various drawing actions, such as adding images or text.
|
|
198
80
|
|
|
199
81
|
Args:
|
|
200
|
-
to_draw:
|
|
201
|
-
|
|
202
|
-
|
|
82
|
+
to_draw (dict): A dictionary containing page numbers as keys and lists of drawing instructions as values.
|
|
83
|
+
Each drawing instruction specifies the type of drawing, position, dimensions, and content.
|
|
84
|
+
stream (bytes): The PDF content as bytes.
|
|
85
|
+
action (str): The type of action to perform (e.g., "image", "text").
|
|
203
86
|
|
|
204
87
|
Returns:
|
|
205
|
-
bytes:
|
|
88
|
+
bytes: The modified PDF content with watermarks applied.
|
|
206
89
|
"""
|
|
207
|
-
|
|
208
90
|
watermark_list = []
|
|
209
91
|
for page, stuffs in to_draw.items():
|
|
210
92
|
watermark_list.append(b"")
|
|
@@ -217,184 +99,78 @@ def get_drawn_stream(to_draw: dict, stream: bytes, action: str) -> bytes:
|
|
|
217
99
|
|
|
218
100
|
|
|
219
101
|
def fill(
|
|
220
|
-
template_stream: bytes,
|
|
221
|
-
widgets: Dict[str, WIDGET_TYPES],
|
|
222
|
-
use_full_widget_name: bool,
|
|
223
|
-
) -> bytes:
|
|
224
|
-
"""Fills a PDF form using watermark technique for complex rendering.
|
|
225
|
-
|
|
226
|
-
This method:
|
|
227
|
-
- Handles text, images, borders for all widget types
|
|
228
|
-
- Preserves original form fields while adding visual elements
|
|
229
|
-
- Supports complex cases like multiline text and image scaling
|
|
230
|
-
|
|
231
|
-
Args:
|
|
232
|
-
template_stream: Input PDF form as bytes
|
|
233
|
-
widgets: Dictionary mapping field names to widget middleware
|
|
234
|
-
use_full_widget_name: If True, uses the full widget name as the key in the widgets dictionary
|
|
235
|
-
|
|
236
|
-
Returns:
|
|
237
|
-
bytes: Filled PDF form as bytes
|
|
238
|
-
"""
|
|
239
|
-
|
|
240
|
-
texts_to_draw = {}
|
|
241
|
-
images_to_draw = {}
|
|
242
|
-
rect_borders_to_draw = {}
|
|
243
|
-
ellipse_borders_to_draw = {}
|
|
244
|
-
line_borders_to_draw = {}
|
|
245
|
-
any_image_to_draw = False
|
|
246
|
-
|
|
247
|
-
radio_button_tracker = {}
|
|
248
|
-
|
|
249
|
-
for page, widget_dicts in get_widgets_by_page(template_stream).items():
|
|
250
|
-
texts_to_draw[page] = []
|
|
251
|
-
images_to_draw[page] = []
|
|
252
|
-
rect_borders_to_draw[page] = []
|
|
253
|
-
ellipse_borders_to_draw[page] = []
|
|
254
|
-
line_borders_to_draw[page] = []
|
|
255
|
-
for widget_dict in widget_dicts:
|
|
256
|
-
key = get_widget_key(widget_dict, use_full_widget_name)
|
|
257
|
-
text_needs_to_be_drawn = False
|
|
258
|
-
to_draw = x = y = None
|
|
259
|
-
|
|
260
|
-
if widgets[key].render_widget:
|
|
261
|
-
border_handler(
|
|
262
|
-
widget_dict,
|
|
263
|
-
widgets[key],
|
|
264
|
-
rect_borders_to_draw[page],
|
|
265
|
-
ellipse_borders_to_draw[page],
|
|
266
|
-
line_borders_to_draw[page],
|
|
267
|
-
)
|
|
268
|
-
|
|
269
|
-
if isinstance(widgets[key], (Checkbox, Radio)):
|
|
270
|
-
to_draw, x, y, text_needs_to_be_drawn = check_radio_handler(
|
|
271
|
-
widget_dict, widgets[key], radio_button_tracker
|
|
272
|
-
)
|
|
273
|
-
elif isinstance(widgets[key], (Signature, Image)):
|
|
274
|
-
any_image_to_draw |= signature_image_handler(
|
|
275
|
-
widget_dict, widgets[key], images_to_draw[page]
|
|
276
|
-
)
|
|
277
|
-
else:
|
|
278
|
-
to_draw, x, y, text_needs_to_be_drawn = text_handler(
|
|
279
|
-
widget_dict, widgets[key]
|
|
280
|
-
)
|
|
281
|
-
|
|
282
|
-
if all(
|
|
283
|
-
[
|
|
284
|
-
text_needs_to_be_drawn,
|
|
285
|
-
to_draw is not None,
|
|
286
|
-
x is not None,
|
|
287
|
-
y is not None,
|
|
288
|
-
]
|
|
289
|
-
):
|
|
290
|
-
texts_to_draw[page].append(
|
|
291
|
-
{
|
|
292
|
-
"widget": to_draw,
|
|
293
|
-
"x": x,
|
|
294
|
-
"y": y,
|
|
295
|
-
}
|
|
296
|
-
)
|
|
297
|
-
|
|
298
|
-
result = template_stream
|
|
299
|
-
result = get_drawn_stream(rect_borders_to_draw, result, "rect")
|
|
300
|
-
result = get_drawn_stream(ellipse_borders_to_draw, result, "ellipse")
|
|
301
|
-
result = get_drawn_stream(line_borders_to_draw, result, "line")
|
|
302
|
-
result = get_drawn_stream(texts_to_draw, result, "text")
|
|
303
|
-
|
|
304
|
-
if any_image_to_draw:
|
|
305
|
-
result = get_drawn_stream(images_to_draw, result, "image")
|
|
306
|
-
|
|
307
|
-
return result
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
def enable_adobe_mode(reader: PdfReader, writer: PdfWriter, adobe_mode: bool) -> None:
|
|
311
|
-
"""Configures the PDF for Adobe Acrobat compatibility by setting the NeedAppearances flag
|
|
312
|
-
and ensuring the AcroForm structure is properly initialized.
|
|
313
|
-
|
|
314
|
-
Args:
|
|
315
|
-
reader: PdfReader instance of the PDF
|
|
316
|
-
writer: PdfWriter instance to configure
|
|
317
|
-
adobe_mode: If True, enables Adobe Acrobat compatibility mode
|
|
318
|
-
"""
|
|
319
|
-
|
|
320
|
-
if not adobe_mode:
|
|
321
|
-
return
|
|
322
|
-
|
|
323
|
-
# https://stackoverflow.com/questions/47288578/pdf-form-filled-with-pypdf2-does-not-show-in-print
|
|
324
|
-
if AcroForm in reader.trailer[Root]:
|
|
325
|
-
reader.trailer[Root][AcroForm].update(
|
|
326
|
-
{NameObject(NeedAppearances): BooleanObject(True)}
|
|
327
|
-
)
|
|
328
|
-
|
|
329
|
-
if AcroForm not in writer.root_object:
|
|
330
|
-
writer.root_object.update(
|
|
331
|
-
{NameObject(AcroForm): IndirectObject(len(writer.root_object), 0, writer)}
|
|
332
|
-
)
|
|
333
|
-
writer.root_object[AcroForm][NameObject(NeedAppearances)] = BooleanObject(True)
|
|
334
|
-
writer.root_object[AcroForm][NameObject(Fields)] = ArrayObject()
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
def simple_fill(
|
|
338
102
|
template: bytes,
|
|
339
103
|
widgets: Dict[str, WIDGET_TYPES],
|
|
340
104
|
use_full_widget_name: bool,
|
|
341
105
|
flatten: bool = False,
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
"""Fills a PDF form by directly modifying form fields.
|
|
106
|
+
) -> tuple:
|
|
107
|
+
"""Fills a PDF template with the given widgets.
|
|
345
108
|
|
|
346
|
-
This
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
109
|
+
This function fills a PDF template with the provided widget values. It iterates through the
|
|
110
|
+
widgets on each page of the PDF and updates their values based on the provided `widgets`
|
|
111
|
+
dictionary. The function supports various widget types, including text fields, checkboxes,
|
|
112
|
+
radio buttons, dropdowns, images, and signatures. It also supports flattening the filled
|
|
113
|
+
form to prevent further modifications.
|
|
350
114
|
|
|
351
115
|
Args:
|
|
352
|
-
template:
|
|
353
|
-
widgets:
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
116
|
+
template (bytes): The PDF template as bytes.
|
|
117
|
+
widgets (Dict[str, WIDGET_TYPES]): A dictionary of widgets to fill, where the keys are the
|
|
118
|
+
widget names and the values are the widget objects.
|
|
119
|
+
use_full_widget_name (bool): Whether to use the full widget name when looking up widgets
|
|
120
|
+
in the `widgets` dictionary.
|
|
121
|
+
flatten (bool): Whether to flatten the filled PDF. Defaults to False.
|
|
357
122
|
|
|
358
123
|
Returns:
|
|
359
|
-
|
|
124
|
+
tuple: A tuple containing the filled PDF as bytes and the image drawn stream as bytes, if any.
|
|
125
|
+
The image drawn stream is only returned if there are any image or signature widgets
|
|
126
|
+
in the form.
|
|
360
127
|
"""
|
|
361
|
-
|
|
362
128
|
pdf = PdfReader(stream_to_io(template))
|
|
363
129
|
out = PdfWriter()
|
|
364
|
-
enable_adobe_mode(pdf, out, adobe_mode)
|
|
365
130
|
out.append(pdf)
|
|
366
131
|
|
|
367
132
|
radio_button_tracker = {}
|
|
133
|
+
images_to_draw = {}
|
|
134
|
+
any_image_to_draw = False
|
|
368
135
|
|
|
369
|
-
for page in out.pages:
|
|
136
|
+
for page_num, page in enumerate(out.pages):
|
|
137
|
+
images_to_draw[page_num + 1] = []
|
|
370
138
|
for annot in page.get(Annots, []):
|
|
371
139
|
annot = cast(DictionaryObject, annot.get_object())
|
|
372
140
|
key = get_widget_key(annot.get_object(), use_full_widget_name)
|
|
373
141
|
|
|
374
142
|
widget = widgets.get(key)
|
|
375
|
-
if widget is None
|
|
143
|
+
if widget is None:
|
|
144
|
+
continue
|
|
145
|
+
|
|
146
|
+
# flatten all
|
|
147
|
+
if flatten:
|
|
148
|
+
(flatten_radio if isinstance(widget, Radio) else flatten_generic)(annot)
|
|
149
|
+
if widget.value is None:
|
|
376
150
|
continue
|
|
377
151
|
|
|
378
|
-
if
|
|
379
|
-
|
|
152
|
+
if isinstance(widgets[key], (Signature, Image)):
|
|
153
|
+
any_image_to_draw |= signature_image_handler(
|
|
154
|
+
annot, widgets[key], images_to_draw[page_num + 1]
|
|
155
|
+
)
|
|
156
|
+
elif type(widget) is Checkbox:
|
|
157
|
+
update_checkbox_value(annot, widget.value)
|
|
380
158
|
elif isinstance(widget, Radio):
|
|
381
159
|
if key not in radio_button_tracker:
|
|
382
160
|
radio_button_tracker[key] = 0
|
|
383
161
|
radio_button_tracker[key] += 1
|
|
384
162
|
if widget.value == radio_button_tracker[key] - 1:
|
|
385
|
-
|
|
163
|
+
update_radio_value(annot)
|
|
386
164
|
elif isinstance(widget, Dropdown):
|
|
387
|
-
|
|
165
|
+
update_dropdown_value(annot, widget)
|
|
388
166
|
elif isinstance(widget, Text):
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
if flatten:
|
|
392
|
-
if isinstance(widget, Radio):
|
|
393
|
-
simple_flatten_radio(annot)
|
|
394
|
-
else:
|
|
395
|
-
simple_flatten_generic(annot)
|
|
167
|
+
update_text_value(annot, widget)
|
|
396
168
|
|
|
397
169
|
with BytesIO() as f:
|
|
398
170
|
out.write(f)
|
|
399
171
|
f.seek(0)
|
|
400
|
-
|
|
172
|
+
result = f.read()
|
|
173
|
+
|
|
174
|
+
return result, (
|
|
175
|
+
get_drawn_stream(images_to_draw, result, "image") if any_image_to_draw else None
|
|
176
|
+
)
|