fix: PNG-Export-Canvas + Doppel-Borders bei field-chip/party-pill
User: 'immer noch doppelte Borders ... Inhalte zu klein skaliert
nach oben links gerutscht (800 px breit statt 1080)'
Ursachen:
1. Canvas-Content-Mismatch (Inhalt 75% der PNG-Breite):
WeasyPrint rechnet 1 CSS-px = 0.75 PDF-pt (96dpi → 72dpi). @page
war auf {width}pt × {height}pt (1080×1350) gesetzt, body aber auf
1080×1350 CSS-px. Folge: Body fuellte nur 1080*0.75=810pt der
1080pt-Page → Content top-left, 25% rechts/unten leer; PyMuPDF
rasterisiert mit zoom=1 → 1080×1350 PNG, Content nur in den linken
810×1012 px → 'Inhalte zu klein nach oben links gerutscht'.
Fix: @page-Groesse auf (width * 0.75)pt × (height * 0.75)pt setzen.
Body fuellt jetzt die volle Canvas-Breite. PyMuPDF kompensiert mit
zoom = scale * 4/3, damit die PNG wieder die gewuenschten Pixel-
Dimensionen hat (1080×1350 für scale=1).
2. Doppel-Borders auf field-chip + party-pill:
WeasyPrint hat einen bekannten Render-Bug bei
'border + border-radius' auf inline-flex-Elementen — der Border
wird zweimal gezeichnet (innen + aussen). 1.5px → 2px hat das
nicht behoben, weil's nicht am Subpixel-Wert lag.
Fix: border ersetzt durch box-shadow: inset 0 0 0 2px var(--rule).
Inset-Shadow rendert sauber, kein Doppel-Effekt. border-radius
bleibt erhalten.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
4e122bceb0
commit
f59286d15f
19
app/main.py
19
app/main.py
@ -3811,11 +3811,15 @@ async def _render_scorecard_pdf(
|
|||||||
width=width, height=height,
|
width=width, height=height,
|
||||||
)
|
)
|
||||||
|
|
||||||
# `size: NNNpt` → PDF-Page hat exakt N×M Punkte. PyMuPDF rendert
|
# CSS rechnet 1px = 0.75pt (96dpi vs. 72dpi). Wenn body width:1080px
|
||||||
# bei zoom=1 dann 1 PDF-Punkt = 1 PNG-Pixel. CSS-Pixel werden
|
# gerendert wird und @page size:1080pt ist, fuellt der Body nur 75%
|
||||||
# aber auch in pt umgerechnet (96dpi → 72dpi → ×0.75) — daher
|
# der Page-Breite (810pt) → Inhalt rutscht oben links und ist zu klein.
|
||||||
# konvertiere pt→css-px so, dass die Inhalts-Layouts passen.
|
# Fix: @page-Groesse in pt = (CSS-px * 0.75) setzen, Body fuellt
|
||||||
page_size_css = f"@page {{ size: {width}pt {height}pt; margin: 0; }}"
|
# 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)])
|
pdf = HTML(string=html_content).write_pdf(stylesheets=[CSS(string=page_size_css)])
|
||||||
safe = drucksache.replace("/", "-")
|
safe = drucksache.replace("/", "-")
|
||||||
return pdf, width, height, f"scorecard-{safe}-{format}"
|
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")
|
doc = fitz.open(stream=pdf_bytes, filetype="pdf")
|
||||||
page = doc[0]
|
page = doc[0]
|
||||||
# zoom-Matrix für höhere Auflösung
|
# 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)
|
mat = fitz.Matrix(zoom, zoom)
|
||||||
pix = page.get_pixmap(matrix=mat, alpha=False)
|
pix = page.get_pixmap(matrix=mat, alpha=False)
|
||||||
png = pix.tobytes("png")
|
png = pix.tobytes("png")
|
||||||
|
|||||||
@ -53,7 +53,10 @@
|
|||||||
.ids strong{color:var(--ink);font-weight:600}
|
.ids strong{color:var(--ink);font-weight:600}
|
||||||
.party-pill{
|
.party-pill{
|
||||||
display:inline-flex;align-items:center;gap:10px;
|
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;
|
font-weight:700;letter-spacing:.04em;
|
||||||
}
|
}
|
||||||
.party-pill::before{content:"";border-radius:50%;background:#d44}
|
.party-pill::before{content:"";border-radius:50%;background:#d44}
|
||||||
@ -77,7 +80,8 @@
|
|||||||
.verdict .fields{display:flex;flex-wrap:wrap}
|
.verdict .fields{display:flex;flex-wrap:wrap}
|
||||||
.field-chip{
|
.field-chip{
|
||||||
font-family:'JetBrains Mono',monospace;font-weight:600;
|
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)}
|
.fractions{display:grid;grid-template-columns:repeat({{ fraktionen_count }},1fr);border:2px solid var(--rule)}
|
||||||
.frac{
|
.frac{
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user