#!/usr/bin/env bash # Generate Android adaptive launcher icons from source PNGs. # Usage: ./scripts/gen-icons.sh # # Source images should be 1024x1024. Base icon sources are read from # composeApp/src/androidMain/res/{fg,bg,mono}.png. Partner foregrounds live # in composeApp/src/androidMain/app-icon-assets/_{fg,mono}.png and are # generated as alternate launcher icons using the default background. set -euo pipefail RES="$(dirname "$0")/../composeApp/src/androidMain/res" FG="$RES/fg.png" BG="$RES/bg.png" MONO="$RES/mono.png" PARTNER_FG="$(dirname "$0")/../composeApp/src/androidMain/app-icon-assets" for source in "$FG" "$BG" "$MONO"; do if [[ ! -f "$source" ]]; then echo "missing icon source: $source" >&2 exit 2 fi done DENSITIES=(mdpi hdpi xhdpi xxhdpi xxxhdpi) declare -A SIZES=(["mdpi"]=48 ["hdpi"]=72 ["xhdpi"]=96 ["xxhdpi"]=144 ["xxxhdpi"]=192) declare -A ADAPTIVE=(["mdpi"]=108 ["hdpi"]=162 ["xhdpi"]=216 ["xxhdpi"]=324 ["xxxhdpi"]=432) generate_icon() { local name="$1" local fg="$2" local bg="$3" local mono="$4" for density in "${DENSITIES[@]}"; do local s=${SIZES[$density]} local a=${ADAPTIVE[$density]} local d="$RES/mipmap-$density" mkdir -p "$d" magick "$fg" -resize "${a}x${a}" -quality 90 "$d/${name}_foreground.webp" magick "$bg" -resize "${a}x${a}" -quality 90 "$d/${name}_background.webp" magick "$mono" -resize "${a}x${a}" -quality 90 "$d/${name}_monochrome.webp" magick \( "$bg" -resize "${s}x${s}" \) \( "$fg" -resize "${s}x${s}" \) \ -composite -quality 90 "$d/${name}.webp" magick \( "$bg" -resize "${s}x${s}" \) \( "$fg" -resize "${s}x${s}" \) \ -composite \ \( -size "${s}x${s}" xc:none -fill white -draw "circle $((s/2)),$((s/2)) $((s/2)),0" \) \ -compose DstIn -composite -quality 90 "$d/${name}_round.webp" done } write_adaptive_icon() { local name="$1" local file="$RES/mipmap-anydpi-v26/${name}.xml" mkdir -p "$(dirname "$file")" cat >"$file" < XML } write_alias_adaptive_icon() { local alias="$1" local target="$2" local file="$RES/mipmap-anydpi-v26/${alias}.xml" mkdir -p "$(dirname "$file")" cat >"$file" < XML } generate_icon "ic_launcher" "$FG" "$BG" "$MONO" write_adaptive_icon "ic_launcher" write_alias_adaptive_icon "ic_launcher_round" "ic_launcher" if [[ -d "$PARTNER_FG" ]]; then shopt -s nullglob for partner_fg in "$PARTNER_FG"/*_fg.png; do slug="$(basename "$partner_fg" _fg.png)" partner_mono="$PARTNER_FG/${slug}_mono.png" if [[ ! -f "$partner_mono" ]]; then echo "skipping $slug: missing $partner_mono" >&2 continue fi name="ic_launcher_${slug}" generate_icon "$name" "$partner_fg" "$BG" "$partner_mono" write_adaptive_icon "$name" write_alias_adaptive_icon "${name}_round" "$name" echo "generated partner icon: $slug" done shopt -u nullglob fi for density in "${DENSITIES[@]}"; do echo "$density: ${SIZES[$density]}px launcher, ${ADAPTIVE[$density]}px adaptive" done echo "done"