PyPDFForm 2.2.2__py3-none-any.whl → 2.2.3__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 CHANGED
@@ -5,7 +5,7 @@ This package provides tools for filling PDF forms, drawing text and images,
5
5
  and manipulating PDF form elements programmatically.
6
6
  """
7
7
 
8
- __version__ = "2.2.2"
8
+ __version__ = "2.2.3"
9
9
 
10
10
  from .wrapper import FormWrapper, PdfWrapper
11
11
 
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,22 @@ def merge_watermarks_with_pdf(
335
335
 
336
336
 
337
337
  def copy_watermark_widgets(
338
- pdf: bytes, watermarks: List[bytes], keys: List[str]
338
+ pdf: bytes, watermarks: Union[List[bytes], bytes], keys: Union[List[str], None]
339
339
  ) -> bytes:
340
340
  """
341
341
  Copies annotation widgets (form fields) from watermark PDFs onto the corresponding pages of a base PDF,
342
342
  including only those widgets whose key matches an entry in the provided keys list.
343
343
 
344
- For each watermark in the provided list, any annotation widgets (such as form fields) are cloned
345
- and appended to the annotations of the corresponding page in the base PDF, but only if their key
346
- matches one of the specified keys.
344
+ For each watermark in the provided list (or single watermark PDF if bytes input is provided),
345
+ any annotation widgets (such as form fields) are cloned and appended to the annotations of the
346
+ corresponding page in the base PDF, but only if their key matches one of the specified keys.
347
347
 
348
348
  Args:
349
349
  pdf: The original PDF document as bytes.
350
- watermarks: List of watermark PDF data (as bytes), one per page. Empty or None entries are skipped.
350
+ watermarks: Either a list of watermark PDF data (as bytes, one per page) or a single watermark PDF.
351
+ Empty or None entries are skipped.
351
352
  keys: List of widget keys (str). Only widgets whose key is in this list will be copied.
353
+ If None, all widgets will be copied.
352
354
 
353
355
  Returns:
354
356
  bytes: The resulting PDF document with selected annotation widgets from watermarks copied onto their respective pages.
@@ -358,21 +360,29 @@ def copy_watermark_widgets(
358
360
  out = PdfWriter()
359
361
  out.append(pdf_file)
360
362
 
361
- widgets_to_copy = {}
363
+ widgets_to_copy_watermarks = {}
364
+ widgets_to_copy_pdf = {}
365
+
366
+ widgets_to_copy = widgets_to_copy_watermarks
367
+ if isinstance(watermarks, bytes):
368
+ watermarks = [watermarks]
369
+ widgets_to_copy = widgets_to_copy_pdf
362
370
 
363
371
  for i, watermark in enumerate(watermarks):
364
372
  if not watermark:
365
373
  continue
366
374
 
367
- widgets_to_copy[i] = []
375
+ widgets_to_copy_watermarks[i] = []
368
376
  watermark_file = PdfReader(stream_to_io(watermark))
369
- for page in watermark_file.pages:
377
+ for j, page in enumerate(watermark_file.pages):
378
+ widgets_to_copy_pdf[j] = []
370
379
  for annot in page.get(Annots, []): # noqa
371
380
  key = extract_widget_property(
372
381
  annot.get_object(), WIDGET_KEY_PATTERNS, None, str
373
382
  )
374
- if key in keys:
375
- widgets_to_copy[i].append(annot.clone(out))
383
+ if keys is None or key in keys:
384
+ widgets_to_copy_watermarks[i].append(annot.clone(out))
385
+ widgets_to_copy_pdf[j].append(annot.clone(out))
376
386
 
377
387
  for i, page in enumerate(out.pages):
378
388
  if i in widgets_to_copy:
PyPDFForm/wrapper.py CHANGED
@@ -586,7 +586,10 @@ class PdfWrapper(FormWrapper):
586
586
  """Draws static text onto the PDF document at specified coordinates.
587
587
 
588
588
  Adds non-interactive text that becomes part of the PDF content rather
589
- than a form field. Useful for annotations, labels, signatures, etc.
589
+ than a form field. The text is drawn using a temporary Text widget and
590
+ merged via watermark operations, preserving existing form fields.
591
+
592
+ Supports multi-line text (using NEW_LINE_SYMBOL) and custom formatting.
590
593
 
591
594
  Args:
592
595
  text: The text content to draw (supports newlines with NEW_LINE_SYMBOL)
@@ -624,7 +627,11 @@ class PdfWrapper(FormWrapper):
624
627
  ],
625
628
  )
626
629
 
630
+ stream_with_widgets = self.read()
627
631
  self.stream = merge_watermarks_with_pdf(self.stream, watermarks)
632
+ self.stream = copy_watermark_widgets(
633
+ remove_all_widgets(self.stream), stream_with_widgets, None
634
+ )
628
635
 
629
636
  return self
630
637
 
@@ -640,10 +647,8 @@ class PdfWrapper(FormWrapper):
640
647
  ) -> PdfWrapper:
641
648
  """Draws an image onto the PDF document at specified coordinates.
642
649
 
643
- Supports common image formats (JPEG, PNG) from various sources:
644
- - Raw image bytes
645
- - File path
646
- - File-like object
650
+ The image is merged via watermark operations, preserving existing form fields.
651
+ Supports common formats (JPEG, PNG) from bytes, file paths, or file objects.
647
652
 
648
653
  Args:
649
654
  image: Image data as bytes, file path, or file object
@@ -664,7 +669,11 @@ class PdfWrapper(FormWrapper):
664
669
  self.stream, page_number, "image", [[image, x, y, width, height]]
665
670
  )
666
671
 
672
+ stream_with_widgets = self.read()
667
673
  self.stream = merge_watermarks_with_pdf(self.stream, watermarks)
674
+ self.stream = copy_watermark_widgets(
675
+ remove_all_widgets(self.stream), stream_with_widgets, None
676
+ )
668
677
 
669
678
  return self
670
679
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyPDFForm
3
- Version: 2.2.2
3
+ Version: 2.2.3
4
4
  Summary: The Python library for PDF forms.
5
5
  Author: Jinge Li
6
6
  License-Expression: MIT
@@ -1,4 +1,4 @@
1
- PyPDFForm/__init__.py,sha256=HNulIew3N71YCiwiDKAcAlO6PzDIaF1VrqRgHbnFC6A,328
1
+ PyPDFForm/__init__.py,sha256=d9ZbQFm7UFo3onEPCwtI7pK9dvp_efBkmx-jiBd-sks,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=9ydcqy8wNrea_1BvywyUsbcD4TzxQuEAdo0izOZKYyU,11101
12
- PyPDFForm/wrapper.py,sha256=4owXTiSyvx2DSA2XGnssIjH-ygL2pznmRjpPOuWwaWw,24625
11
+ PyPDFForm/watermark.py,sha256=klvK_ojHa3SzGpzfC8gwaXEamurr63P32xqjkTzE2Yw,11661
12
+ PyPDFForm/wrapper.py,sha256=RuWpsmAxYuaEykjEE6B01jWb4GFz0pII2LYmnlETcu0,25148
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.2.dist-info/licenses/LICENSE,sha256=43awmYkI6opyTpg19me731iO1WfXZwViqb67oWtCsFY,1065
31
- pypdfform-2.2.2.dist-info/METADATA,sha256=uConsIdDy3O6gtKYxjRAROunBPR5ghd4_gNAoedhQ3A,5605
32
- pypdfform-2.2.2.dist-info/WHEEL,sha256=pxyMxgL8-pra_rKaQ4drOZAegBVuX-G_4nRHjjgWbmo,91
33
- pypdfform-2.2.2.dist-info/top_level.txt,sha256=GQQKuWqPUjT9YZqwK95NlAQzxjwoQrsxQ8ureM8lWOY,10
34
- pypdfform-2.2.2.dist-info/RECORD,,
30
+ pypdfform-2.2.3.dist-info/licenses/LICENSE,sha256=43awmYkI6opyTpg19me731iO1WfXZwViqb67oWtCsFY,1065
31
+ pypdfform-2.2.3.dist-info/METADATA,sha256=UeGBFtSfqWCmWnfOHagTjplpUru1pZoxyJ_Js9VBzNo,5605
32
+ pypdfform-2.2.3.dist-info/WHEEL,sha256=pxyMxgL8-pra_rKaQ4drOZAegBVuX-G_4nRHjjgWbmo,91
33
+ pypdfform-2.2.3.dist-info/top_level.txt,sha256=GQQKuWqPUjT9YZqwK95NlAQzxjwoQrsxQ8ureM8lWOY,10
34
+ pypdfform-2.2.3.dist-info/RECORD,,