import { test } from 'node:test'; import assert from 'node:assert/strict'; import { preprocess } from '../src/ocr.js'; /** Minimaler ImageData-Ersatz, damit der Test ohne Browser laeuft. */ function image(pixels) { const data = new Uint8ClampedArray(pixels.length * 4); pixels.forEach((value, i) => { data[i * 4] = value; data[i * 4 + 1] = value; data[i * 4 + 2] = value; data[i * 4 + 3] = 255; }); return { width: pixels.length, height: 1, data }; } test('preprocess erzeugt ein reines Schwarz-Weiss-Bild', () => { const result = preprocess(image([10, 40, 200, 250])); for (let i = 0; i < result.data.length; i += 4) { const value = result.data[i]; assert.ok(value === 0 || value === 255, `Pixel ${i / 4} ist ${value}`); assert.equal(result.data[i + 1], value); assert.equal(result.data[i + 2], value); assert.equal(result.data[i + 3], 255); } }); test('preprocess trennt dunkle von hellen Pixeln', () => { const result = preprocess(image([10, 40, 200, 250])); assert.equal(result.data[0], 0, 'dunkelstes Pixel wird schwarz'); assert.equal(result.data[12], 255, 'hellstes Pixel wird weiss'); }); test('preprocess laesst Breite und Hoehe unveraendert', () => { const result = preprocess(image([0, 128, 255])); assert.equal(result.width, 3); assert.equal(result.height, 1); }); test('preprocess trennt Schrift vom Untergrund trotz einzelnem Reflexpixel', () => { // Untergrund 60, Schrift 80, dazu ein einzelnes Reflexpixel 255. // Ein fester Schwellwert nach Kontrastspreizung reisst hier ab: das eine // Reflexpixel dominiert Minimum/Maximum und drueckt Untergrund und Schrift // gemeinsam unter den Schwellwert - die Schrift verschwindet. // // Untergrund und Schrift stehen hier zu gleichen Teilen im Bild (je 200 // Pixel), so wie auf einem echten Foto Untergrund- und Schriftflaechen // die grosse Masse der Pixel stellen und ein einzelner Reflex nur ein // einzelnes Pixel unter vielen ist. Bei einem Miniaturbild mit nur ein- // oder zweistelliger Pixelzahl waere der Reflex dagegen ein spuerbarer // Bruchteil des gesamten Histogramms; dann kann selbst Otsu ihn nicht // von echten Bildmerkmalen unterscheiden. Das ist keine Schwaeche des // Verfahrens, sondern der Grund, warum die Aussage "ein einzelnes Pixel // verschiebt das Histogramm kaum" erst bei realistischer Pixelzahl gilt. const background = new Array(200).fill(60); const text = new Array(200).fill(80); const reflex = [255]; const result = preprocess(image([...background, ...text, ...reflex])); assert.equal(result.data[0], 0, 'Untergrund bleibt schwarz'); assert.equal(result.data[199 * 4], 0, 'letztes Untergrundpixel bleibt schwarz'); assert.equal(result.data[200 * 4], 255, 'erstes Schriftpixel wird weiss'); assert.equal(result.data[399 * 4], 255, 'letztes Schriftpixel wird weiss'); }); test('preprocess liefert bei einem Bild ohne Pixel kein NaN und wirft nicht', () => { const result = preprocess(image([])); assert.equal(result.width, 0); assert.equal(result.height, 1); assert.equal(result.data.length, 0); }); test('preprocess wirft nicht, wenn alle Pixel dieselbe Helligkeit haben', () => { const result = preprocess(image([128, 128, 128, 128])); for (let i = 0; i < result.data.length; i += 4) { const value = result.data[i]; assert.ok(value === 0 || value === 255, `Pixel ${i / 4} ist ${value}`); assert.ok(!Number.isNaN(value)); } });