Skip to content

Commit

Permalink
MAINT: Refactor _update_field_annotation (#2862)
Browse files Browse the repository at this point in the history
  • Loading branch information
MartinThoma authored Sep 21, 2024
1 parent 8dd9fcb commit 966e015
Showing 1 changed file with 52 additions and 39 deletions.
91 changes: 52 additions & 39 deletions pypdf/_writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,26 +220,24 @@ def _get_clone_from(
fileobj: Union[None, PdfReader, str, Path, IO[Any], BytesIO],
clone_from: Union[None, PdfReader, str, Path, IO[Any], BytesIO],
) -> Union[None, PdfReader, str, Path, IO[Any], BytesIO]:
if not isinstance(fileobj, (str, Path, IO, BytesIO)) or (
fileobj != "" and clone_from is None
if isinstance(fileobj, (str, Path, IO, BytesIO)) and (
fileobj == "" or clone_from is not None
):
cloning = True
if not (
not isinstance(fileobj, (str, Path))
or (
Path(str(fileobj)).exists()
and Path(str(fileobj)).stat().st_size > 0
)
):
return clone_from
cloning = True
if isinstance(fileobj, (str, Path)) and (
not Path(str(fileobj)).exists()
or Path(str(fileobj)).stat().st_size == 0
):
cloning = False
if isinstance(fileobj, (IO, BytesIO)):
t = fileobj.tell()
fileobj.seek(-1, 2)
if fileobj.tell() == 0:
cloning = False
if isinstance(fileobj, (IO, BytesIO)):
t = fileobj.tell()
fileobj.seek(-1, 2)
if fileobj.tell() == 0:
cloning = False
fileobj.seek(t, 0)
if cloning:
clone_from = fileobj
fileobj.seek(t, 0)
if cloning:
clone_from = fileobj
return clone_from

clone_from = _get_clone_from(fileobj, clone_from)
Expand Down Expand Up @@ -966,27 +964,9 @@ def _update_field_annotation(
# Escape parentheses (pdf 1.7 reference, table 3.2 Literal Strings)
txt = txt.replace("\\", "\\\\").replace("(", r"\(").replace(")", r"\)")
# Generate appearance stream
ap_stream = f"q\n/Tx BMC \nq\n1 1 {rct.width - 1} {rct.height - 1} re\nW\nBT\n{da}\n".encode()
for line_number, line in enumerate(txt.replace("\n", "\r").split("\r")):
if line in sel:
# may be improved but cannot find how to get fill working => replaced with lined box
ap_stream += (
f"1 {y_offset - (line_number * font_height * 1.4) - 1} {rct.width - 2} {font_height + 2} re\n"
f"0.5 0.5 0.5 rg s\n{da}\n"
).encode()
if line_number == 0:
ap_stream += f"2 {y_offset} Td\n".encode()
else:
# Td is a relative translation
ap_stream += f"0 {- font_height * 1.4} Td\n".encode()
enc_line: List[bytes] = [
font_full_rev.get(c, c.encode("utf-16-be")) for c in line
]
if any(len(c) >= 2 for c in enc_line):
ap_stream += b"<" + (b"".join(enc_line)).hex().encode() + b"> Tj\n"
else:
ap_stream += b"(" + b"".join(enc_line) + b") Tj\n"
ap_stream += b"ET\nQ\nEMC\nQ\n"
ap_stream = generate_appearance_stream(
txt, sel, da, font_full_rev, rct, font_height, y_offset
)

# Create appearance dictionary
dct = DecodedStreamObject.initialize_from_dictionary(
Expand Down Expand Up @@ -3297,3 +3277,36 @@ def _create_outline_item(
format_flag += 2
outline_item.update({NameObject("/F"): NumberObject(format_flag)})
return outline_item


def generate_appearance_stream(
txt: str,
sel: List[str],
da: str,
font_full_rev: Dict[str, bytes],
rct: RectangleObject,
font_height: float,
y_offset: float,
) -> bytes:
ap_stream = f"q\n/Tx BMC \nq\n1 1 {rct.width - 1} {rct.height - 1} re\nW\nBT\n{da}\n".encode()
for line_number, line in enumerate(txt.replace("\n", "\r").split("\r")):
if line in sel:
# may be improved but cannot find how to get fill working => replaced with lined box
ap_stream += (
f"1 {y_offset - (line_number * font_height * 1.4) - 1} {rct.width - 2} {font_height + 2} re\n"
f"0.5 0.5 0.5 rg s\n{da}\n"
).encode()
if line_number == 0:
ap_stream += f"2 {y_offset} Td\n".encode()
else:
# Td is a relative translation
ap_stream += f"0 {- font_height * 1.4} Td\n".encode()
enc_line: List[bytes] = [
font_full_rev.get(c, c.encode("utf-16-be")) for c in line
]
if any(len(c) >= 2 for c in enc_line):
ap_stream += b"<" + (b"".join(enc_line)).hex().encode() + b"> Tj\n"
else:
ap_stream += b"(" + b"".join(enc_line) + b") Tj\n"
ap_stream += b"ET\nQ\nEMC\nQ\n"
return ap_stream

0 comments on commit 966e015

Please sign in to comment.