PyPDFForm 1.5.4__tar.gz → 1.5.6__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.
Potentially problematic release.
This version of PyPDFForm might be problematic. Click here for more details.
- {pypdfform-1.5.4 → pypdfform-1.5.6}/PKG-INFO +1 -1
- {pypdfform-1.5.4 → pypdfform-1.5.6}/PyPDFForm/__init__.py +1 -1
- {pypdfform-1.5.4 → pypdfform-1.5.6}/PyPDFForm/constants.py +1 -0
- {pypdfform-1.5.4 → pypdfform-1.5.6}/PyPDFForm/filler.py +1 -2
- {pypdfform-1.5.4 → pypdfform-1.5.6}/PyPDFForm/image.py +0 -25
- {pypdfform-1.5.4 → pypdfform-1.5.6}/PyPDFForm/utils.py +15 -1
- {pypdfform-1.5.4 → pypdfform-1.5.6}/PyPDFForm/watermark.py +1 -0
- {pypdfform-1.5.4 → pypdfform-1.5.6}/PyPDFForm/wrapper.py +5 -5
- {pypdfform-1.5.4 → pypdfform-1.5.6}/PyPDFForm.egg-info/PKG-INFO +1 -1
- {pypdfform-1.5.4 → pypdfform-1.5.6}/tests/test_functional_simple.py +4 -9
- {pypdfform-1.5.4 → pypdfform-1.5.6}/LICENSE +0 -0
- {pypdfform-1.5.4 → pypdfform-1.5.6}/PyPDFForm/adapter.py +0 -0
- {pypdfform-1.5.4 → pypdfform-1.5.6}/PyPDFForm/coordinate.py +0 -0
- {pypdfform-1.5.4 → pypdfform-1.5.6}/PyPDFForm/font.py +0 -0
- {pypdfform-1.5.4 → pypdfform-1.5.6}/PyPDFForm/middleware/__init__.py +0 -0
- {pypdfform-1.5.4 → pypdfform-1.5.6}/PyPDFForm/middleware/base.py +0 -0
- {pypdfform-1.5.4 → pypdfform-1.5.6}/PyPDFForm/middleware/checkbox.py +0 -0
- {pypdfform-1.5.4 → pypdfform-1.5.6}/PyPDFForm/middleware/dropdown.py +0 -0
- {pypdfform-1.5.4 → pypdfform-1.5.6}/PyPDFForm/middleware/image.py +0 -0
- {pypdfform-1.5.4 → pypdfform-1.5.6}/PyPDFForm/middleware/radio.py +0 -0
- {pypdfform-1.5.4 → pypdfform-1.5.6}/PyPDFForm/middleware/signature.py +0 -0
- {pypdfform-1.5.4 → pypdfform-1.5.6}/PyPDFForm/middleware/text.py +0 -0
- {pypdfform-1.5.4 → pypdfform-1.5.6}/PyPDFForm/patterns.py +0 -0
- {pypdfform-1.5.4 → pypdfform-1.5.6}/PyPDFForm/template.py +0 -0
- {pypdfform-1.5.4 → pypdfform-1.5.6}/PyPDFForm/widgets/__init__.py +0 -0
- {pypdfform-1.5.4 → pypdfform-1.5.6}/PyPDFForm/widgets/base.py +0 -0
- {pypdfform-1.5.4 → pypdfform-1.5.6}/PyPDFForm/widgets/checkbox.py +0 -0
- {pypdfform-1.5.4 → pypdfform-1.5.6}/PyPDFForm/widgets/dropdown.py +0 -0
- {pypdfform-1.5.4 → pypdfform-1.5.6}/PyPDFForm/widgets/text.py +0 -0
- {pypdfform-1.5.4 → pypdfform-1.5.6}/PyPDFForm.egg-info/SOURCES.txt +0 -0
- {pypdfform-1.5.4 → pypdfform-1.5.6}/PyPDFForm.egg-info/dependency_links.txt +0 -0
- {pypdfform-1.5.4 → pypdfform-1.5.6}/PyPDFForm.egg-info/requires.txt +0 -0
- {pypdfform-1.5.4 → pypdfform-1.5.6}/PyPDFForm.egg-info/top_level.txt +0 -0
- {pypdfform-1.5.4 → pypdfform-1.5.6}/README.md +0 -0
- {pypdfform-1.5.4 → pypdfform-1.5.6}/setup.cfg +0 -0
- {pypdfform-1.5.4 → pypdfform-1.5.6}/setup.py +0 -0
- {pypdfform-1.5.4 → pypdfform-1.5.6}/tests/test_adobe_mode.py +0 -0
- {pypdfform-1.5.4 → pypdfform-1.5.6}/tests/test_create_widget.py +0 -0
- {pypdfform-1.5.4 → pypdfform-1.5.6}/tests/test_dropdown.py +0 -0
- {pypdfform-1.5.4 → pypdfform-1.5.6}/tests/test_dropdown_simple.py +0 -0
- {pypdfform-1.5.4 → pypdfform-1.5.6}/tests/test_fill_max_length_text_field.py +0 -0
- {pypdfform-1.5.4 → pypdfform-1.5.6}/tests/test_fill_max_length_text_field_simple.py +0 -0
- {pypdfform-1.5.4 → pypdfform-1.5.6}/tests/test_fill_method.py +0 -0
- {pypdfform-1.5.4 → pypdfform-1.5.6}/tests/test_functional.py +0 -0
- {pypdfform-1.5.4 → pypdfform-1.5.6}/tests/test_paragraph.py +0 -0
- {pypdfform-1.5.4 → pypdfform-1.5.6}/tests/test_paragraph_simple.py +0 -0
- {pypdfform-1.5.4 → pypdfform-1.5.6}/tests/test_preview.py +0 -0
- {pypdfform-1.5.4 → pypdfform-1.5.6}/tests/test_signature.py +0 -0
- {pypdfform-1.5.4 → pypdfform-1.5.6}/tests/test_use_full_widget_name.py +0 -0
|
@@ -13,7 +13,7 @@ from .coordinate import (get_draw_checkbox_radio_coordinates,
|
|
|
13
13
|
get_draw_text_coordinates,
|
|
14
14
|
get_text_line_x_coordinates)
|
|
15
15
|
from .font import checkbox_radio_font_size
|
|
16
|
-
from .image import
|
|
16
|
+
from .image import get_image_dimensions
|
|
17
17
|
from .middleware.checkbox import Checkbox
|
|
18
18
|
from .middleware.dropdown import Dropdown
|
|
19
19
|
from .middleware.image import Image
|
|
@@ -61,7 +61,6 @@ def signature_image_handler(
|
|
|
61
61
|
any_image_to_draw = False
|
|
62
62
|
if stream is not None:
|
|
63
63
|
any_image_to_draw = True
|
|
64
|
-
stream = any_image_to_jpg(stream)
|
|
65
64
|
image_width, image_height = get_image_dimensions(stream)
|
|
66
65
|
x, y, width, height = get_draw_image_coordinates_resolutions(
|
|
67
66
|
widget, middleware.preserve_aspect_ratio, image_width, image_height
|
|
@@ -38,28 +38,3 @@ def get_image_dimensions(image_stream: bytes) -> Tuple[float, float]:
|
|
|
38
38
|
image = Image.open(buff)
|
|
39
39
|
|
|
40
40
|
return image.size
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
def any_image_to_jpg(image_stream: bytes) -> bytes:
|
|
44
|
-
"""Converts an image of any type to jpg."""
|
|
45
|
-
|
|
46
|
-
buff = BytesIO()
|
|
47
|
-
buff.write(image_stream)
|
|
48
|
-
buff.seek(0)
|
|
49
|
-
|
|
50
|
-
image = Image.open(buff)
|
|
51
|
-
|
|
52
|
-
if image.format == "JPEG":
|
|
53
|
-
buff.close()
|
|
54
|
-
return image_stream
|
|
55
|
-
|
|
56
|
-
rgb_image = Image.new("RGB", image.size, (255, 255, 255))
|
|
57
|
-
rgb_image.paste(image, mask=image.split()[3] if len(image.split()) == 4 else None)
|
|
58
|
-
|
|
59
|
-
with BytesIO() as _file:
|
|
60
|
-
rgb_image.save(_file, format="JPEG")
|
|
61
|
-
_file.seek(0)
|
|
62
|
-
result = _file.read()
|
|
63
|
-
|
|
64
|
-
buff.close()
|
|
65
|
-
return result
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
"""Contains utility helpers."""
|
|
3
3
|
|
|
4
4
|
from io import BytesIO
|
|
5
|
+
from secrets import choice
|
|
6
|
+
from string import ascii_letters, digits, punctuation
|
|
5
7
|
from typing import BinaryIO, List, Union
|
|
6
8
|
|
|
7
9
|
from pypdf import PdfReader, PdfWriter
|
|
@@ -9,7 +11,8 @@ from pypdf.generic import DictionaryObject
|
|
|
9
11
|
|
|
10
12
|
from .constants import (BUTTON_STYLES, DEFAULT_CHECKBOX_STYLE, DEFAULT_FONT,
|
|
11
13
|
DEFAULT_FONT_COLOR, DEFAULT_FONT_SIZE,
|
|
12
|
-
DEFAULT_RADIO_STYLE, PREVIEW_FONT_COLOR,
|
|
14
|
+
DEFAULT_RADIO_STYLE, PREVIEW_FONT_COLOR,
|
|
15
|
+
UNIQUE_SUFFIX_LENGTH, WIDGET_TYPES)
|
|
13
16
|
from .middleware.checkbox import Checkbox
|
|
14
17
|
from .middleware.radio import Radio
|
|
15
18
|
from .middleware.text import Text
|
|
@@ -150,3 +153,14 @@ def traverse_pattern(
|
|
|
150
153
|
if result:
|
|
151
154
|
return result
|
|
152
155
|
return None
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def generate_unique_suffix() -> str:
|
|
159
|
+
"""Generates a unique suffix string for widgets during form merging."""
|
|
160
|
+
|
|
161
|
+
return "".join(
|
|
162
|
+
[
|
|
163
|
+
choice(ascii_letters + digits + punctuation.replace("-", ""))
|
|
164
|
+
for _ in range(UNIQUE_SUFFIX_LENGTH)
|
|
165
|
+
]
|
|
166
|
+
)
|
|
@@ -13,14 +13,14 @@ from .constants import (DEFAULT_FONT, DEFAULT_FONT_COLOR, DEFAULT_FONT_SIZE,
|
|
|
13
13
|
from .coordinate import generate_coordinate_grid
|
|
14
14
|
from .filler import fill, simple_fill
|
|
15
15
|
from .font import register_font
|
|
16
|
-
from .image import
|
|
16
|
+
from .image import rotate_image
|
|
17
17
|
from .middleware.dropdown import Dropdown
|
|
18
18
|
from .middleware.text import Text
|
|
19
19
|
from .template import (build_widgets, dropdown_to_text,
|
|
20
20
|
set_character_x_paddings, update_text_field_attributes,
|
|
21
21
|
update_widget_keys, widget_rect_watermarks)
|
|
22
|
-
from .utils import (get_page_streams, merge_two_pdfs,
|
|
23
|
-
remove_all_widgets)
|
|
22
|
+
from .utils import (generate_unique_suffix, get_page_streams, merge_two_pdfs,
|
|
23
|
+
preview_widget_to_draw, remove_all_widgets)
|
|
24
24
|
from .watermark import create_watermarks_and_draw, merge_watermarks_with_pdf
|
|
25
25
|
from .widgets.base import handle_non_acro_form_params
|
|
26
26
|
from .widgets.checkbox import CheckBoxWidget
|
|
@@ -166,9 +166,10 @@ class PdfWrapper(FormWrapper):
|
|
|
166
166
|
if not other.stream:
|
|
167
167
|
return self
|
|
168
168
|
|
|
169
|
+
unique_suffix = generate_unique_suffix()
|
|
169
170
|
for k in self.widgets:
|
|
170
171
|
if k in other.widgets:
|
|
171
|
-
other.update_widget_key(k, f"{k}-{
|
|
172
|
+
other.update_widget_key(k, f"{k}-{unique_suffix}", defer=True)
|
|
172
173
|
|
|
173
174
|
other.commit_widget_key_updates()
|
|
174
175
|
|
|
@@ -353,7 +354,6 @@ class PdfWrapper(FormWrapper):
|
|
|
353
354
|
"""Draws an image on a PDF form."""
|
|
354
355
|
|
|
355
356
|
image = fp_or_f_obj_or_stream_to_stream(image)
|
|
356
|
-
image = any_image_to_jpg(image)
|
|
357
357
|
image = rotate_image(image, rotation)
|
|
358
358
|
watermarks = create_watermarks_and_draw(
|
|
359
359
|
self.stream, page_number, "image", [[image, x, y, width, height]]
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import os
|
|
4
4
|
|
|
5
5
|
from PyPDFForm import FormWrapper, PdfWrapper
|
|
6
|
-
from PyPDFForm.constants import T, V
|
|
6
|
+
from PyPDFForm.constants import UNIQUE_SUFFIX_LENGTH, T, V
|
|
7
7
|
from PyPDFForm.template import get_widgets_by_page
|
|
8
8
|
|
|
9
9
|
|
|
@@ -155,22 +155,17 @@ def test_undo_checkbox(pdf_samples, request):
|
|
|
155
155
|
assert obj.stream == expected
|
|
156
156
|
|
|
157
157
|
|
|
158
|
-
def
|
|
158
|
+
def test_merging_unique_suffix(template_stream):
|
|
159
159
|
result = PdfWrapper()
|
|
160
|
-
ids = []
|
|
161
160
|
|
|
162
|
-
for i in range(
|
|
161
|
+
for i in range(10):
|
|
163
162
|
obj = PdfWrapper(
|
|
164
163
|
FormWrapper(template_stream).fill({"test": f"value-{i}"}).read()
|
|
165
164
|
)
|
|
166
165
|
result += obj
|
|
167
|
-
ids.append(id(obj))
|
|
168
166
|
|
|
169
167
|
merged = PdfWrapper(result.read())
|
|
170
168
|
|
|
171
|
-
for each in ids[1:]:
|
|
172
|
-
assert f"test-{each}" in merged.widgets
|
|
173
|
-
|
|
174
169
|
for page, widgets in get_widgets_by_page(result.read()).items():
|
|
175
170
|
for widget in widgets:
|
|
176
171
|
assert widget[T] in merged.widgets
|
|
@@ -179,4 +174,4 @@ def test_add_object_id(template_stream):
|
|
|
179
174
|
elif V in widget and "value-" in widget[V]:
|
|
180
175
|
assert widget[V] == f"value-{page // 3}"
|
|
181
176
|
assert widget[T].split("-")[0] == "test"
|
|
182
|
-
assert
|
|
177
|
+
assert len(widget[T].split("-")[1]) == UNIQUE_SUFFIX_LENGTH
|
|
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
|