import { test } from 'node:test'; import assert from 'node:assert/strict'; import zlib from 'node:zlib'; import { pngDominantShare, looksLikePlaceholder } from '../server/image.js'; /** Minimaler PNG-Encoder für Testbilder (RGB, 8 Bit, Filter 0). */ function png(width, height, pixel) { const raw = Buffer.alloc((width * 3 + 1) * height); for (let y = 0; y < height; y += 1) { raw[y * (width * 3 + 1)] = 0; for (let x = 0; x < width; x += 1) { const [r, g, b] = pixel(x, y); raw.set([r, g, b], y * (width * 3 + 1) + 1 + x * 3); } } const chunk = (type, body) => { const len = Buffer.alloc(4); len.writeUInt32BE(body.length); const crc = Buffer.alloc(4); crc.writeUInt32BE(zlib.crc32(Buffer.concat([Buffer.from(type), body])) >>> 0); return Buffer.concat([len, Buffer.from(type), body, crc]); }; const ihdr = Buffer.alloc(13); ihdr.writeUInt32BE(width, 0); ihdr.writeUInt32BE(height, 4); ihdr[8] = 8; ihdr[9] = 2; return Buffer.concat([Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]), chunk('IHDR', ihdr), chunk('IDAT', zlib.deflateSync(raw)), chunk('IEND', Buffer.alloc(0))]); } test('Initialen-Platzhalter: eine Hintergrundfarbe mit Buchstaben wird erkannt', () => { const img = png(64, 64, (x, y) => (x > 20 && x < 44 && y > 24 && y < 40 ? [40, 40, 40] : [230, 200, 150])); const info = pngDominantShare(img); assert.ok(info.share > 0.85, `share ${info.share}`); assert.ok(looksLikePlaceholder(img)); }); test('Foto mit Farbverlauf ist kein Platzhalter', () => { const img = png(64, 64, (x, y) => [x * 4, y * 4, (x + y) * 2]); const info = pngDominantShare(img); assert.ok(info.share < 0.1, `share ${info.share}`); assert.ok(!looksLikePlaceholder(img)); }); test('JPEG und Unbekanntes werden nie als Platzhalter gewertet', () => { assert.equal(looksLikePlaceholder(Buffer.from([0xff, 0xd8, 0xff, 0xe0, 0, 0, 0, 0, 0, 0, 0, 0, 0])), false); assert.equal(pngDominantShare(Buffer.from('kein png')), null); assert.equal(looksLikePlaceholder(null), false); });