diff --git a/admin-lehrer/components/ocr-kombi/StepAnsicht.tsx b/admin-lehrer/components/ocr-kombi/StepAnsicht.tsx
index 1f727de..f9a4036 100644
--- a/admin-lehrer/components/ocr-kombi/StepAnsicht.tsx
+++ b/admin-lehrer/components/ocr-kombi/StepAnsicht.tsx
@@ -71,7 +71,8 @@ export function StepAnsicht({ sessionId, onNext }: StepAnsichtProps) {
const panelHeight = imgH * scale
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
const allWordBoxes = grid.zones.flatMap((z) =>
@@ -161,7 +162,7 @@ export function StepAnsicht({ sessionId, onNext }: StepAnsichtProps) {
{/* Rendered zones */}
{grid.zones.map((zone) => (
-
+
))}
{/* Coordinate grid */}
@@ -208,8 +209,8 @@ function CoordinateGrid({ imgW, imgH, scale, spacing }: {
// Zone renderer (reconstruction side)
// ---------------------------------------------------------------------------
-function ZoneRenderer({ zone, scale, fontSize }: {
- zone: GridZone; scale: number; fontSize: number
+function ZoneRenderer({ zone, scale, fontSize, avgRowH }: {
+ zone: GridZone; scale: number; fontSize: number; avgRowH: number
}) {
const isBox = zone.zone_type === 'box'
const boxColor = (zone as any).box_bg_hex || '#6b7280'
@@ -253,10 +254,22 @@ function ZoneRenderer({ zone, scale, fontSize }: {
}}
>
`${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 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 (
@@ -273,7 +286,7 @@ function ZoneRenderer({ zone, scale, fontSize }: {
className={`px-0.5 overflow-hidden ${row.is_header ? 'font-bold' : ''}`}
style={{
gridColumn: `${cell.col_index + 1} / ${cell.col_index + 1 + colspan}`,
- minHeight: `${rowH}px`,
+ minHeight: `${effectiveRowH}px`,
color: color || undefined,
whiteSpace: 'pre-wrap',
}}