diff --git a/admin-lehrer/components/ocr-overlay/useSlideWordPositions.ts b/admin-lehrer/components/ocr-overlay/useSlideWordPositions.ts index 41823fc..d7f060a 100644 --- a/admin-lehrer/components/ocr-overlay/useSlideWordPositions.ts +++ b/admin-lehrer/components/ocr-overlay/useSlideWordPositions.ts @@ -129,16 +129,23 @@ export function useSlideWordPositions( const spaceWidth = ctx.measureText(' ').width const totalTextW = tokenWidths.reduce((a, b) => a + b, 0) + (tokens.length - 1) * spaceWidth - // Scale factor: how much to scale reference measurements to cell pixels - // We use the total ink coverage as reference for total text width. - let totalInk = 0 - for (let x = 0; x < cw; x++) totalInk += ink[x] + // Scale factor: map measured text width → pixel width on image. + // Use the total INK SPAN (first dark pixel to last dark pixel), + // not the count of dark columns. Text characters have gaps between + // strokes, so counting only dark pixels gives a much-too-small scale. + let firstInk = -1, lastInk = -1 + for (let x = 0; x < cw; x++) { + if (ink[x]) { + if (firstInk < 0) firstInk = x + lastInk = x + } + } - // If almost no ink, fall back to centering - if (totalInk < 3) continue + // If almost no ink, skip + if (firstInk < 0 || lastInk <= firstInk) continue - // The scale maps measured text width → pixel width on the image - const scale = Math.min(totalInk / totalTextW, cw / totalTextW) + const inkSpan = lastInk - firstInk + 1 + const scale = inkSpan / totalTextW // --- Slide each token from left to right --- const wordPos: WordPosition[] = []