Files
felhom.eu/scripts/iso/grub/generate-grub-background.sh
T

97 lines
5.3 KiB
Bash
Executable File

#!/bin/bash
#===============================================================================
# generate-grub-background.sh — build the Felhom GRUB boot background (scripts v1.22.0, R-38).
#
# Turns Viktor's square brand card (website/assets/og-image_2.png, 1017x1016) into a GRUB-friendly
# 1024x768 PNG. Runs INSIDE the felhom-iso-assistant container (needs ImageMagick); called by
# iso-repack.sh.
#
# THE LAYOUT, AND WHY:
#
# * 1024x768 canvas — gfxterm-safe. The stock PVE grub.cfg already asks for `gfxmode=1024x768`, so
# this is the mode the ISO's GRUB is known to get on real firmware. Anything larger risks a
# fallback to 800x600 and a scaled/cropped background.
#
# * The card is scaled to 500x500 and composited TOP-CENTERED (y=16). That deliberately leaves the
# bottom ~250px empty: it is where felhom-theme.txt positions the boot menu (top=70%) and the
# countdown label (top=84%). Menu text therefore never lands on the cloud/wordmark/tagline. If
# you change CARD or CARD_Y here, move `boot_menu.top` in felhom-theme.txt to match.
#
# * THE GRID. The card carries a subtle background grid (4px lines of #0D131A on #0D1117, every
# 131px) and Viktor asked for it to stay visible. Two things could destroy it: the downscale
# (handled — at 500/1017 the lines land at ~2px, still legible), and the letterbox fill. A flat
# navy fill would leave an obvious 500px square of grid floating in a plain field.
#
# So the grid is drawn across the WHOLE canvas first, PHASE-LOCKED to where the card's own grid
# will land, in the card's own line color — then the card is composited on top. Inside the card
# region the card's real grid shows; outside, the drawn continuation lines up exactly. The seam
# is invisible because the card's background (#0D1117) is also the canvas fill.
#
# The phase-lock math: source line centers are x=81.5+n*131, y=21.5+n*131 (measured, not guessed
# — sampled from og-image_2.png). Scale s=CARD/SRC_W maps them onto the canvas, offset by the
# card's origin. Line width scales the same way.
#
# Usage: generate-grub-background.sh <source.png> <out.png>
#===============================================================================
set -euo pipefail
SRC="${1:?source card PNG required}"
OUT="${2:?output PNG path required}"
# --- canvas ---------------------------------------------------------------------------------------
CW=1024; CH=768
BG="#0D1117" # the card's own background — the letterbox must be seamless, not merely "navy"
GRID="#0D131A" # the card's own grid line color (sampled)
# --- card placement (keep in sync with felhom-theme.txt boot_menu.top) ------------------------------
CARD=500; CARD_X=262; CARD_Y=16
# --- measured properties of og-image_2.png ----------------------------------------------------------
SRC_W=1017 # source width; the card is square (1017x1016)
PITCH=131 # grid pitch in source px
V0=81.5 # center of the first vertical grid line, source px
H0=21.5 # center of the first horizontal grid line, source px
LINE=4 # grid line width in source px
command -v magick >/dev/null && IM=magick || IM=convert
[[ -f "$SRC" ]] || { echo "generate-grub-background: source card not found: $SRC" >&2; exit 2; }
# Refuse a source whose geometry no longer matches the measured constants above — a silently swapped
# asset would misplace every grid line, and the result only shows up on a boot screen nobody re-checks.
GEOM="$($IM identify -format '%wx%h' "$SRC")"
[[ "$GEOM" == "1017x1016" ]] || {
echo "generate-grub-background: source card is ${GEOM}, expected 1017x1016." >&2
echo " The grid phase-lock constants (PITCH/V0/H0/LINE) were measured against that geometry." >&2
echo " Re-measure them for the new asset before changing this check." >&2
exit 3
}
S=$(awk -v c="$CARD" -v w="$SRC_W" 'BEGIN{printf "%.6f", c/w}') # card scale factor
P=$(awk -v p="$PITCH" -v s="$S" 'BEGIN{printf "%.4f", p*s}') # canvas grid pitch
LW=$(awk -v l="$LINE" -v s="$S" 'BEGIN{printf "%.2f", l*s}') # canvas grid line width
# Walk n outward far enough to cover the canvas in both axes from the card-anchored origin.
draw=""
for n in $(seq -20 40); do
x=$(awk -v a="$CARD_X" -v v="$V0" -v s="$S" -v p="$P" -v n="$n" 'BEGIN{printf "%.2f", a+v*s+n*p}')
if awk -v x="$x" -v w="$CW" 'BEGIN{exit !(x>-2 && x<w+2)}'; then
draw="$draw line $x,0 $x,$CH"
fi
y=$(awk -v a="$CARD_Y" -v v="$H0" -v s="$S" -v p="$P" -v n="$n" 'BEGIN{printf "%.2f", a+v*s+n*p}')
if awk -v y="$y" -v h="$CH" 'BEGIN{exit !(y>-2 && y<h+2)}'; then
draw="$draw line 0,$y $CW,$y"
fi
done
[[ -n "$draw" ]] || { echo "generate-grub-background: grid draw list came out empty" >&2; exit 4; }
# PNG24 (no palette, no alpha): GRUB's png module reads plain 8-bit RGB reliably; an indexed or
# 16-bit PNG is where "the background silently doesn't render" comes from.
$IM -size "${CW}x${CH}" xc:"$BG" \
-stroke "$GRID" -strokewidth "$LW" -draw "$draw" -stroke none \
\( "$SRC" -resize "${CARD}x${CARD}!" \) -geometry "+${CARD_X}+${CARD_Y}" -composite \
-depth 8 "PNG24:$OUT"
[[ -s "$OUT" ]] || { echo "generate-grub-background: produced no output" >&2; exit 5; }
OGEOM="$($IM identify -format '%wx%h %[channels] %[depth]' "$OUT")"
echo "generate-grub-background: $OUT ($OGEOM, $(stat -c%s "$OUT") bytes)"