Files
ferdi2goandClaude Fable 5.1 9ed59bcf56 Fotoupload im Personenformular ergänzen und Initialen-Platzhalter aussortieren
Fotofeld mit Dateiauswahl, Einfügen per Strg+V, Zwischenablage-Schaltfläche
und Drag & Drop; sichtbarer Foto-Button je Zeile. Foto wird beim Anlegen
oder Speichern übernommen bzw. entfernt.

Nextcloud meldet generierte Initialen-Avatare teils als eigene Profilbilder.
Der Import erkennt Bilder mit dominanter Hintergrundfarbe und lässt sie aus;
„Platzhalter-Fotos entfernen" bereinigt bereits importierte.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-16 09:57:54 +00:00

44 lines
2.0 KiB
JavaScript

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);
});