"""Regression coverage for canonical-coordinate PDF export.""" import json import pymupdf from app.services.export.renderer import export_annotations def _source_pdf(path) -> None: document = pymupdf.open() page = document.new_page(width=720, height=936) page.set_cropbox(pymupdf.Rect(36, 72, 648, 864)) page.set_rotation(90) document.save(path) document.close() def test_export_preserves_rotation_and_flattens_supported_annotations(tmp_path) -> None: source = tmp_path / "source.pdf" _source_pdf(source) annotations = [ { "id": "text", "page": 0, "type": "text", "rect": {"x": 40, "y": 50, "width": 180, "height": 40}, "props": { "text": "Exported text", "fontFamily": "Liberation Sans", "fontSize": 14, "color": "#112233", "styles": {"0": {"0": {"fill": "#ff0000", "fontWeight": "bold"}}}, }, }, { "id": "line", "page": 0, "type": "draw", "rect": {"x": 40, "y": 110, "width": 80, "height": 40}, "props": { "paths": [[0, 0], [80, 40]], "strokeColor": "#ff0000", "strokeWidth": 2, "opacity": 1, }, }, { "id": "highlight", "page": 0, "type": "highlight", "rect": {"x": 40, "y": 170, "width": 100, "height": 20}, "props": {"color": "#ffff00", "opacity": 0.4}, }, { "id": "signature", "page": 0, "type": "signature", "rect": {"x": 40, "y": 220, "width": 160, "height": 50}, "props": { "mode": "type", "text": "Ava", "fontFamily": "Great Vibes", "color": "#000000", }, }, { "id": "shape", "page": 0, "type": "shape", "rect": {"x": 180, "y": 170, "width": 60, "height": 30}, "props": {"kind": "ellipse", "strokeColor": "#0000ff", "strokeWidth": 2}, }, { "id": "future", "page": 0, "type": "future-stamp", "rect": {"x": 0, "y": 0, "width": 10, "height": 10}, "props": {}, }, ] exported = export_annotations(source, annotations, tmp_path / "assets") output = tmp_path / "exported.pdf" output.write_bytes(exported) with pymupdf.open(output) as document: page = document[0] assert page.rotation == 90 assert page.rect.width == 792 assert page.rect.height == 612 assert "Exported text" in page.get_text("text") assert "Ava" in page.get_text("text") # Normalize only for inspection: the exported PDF still retains the # original page rotation above. page.set_rotation(0) words = page.get_text("words") text_word = next(word for word in words if word[4] == "Exported") assert 35 <= text_word[0] <= 45 assert 45 <= text_word[1] <= 60 assert len(page.get_drawings()) >= 3 def test_export_does_not_mutate_annotation_input(tmp_path) -> None: source = tmp_path / "source.pdf" _source_pdf(source) annotations = [ { "id": "unknown", "page": 0, "type": "not-yet-supported", "rect": {"x": 1, "y": 2, "width": 3, "height": 4}, "props": {"future": True}, } ] before = json.loads(json.dumps(annotations)) export_annotations(source, annotations, tmp_path / "assets") assert annotations == before