#!/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"