Files
KantSites/scripts/build-becker-assets.php
T
kantarciandClaude Opus 5.5 9e3862093e
CMS quality / php (8.2) (push) Waiting to run
CMS quality / php (8.4) (push) Waiting to run
CMS quality / browser (push) Waiting to run
CMS quality / mysql (push) Waiting to run
Add the Becker Just In Time site build
Seed, asset and reset scripts for Becker - Just In Time e. Kfm.
(Wiernsheim): logo cut from the PDF raster, logo-free photos generated
with ChatGPT, before/after slider, service pages, contact form, legal
pages. Launch configs on ports 8116/8117, Manrope 800 and Montserrat
700/800 fetched locally.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 10:03:16 +01:00

130 lines
6.0 KiB
PHP
Raw 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.
<?php
/**
* Bereitet Logo und Fotos von „Becker – Just In Time e. Kfm.“ für die Mediathek des Nachbaus vor.
*
* Quellordner (var/becker-quelle):
* - logo-original.png: das Rasterbild aus Logo_Becker_original.pdf (1536 × 1024, Navy-Grund #172234),
* - ki/*.png: die von ChatGPT ohne Logos neu erzeugten Fotos (10.11.2026, nach Umuts Vorlagen).
*
* Daraus entstehen im Zielordner:
* - logo.png: Bagger-Signet links, „BECKER / JUST IN TIME e. Kfm.“ rechts – für den Kopf,
* - logo-gross.png: das Logo gestapelt mit den drei Leistungssymbolen – für den Fuß,
* - favicon.png: das Bagger-Signet auf Navy, 192 × 192,
* - je Foto eine WebP-Datei (Startbild 1920 px, sonst 1600 px breit).
*
* Der Navy-Grund des Logos wird weich freigestellt: Deckkraft aus dem Farbabstand zum Grund,
* die Kantenfarbe zurückgerechnet. So passt das Logo auf jede dunkle Fläche.
*
* Aufruf: php scripts/build-becker-assets.php <Quellordner> <Zielordner>
*/
$quelle = rtrim($argv[1] ?? '', '/\\');
$ziel = rtrim($argv[2] ?? '', '/\\');
if ('' === $quelle || '' === $ziel || !is_file($quelle.'/logo-original.png')) {
fwrite(STDERR, "Aufruf: php scripts/build-becker-assets.php <Ordner mit logo-original.png und ki/> <Zielordner>\n");
exit(1);
}
if (!is_dir($ziel) && !mkdir($ziel, 0775, true)) {
fwrite(STDERR, "Zielordner lässt sich nicht anlegen: $ziel\n");
exit(1);
}
$logo = imagecreatefrompng($quelle.'/logo-original.png');
$grund = [23, 34, 52];
/** Ein Ausschnitt des Logos mit freigestelltem Navy-Grund. */
$freistellen = static function (int $x, int $y, int $b, int $h) use ($logo, $grund): GdImage {
$bild = imagecreatetruecolor($b, $h);
imagealphablending($bild, false);
imagesavealpha($bild, true);
for ($j = 0; $j < $h; ++$j) {
for ($i = 0; $i < $b; ++$i) {
$c = imagecolorat($logo, $x + $i, $y + $j);
$p = [$c >> 16 & 0xFF, $c >> 8 & 0xFF, $c & 0xFF];
$abstand = max(abs($p[0] - $grund[0]), abs($p[1] - $grund[1]), abs($p[2] - $grund[2]));
$a = min(1.0, max(0.0, ($abstand - 6) / 90));
if ($a <= 0.0) {
imagesetpixel($bild, $i, $j, imagecolorallocatealpha($bild, 0, 0, 0, 127));
continue;
}
$f = array_map(static fn (int $k): int => (int) max(0, min(255, round($grund[$k] + ($p[$k] - $grund[$k]) / $a))), [0, 1, 2]);
imagesetpixel($bild, $i, $j, imagecolorallocatealpha($bild, $f[0], $f[1], $f[2], (int) round(127 * (1 - $a))));
}
}
return $bild;
};
/** Verkleinert mit Durchsichtigkeit. */
$verkleinern = static function (GdImage $bild, int $breite): GdImage {
$hoehe = (int) round(imagesy($bild) * $breite / imagesx($bild));
$neu = imagecreatetruecolor($breite, $hoehe);
imagealphablending($neu, false);
imagesavealpha($neu, true);
imagefill($neu, 0, 0, imagecolorallocatealpha($neu, 0, 0, 0, 127));
imagecopyresampled($neu, $bild, 0, 0, 0, 0, $breite, $hoehe, imagesx($bild), imagesy($bild));
return $neu;
};
// Bänder im Original (gemessen): Signet y 15–455 / x 360–1196, „BECKER“ y 466–636,
// „JUST IN TIME e. Kfm.“ mit Linien y 647–701 / x 162–1382, Leistungssymbole y 722–897.
$signet = $freistellen(352, 8, 852, 456);
$schrift = $freistellen(154, 458, 1236, 252);
// Querformat für den Kopf: Signet links (so hoch wie die Schrift plus etwas), Schrift rechts.
$sh = 330;
$sb = (int) round(852 * $sh / 456);
$quer = imagecreatetruecolor($sb + 36 + 1236, $sh);
imagealphablending($quer, false);
imagesavealpha($quer, true);
imagefill($quer, 0, 0, imagecolorallocatealpha($quer, 0, 0, 0, 127));
imagealphablending($quer, true);
imagecopyresampled($quer, $signet, 0, 0, 0, 0, $sb, $sh, 852, 456);
imagecopy($quer, $schrift, $sb + 36, (int) round(($sh - 252) / 2) + 10, 0, 0, 1236, 252);
imagealphablending($quer, false);
imagepng($verkleinern($quer, 760), $ziel.'/logo.png', 9);
echo 'logo.png: 760 × '.(int) round($sh * 760 / imagesx($quer))."\n";
$gross = $freistellen(100, 8, 1336, 898);
imagepng($verkleinern($gross, 560), $ziel.'/logo-gross.png', 9);
echo "logo-gross.png: 560 px breit\n";
// Die drei Leistungssymbole des Logos (Blätter, Zaun, Dach) einzeln, quadratisch, 128 px.
foreach (['symbol-garten' => [250, 716, 186, 120], 'symbol-zaun' => [679, 716, 176, 124], 'symbol-asbest' => [1071, 716, 226, 120]] as $name => [$x, $y, $b, $h]) {
$teil = $freistellen($x, $y, $b, $h);
$q = max($b, $h);
$quadrat = imagecreatetruecolor(128, 128);
imagealphablending($quadrat, false);
imagesavealpha($quadrat, true);
imagefill($quadrat, 0, 0, imagecolorallocatealpha($quadrat, 0, 0, 0, 127));
$f = 128 / $q;
imagecopyresampled($quadrat, $teil, (int) round((128 - $b * $f) / 2), (int) round((128 - $h * $f) / 2), 0, 0, (int) round($b * $f), (int) round($h * $f), $b, $h);
imagepng($quadrat, $ziel.'/'.$name.'.png', 9);
echo "$name.png: 128 × 128\n";
}
// Seitensymbol: Signet mittig auf Navy.
$fav = imagecreatetruecolor(192, 192);
imagefill($fav, 0, 0, imagecolorallocate($fav, ...$grund));
imagecopyresampled($fav, $logo, 14, 22 + (int) round((148 - 164 * 440 / 836) / 2), 360, 15, 164, (int) round(164 * 440 / 836), 836, 440);
imagepng($fav, $ziel.'/favicon.png', 9);
echo "favicon.png: 192 × 192\n";
// Fotos: ChatGPT liefert PNG; als WebP auf Zielbreite.
foreach (['haus' => 1920, 'team' => 1600, 'zaun' => 1600, 'zauntor' => 1600, 'asbest' => 1600, 'dach' => 1600,
'bagger' => 1600, 'terrasse' => 1600, 'zisterne' => 1600, 'vorher' => 1600, 'nachher' => 1600] as $name => $breite) {
$pfad = $quelle.'/ki/'.$name.'.png';
if (!is_file($pfad)) {
fwrite(STDERR, "Foto fehlt: $pfad\n");
exit(1);
}
$bild = imagecreatefrompng($pfad);
$breite = min($breite, imagesx($bild));
$hoehe = (int) round(imagesy($bild) * $breite / imagesx($bild));
$neu = imagecreatetruecolor($breite, $hoehe);
imagecopyresampled($neu, $bild, 0, 0, 0, 0, $breite, $hoehe, imagesx($bild), imagesy($bild));
imagewebp($neu, $ziel.'/'.$name.'.webp', 80);
echo "$name.webp: $breite × $hoehe\n";
}