StepAnsicht: fix font size and row spacing to match original
Some checks failed
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-school (push) Successful in 43s
CI / test-go-edu-search (push) Successful in 40s
CI / test-nodejs-website (push) Has been cancelled
CI / test-python-agent-core (push) Has been cancelled
CI / test-python-klausur (push) Has been cancelled

- Font: use font_size_suggestion_px * scale directly (removed 0.85 factor)
- Row height: calculate from row-to-row spacing (y_min of next row
  minus y_min of current row) instead of text height (y_max - y_min).
  This produces correct line spacing matching the original layout.
- Multi-line cells: height multiplied by line count

Content zone should now span from ~250 to ~2050 matching the original.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-04-13 23:24:27 +02:00
parent 18213f0bde
commit c5733a171b

View File

@@ -71,7 +71,8 @@ export function StepAnsicht({ sessionId, onNext }: StepAnsichtProps) {
const panelHeight = imgH * scale const panelHeight = imgH * scale
const baseFontPx = (grid as any).layout_metrics?.font_size_suggestion_px || 14 const baseFontPx = (grid as any).layout_metrics?.font_size_suggestion_px || 14
const scaledFont = Math.max(7, baseFontPx * scale * 0.85) const avgRowH = (grid as any).layout_metrics?.avg_row_height_px || 31
const scaledFont = Math.max(7, baseFontPx * scale)
// Collect all word boxes for OCR overlay // Collect all word boxes for OCR overlay
const allWordBoxes = grid.zones.flatMap((z) => const allWordBoxes = grid.zones.flatMap((z) =>
@@ -161,7 +162,7 @@ export function StepAnsicht({ sessionId, onNext }: StepAnsichtProps) {
{/* Rendered zones */} {/* Rendered zones */}
{grid.zones.map((zone) => ( {grid.zones.map((zone) => (
<ZoneRenderer key={zone.zone_index} zone={zone} scale={scale} fontSize={scaledFont} /> <ZoneRenderer key={zone.zone_index} zone={zone} scale={scale} fontSize={scaledFont} avgRowH={avgRowH} />
))} ))}
{/* Coordinate grid */} {/* Coordinate grid */}
@@ -208,8 +209,8 @@ function CoordinateGrid({ imgW, imgH, scale, spacing }: {
// Zone renderer (reconstruction side) // Zone renderer (reconstruction side)
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
function ZoneRenderer({ zone, scale, fontSize }: { function ZoneRenderer({ zone, scale, fontSize, avgRowH }: {
zone: GridZone; scale: number; fontSize: number zone: GridZone; scale: number; fontSize: number; avgRowH: number
}) { }) {
const isBox = zone.zone_type === 'box' const isBox = zone.zone_type === 'box'
const boxColor = (zone as any).box_bg_hex || '#6b7280' const boxColor = (zone as any).box_bg_hex || '#6b7280'
@@ -253,10 +254,22 @@ function ZoneRenderer({ zone, scale, fontSize }: {
}} }}
> >
<div style={{ display: 'grid', gridTemplateColumns: scaledColWidths.map((w) => `${w.toFixed(1)}px`).join(' ') }}> <div style={{ display: 'grid', gridTemplateColumns: scaledColWidths.map((w) => `${w.toFixed(1)}px`).join(' ') }}>
{zone.rows.map((row) => { {zone.rows.map((row, rowIdx) => {
const isSpanning = zone.cells.some((c) => c.row_index === row.index && c.col_type === 'spanning_header') const isSpanning = zone.cells.some((c) => c.row_index === row.index && c.col_type === 'spanning_header')
const measuredH = (row.y_max_px ?? 0) - (row.y_min_px ?? 0)
const rowH = Math.max(fontSize * 1.3, measuredH * scale) // Row height = distance to next row's start (not text height)
// This produces correct line spacing matching the original
const nextRow = rowIdx + 1 < zone.rows.length ? zone.rows[rowIdx + 1] : null
const rowStartY = row.y_min_px ?? row.y_min ?? 0
const nextStartY = nextRow ? (nextRow.y_min_px ?? nextRow.y_min ?? 0) : rowStartY + avgRowH
const rowSpacing = nextStartY - rowStartY
const rowH = Math.max(fontSize * 1.3, rowSpacing * scale)
// Multi-line cells need more height
const maxLines = Math.max(1, ...zone.cells
.filter((c) => c.row_index === row.index)
.map((c) => (c.text ?? '').split('\n').length))
const effectiveRowH = rowH * Math.max(1, maxLines)
return ( return (
<div key={row.index} style={{ display: 'contents' }}> <div key={row.index} style={{ display: 'contents' }}>
@@ -273,7 +286,7 @@ function ZoneRenderer({ zone, scale, fontSize }: {
className={`px-0.5 overflow-hidden ${row.is_header ? 'font-bold' : ''}`} className={`px-0.5 overflow-hidden ${row.is_header ? 'font-bold' : ''}`}
style={{ style={{
gridColumn: `${cell.col_index + 1} / ${cell.col_index + 1 + colspan}`, gridColumn: `${cell.col_index + 1} / ${cell.col_index + 1 + colspan}`,
minHeight: `${rowH}px`, minHeight: `${effectiveRowH}px`,
color: color || undefined, color: color || undefined,
whiteSpace: 'pre-wrap', whiteSpace: 'pre-wrap',
}} }}