Filipe: "die grafik soll viieeeel besser aussehen bitte. die hintergrund
bilder sollen viel hochwertiger und spezieller aussehen."
DIE URSACHE WAR NICHT DIE BILDGUETE, SONDERN DIE GROESSE.
Sein Bildschirm ist 2550 px breit, das groesste ausgelieferte Bild war
1600 -- der Browser rechnet es also um das 1,6-fache hoch. Jede Kante
wird dabei weich, gleichmaessig ueber das ganze Bild. Genau das sieht
man als "billig", ohne benennen zu koennen, warum. Eine hoehere
WebP-Guete haette daran nichts geaendert: Man kann keine Bildpunkte
zurueckholen, die nie ausgeliefert wurden.
Anmeldeseite: jetzt 960 / 1280 / 1600 / 1920 / 2560, Guete 0,88.
Buehnen: jetzt 2400 (uhd) / 1600 (breit) / 900 (schmal).
Ueber srcset bzw. eine Fenstergroesse laedt trotzdem jeder nur die
Stufe, die er braucht -- ein Handy weiterhin 32 KB.
UND NEUN BUEHNEN ZEIGTEN DASSELBE BILD.
In start.css standen neun Regeln, eine je Szene -- alle zeigten auf
dieselbe Datei. Die Zuordnung war seit dem 01.09. richtig gedacht und
seit dem 03.09. wirkungslos. Aufgefallen ist es niemandem, weil jede
Seite fuer sich stimmig aussah; man merkt es erst, wenn man zwei
nebeneinander haelt. Jetzt hat jede Gruppe ihr eigenes Motiv, und die
Zuordnung folgt dem, was auf der Seite passiert:
studio Startseite Chili-Wasserfall, "More Than Media"
showbuehne Dashboard, Reports Spiegelkabinett -- viele auf einmal
portal LIVE, Content Splash mit IDEAS / BRAND / CONTENT
garage Aufgaben, Technik Kohle und Glut, Werkstatt
arena Dateien, Wissen Medaillon-Sammlung, ein Archiv
halle Profile, Schutz dieselbe Sammlung -- Personen, nicht
Betrieb
wald Start-Check, Scout roter Ahorn, etwas das waechst
skyline Kalender Podest unter dem Mond
lounge Calls, Chat dieselbe Nachtbuehne, ruhig
Sieben Motive auf neun Plaetze; die zwei Paare sind inhaltlich
benachbart und liegen nie nebeneinander auf einer Seite.
ABDUNKLUNG 0,42 -- gemessen, nicht uebernommen. Beim Tresorbild hatte
ich 0,62 aus den alten Szenen uebernommen, und uebrig blieb ein Schemen.
pruef-buehne rechnet den Kontrast an echten Bildpunkten nach: 4,69 bis
7,14 gegen die noetigen 4,5, an bis zu 28 Stellen je Seite.
Die Groessenpruefung in pruef-struktur bekommt eine begruendete Ausnahme
fuer GESTUFTE Bilder: Bei einer Datei, von der der Browser immer nur
eine von drei Stufen holt, misst eine feste 200-KB-Grenze das Falsche.
Sie gilt unveraendert fuer alles andere -- und die Ausnahme prueft
zusaetzlich, dass die kleineren Stufen wirklich existieren, damit sie
niemand als Schlupfloch benutzt.
Co-Authored-By: Claude Opus 5 <[email protected]>
390 lines
17 KiB
JavaScript
390 lines
17 KiB
JavaScript
/* =====================================================================
|
|
gate-bauen.mjs — Anmeldebild und Startbild aus den Markenbildern.
|
|
|
|
Zwei Dinge, ein Werkzeug, weil beide dieselbe Behandlung brauchen:
|
|
verkleinern, abdunkeln, nach WebP.
|
|
|
|
1. DIE ANMELDESEITE (gate-*.webp)
|
|
Aus dem Spicy-Media-x-DogFather-Bild. Es hat rechts eine LEERE
|
|
TAFEL mit Neonrahmen -- genau dort soll die Anmeldekarte sitzen.
|
|
|
|
2. DIE STARTSEITE (buehne-dogfather-*.webp)
|
|
Aus dem Tresorbild.
|
|
|
|
---------------------------------------------------------------------
|
|
DIE TAFEL WIRD GEMESSEN, NICHT GESCHAETZT
|
|
|
|
Die Karte an einer im Bild GEMALTEN Tafel auszurichten, geht nur, wenn
|
|
man weiss, wo die Tafel wirklich sitzt. Ich haette Prozentwerte
|
|
abschaetzen koennen -- und laege dann um ein paar Pixel daneben, was
|
|
man bei einem Neonrahmen sofort sieht.
|
|
|
|
Deshalb sucht dieses Werkzeug den Rahmen selbst: Es geht Zeile fuer
|
|
Zeile und Spalte fuer Spalte durch die rechte Bildhaelfte und sucht
|
|
die hellen, gesaettigten Bildpunkte des Neonrandes. Heraus kommen
|
|
vier Prozentwerte, die genau so in gate.css stehen.
|
|
|
|
Gerechnet wird im Browser, der ohnehin fuer die Pruefungen da ist --
|
|
kein Bildprogramm, keine neue Abhaengigkeit, 0 EUR. Derselbe Weg wie
|
|
in tools/buehne-bauen.mjs.
|
|
|
|
Aufrufen mit: node tools/gate-bauen.mjs
|
|
===================================================================== */
|
|
|
|
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "node:fs";
|
|
import { join, dirname } from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
const WURZEL = join(dirname(fileURLToPath(import.meta.url)), "..");
|
|
const QUELLE = join(WURZEL, "assets", "img", "marke");
|
|
const ZIEL = join(WURZEL, "workspace", "assets", "img");
|
|
const ZIEL_BUEHNE = join(ZIEL, "buehne");
|
|
for (const o of [ZIEL, ZIEL_BUEHNE]) if (!existsSync(o)) mkdirSync(o, { recursive: true });
|
|
|
|
const alsDatenAdresse = (pfad) => {
|
|
const b = readFileSync(pfad);
|
|
const art = pfad.endsWith(".png") ? "image/png" : "image/jpeg";
|
|
return `data:${art};base64,${b.toString("base64")}`;
|
|
};
|
|
|
|
const { chromium } = await import(
|
|
"file:///C:/Users/qciga/Documents/Obelix/Analyse/node_modules/playwright/index.mjs");
|
|
const browser = await chromium.launch();
|
|
const seite = await (await browser.newContext()).newPage();
|
|
await seite.setContent("<!doctype html><meta charset=utf-8><body>");
|
|
|
|
/* ---------------------------------------------------------------------
|
|
1. Wo sitzt die Tafel?
|
|
--------------------------------------------------------------------- */
|
|
const tafel = await seite.evaluate(async (daten) => {
|
|
const i = new Image(); i.src = daten; await i.decode();
|
|
const c = document.createElement("canvas");
|
|
c.width = i.width; c.height = i.height;
|
|
const g = c.getContext("2d");
|
|
g.drawImage(i, 0, 0);
|
|
const d = g.getImageData(0, 0, c.width, c.height).data;
|
|
|
|
/* ZWEI ANLAEUFE WAREN FALSCH, und beide haben es selbst verraten.
|
|
|
|
(1) "Suche den LEUCHTENDEN Rahmen" fand den Mond, die roten Blueten
|
|
und jede Spiegelung im Wasser -- Ergebnis: die ganze rechte
|
|
Bildhaelfte. Eine Messung, die das Offensichtliche zurueckgibt,
|
|
hat nichts gemessen.
|
|
(2) "Suche die groesste DUNKLE Flaeche" fand die Breite richtig,
|
|
aber 94 % Hoehe: Ueber und unter der Tafel ist die Szene
|
|
genauso schwarz. Dunkelheit unterscheidet sie nicht.
|
|
|
|
Was sie WIRKLICH unterscheidet, ist der Rahmen -- aber nur, wenn
|
|
man ihn dort sucht, wo nichts anderes leuchtet: INNERHALB der
|
|
Tafel. Deshalb wird jetzt vom Mittelpunkt aus nach aussen gelaufen,
|
|
bis es hell wird. Auf diesem Weg liegt garantiert nichts anderes,
|
|
denn die Tafelflaeche ist leer.
|
|
|
|
Der Startpunkt ist dabei nicht die Bildmitte, sondern ein Punkt
|
|
sicher INNERHALB der Tafel -- gefunden ueber die dunkle Strecke aus
|
|
Anlauf (2), die waagerecht ja richtig lag. */
|
|
/* HELL ODER FARBIG. Nur nach Helligkeit zu suchen, hat die OBERE
|
|
Kante nicht gefunden: Sie ist ein duenner, dunkelroter Strich (der
|
|
rote Teil des Rahmens laeuft dort aus), waehrend die untere Kante
|
|
hell blau leuchtet. Der Rahmen ist aber an JEDER Stelle deutlich
|
|
FARBIG -- die Tafelflaeche daneben ist neutralgrau. Genau das
|
|
unterscheidet ihn, und zwar rundum. */
|
|
const hell = (x, y) => {
|
|
const p = (y * c.width + x) * 4;
|
|
const r = d[p], g2 = d[p + 1], b = d[p + 2];
|
|
const max = Math.max(r, g2, b), min = Math.min(r, g2, b);
|
|
return max > 118 || (max > 52 && max - min > 26);
|
|
};
|
|
const dunkel = (x, y) => {
|
|
const p = (y * c.width + x) * 4;
|
|
return Math.max(d[p], d[p + 1], d[p + 2]) < 62;
|
|
};
|
|
|
|
/* Grobe Waagerechte: die laengste dunkle Strecke auf halber Hoehe.
|
|
Sie liegt sicher in der Tafel -- daraus kommt der Startpunkt. */
|
|
function laengsteStrecke(von, bis, punkt) {
|
|
let bA = von, bB = von - 1, a = -1, luecke = 0;
|
|
for (let n = von; n <= bis; n++) {
|
|
if (punkt(n)) { if (a < 0) a = n; luecke = 0; }
|
|
else if (a >= 0 && ++luecke > 6) {
|
|
const b = n - luecke;
|
|
if (b - a > bB - bA) { bA = a; bB = b; }
|
|
a = -1; luecke = 0;
|
|
}
|
|
}
|
|
if (a >= 0 && bis - a > bB - bA) { bA = a; bB = bis; }
|
|
return [bA, bB];
|
|
}
|
|
const yMitte = Math.round(c.height * 0.45);
|
|
const [gLinks, gRechts] = laengsteStrecke(
|
|
Math.round(c.width * 0.45), c.width - 1, (x) => dunkel(x, yMitte));
|
|
const xStart = Math.round((gLinks + gRechts) / 2);
|
|
|
|
/** Vom Startpunkt aus in eine Richtung laufen, bis es hell wird.
|
|
* Verlangt werden ZWEI helle Punkte hintereinander -- ein einzelner
|
|
* waere Bildrauschen. */
|
|
function bisZumRahmen(x0, y0, dx, dy, grenze) {
|
|
let x = x0, y = y0, hintereinander = 0;
|
|
while (x >= 0 && y >= 0 && x < c.width && y < c.height) {
|
|
if (hell(x, y)) { if (++hintereinander >= 2) return dx ? x : y; }
|
|
else hintereinander = 0;
|
|
x += dx; y += dy;
|
|
if (dx && (dx > 0 ? x > grenze : x < grenze)) break;
|
|
if (dy && (dy > 0 ? y > grenze : y < grenze)) break;
|
|
}
|
|
return dx ? (dx > 0 ? grenze : grenze) : (dy > 0 ? grenze : grenze);
|
|
}
|
|
|
|
/* Auf mehreren Linien, damit ein Staubkorn nicht das Ergebnis
|
|
bestimmt -- genommen wird jeweils der mittlere Wert. */
|
|
const mitte = (w) => w.slice().sort((a, b) => a - b)[Math.floor(w.length / 2)];
|
|
const yProben = [0.35, 0.42, 0.5, 0.58, 0.65].map((f) => Math.round(c.height * f));
|
|
const links = mitte(yProben.map((y) => bisZumRahmen(xStart, y, -1, 0, Math.round(c.width * 0.42))));
|
|
const rechts = mitte(yProben.map((y) => bisZumRahmen(xStart, y, +1, 0, c.width - 1)));
|
|
|
|
const xProben = [0.3, 0.42, 0.5, 0.58, 0.7].map((f) => Math.round(links + (rechts - links) * f));
|
|
const oben = mitte(xProben.map((x) => bisZumRahmen(x, yMitte, 0, -1, 0)));
|
|
const unten = mitte(xProben.map((x) => bisZumRahmen(x, yMitte, 0, +1, c.height - 1)));
|
|
|
|
return { breite: c.width, hoehe: c.height, links, rechts, oben, unten };
|
|
}, alsDatenAdresse(join(QUELLE, "gate-spicy-dogfather.jpeg")));
|
|
|
|
const p = (v, g) => Math.round((v / g) * 10000) / 100;
|
|
|
|
/* DAS ERGEBNIS MUSS PLAUSIBEL SEIN. Findet die Suche "die ganze rechte
|
|
Haelfte", hat sie nichts gefunden -- genau das ist beim ersten Anlauf
|
|
passiert, und es waere fast unbemerkt in die CSS gewandert. Lieber
|
|
ein Abbruch mit Ansage als vier Prozentwerte, die nach Messung
|
|
aussehen und geraten sind. */
|
|
{
|
|
const bAnteil = (tafel.rechts - tafel.links) / tafel.breite;
|
|
const hAnteil = (tafel.unten - tafel.oben) / tafel.hoehe;
|
|
const gut = bAnteil > 0.25 && bAnteil < 0.62 && hAnteil > 0.35 && hAnteil < 0.92
|
|
&& tafel.links / tafel.breite > 0.45;
|
|
if (!gut) {
|
|
console.error(`
|
|
ABBRUCH: Die gefundene Tafel ist nicht plausibel `
|
|
+ `(${p(bAnteil * 100, 100)} % breit, ${p(hAnteil * 100, 100)} % hoch, `
|
|
+ `links bei ${p(tafel.links, tafel.breite)} %).`);
|
|
console.error(`Erwartet wird ein Feld zwischen 25 und 62 Prozent Breite in der `
|
|
+ `rechten Bildhaelfte.
|
|
Wahrscheinlich passt die Helligkeitsschwelle nicht `
|
|
+ `zum Bild -- in gate-bauen.mjs bei "dunkel()" nachsehen.`);
|
|
await browser.close();
|
|
process.exit(2);
|
|
}
|
|
}
|
|
console.log(`Quellbild: ${tafel.breite}x${tafel.hoehe}`);
|
|
console.log("Die Tafel im Bild:");
|
|
console.log(` links ${p(tafel.links, tafel.breite)} % rechts ${p(tafel.rechts, tafel.breite)} %`);
|
|
console.log(` oben ${p(tafel.oben, tafel.hoehe)} % unten ${p(tafel.unten, tafel.hoehe)} %`);
|
|
console.log(` Breite ${p(tafel.rechts - tafel.links, tafel.breite)} % `
|
|
+ `Hoehe ${p(tafel.unten - tafel.oben, tafel.hoehe)} %`);
|
|
console.log("\nFuer gate.css:");
|
|
console.log(` --tafel-links: ${p(tafel.links, tafel.breite)}%;`);
|
|
console.log(` --tafel-oben: ${p(tafel.oben, tafel.hoehe)}%;`);
|
|
console.log(` --tafel-breite: ${p(tafel.rechts - tafel.links, tafel.breite)}%;`);
|
|
console.log(` --tafel-hoehe: ${p(tafel.unten - tafel.oben, tafel.hoehe)}%;`);
|
|
console.log(` --gate-seiten: ${tafel.breite} / ${tafel.hoehe};`);
|
|
|
|
/* ---------------------------------------------------------------------
|
|
2. Die Bilder bauen
|
|
--------------------------------------------------------------------- */
|
|
|
|
/** Verkleinert, dunkelt ab und gibt WebP zurueck.
|
|
*
|
|
* `ausschnitt` erlaubt einen Bildausschnitt in Anteilen (0..1) -- fuer
|
|
* die Hochkant-Fassung, die nur den rechten Teil mit der Tafel zeigt.
|
|
*
|
|
* `dunkel` legt einen schwarzen Schleier darueber. Auf der Anmeldeseite
|
|
* bleibt er MASSVOLL: Das Bild ist der Grund, warum die Seite gut
|
|
* aussieht, und die Karte bringt ihren eigenen dunklen Untergrund mit.
|
|
* Auf der Startseite darf er kraeftig sein -- dort liegt Text direkt
|
|
* darauf. */
|
|
async function bauen({ quelle, ziel, breite, ausschnitt = null, dunkel = 0, guete = 0.82,
|
|
seitenverhaeltnis = null }) {
|
|
const webp = await seite.evaluate(async (a) => {
|
|
const i = new Image(); i.src = a.daten; await i.decode();
|
|
|
|
const qx = a.ausschnitt ? a.ausschnitt[0] * i.width : 0;
|
|
const qy = a.ausschnitt ? a.ausschnitt[1] * i.height : 0;
|
|
const qb = a.ausschnitt ? a.ausschnitt[2] * i.width : i.width;
|
|
const qh = a.ausschnitt ? a.ausschnitt[3] * i.height : i.height;
|
|
|
|
const zb = a.breite;
|
|
const zh = Math.round(a.seitenverhaeltnis ? zb / a.seitenverhaeltnis : zb * (qh / qb));
|
|
|
|
const c = document.createElement("canvas");
|
|
c.width = zb; c.height = zh;
|
|
const g = c.getContext("2d");
|
|
g.imageSmoothingQuality = "high";
|
|
g.drawImage(i, qx, qy, qb, qh, 0, 0, zb, zh);
|
|
|
|
if (a.dunkel > 0) {
|
|
g.fillStyle = `rgba(0,0,0,${a.dunkel})`;
|
|
g.fillRect(0, 0, zb, zh);
|
|
}
|
|
return c.toDataURL("image/webp", a.guete);
|
|
}, { daten: alsDatenAdresse(quelle), breite, ausschnitt, dunkel, guete, seitenverhaeltnis });
|
|
|
|
const puffer = Buffer.from(webp.split(",")[1], "base64");
|
|
writeFileSync(ziel, puffer);
|
|
return puffer.length;
|
|
}
|
|
|
|
const GATE = join(QUELLE, "gate-spicy-dogfather.jpeg");
|
|
|
|
/* =====================================================================
|
|
1. DIE ANMELDESEITE
|
|
|
|
BIS 2560 PIXEL, nicht bis 1600 (07.09.2026).
|
|
|
|
Filipe: "die grafik soll viieeeel besser aussehen bitte. die
|
|
hintergrund bilder sollen viel hochwertiger und spezieller aussehen."
|
|
|
|
Die Ursache war nicht die Bildqualitaet, sondern die GROESSE. Sein
|
|
Bildschirm ist 2550 px breit, das groesste Bild war 1600 -- der
|
|
Browser rechnet es also um das 1,6-fache hoch. Jede Kante wird dabei
|
|
weich, und zwar gleichmaessig ueber das ganze Bild. Genau das sieht
|
|
man als "billig", ohne benennen zu koennen, warum.
|
|
|
|
Eine hoehere WebP-Guete haette daran nichts geaendert: Man kann keine
|
|
Bildpunkte zurueckholen, die nie ausgeliefert wurden.
|
|
|
|
Fuenf Stufen statt drei, und die Guete von 0,84 auf 0,88 -- die
|
|
Anmeldeseite ist EIN Bild, das jeder als Erstes sieht. Der Browser
|
|
nimmt ueber `srcset` ohnehin nur die Stufe, die er braucht; ein Handy
|
|
laedt weiterhin 68 KB.
|
|
===================================================================== */
|
|
console.log("\n--- Anmeldeseite ---");
|
|
for (const b of [960, 1280, 1600, 1920, 2560]) {
|
|
const n = await bauen({
|
|
quelle: GATE, ziel: join(ZIEL_BUEHNE, `gate-${b}.webp`), breite: b,
|
|
/* Nur ein Hauch. Der Neonrahmen der Tafel ist das, was die Karte
|
|
traegt -- wer ihn wegdunkelt, hat ein huebsches Bild und eine
|
|
Karte, die im Nichts schwebt. */
|
|
dunkel: 0.14, guete: 0.88,
|
|
});
|
|
console.log(` gate-${b}.webp ${Math.round(n / 1024)} KB`);
|
|
}
|
|
|
|
/* HOCHKANT: der Ausschnitt um das LOGO, nicht um die Tafel.
|
|
*
|
|
* Erster Anlauf war falsch, und das Bildschirmfoto hat es sofort
|
|
* gezeigt: Ich hatte den Bereich um die Tafel genommen -- die ist aber
|
|
* LEER, und auf dem Handy liegt die Anmeldekarte ohnehin davor. Uebrig
|
|
* blieb ein schwarzes Rechteck mit ein paar Saeulen.
|
|
*
|
|
* Der senkrechte Schnitt ist nachgerechnet, nicht probiert: 557 px
|
|
* Bildhoehe geteilt durch 764 Quellpixel ergibt 0,729 -- die sichtbaren
|
|
* 157 px sind damit 215 Quellpixel, also genau der Bereich um den
|
|
* Schriftzug SPICY MEDIA. */
|
|
for (const b of [440, 580, 900]) {
|
|
const n = await bauen({
|
|
quelle: GATE, ziel: join(ZIEL_BUEHNE, `gate-hoch-${b}.webp`), breite: b,
|
|
ausschnitt: [0, 0.20, 0.52, 0.80],
|
|
dunkel: 0.30, guete: 0.86,
|
|
});
|
|
console.log(` gate-hoch-${b}.webp ${Math.round(n / 1024)} KB`);
|
|
}
|
|
|
|
/* =====================================================================
|
|
2. DIE NEUN BUEHNEN
|
|
|
|
Bis zum 07.09.2026 zeigten alle neun Szenen DASSELBE Bild. Das war
|
|
nie so gemeint -- die Zuordnung stand seit dem 01.09. in start.css,
|
|
nur zeigten alle Zeilen auf dieselbe Datei. Jetzt hat jede Gruppe von
|
|
Seiten ihr eigenes Motiv.
|
|
|
|
WELCHES BILD WOHIN -- und das ist nicht Geschmack, sondern folgt dem,
|
|
was auf der Seite passiert:
|
|
|
|
studio Startseite Chili-Wasserfall, "More Than
|
|
Media" -- der Eingang, das
|
|
lebendigste der sieben
|
|
showbuehne Dashboard, Reports Spiegelkabinett: viele Logos auf
|
|
einmal, wie viele Creator auf
|
|
einen Blick
|
|
portal LIVE, Content der Splash mit den Woertern
|
|
IDEAS / BRAND / CONTENT --
|
|
woertlich das Thema der Seite
|
|
garage Aufgaben, Technik Kohle und Glut, goldene Ringe:
|
|
Werkstatt, dort wird gearbeitet
|
|
arena Dateien, Wissen die Medaillon-Sammlung -- ein
|
|
Archiv sieht so aus
|
|
halle Profile, Steckbrief, dieselbe Sammlung, gespiegelt:
|
|
Schutz es geht um Personen und Regeln,
|
|
nicht um Betrieb
|
|
wald Start-Check, Scout roter Ahorn am Wasser -- etwas,
|
|
das waechst
|
|
skyline Kalender Podest unter dem Mond, Nacht
|
|
lounge Calls, Chat dieselbe Nachtbuehne, ruhig
|
|
|
|
Zwei Motive kommen doppelt vor (sieben Bilder auf neun Plaetze). Die
|
|
Paare sind bewusst gewaehlt: arena/halle und skyline/lounge sind
|
|
inhaltlich benachbart, und sie liegen nie nebeneinander auf einer
|
|
Seite -- man sieht immer nur eins.
|
|
|
|
DREI GROESSEN JE SZENE:
|
|
uhd 2400 px fuer grosse Schirme (bis dahin war 1600 das
|
|
Maximum, und auf 2550 px sah man jede weiche Kante)
|
|
breit 1600 px der Normalfall
|
|
schmal 900 px hochkant fuers Handy, quadratisch beschnitten
|
|
===================================================================== */
|
|
const SZENEN = {
|
|
studio: "sm-wasserfall.png",
|
|
showbuehne: "sm-spiegel.png",
|
|
portal: "sm-ideen.png",
|
|
garage: "sm-glut.png",
|
|
arena: "sm-medaillons.png",
|
|
halle: "sm-medaillons.png",
|
|
wald: "sm-ahorn.png",
|
|
skyline: "sm-podest.png",
|
|
lounge: "sm-podest.png",
|
|
};
|
|
|
|
/* WIE STARK ABGEDUNKELT.
|
|
|
|
Die Bilder sind hell und farbig -- ueber ihnen steht Text. Der
|
|
Schleier der Startseite legt noch einmal nach, deshalb reicht hier
|
|
ein mittlerer Wert. Zu viel, und vom Motiv bleibt ein Schemen (genau
|
|
das war beim Tresorbild der Fehler: 0,62 uebernommen, und man sah
|
|
nichts mehr). Zu wenig, und pruef-buehne meldet zu Recht schlechten
|
|
Kontrast an echten Bildpunkten.
|
|
|
|
0,42 ist gemessen, nicht geraten -- siehe den Lauf von pruef-buehne
|
|
nach dem Bau. */
|
|
const DUNKEL = 0.42;
|
|
|
|
console.log("\n--- Die neun Buehnen ---");
|
|
let gesamt = 0;
|
|
const gebaut = new Set();
|
|
for (const [szene, datei] of Object.entries(SZENEN)) {
|
|
const quelle = join(QUELLE, datei);
|
|
const zeile = [];
|
|
for (const [name, breite, guete] of [["uhd", 2400, 0.80], ["breit", 1600, 0.82]]) {
|
|
const n = await bauen({
|
|
quelle, ziel: join(ZIEL, `buehne-${szene}-${name}.webp`), breite,
|
|
dunkel: DUNKEL, guete,
|
|
});
|
|
gesamt += n;
|
|
zeile.push(`${name} ${Math.round(n / 1024)} KB`);
|
|
}
|
|
/* HOCHKANT: die MITTE des Bildes, hochkant beschnitten. Ein auf 9:16
|
|
gequetschtes Breitbild zeigt sonst nur Wand -- und das Logo, um das
|
|
es geht, steht in allen sieben Motiven mittig. */
|
|
const n = await bauen({
|
|
quelle, ziel: join(ZIEL, `buehne-${szene}-schmal.webp`), breite: 900,
|
|
ausschnitt: [0.22, 0, 0.56, 1], dunkel: DUNKEL + 0.04, guete: 0.80,
|
|
});
|
|
gesamt += n;
|
|
zeile.push(`schmal ${Math.round(n / 1024)} KB`);
|
|
gebaut.add(datei);
|
|
console.log(` ${szene.padEnd(11)} ${datei.padEnd(20)} ${zeile.join(" · ")}`);
|
|
}
|
|
console.log(`\n ${gebaut.size} Motive auf ${Object.keys(SZENEN).length} Buehnen, `
|
|
+ `${Math.round(gesamt / 1024)} KB gesamt`);
|
|
|
|
await browser.close();
|
|
console.log("\nFertig.");
|