PyPDFForm 2.2.2__py3-none-any.whl → 2.2.4__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/watermark.py +35 -14
- PyPDFForm/wrapper.py +18 -8
- {pypdfform-2.2.2.dist-info → pypdfform-2.2.4.dist-info}/METADATA +1 -1
- {pypdfform-2.2.2.dist-info → pypdfform-2.2.4.dist-info}/RECORD +8 -8
- {pypdfform-2.2.2.dist-info → pypdfform-2.2.4.dist-info}/WHEEL +1 -1
- {pypdfform-2.2.2.dist-info → pypdfform-2.2.4.dist-info}/licenses/LICENSE +0 -0
- {pypdfform-2.2.2.dist-info → pypdfform-2.2.4.dist-info}/top_level.txt +0 -0
PyPDFForm/__init__.py
CHANGED
PyPDFForm/watermark.py
CHANGED
|
@@ -10,7 +10,7 @@ This module handles:
|
|
|
10
10
|
"""
|
|
11
11
|
|
|
12
12
|
from io import BytesIO
|
|
13
|
-
from typing import List
|
|
13
|
+
from typing import List, Union
|
|
14
14
|
|
|
15
15
|
from pypdf import PdfReader, PdfWriter
|
|
16
16
|
from pypdf.generic import ArrayObject, NameObject
|
|
@@ -335,20 +335,28 @@ def merge_watermarks_with_pdf(
|
|
|
335
335
|
|
|
336
336
|
|
|
337
337
|
def copy_watermark_widgets(
|
|
338
|
-
pdf: bytes,
|
|
338
|
+
pdf: bytes,
|
|
339
|
+
watermarks: Union[List[bytes], bytes],
|
|
340
|
+
keys: Union[List[str], None],
|
|
341
|
+
page_num: Union[int, None],
|
|
339
342
|
) -> bytes:
|
|
340
|
-
"""
|
|
341
|
-
|
|
342
|
-
|
|
343
|
+
"""Copies annotation widgets (form fields) from watermark PDFs onto the corresponding pages of a base PDF.
|
|
344
|
+
|
|
345
|
+
This function selectively copies annotation widgets (form fields) from watermark PDFs to a base PDF.
|
|
346
|
+
It allows specifying which widgets to copy based on their keys, and optionally restricts the operation
|
|
347
|
+
to a specific page number.
|
|
343
348
|
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
matches one of the specified keys.
|
|
349
|
+
The function can handle either a list of watermarks (one per page) or a single watermark PDF applied to all pages.
|
|
350
|
+
Widgets are only copied if their key is present in the provided keys list.
|
|
347
351
|
|
|
348
352
|
Args:
|
|
349
353
|
pdf: The original PDF document as bytes.
|
|
350
|
-
watermarks:
|
|
354
|
+
watermarks: Either a list of watermark PDF data (as bytes, one per page) or a single watermark PDF as bytes.
|
|
355
|
+
Empty or None entries are skipped.
|
|
351
356
|
keys: List of widget keys (str). Only widgets whose key is in this list will be copied.
|
|
357
|
+
If None, all widgets will be copied.
|
|
358
|
+
page_num: Optional page number (0-based) to restrict widget copying to. If None, widgets are copied
|
|
359
|
+
across all pages.
|
|
352
360
|
|
|
353
361
|
Returns:
|
|
354
362
|
bytes: The resulting PDF document with selected annotation widgets from watermarks copied onto their respective pages.
|
|
@@ -358,21 +366,34 @@ def copy_watermark_widgets(
|
|
|
358
366
|
out = PdfWriter()
|
|
359
367
|
out.append(pdf_file)
|
|
360
368
|
|
|
361
|
-
|
|
369
|
+
widgets_to_copy_watermarks = {}
|
|
370
|
+
widgets_to_copy_pdf = {}
|
|
371
|
+
|
|
372
|
+
widgets_to_copy = widgets_to_copy_watermarks
|
|
373
|
+
if isinstance(watermarks, bytes):
|
|
374
|
+
watermarks = [watermarks]
|
|
375
|
+
widgets_to_copy = widgets_to_copy_pdf
|
|
376
|
+
|
|
377
|
+
if page_num is not None:
|
|
378
|
+
widgets_to_copy = widgets_to_copy_watermarks
|
|
362
379
|
|
|
363
380
|
for i, watermark in enumerate(watermarks):
|
|
364
381
|
if not watermark:
|
|
365
382
|
continue
|
|
366
383
|
|
|
367
|
-
|
|
384
|
+
widgets_to_copy_watermarks[i] = []
|
|
368
385
|
watermark_file = PdfReader(stream_to_io(watermark))
|
|
369
|
-
for page in watermark_file.pages:
|
|
386
|
+
for j, page in enumerate(watermark_file.pages):
|
|
387
|
+
widgets_to_copy_pdf[j] = []
|
|
370
388
|
for annot in page.get(Annots, []): # noqa
|
|
371
389
|
key = extract_widget_property(
|
|
372
390
|
annot.get_object(), WIDGET_KEY_PATTERNS, None, str
|
|
373
391
|
)
|
|
374
|
-
if key in keys
|
|
375
|
-
|
|
392
|
+
if (keys is None or key in keys) and (
|
|
393
|
+
page_num is None or page_num == j
|
|
394
|
+
):
|
|
395
|
+
widgets_to_copy_watermarks[i].append(annot.clone(out))
|
|
396
|
+
widgets_to_copy_pdf[j].append(annot.clone(out))
|
|
376
397
|
|
|
377
398
|
for i, page in enumerate(out.pages):
|
|
378
399
|
if i in widgets_to_copy:
|
PyPDFForm/wrapper.py
CHANGED
|
@@ -288,9 +288,10 @@ class PdfWrapper(FormWrapper):
|
|
|
288
288
|
|
|
289
289
|
return [
|
|
290
290
|
self.__class__(
|
|
291
|
-
each,
|
|
291
|
+
copy_watermark_widgets(each, self.stream, None, i),
|
|
292
|
+
**{param: getattr(self, param) for param, _ in self.USER_PARAMS},
|
|
292
293
|
)
|
|
293
|
-
for each in get_page_streams(self.
|
|
294
|
+
for i, each in enumerate(get_page_streams(remove_all_widgets(self.read())))
|
|
294
295
|
]
|
|
295
296
|
|
|
296
297
|
def change_version(self, version: str) -> PdfWrapper:
|
|
@@ -497,7 +498,7 @@ class PdfWrapper(FormWrapper):
|
|
|
497
498
|
obj = _class(name=name, page_number=page_number, x=x, y=y, **kwargs)
|
|
498
499
|
watermarks = obj.watermarks(self.read())
|
|
499
500
|
|
|
500
|
-
self.stream = copy_watermark_widgets(self.read(), watermarks, [name])
|
|
501
|
+
self.stream = copy_watermark_widgets(self.read(), watermarks, [name], None)
|
|
501
502
|
if obj.non_acro_form_params:
|
|
502
503
|
self.stream = handle_non_acro_form_params(
|
|
503
504
|
self.stream, name, obj.non_acro_form_params
|
|
@@ -586,7 +587,10 @@ class PdfWrapper(FormWrapper):
|
|
|
586
587
|
"""Draws static text onto the PDF document at specified coordinates.
|
|
587
588
|
|
|
588
589
|
Adds non-interactive text that becomes part of the PDF content rather
|
|
589
|
-
than a form field.
|
|
590
|
+
than a form field. The text is drawn using a temporary Text widget and
|
|
591
|
+
merged via watermark operations, preserving existing form fields.
|
|
592
|
+
|
|
593
|
+
Supports multi-line text (using NEW_LINE_SYMBOL) and custom formatting.
|
|
590
594
|
|
|
591
595
|
Args:
|
|
592
596
|
text: The text content to draw (supports newlines with NEW_LINE_SYMBOL)
|
|
@@ -624,7 +628,11 @@ class PdfWrapper(FormWrapper):
|
|
|
624
628
|
],
|
|
625
629
|
)
|
|
626
630
|
|
|
631
|
+
stream_with_widgets = self.read()
|
|
627
632
|
self.stream = merge_watermarks_with_pdf(self.stream, watermarks)
|
|
633
|
+
self.stream = copy_watermark_widgets(
|
|
634
|
+
remove_all_widgets(self.stream), stream_with_widgets, None, None
|
|
635
|
+
)
|
|
628
636
|
|
|
629
637
|
return self
|
|
630
638
|
|
|
@@ -640,10 +648,8 @@ class PdfWrapper(FormWrapper):
|
|
|
640
648
|
) -> PdfWrapper:
|
|
641
649
|
"""Draws an image onto the PDF document at specified coordinates.
|
|
642
650
|
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
- File path
|
|
646
|
-
- File-like object
|
|
651
|
+
The image is merged via watermark operations, preserving existing form fields.
|
|
652
|
+
Supports common formats (JPEG, PNG) from bytes, file paths, or file objects.
|
|
647
653
|
|
|
648
654
|
Args:
|
|
649
655
|
image: Image data as bytes, file path, or file object
|
|
@@ -664,7 +670,11 @@ class PdfWrapper(FormWrapper):
|
|
|
664
670
|
self.stream, page_number, "image", [[image, x, y, width, height]]
|
|
665
671
|
)
|
|
666
672
|
|
|
673
|
+
stream_with_widgets = self.read()
|
|
667
674
|
self.stream = merge_watermarks_with_pdf(self.stream, watermarks)
|
|
675
|
+
self.stream = copy_watermark_widgets(
|
|
676
|
+
remove_all_widgets(self.stream), stream_with_widgets, None, None
|
|
677
|
+
)
|
|
668
678
|
|
|
669
679
|
return self
|
|
670
680
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
PyPDFForm/__init__.py,sha256=
|
|
1
|
+
PyPDFForm/__init__.py,sha256=O-6vjBgvz5Cs4XbRwRyzJxW8Qk81vE3itghTLrSUgkI,328
|
|
2
2
|
PyPDFForm/adapter.py,sha256=_5fP5UR-NzjDDayJmBRO36DgbnbUzNbjZtHZtPvSM14,1909
|
|
3
3
|
PyPDFForm/constants.py,sha256=r4lR-lQ8KjKRLMowjxIv6k3wBPOxvt9-JAMugZwQmZM,2285
|
|
4
4
|
PyPDFForm/coordinate.py,sha256=AgVrBoUo6fLVTVdZrlVRf6tGwD-AX54ICMLfbvhYfRs,14879
|
|
@@ -8,8 +8,8 @@ PyPDFForm/image.py,sha256=aYk7BC-AHiqt73durGIQ3e6gE5Ggbdr8jmkCUaQdsk8,1627
|
|
|
8
8
|
PyPDFForm/patterns.py,sha256=iChwqR-aZUKhEdnbQ8OEwnES2-NaMhBUy4dUrnuDPpA,9243
|
|
9
9
|
PyPDFForm/template.py,sha256=v1ZM52xHCzO8Xm7EXinbTepm2G7MU7StUgCFtuUdcbI,18899
|
|
10
10
|
PyPDFForm/utils.py,sha256=ubqTaItrs6pEYcza-12bxLUiFYe_sl-0SdeowD_BSG0,8444
|
|
11
|
-
PyPDFForm/watermark.py,sha256=
|
|
12
|
-
PyPDFForm/wrapper.py,sha256=
|
|
11
|
+
PyPDFForm/watermark.py,sha256=w4m5wMOnVvDD693gbKrpZ1rvmjsgxrRaiSvDQfFCky0,12074
|
|
12
|
+
PyPDFForm/wrapper.py,sha256=spClcCLAfjTrwMwn6lP4zEtEKQ_Pb-SBy_US9SmS_Xc,25263
|
|
13
13
|
PyPDFForm/middleware/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
14
|
PyPDFForm/middleware/base.py,sha256=d4z7M7pm80176cC4H85m3ZRWzAu_Fm1HkwQkmSSi-WE,2832
|
|
15
15
|
PyPDFForm/middleware/checkbox.py,sha256=gRGhFySPoIpKBseoiOTS3WggoBBik12dXbZ-LJKzIwM,2611
|
|
@@ -27,8 +27,8 @@ PyPDFForm/widgets/image.py,sha256=6y8Ysmk49USr_qWOXD6KGL6cch516cUIlrxoj0pJy9Q,79
|
|
|
27
27
|
PyPDFForm/widgets/radio.py,sha256=ipadJyHbgftDUvjGk15kapzgHPN3HjdF_iB_7amXR6o,2737
|
|
28
28
|
PyPDFForm/widgets/signature.py,sha256=RII_fgjPRbM5_72ih4L6ohaWCBOyjgIoY6odkd15VY8,5107
|
|
29
29
|
PyPDFForm/widgets/text.py,sha256=HP2cPEUAzK5QL3kDfMz7gQcC3svCpmYuyFItBjlrBpI,1233
|
|
30
|
-
pypdfform-2.2.
|
|
31
|
-
pypdfform-2.2.
|
|
32
|
-
pypdfform-2.2.
|
|
33
|
-
pypdfform-2.2.
|
|
34
|
-
pypdfform-2.2.
|
|
30
|
+
pypdfform-2.2.4.dist-info/licenses/LICENSE,sha256=43awmYkI6opyTpg19me731iO1WfXZwViqb67oWtCsFY,1065
|
|
31
|
+
pypdfform-2.2.4.dist-info/METADATA,sha256=40T0_d8c8w_xm84oLVUOTdl60vutnZgAMu_Y6KQrtug,5605
|
|
32
|
+
pypdfform-2.2.4.dist-info/WHEEL,sha256=SmOxYU7pzNKBqASvQJ7DjX3XGUF92lrGhMb3R6_iiqI,91
|
|
33
|
+
pypdfform-2.2.4.dist-info/top_level.txt,sha256=GQQKuWqPUjT9YZqwK95NlAQzxjwoQrsxQ8ureM8lWOY,10
|
|
34
|
+
pypdfform-2.2.4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|