/* ===================================================================== Verkleinert bild-vorbereiten.js richtig? Läuft in einem echten Browser (Canvas/Image gibt es nur dort). Erzeugt Testbilder verschiedener Größe/Format und prüft das Verhalten, auf das es ankommt: große Bilder werden auf die vorgegebene Breite gebracht, kleine bleiben unangetastet, große PNGs werden zu JPEG, und die Avatar-Grenze (512) macht ein Foto deutlich kleiner als die Verwaltungs-Grenze (1600). ===================================================================== */ import { chromium } from "playwright"; import { readFileSync } from "node:fs"; const quelle = readFileSync("assets/js/bild-vorbereiten.js", "utf8"); const browser = await chromium.launch(); const seite = await browser.newPage(); await seite.setContent(""); await seite.addScriptTag({ content: quelle }); let ok = 0, fehl = 0; const pruefe = (name, gut, info) => { if (gut) { ok++; console.log(" ok " + name + (info ? " -> " + info : "")); } else { fehl++; console.log(" FEHL " + name + (info ? " -> " + info : "")); } }; /* Hilfsfunktion im Browser: erzeugt ein Testbild als File, jagt es durch bildVorbereiten und meldet Maße/Größe/Typ vorher und nachher. */ const test = (breite, hoehe, typ, opt) => seite.evaluate(async ([breite, hoehe, typ, opt]) => { const c = document.createElement("canvas"); c.width = breite; c.height = hoehe; const ctx = c.getContext("2d"); /* Echtes Zufallsrauschen, damit die Testbilder realistisch groß werden (ein Muster oder eine Fläche würde PNG so stark komprimieren, dass die "großes PNG"-Grenze von 400 KB nie erreicht wird -- dann bliebe der PNG->JPEG-Pfad ungetestet). */ const img = ctx.createImageData(breite, hoehe); for (let i = 0; i < img.data.length; i += 4) { img.data[i] = Math.random() * 256; img.data[i+1] = Math.random() * 256; img.data[i+2] = Math.random() * 256; img.data[i+3] = 255; } ctx.putImageData(img, 0, 0); const blob = await new Promise((f) => c.toBlob(f, typ, 0.95)); const datei = new File([blob], "test." + (typ === "image/png" ? "png" : "jpg"), { type: typ }); const raus = await window.bildVorbereiten(datei, opt); /* Maße des Ergebnisses auslesen. */ const masse = await new Promise((f) => { const b = new Image(); b.onload = () => f({ w: b.naturalWidth, h: b.naturalHeight }); b.src = URL.createObjectURL(raus); }); return { vorherBytes: datei.size, nachherBytes: raus.size, w: masse.w, h: masse.h, typ: raus.type }; }, [breite, hoehe, typ, opt]); console.log("\n=== Großes Foto, Verwaltungs-Grenze (1600) ==="); { const r = await test(2400, 1350, "image/jpeg", { maxBreite: 1600 }); pruefe("wird auf 1600 Breite gebracht", r.w === 1600, `${r.w}px breit`); pruefe("wird kleiner", r.nachherBytes < r.vorherBytes, `${Math.round(r.vorherBytes/1024)} -> ${Math.round(r.nachherBytes/1024)} KB`); } console.log("\n=== Großes Foto, Avatar-Grenze (512) ==="); { const r = await test(2400, 1350, "image/jpeg", { maxBreite: 512 }); pruefe("wird auf 512 Breite gebracht", r.w === 512, `${r.w}px breit`); pruefe("Avatar ist DEUTLICH kleiner als 1600er", r.nachherBytes < 80 * 1024, `${Math.round(r.nachherBytes/1024)} KB`); } console.log("\n=== Kleines Bild bleibt unangetastet ==="); { const r = await test(300, 300, "image/jpeg", { maxBreite: 512 }); pruefe("300px-Bild behält 300px", r.w === 300, `${r.w}px`); } console.log("\n=== Großes PNG wird zu JPEG ==="); { const r = await test(2000, 1200, "image/png", { maxBreite: 1600 }); pruefe("Format wird JPEG", r.typ === "image/jpeg", r.typ); pruefe("auf 1600 gebracht", r.w === 1600, `${r.w}px`); } console.log("\n=== Seitenverhältnis bleibt erhalten ==="); { const r = await test(1600, 900, "image/jpeg", { maxBreite: 800 }); const verh = (r.w / r.h).toFixed(2); pruefe("16:9 bleibt 16:9", verh === "1.78", `${r.w}x${r.h} (${verh})`); } await browser.close(); console.log(`\n===== ${ok} bestanden, ${fehl} fehlgeschlagen =====`); process.exitCode = fehl ? 1 : 0;