diff --git a/app/main.py b/app/main.py index fcfb7b8..8e2c3ca 100644 --- a/app/main.py +++ b/app/main.py @@ -3811,11 +3811,15 @@ async def _render_scorecard_pdf( width=width, height=height, ) - # `size: NNNpt` → PDF-Page hat exakt N×M Punkte. PyMuPDF rendert - # bei zoom=1 dann 1 PDF-Punkt = 1 PNG-Pixel. CSS-Pixel werden - # aber auch in pt umgerechnet (96dpi → 72dpi → ×0.75) — daher - # konvertiere pt→css-px so, dass die Inhalts-Layouts passen. - page_size_css = f"@page {{ size: {width}pt {height}pt; margin: 0; }}" + # CSS rechnet 1px = 0.75pt (96dpi vs. 72dpi). Wenn body width:1080px + # gerendert wird und @page size:1080pt ist, fuellt der Body nur 75% + # der Page-Breite (810pt) → Inhalt rutscht oben links und ist zu klein. + # Fix: @page-Groesse in pt = (CSS-px * 0.75) setzen, Body fuellt + # damit die volle Canvas-Breite. PyMuPDF kompensiert beim Render mit + # zoom=4/3 zurueck auf die gewuenschten Pixel-Dimensionen. + pt_w = width * 0.75 + pt_h = height * 0.75 + page_size_css = f"@page {{ size: {pt_w}pt {pt_h}pt; margin: 0; }}" pdf = HTML(string=html_content).write_pdf(stylesheets=[CSS(string=page_size_css)]) safe = drucksache.replace("/", "-") return pdf, width, height, f"scorecard-{safe}-{format}" @@ -3838,7 +3842,10 @@ async def api_scorecard_png( doc = fitz.open(stream=pdf_bytes, filetype="pdf") page = doc[0] # zoom-Matrix für höhere Auflösung - zoom = max(0.5, min(4.0, float(scale))) + # PDF wird mit @page in pt = CSS-px * 0.75 erzeugt. Um die + # gewuenschte Pixel-Dimension (width × height) wieder zu + # erreichen, kompensiert PyMuPDF mit zoom = 4/3 * scale. + zoom = max(0.5, min(4.0, float(scale))) * 4.0 / 3.0 mat = fitz.Matrix(zoom, zoom) pix = page.get_pixmap(matrix=mat, alpha=False) png = pix.tobytes("png") diff --git a/app/templates/v2/screens/scorecard_portrait.html b/app/templates/v2/screens/scorecard_portrait.html index 0650f7d..974d367 100644 --- a/app/templates/v2/screens/scorecard_portrait.html +++ b/app/templates/v2/screens/scorecard_portrait.html @@ -53,7 +53,10 @@ .ids strong{color:var(--ink);font-weight:600} .party-pill{ display:inline-flex;align-items:center;gap:10px; - border:2px solid var(--rule);border-radius:999px; + /* box-shadow inset statt border: WeasyPrint rendert border+border-radius + auf inline-flex-Elementen doppelt (ein Render-Bug). inset ist sauber. */ + box-shadow: inset 0 0 0 2px var(--rule); + border-radius:999px; font-weight:700;letter-spacing:.04em; } .party-pill::before{content:"";border-radius:50%;background:#d44} @@ -77,7 +80,8 @@ .verdict .fields{display:flex;flex-wrap:wrap} .field-chip{ font-family:'JetBrains Mono',monospace;font-weight:600; - border:2px solid var(--rule);border-radius:4px;background:transparent; + box-shadow: inset 0 0 0 2px var(--rule); + border-radius:4px;background:transparent; } .fractions{display:grid;grid-template-columns:repeat({{ fraktionen_count }},1fr);border:2px solid var(--rule)} .frac{