PyPDFForm 5.2.0__tar.gz → 5.2.1__tar.gz
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.
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PKG-INFO +2 -2
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/__init__.py +1 -1
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/lib/filler.py +3 -1
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/lib/image.py +6 -9
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/lib/template.py +25 -17
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/lib/watermark.py +16 -7
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/lib/widgets/base.py +25 -7
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/lib/widgets/signature.py +5 -2
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/lib/wrapper.py +25 -5
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm.egg-info/PKG-INFO +2 -2
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm.egg-info/requires.txt +1 -1
- {pypdfform-5.2.0 → pypdfform-5.2.1}/pyproject.toml +1 -1
- {pypdfform-5.2.0 → pypdfform-5.2.1}/LICENSE +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/cli/__init__.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/cli/common.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/cli/create.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/cli/entry.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/cli/inspect.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/cli/remove.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/cli/root.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/cli/schemas/__init__.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/cli/schemas/create.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/cli/schemas/update.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/cli/update.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/lib/__init__.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/lib/adapter.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/lib/annotations/__init__.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/lib/annotations/base.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/lib/annotations/link.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/lib/annotations/stamp.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/lib/annotations/text.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/lib/annotations/text_markup.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/lib/assets/__init__.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/lib/assets/bedrock.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/lib/assets/blank.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/lib/constants.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/lib/coordinate.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/lib/deprecation.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/lib/egress.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/lib/font.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/lib/hooks.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/lib/middleware/__init__.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/lib/middleware/base.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/lib/middleware/checkbox.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/lib/middleware/dropdown.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/lib/middleware/image.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/lib/middleware/radio.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/lib/middleware/signature.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/lib/middleware/text.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/lib/patterns.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/lib/raw/__init__.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/lib/raw/circle.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/lib/raw/ellipse.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/lib/raw/image.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/lib/raw/line.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/lib/raw/rect.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/lib/raw/text.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/lib/types.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/lib/utils.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/lib/widgets/__init__.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/lib/widgets/checkbox.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/lib/widgets/dropdown.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/lib/widgets/image.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/lib/widgets/radio.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm/lib/widgets/text.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm.egg-info/SOURCES.txt +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm.egg-info/dependency_links.txt +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm.egg-info/entry_points.txt +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/PyPDFForm.egg-info/top_level.txt +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/README.md +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/setup.cfg +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/tests/test_bulk_create_fields.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/tests/test_create_widget.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/tests/test_draw_elements.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/tests/test_dropdown.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/tests/test_extract_middleware_attributes.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/tests/test_fill_max_length_text_field.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/tests/test_font_widths.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/tests/test_functional.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/tests/test_generate_appearance_streams.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/tests/test_js.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/tests/test_need_appearances.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/tests/test_paragraph.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/tests/test_signature.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/tests/test_use_full_widget_name.py +0 -0
- {pypdfform-5.2.0 → pypdfform-5.2.1}/tests/test_widget_attr_trigger.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: PyPDFForm
|
|
3
|
-
Version: 5.2.
|
|
3
|
+
Version: 5.2.1
|
|
4
4
|
Summary: The Python library & CLI for PDF forms.
|
|
5
5
|
Author: Jinge Li
|
|
6
6
|
License-Expression: MIT
|
|
@@ -24,7 +24,7 @@ Classifier: Topic :: Utilities
|
|
|
24
24
|
Requires-Python: >=3.10
|
|
25
25
|
Description-Content-Type: text/markdown
|
|
26
26
|
License-File: LICENSE
|
|
27
|
-
Requires-Dist: cryptography<
|
|
27
|
+
Requires-Dist: cryptography<50.0.0,>=48.0.0
|
|
28
28
|
Requires-Dist: fonttools<5.0.0,>=4.63.0
|
|
29
29
|
Requires-Dist: pikepdf<11.0.0,>=10.7.2
|
|
30
30
|
Requires-Dist: pillow<13.0.0,>=12.2.0
|
|
@@ -57,7 +57,9 @@ def signature_image_handler(
|
|
|
57
57
|
any_image_to_draw = False
|
|
58
58
|
if stream is not None:
|
|
59
59
|
any_image_to_draw = True
|
|
60
|
-
image_width, image_height =
|
|
60
|
+
image_width, image_height = (
|
|
61
|
+
get_image_dimensions(stream) if middleware.preserve_aspect_ratio else (0, 0)
|
|
62
|
+
)
|
|
61
63
|
x, y, width, height = get_draw_image_resolutions(
|
|
62
64
|
widget, middleware.preserve_aspect_ratio, image_width, image_height
|
|
63
65
|
)
|
|
@@ -7,6 +7,7 @@ calculating the resolutions for drawing an image on a PDF page, taking into
|
|
|
7
7
|
account whether to preserve the aspect ratio.
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
|
+
from functools import lru_cache
|
|
10
11
|
from io import BytesIO
|
|
11
12
|
from typing import Tuple
|
|
12
13
|
|
|
@@ -50,12 +51,13 @@ def rotate_image(image_stream: bytes, rotation: float | int) -> bytes:
|
|
|
50
51
|
return result
|
|
51
52
|
|
|
52
53
|
|
|
54
|
+
@lru_cache
|
|
53
55
|
def get_image_dimensions(image_stream: bytes) -> Tuple[float, float]:
|
|
54
56
|
"""
|
|
55
57
|
Retrieves the width and height of an image from its byte stream.
|
|
56
58
|
|
|
57
|
-
This function uses the PIL library to open the image from the provided
|
|
58
|
-
and returns its dimensions (width and height) as a tuple of floats.
|
|
59
|
+
This cached function uses the PIL library to open the image from the provided
|
|
60
|
+
byte stream and returns its dimensions (width and height) as a tuple of floats.
|
|
59
61
|
|
|
60
62
|
Args:
|
|
61
63
|
image_stream (bytes): The image data as bytes.
|
|
@@ -63,13 +65,8 @@ def get_image_dimensions(image_stream: bytes) -> Tuple[float, float]:
|
|
|
63
65
|
Returns:
|
|
64
66
|
Tuple[float, float]: The width and height of the image in pixels.
|
|
65
67
|
"""
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
buff.seek(0)
|
|
69
|
-
|
|
70
|
-
image = Image.open(buff)
|
|
71
|
-
|
|
72
|
-
return image.size
|
|
68
|
+
with Image.open(BytesIO(image_stream)) as image:
|
|
69
|
+
return image.size
|
|
73
70
|
|
|
74
71
|
|
|
75
72
|
def get_draw_image_resolutions(
|
|
@@ -449,8 +449,7 @@ def update_widget_keys(
|
|
|
449
449
|
out = PdfWriter()
|
|
450
450
|
out.append(pdf)
|
|
451
451
|
|
|
452
|
-
|
|
453
|
-
_update_single_widget_key(out, widgets, old_key, new_keys[i], indices[i])
|
|
452
|
+
_apply_widget_key_updates(out, widgets, old_keys, new_keys, indices)
|
|
454
453
|
|
|
455
454
|
with BytesIO() as f:
|
|
456
455
|
out.write(f)
|
|
@@ -458,35 +457,44 @@ def update_widget_keys(
|
|
|
458
457
|
return f.read()
|
|
459
458
|
|
|
460
459
|
|
|
461
|
-
def
|
|
460
|
+
def _apply_widget_key_updates(
|
|
462
461
|
writer: PdfWriter,
|
|
463
462
|
widgets: Dict[str, WIDGET_TYPES],
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
463
|
+
old_keys: List[str],
|
|
464
|
+
new_keys: List[str],
|
|
465
|
+
indices: List[int],
|
|
467
466
|
) -> None:
|
|
468
467
|
"""
|
|
469
|
-
|
|
468
|
+
Applies queued widget key updates to matching annotations.
|
|
469
|
+
|
|
470
|
+
The update queue is converted into a lookup keyed by old widget name, then
|
|
471
|
+
each annotation is checked against that lookup as pages are traversed.
|
|
472
|
+
Non-radio widgets honor the requested occurrence index, while radio widgets
|
|
473
|
+
update every annotation in the radio group.
|
|
470
474
|
|
|
471
475
|
Args:
|
|
472
476
|
writer (PdfWriter): The PDF writer object.
|
|
473
477
|
widgets (Dict[str, WIDGET_TYPES]): A dictionary of widgets in the template.
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
478
|
+
old_keys (List[str]): The old widget keys to replace.
|
|
479
|
+
new_keys (List[str]): The new widget keys to apply.
|
|
480
|
+
indices (List[int]): Widget occurrence indices for duplicate field names.
|
|
477
481
|
"""
|
|
478
|
-
|
|
482
|
+
updates = {old_key: (new_keys[i], indices[i]) for i, old_key in enumerate(old_keys)}
|
|
483
|
+
trackers = {}
|
|
484
|
+
|
|
479
485
|
for page in writer.pages:
|
|
480
486
|
for annot in page.get(Annots, []):
|
|
481
487
|
annot = cast(DictionaryObject, annot.get_object())
|
|
482
488
|
key = get_widget_key(annot.get_object(), False)
|
|
483
489
|
|
|
484
|
-
|
|
485
|
-
if widget is None or old_key != key:
|
|
490
|
+
if key not in updates:
|
|
486
491
|
continue
|
|
487
492
|
|
|
488
|
-
|
|
489
|
-
if
|
|
490
|
-
|
|
493
|
+
widget = widgets.get(key)
|
|
494
|
+
if widget is not None:
|
|
495
|
+
trackers[key] = trackers.get(key, -1) + 1
|
|
496
|
+
new_key, index = updates[key]
|
|
497
|
+
if not isinstance(widget, Radio) and trackers[key] != index:
|
|
498
|
+
continue
|
|
491
499
|
|
|
492
|
-
|
|
500
|
+
update_annotation_name(annot, new_key)
|
|
@@ -9,6 +9,7 @@ and to copy specific widgets from the watermarks to the original PDF.
|
|
|
9
9
|
"""
|
|
10
10
|
|
|
11
11
|
from collections import defaultdict
|
|
12
|
+
from functools import lru_cache
|
|
12
13
|
from io import BytesIO
|
|
13
14
|
from typing import Any, Dict, List, Optional
|
|
14
15
|
|
|
@@ -21,6 +22,20 @@ from .constants import Annots
|
|
|
21
22
|
from .patterns import get_widget_key
|
|
22
23
|
|
|
23
24
|
|
|
25
|
+
@lru_cache(maxsize=128)
|
|
26
|
+
def _get_image_reader(image_stream: bytes) -> ImageReader:
|
|
27
|
+
"""
|
|
28
|
+
Creates a cached ReportLab image reader for an image byte stream.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
image_stream (bytes): The image data as a byte stream.
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
ImageReader: The cached ReportLab image reader.
|
|
35
|
+
"""
|
|
36
|
+
return ImageReader(BytesIO(image_stream))
|
|
37
|
+
|
|
38
|
+
|
|
24
39
|
def draw_text(canvas: Canvas, **kwargs) -> None:
|
|
25
40
|
"""
|
|
26
41
|
Draws a text string on the given canvas using the specified font, size, and color.
|
|
@@ -206,12 +221,8 @@ def draw_image(canvas: Canvas, **kwargs) -> None:
|
|
|
206
221
|
width = kwargs["width"]
|
|
207
222
|
height = kwargs["height"]
|
|
208
223
|
|
|
209
|
-
image_buff = BytesIO()
|
|
210
|
-
image_buff.write(image_stream)
|
|
211
|
-
image_buff.seek(0)
|
|
212
|
-
|
|
213
224
|
canvas.drawImage(
|
|
214
|
-
|
|
225
|
+
_get_image_reader(image_stream),
|
|
215
226
|
coordinate_x,
|
|
216
227
|
coordinate_y,
|
|
217
228
|
width=width,
|
|
@@ -219,8 +230,6 @@ def draw_image(canvas: Canvas, **kwargs) -> None:
|
|
|
219
230
|
mask="auto",
|
|
220
231
|
)
|
|
221
232
|
|
|
222
|
-
image_buff.close()
|
|
223
|
-
|
|
224
233
|
|
|
225
234
|
def create_watermarks_and_draw(
|
|
226
235
|
pdf: bytes, to_draw: List[dict], font_mapping: Optional[Dict[str, str]] = None
|
|
@@ -15,6 +15,7 @@ Classes:
|
|
|
15
15
|
from __future__ import annotations
|
|
16
16
|
|
|
17
17
|
from dataclasses import dataclass
|
|
18
|
+
from functools import lru_cache
|
|
18
19
|
from inspect import signature
|
|
19
20
|
from io import BytesIO
|
|
20
21
|
from typing import List, Optional
|
|
@@ -102,6 +103,28 @@ class Widget:
|
|
|
102
103
|
if each in kwargs:
|
|
103
104
|
self.hook_params.append((each, kwargs.get(each)))
|
|
104
105
|
|
|
106
|
+
@staticmethod
|
|
107
|
+
@lru_cache
|
|
108
|
+
def _get_default_field_flags(acro_form_class: type, acro_form_func: str) -> tuple:
|
|
109
|
+
"""
|
|
110
|
+
Retrieves the default field flags for a ReportLab AcroForm method.
|
|
111
|
+
|
|
112
|
+
Args:
|
|
113
|
+
acro_form_class (type): The ReportLab AcroForm class.
|
|
114
|
+
acro_form_func (str): The AcroForm method name.
|
|
115
|
+
|
|
116
|
+
Returns:
|
|
117
|
+
tuple: The default field flags split into individual flag names.
|
|
118
|
+
"""
|
|
119
|
+
default_flags = signature(
|
|
120
|
+
getattr(acro_form_class, acro_form_func)
|
|
121
|
+
).parameters.get(fieldFlags)
|
|
122
|
+
return (
|
|
123
|
+
tuple(default_flags.default.split(" "))
|
|
124
|
+
if default_flags and default_flags.default
|
|
125
|
+
else ()
|
|
126
|
+
)
|
|
127
|
+
|
|
105
128
|
def _required_handler(self, canvas: Canvas) -> None:
|
|
106
129
|
"""
|
|
107
130
|
Handles the 'Required' flag for the widget's AcroForm field.
|
|
@@ -115,13 +138,8 @@ class Widget:
|
|
|
115
138
|
Args:
|
|
116
139
|
canvas (Canvas): The ReportLab canvas object used for PDF operations.
|
|
117
140
|
"""
|
|
118
|
-
default_flags =
|
|
119
|
-
|
|
120
|
-
).parameters.get(fieldFlags)
|
|
121
|
-
default_flags = (
|
|
122
|
-
default_flags.default.split(" ")
|
|
123
|
-
if default_flags and default_flags.default
|
|
124
|
-
else []
|
|
141
|
+
default_flags = list(
|
|
142
|
+
self._get_default_field_flags(type(canvas.acroForm), self.ACRO_FORM_FUNC)
|
|
125
143
|
)
|
|
126
144
|
|
|
127
145
|
if self.acro_form_params.get(required):
|
|
@@ -120,6 +120,11 @@ class SignatureWidget:
|
|
|
120
120
|
annot_type_to_annot[key] = annot.get_object()
|
|
121
121
|
|
|
122
122
|
for i, p in enumerate(input_pdf.pages):
|
|
123
|
+
page_widgets = page_to_widgets.get(i + 1, [])
|
|
124
|
+
if not page_widgets:
|
|
125
|
+
result.append(b"")
|
|
126
|
+
continue
|
|
127
|
+
|
|
123
128
|
# pylint: disable=R0801
|
|
124
129
|
watermark = BytesIO()
|
|
125
130
|
canvas = Canvas(
|
|
@@ -135,8 +140,6 @@ class SignatureWidget:
|
|
|
135
140
|
|
|
136
141
|
out = PdfWriter(watermark)
|
|
137
142
|
|
|
138
|
-
page_widgets = page_to_widgets.get(i + 1, [])
|
|
139
|
-
|
|
140
143
|
widgets_to_copy = []
|
|
141
144
|
for widget in page_widgets:
|
|
142
145
|
widget_to_copy = annot_type_to_annot[
|
|
@@ -20,7 +20,7 @@ from __future__ import annotations
|
|
|
20
20
|
|
|
21
21
|
from collections import defaultdict
|
|
22
22
|
from dataclasses import asdict
|
|
23
|
-
from functools import
|
|
23
|
+
from functools import lru_cache
|
|
24
24
|
from os import PathLike
|
|
25
25
|
from typing import (
|
|
26
26
|
TYPE_CHECKING,
|
|
@@ -241,6 +241,27 @@ class PdfWrapper:
|
|
|
241
241
|
if self._read():
|
|
242
242
|
self._available_fonts.update(**get_all_available_fonts(self._read()))
|
|
243
243
|
|
|
244
|
+
@staticmethod
|
|
245
|
+
@lru_cache
|
|
246
|
+
def _get_page_streams_with_widgets(stream: bytes) -> tuple[bytes, ...]:
|
|
247
|
+
"""
|
|
248
|
+
Extracts page streams while preserving the original page widgets.
|
|
249
|
+
|
|
250
|
+
Args:
|
|
251
|
+
stream (bytes): The PDF stream to split into pages.
|
|
252
|
+
|
|
253
|
+
Returns:
|
|
254
|
+
tuple[bytes, ...]: Single-page PDF streams with widgets preserved.
|
|
255
|
+
"""
|
|
256
|
+
|
|
257
|
+
return tuple(
|
|
258
|
+
# Case: Single watermark PDF, extracting a specific page to the first output page.
|
|
259
|
+
copy_watermark_widgets(page_stream, stream, None, i)
|
|
260
|
+
for i, page_stream in enumerate(
|
|
261
|
+
get_page_streams(remove_all_widgets(stream))
|
|
262
|
+
)
|
|
263
|
+
)
|
|
264
|
+
|
|
244
265
|
def _reregister_font(self) -> PdfWrapper:
|
|
245
266
|
"""
|
|
246
267
|
Reregisters fonts after PDF content modifications.
|
|
@@ -334,7 +355,7 @@ class PdfWrapper:
|
|
|
334
355
|
|
|
335
356
|
return list(self._available_fonts.keys())
|
|
336
357
|
|
|
337
|
-
@
|
|
358
|
+
@property
|
|
338
359
|
def pages(self) -> Sequence[PdfWrapper]:
|
|
339
360
|
"""
|
|
340
361
|
Returns a list of `PdfWrapper` objects, each representing a single page in the PDF document.
|
|
@@ -347,11 +368,10 @@ class PdfWrapper:
|
|
|
347
368
|
|
|
348
369
|
result = [
|
|
349
370
|
self.__class__(
|
|
350
|
-
|
|
351
|
-
copy_watermark_widgets(each, self._read(), None, i),
|
|
371
|
+
each,
|
|
352
372
|
**{param: getattr(self, param) for param, _ in self.USER_PARAMS},
|
|
353
373
|
)
|
|
354
|
-
for
|
|
374
|
+
for each in self._get_page_streams_with_widgets(self._read())
|
|
355
375
|
]
|
|
356
376
|
|
|
357
377
|
# because copy_watermark_widgets and remove_all_widgets
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: PyPDFForm
|
|
3
|
-
Version: 5.2.
|
|
3
|
+
Version: 5.2.1
|
|
4
4
|
Summary: The Python library & CLI for PDF forms.
|
|
5
5
|
Author: Jinge Li
|
|
6
6
|
License-Expression: MIT
|
|
@@ -24,7 +24,7 @@ Classifier: Topic :: Utilities
|
|
|
24
24
|
Requires-Python: >=3.10
|
|
25
25
|
Description-Content-Type: text/markdown
|
|
26
26
|
License-File: LICENSE
|
|
27
|
-
Requires-Dist: cryptography<
|
|
27
|
+
Requires-Dist: cryptography<50.0.0,>=48.0.0
|
|
28
28
|
Requires-Dist: fonttools<5.0.0,>=4.63.0
|
|
29
29
|
Requires-Dist: pikepdf<11.0.0,>=10.7.2
|
|
30
30
|
Requires-Dist: pillow<13.0.0,>=12.2.0
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|