Files
KantSites/scripts/build-kantarci-markt-assets.mjs
kantarciandClaude Opus 5.5 5e5d380fd3 Build Kantarci Markt as an eighth installation, allow content in own CSS and keep other fonts when fetching
- Coming-soon page "Kantarci Markt – Neueröffnung" rebuilt from the delivered package with
  imprint, privacy and 404 (scripts/reset-kantarci-markt.sh, ports 8100/8101).
- Own CSS accepts a short quoted string for `content`, so ::before/::after work.
- cms:fonts:fetch replaces only the rules of the fetched families in fonts.css.
- A variable font is linked and preloaded once with a weight range instead of once per weight.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 10:37:54 +02:00

83 lines
4.5 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* Bereitet die Bilder der Seite „Kantarci Markt – Neueröffnung“ für die Mediathek vor.
*
* Die Mediathek nimmt kein SVG. Das Seitensymbol und der runde Stempel „Frische • Qualität •
* Vertrauen“ der Vorlage sind aber SVG (der Stempel mit Text auf einem Kreisbogen, das kann kein
* Baustein). Chromium rastert beide zu PNG. Das Logo der Vorlage (1536 × 1024, 1,3 MB) wird auf
* seinen sichtbaren Teil zugeschnitten und auf 600 px Breite verkleinert (doppelte Anzeigebreite),
* angezeigt wird es mit höchstens 300 px.
*
* node scripts/build-kantarci-markt-assets.mjs [ordner]
* → logo.png, symbol.png, stempel.png im Ordner (Standard var/kantarci-markt-assets)
*/
import { chromium } from 'playwright';
import { readFile, writeFile } from 'node:fs/promises';
const ordner = process.argv[2] || 'var/kantarci-markt-assets';
const FORST = '#123b26', GOLD = '#a88332', GOLD_HELL = '#d2b978';
const browser = await chromium.launch();
const seite = await browser.newPage();
// Logo: sichtbaren Bereich über den Alphakanal bestimmen, zuschneiden, verkleinern.
const logo = (await readFile(`${ordner}/kantarci-markt-logo.png`)).toString('base64');
const logoPng = await seite.evaluate(async (daten) => {
const bild = new Image();
bild.src = `data:image/png;base64,${daten}`;
await bild.decode();
const quelle = new OffscreenCanvas(bild.width, bild.height);
const q = quelle.getContext('2d');
q.drawImage(bild, 0, 0);
const { data } = q.getImageData(0, 0, bild.width, bild.height);
let [x0, y0, x1, y1] = [bild.width, bild.height, 0, 0];
for (let y = 0; y < bild.height; y++) {
for (let x = 0; x < bild.width; x++) {
// Der Schein um die Waage läuft sehr flach aus; erst ab etwa 8 % Deckkraft zählt er.
if (data[(y * bild.width + x) * 4 + 3] > 20) {
x0 = Math.min(x0, x); y0 = Math.min(y0, y); x1 = Math.max(x1, x); y1 = Math.max(y1, y);
}
}
}
const rand = 8;
x0 = Math.max(0, x0 - rand); y0 = Math.max(0, y0 - rand);
x1 = Math.min(bild.width - 1, x1 + rand); y1 = Math.min(bild.height - 1, y1 + rand);
const breite = x1 - x0 + 1, hoehe = y1 - y0 + 1;
const ziel = Math.min(600, breite);
const leinwand = new OffscreenCanvas(ziel, Math.round(hoehe * ziel / breite));
const z = leinwand.getContext('2d');
z.imageSmoothingQuality = 'high';
z.drawImage(bild, x0, y0, breite, hoehe, 0, 0, leinwand.width, leinwand.height);
const blob = await leinwand.convertToBlob({ type: 'image/png' });
const bytes = new Uint8Array(await blob.arrayBuffer());
let binaer = '';
for (const b of bytes) binaer += String.fromCharCode(b);
return { png: btoa(binaer), breite: leinwand.width, hoehe: leinwand.height, ausschnitt: [x0, y0, breite, hoehe] };
}, logo);
await writeFile(`${ordner}/logo.png`, Buffer.from(logoPng.png, 'base64'));
console.log(`logo.png ${logoPng.breite} × ${logoPng.hoehe} (Ausschnitt ${logoPng.ausschnitt.join(', ')})`);
const rastern = async (svg, groesse, datei) => {
await seite.setViewportSize({ width: groesse, height: groesse });
await seite.setContent(`<!doctype html><style>html,body{margin:0;background:transparent}svg{display:block}</style>${svg}`);
await seite.screenshot({ path: `${ordner}/${datei}`, omitBackground: true });
console.log(`${datei} ${groesse} × ${groesse}`);
};
// Seitensymbol: das K mit Blatt aus dem Favicon der Vorlage.
await rastern(`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" width="256" height="256">
<rect width="64" height="64" rx="14" fill="#062f24"/>
<path d="M19 43V18h7v10l10-10h9L33 30l13 13h-9L26 32v11z" fill="${GOLD}"/>
<path d="M41 10c-7 2-10 6-9 13 6-1 10-5 9-13Z" fill="${GOLD}"/></svg>`, 256, 'symbol.png');
// Stempel: goldene Scheibe, Umschrift auf dem Kreis, Blatt in der Mitte. Doppelte Größe für
// scharfe Kanten auf hochauflösenden Bildschirmen (angezeigt mit 122 px).
await rastern(`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 122 122" width="244" height="244">
<circle cx="61" cy="61" r="61" fill="${GOLD_HELL}"/>
<g transform="translate(10 10) scale(1.1333)">
<defs><path id="kreis" d="M45,45 m-31,0 a31,31 0 1,1 62,0 a31,31 0 1,1 -62,0"/></defs>
<text font-family="Arial, sans-serif" font-weight="700" font-size="8" letter-spacing="1.4" fill="${FORST}"><textPath href="#kreis">FRISCHE • QUALITÄT • VERTRAUEN • </textPath></text>
<path d="M45 52c-2-16 6-25 22-26-1 16-8 24-22 26Zm0 0c-8-11-17-13-27-7 7 12 16 14 27 7Z" fill="${FORST}"/>
</g></svg>`, 244, 'stempel.png');
await browser.close();