"""The Renderer adapter (the domain's port): contract words → PDF bytes, and the executed copy = the signed version's
EXACT bytes + a certificate page, appended as a PDF incremental update.
WHY A SMALL WRITER OF OUR OWN. An earlier version rendered with WeasyPrint (+99 MB of system libraries). No pure-Python PDF
library ships with the platform image, and a contract needs only text: so this is ~150 lines of PDF 1.4 — Helvetica
(a standard font every reader has), A4, wrapped text, no images, no timestamps, so the same words give the same
bytes. Text is encoded WinAnsi (cp1252): a character outside it prints as '?' in the PDF (the signing page and the
frozen text_body keep the exact words; the sha256 covers the PDF bytes either way).
THE EXECUTED COPY KEEPS THE SIGNED BYTES. The certificate page is appended as an incremental update (new objects, a
new page tree, an xref section pointing back with /Prev), so the executed file STARTS WITH the frozen version byte
for byte: anyone can check that sha256(executed[:len(version)]) is the version's sha256 printed on the certificate.
"""
import re
import textwrap
PAGE_W, PAGE_H = 595, 842 # A4 in points
MARGIN, SIZE, LEADING = 56, 10, 13
CHARS = 92 # a conservative line for 10 pt Helvetica in 483 pt
LINES = (PAGE_H - 2 * MARGIN) // LEADING
def _esc(s: str) -> bytes:
b = s.encode("cp1252", "replace")
return b.replace(b"\\", b"\\\\").replace(b"(", b"\\(").replace(b")", b"\\)")
def _wrap(text: str) -> list:
out = []
for para in (text or "").replace("\r\n", "\n").split("\n"):
if not para.strip():
out.append("")
continue
indent = len(para) - len(para.lstrip(" "))
out += textwrap.wrap(para, CHARS, subsequent_indent=" " * indent, break_long_words=True,
replace_whitespace=False) or [""]
return out
def _pages(text: str) -> list:
lines = _wrap(text)
return [lines[i:i + LINES] for i in range(0, max(len(lines), 1), LINES)] or [[]]
def _content(lines: list, footer: str) -> bytes:
parts = [b"BT", f"/F1 {SIZE} Tf".encode(), f"{LEADING} TL".encode(),
f"{MARGIN} {PAGE_H - MARGIN} Td".encode()]
for ln in lines:
parts.append(b"(" + _esc(ln) + b") Tj T*")
parts.append(b"ET")
if footer:
parts += [b"BT", b"/F1 8 Tf", f"{MARGIN} {MARGIN // 2} Td".encode(), b"(" + _esc(footer) + b") Tj", b"ET"]
return b"\n".join(parts)
def _obj(n: int, body: bytes) -> bytes:
return f"{n} 0 obj\n".encode() + body + b"\nendobj\n"
def _stream(data: bytes) -> bytes:
return f"<< /Length {len(data)} >>\nstream\n".encode() + data + b"\nendstream"
def render(text: str, *, footer: str = "") -> bytes:
"""A PDF of the words: objects 1 catalog, 2 page tree, 3 font, then (page, content) pairs."""
pages = _pages(text)
objs = [b"<< /Type /Catalog /Pages 2 0 R >>", None,
b"<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica /Encoding /WinAnsiEncoding >>"]
kids = []
for i, lines in enumerate(pages):
page_no, content_no = 4 + 2 * i, 5 + 2 * i
kids.append(f"{page_no} 0 R")
objs.append(f"<< /Type /Page /Parent 2 0 R /MediaBox [0 0 {PAGE_W} {PAGE_H}] /Resources << /Font << /F1 3 0 R "
f">> >> /Contents {content_no} 0 R >>".encode())
objs.append(_stream(_content(lines, f"{footer} page {i + 1} of {len(pages)}".strip())))
objs[1] = f"<< /Type /Pages /Kids [{' '.join(kids)}] /Count {len(kids)} >>".encode()
out = bytearray(b"%PDF-1.4\n%\xe2\xe3\xcf\xd3\n")
offsets = []
for n, body in enumerate(objs, start=1):
offsets.append(len(out))
out += _obj(n, body)
xref = len(out)
out += f"xref\n0 {len(objs) + 1}\n0000000000 65535 f \n".encode()
for off in offsets:
out += f"{off:010d} 00000 n \n".encode()
out += f"trailer\n<< /Size {len(objs) + 1} /Root 1 0 R >>\nstartxref\n{xref}\n%%EOF\n".encode()
return bytes(out)
_STARTXREF = re.compile(rb"startxref\s+(\d+)\s+%%EOF\s*$")
_SIZE = re.compile(rb"/Size\s+(\d+)")
_KIDS = re.compile(rb"2 0 obj\s*<<\s*/Type /Pages /Kids \[([^\]]*)\]\s*/Count (\d+)\s*>>")
def append(pdf: bytes, text: str, *, footer: str = "") -> bytes:
"""`pdf` (one this module wrote) + pages of `text`, as an incremental update: the original bytes are kept as they
are, at the start of the result."""
m = _STARTXREF.search(pdf)
sizes = _SIZE.findall(pdf)
kids_all = _KIDS.findall(pdf)
if not m or not sizes or not kids_all:
raise ValueError("not a PDF this renderer wrote")
prev, size = int(m.group(1)), int(sizes[-1])
kids = kids_all[-1][0].decode().split()
kids = [" ".join(kids[i:i + 3]) for i in range(0, len(kids), 3)]
pages = _pages(text)
total = len(kids) + len(pages)
out = bytearray(pdf if pdf.endswith(b"\n") else pdf + b"\n")
offsets = {}
n = size
new_kids = []
for i, lines in enumerate(pages):
page_no, content_no = n, n + 1
n += 2
new_kids.append(f"{page_no} 0 R")
offsets[page_no] = len(out)
out += _obj(page_no, f"<< /Type /Page /Parent 2 0 R /MediaBox [0 0 {PAGE_W} {PAGE_H}] /Resources << /Font << "
f"/F1 3 0 R >> >> /Contents {content_no} 0 R >>".encode())
offsets[content_no] = len(out)
out += _obj(content_no, _stream(_content(lines, f"{footer} page {len(kids) + i + 1} of {total}".strip())))
offsets[2] = len(out)
out += _obj(2, f"<< /Type /Pages /Kids [{' '.join(kids + new_kids)}] /Count {total} >>".encode())
xref = len(out)
out += b"xref\n" + f"2 1\n{offsets[2]:010d} 00000 n \n".encode()
out += f"{size} {n - size}\n".encode()
for k in range(size, n):
out += f"{offsets[k]:010d} 00000 n \n".encode()
out += f"trailer\n<< /Size {n} /Root 1 0 R /Prev {prev} >>\nstartxref\n{xref}\n%%EOF\n".encode()
return bytes(out)
def page_count(pdf: bytes) -> int:
kids = _KIDS.findall(pdf)
return int(kids[-1][1]) if kids else 0
__all__ = ["render", "append", "page_count"]