#!/bin/zsh
# Renders branding/icon/icon.svg into every platform icon and writes them where the builds pick them up:
# android/app/src/main/res/mipmap-* legacy ic_launcher / ic_launcher_round (API 24-25) and the
# adaptive-icon layers (API 26+, mipmap-anydpi-v26/*.xml)
# branding/icon/macos/AppIcon.icns macOS app icon (Big Sur squircle with drop shadow)
# branding/icon/ios/AppIcon.appiconset iOS single-size 1024 icon (opaque)
# The outputs are committed, so building the apps does not need this script. Rerun it after editing the SVG.
# Needs Google Chrome (SVG filters) and ImageMagick (`brew install imagemagick`); iconutil ships with macOS.
set -euo pipefail
here=${0:A:h}
repo=${here:h:h}
chrome=${CHROME:-"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"}
work=$(mktemp -d)
trap 'rm -rf "$work"' EXIT
# icon.svg -> full / background-only / foreground-only (scaled into the adaptive-icon safe zone) SVGs.
python3 - "$here/icon.svg" "$work" <<'EOF'
import re, sys
src, out = sys.argv[1], sys.argv[2]
svg = open(src).read()
# Both layer groups sit at two-space indent; the foreground one is the last element and holds nested groups.
bg = re.search(r' .*?\n \n', svg, re.S)
fg = re.search(r' .*\n \n(?=)', svg, re.S)
assert bg and fg
open(out + "/full.svg", "w").write(svg)
open(out + "/background.svg", "w").write(svg.replace(fg.group(0), ""))
# Adaptive icons show the inner 72 of 108 dp (338 px of the 512 half-width) and launchers mask inside that.
# Scale the foreground so the ring (outer radius 405 around (512, 500)) sits at the same 79% of the visible
# radius as in the full icon: 405 * 0.66 = 267 = 0.79 * 338.
scaled = ' \n' + fg.group(0) + ' \n'
open(out + "/foreground.svg", "w").write(svg.replace(bg.group(0), "").replace(fg.group(0), scaled))
EOF
for name in full background foreground; do
"$chrome" --headless=new --disable-gpu --hide-scrollbars --default-background-color=00000000 \
--window-size=1024,1024 --screenshot="$work/$name.png" "file://$work/$name.svg" >/dev/null 2>&1
done
# Android
res=$repo/android/app/src/main/res
typeset -A legacy=(mdpi 48 hdpi 72 xhdpi 96 xxhdpi 144 xxxhdpi 192)
for density size in ${(kv)legacy}; do
dir=$res/mipmap-$density
mkdir -p $dir
layer=$(( size * 9 / 4 )) # 108 dp at this density
magick "$work/background.png" -resize ${layer}x${layer} "$dir/ic_launcher_background.png"
magick "$work/foreground.png" -resize ${layer}x${layer} "$dir/ic_launcher_foreground.png"
# Legacy launchers show the bitmap as is: a rounded square and a circle.
r=$(( size * 18 / 100 ))
magick "$work/full.png" -alpha set -resize ${size}x${size} \
\( -size ${size}x${size} xc:none -fill white -draw "roundrectangle 0,0 $((size-1)),$((size-1)) $r,$r" \) \
-compose DstIn -composite "$dir/ic_launcher.png"
magick "$work/full.png" -alpha set -resize ${size}x${size} \
\( -size ${size}x${size} xc:none -fill white -draw "circle $((size/2)),$((size/2)) $((size/2)),0" \) \
-compose DstIn -composite "$dir/ic_launcher_round.png"
done
mkdir -p $res/mipmap-anydpi-v26
for name in ic_launcher ic_launcher_round; do
cat > $res/mipmap-anydpi-v26/$name.xml <<'EOF'
EOF
done
# macOS: 824 px squircle-ish rounded rect (radius 185) centred on 1024 with a soft shadow, per the Big Sur grid.
magick "$work/full.png" -alpha set -resize 824x824 \
\( -size 824x824 xc:none -fill white -draw "roundrectangle 0,0 823,823 185,185" \) \
-compose DstIn -composite "$work/tile.png"
magick -size 1024x1024 xc:none \
\( "$work/tile.png" -background black -shadow 50x14+0+10 \) -gravity center -geometry +0+6 -compose Over -composite \
"$work/tile.png" -gravity center -geometry +0+0 -compose Over -composite "$work/mac1024.png"
iconset=$work/AppIcon.iconset
mkdir -p $iconset
for s in 16 32 128 256 512; do
magick "$work/mac1024.png" -resize ${s}x${s} "$iconset/icon_${s}x${s}.png"
magick "$work/mac1024.png" -resize $((s*2))x$((s*2)) "$iconset/icon_${s}x${s}@2x.png"
done
mkdir -p $here/macos
iconutil -c icns -o $here/macos/AppIcon.icns $iconset
cp "$work/mac1024.png" $here/macos/AppIcon-1024.png
# iOS: opaque, square; the system applies the mask.
ios=$here/ios/AppIcon.appiconset
mkdir -p $ios
magick "$work/full.png" -background '#12050a' -alpha remove -alpha off "$ios/AppIcon-1024.png"
cat > $ios/Contents.json <<'EOF'
{
"images" : [
{
"filename" : "AppIcon-1024.png",
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
EOF
echo "icons written"