Skip to content

Commit

Permalink
Merge pull request #536 from chinapandaman/PPF-535
Browse files Browse the repository at this point in the history
PPF-535: refactor simple patterns out
  • Loading branch information
chinapandaman authored Mar 25, 2024
2 parents 751b061 + 057681a commit 5d048b9
Show file tree
Hide file tree
Showing 6 changed files with 138 additions and 123 deletions.
44 changes: 22 additions & 22 deletions PyPDFForm/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,27 +26,27 @@

DEPRECATION_NOTICE = "{} will be deprecated soon. Use {} instead."

ANNOTATION_KEY = "/Annots"
ANNOTATION_FIELD_KEY = "/T"
ANNOTATION_RECTANGLE_KEY = "/Rect"
SUBTYPE_KEY = "/Subtype"
WIDGET_SUBTYPE_KEY = "/Widget"
WIDGET_TYPE_KEY = "/FT"
PARENT_KEY = "/Parent"
FIELD_FLAG_KEY = "/Ff"
TEXT_FIELD_IDENTIFIER = "/Tx"
TEXT_VALUE_IDENTIFIER = "/V"
TEXT_VALUE_SHOW_UP_IDENTIFIER = "/AP"
SIGNATURE_FIELD_IDENTIFIER = "/Sig"
TEXT_FIELD_APPEARANCE_IDENTIFIER = "/DA"
SELECTABLE_IDENTIFIER = "/Btn"
TEXT_FIELD_MAX_LENGTH_KEY = "/MaxLen"
TEXT_FIELD_ALIGNMENT_IDENTIFIER = "/Q"
CHOICE_FIELD_IDENTIFIER = "/Ch"
CHOICES_IDENTIFIER = "/Opt"
BUTTON_IDENTIFIER = "/MK"
BUTTON_STYLE_IDENTIFIER = "/CA"
SELECTED_IDENTIFIER = "/AS"
Annots = "/Annots"
T = "/T"
Rect = "/Rect"
Subtype = "/Subtype"
Widget = "/Widget"
FT = "/FT"
Parent = "/Parent"
Ff = "/Ff"
Tx = "/Tx"
V = "/V"
AP = "/AP"
Sig = "/Sig"
DA = "/DA"
Btn = "/Btn"
MaxLen = "/MaxLen"
Q = "/Q"
Ch = "/Ch"
Opt = "/Opt"
MK = "/MK"
CA = "/CA"
AS = "/AS"

# Field flag bits
READ_ONLY = 1 << 0
Expand All @@ -70,6 +70,6 @@
"l": "\u25CF", # circle
}

CHECKBOX_SELECT = "/Yes"
Yes = "/Yes"

COORDINATE_GRID_FONT_SIZE_MARGIN_RATIO = DEFAULT_FONT_SIZE / 100
40 changes: 20 additions & 20 deletions PyPDFForm/coordinate.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from pypdf import PdfReader
from reportlab.pdfbase.pdfmetrics import stringWidth

from .constants import (ANNOTATION_RECTANGLE_KEY,
from .constants import (Rect,
COORDINATE_GRID_FONT_SIZE_MARGIN_RATIO, DEFAULT_FONT)
from .middleware.text import Text
from .template import (get_char_rect_width, get_widget_alignment,
Expand All @@ -24,12 +24,12 @@ def get_draw_checkbox_radio_coordinates(

string_height = widget_middleware.font_size * 96 / 72
width_mid_point = (
float(widget[ANNOTATION_RECTANGLE_KEY][0])
+ float(widget[ANNOTATION_RECTANGLE_KEY][2])
float(widget[Rect][0])
+ float(widget[Rect][2])
) / 2
height_mid_point = (
float(widget[ANNOTATION_RECTANGLE_KEY][1])
+ float(widget[ANNOTATION_RECTANGLE_KEY][3])
float(widget[Rect][1])
+ float(widget[Rect][3])
) / 2

return (
Expand All @@ -51,15 +51,15 @@ def get_draw_sig_coordinates_resolutions(
Returns coordinates and resolutions to draw signature at given a PDF form signature widget.
"""

x = float(widget[ANNOTATION_RECTANGLE_KEY][0])
y = float(widget[ANNOTATION_RECTANGLE_KEY][1])
x = float(widget[Rect][0])
y = float(widget[Rect][1])
width = abs(
float(widget[ANNOTATION_RECTANGLE_KEY][0])
- float(widget[ANNOTATION_RECTANGLE_KEY][2])
float(widget[Rect][0])
- float(widget[Rect][2])
)
height = abs(
float(widget[ANNOTATION_RECTANGLE_KEY][1])
- float(widget[ANNOTATION_RECTANGLE_KEY][3])
float(widget[Rect][1])
- float(widget[Rect][3])
)

return x, y, width, height
Expand All @@ -72,8 +72,8 @@ def get_draw_text_coordinates(

if widget_middleware.preview:
return (
float(widget[ANNOTATION_RECTANGLE_KEY][0]),
float(widget[ANNOTATION_RECTANGLE_KEY][3]) + 5,
float(widget[Rect][0]),
float(widget[Rect][3]) + 5,
)

text_value = widget_middleware.value or ""
Expand All @@ -94,12 +94,12 @@ def get_draw_text_coordinates(
)

alignment = get_widget_alignment(widget) or 0
x = float(widget[ANNOTATION_RECTANGLE_KEY][0])
x = float(widget[Rect][0])

if int(alignment) != 0:
width_mid_point = (
float(widget[ANNOTATION_RECTANGLE_KEY][0])
+ float(widget[ANNOTATION_RECTANGLE_KEY][2])
float(widget[Rect][0])
+ float(widget[Rect][2])
) / 2
string_width = stringWidth(
text_value,
Expand All @@ -116,7 +116,7 @@ def get_draw_text_coordinates(
if int(alignment) == 1:
x = width_mid_point - string_width / 2
elif int(alignment) == 2:
x = float(widget[ANNOTATION_RECTANGLE_KEY][2]) - string_width
x = float(widget[Rect][2]) - string_width
if length > 0 and widget_middleware.comb is True:
x -= (
get_char_rect_width(widget, widget_middleware)
Expand All @@ -129,12 +129,12 @@ def get_draw_text_coordinates(

string_height = widget_middleware.font_size * 96 / 72
height_mid_point = (
float(widget[ANNOTATION_RECTANGLE_KEY][1])
+ float(widget[ANNOTATION_RECTANGLE_KEY][3])
float(widget[Rect][1])
+ float(widget[Rect][3])
) / 2
y = (height_mid_point - string_height / 2 + height_mid_point) / 2
if is_text_multiline(widget):
y = float(widget[ANNOTATION_RECTANGLE_KEY][3]) - string_height / 1.5
y = float(widget[Rect][3]) - string_height / 1.5

if int(alignment) == 1 and widget_middleware.comb is True and length != 0:
x -= character_paddings[0] / 2
Expand Down
50 changes: 13 additions & 37 deletions PyPDFForm/filler.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,9 @@
from typing import Dict, cast

from pypdf import PdfReader, PdfWriter
from pypdf.generic import (DictionaryObject, NameObject, NumberObject,
TextStringObject)
from pypdf.generic import DictionaryObject

from .constants import (ANNOTATION_KEY, CHECKBOX_SELECT, FIELD_FLAG_KEY,
PARENT_KEY, READ_ONLY, SELECTED_IDENTIFIER,
TEXT_VALUE_IDENTIFIER, TEXT_VALUE_SHOW_UP_IDENTIFIER,
WIDGET_TYPES)
from .constants import WIDGET_TYPES, Annots
from .coordinate import (get_draw_checkbox_radio_coordinates,
get_draw_sig_coordinates_resolutions,
get_draw_text_coordinates,
Expand All @@ -23,6 +19,10 @@
from .middleware.radio import Radio
from .middleware.signature import Signature
from .middleware.text import Text
from .patterns import (simple_flatten_generic, simple_flatten_radio,
simple_update_checkbox_value,
simple_update_dropdown_value, simple_update_radio_value,
simple_update_text_value)
from .template import get_widget_key, get_widgets_by_page
from .utils import checkbox_radio_to_draw, stream_to_io
from .watermark import create_watermarks_and_draw, merge_watermarks_with_pdf
Expand Down Expand Up @@ -143,7 +143,7 @@ def simple_fill(
radio_button_tracker = {}

for page in out.pages:
for annot in page.get(ANNOTATION_KEY, []): # noqa
for annot in page.get(Annots, []): # noqa
annot = cast(DictionaryObject, annot.get_object())
key = get_widget_key(annot.get_object())

Expand All @@ -152,47 +152,23 @@ def simple_fill(
continue

if type(widget) is Checkbox and widget.value is True:
annot[NameObject(SELECTED_IDENTIFIER)] = NameObject(CHECKBOX_SELECT)
simple_update_checkbox_value(annot)
elif isinstance(widget, Radio):
if key not in radio_button_tracker:
radio_button_tracker[key] = 0
radio_button_tracker[key] += 1
if widget.value == radio_button_tracker[key] - 1:
annot[NameObject(SELECTED_IDENTIFIER)] = NameObject(
f"/{widget.value}"
)
simple_update_radio_value(annot, widget)
elif isinstance(widget, Dropdown) and widget.value is not None:
annot[NameObject(TEXT_VALUE_IDENTIFIER)] = TextStringObject(
widget.choices[widget.value]
)
annot[NameObject(TEXT_VALUE_SHOW_UP_IDENTIFIER)] = TextStringObject(
widget.choices[widget.value]
)
simple_update_dropdown_value(annot, widget)
elif isinstance(widget, Text) and widget.value:
annot[NameObject(TEXT_VALUE_IDENTIFIER)] = TextStringObject(
widget.value
)
annot[NameObject(TEXT_VALUE_SHOW_UP_IDENTIFIER)] = TextStringObject(
widget.value
)
simple_update_text_value(annot, widget)

if flatten:
if isinstance(widget, Radio):
annot[NameObject(PARENT_KEY)][ # noqa
NameObject(FIELD_FLAG_KEY)
] = NumberObject(
int(
annot[NameObject(PARENT_KEY)].get( # noqa
NameObject(FIELD_FLAG_KEY), 0
)
)
| READ_ONLY
)
simple_flatten_radio(annot)
else:
annot[NameObject(FIELD_FLAG_KEY)] = NumberObject(
int(annot.get(NameObject(FIELD_FLAG_KEY), 0))
| READ_ONLY # noqa
)
simple_flatten_generic(annot)

with BytesIO() as f:
out.write(f)
Expand Down
14 changes: 7 additions & 7 deletions PyPDFForm/font.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from reportlab.pdfbase.pdfmetrics import registerFont, standardFonts
from reportlab.pdfbase.ttfonts import TTFError, TTFont

from .constants import (ANNOTATION_RECTANGLE_KEY, DEFAULT_FONT,
from .constants import (Rect, DEFAULT_FONT,
FONT_COLOR_IDENTIFIER, FONT_SIZE_IDENTIFIER)
from .patterns import TEXT_FIELD_APPEARANCE_PATTERNS
from .utils import traverse_pattern
Expand Down Expand Up @@ -83,8 +83,8 @@ def text_field_font_size(widget: dict) -> Union[float, int]:
"""

height = abs(
float(widget[ANNOTATION_RECTANGLE_KEY][1])
- float(widget[ANNOTATION_RECTANGLE_KEY][3])
float(widget[Rect][1])
- float(widget[Rect][3])
)

return height * 2 / 3
Expand All @@ -97,11 +97,11 @@ def checkbox_radio_font_size(widget: dict) -> Union[float, int]:
"""

area = abs(
float(widget[ANNOTATION_RECTANGLE_KEY][0])
- float(widget[ANNOTATION_RECTANGLE_KEY][2])
float(widget[Rect][0])
- float(widget[Rect][2])
) * abs(
float(widget[ANNOTATION_RECTANGLE_KEY][1])
- float(widget[ANNOTATION_RECTANGLE_KEY][3])
float(widget[Rect][1])
- float(widget[Rect][3])
)

return sqrt(area) * 72 / 96
Expand Down
Loading

0 comments on commit 5d048b9

Please sign in to comment.