branding/icon/icon.svg (a cracked Metin stone with glowing runes, inside a studded gold ring, in front of a blood moon over ink mountains) is the single source; build_icons.sh renders it with headless Chrome and writes the committed outputs: Android legacy + adaptive mipmaps (wired into the manifest), the macOS AppIcon.icns and the iOS AppIcon.appiconset. scripts/package_mac_app.sh wraps mt_native_render into a local Metin2.app using that icon. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
107 lines
4.9 KiB
Bash
Executable File
107 lines
4.9 KiB
Bash
Executable File
#!/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' <g id="background">.*?\n </g>\n', svg, re.S)
|
|
fg = re.search(r' <g id="foreground">.*\n </g>\n(?=</svg>)', 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 = ' <g transform="translate(512 512) scale(0.66) translate(-512 -500)">\n' + fg.group(0) + ' </g>\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'
|
|
<?xml version="1.0" encoding="utf-8"?>
|
|
<!-- Generated by branding/icon/build_icons.sh. -->
|
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
|
<background android:drawable="@mipmap/ic_launcher_background" />
|
|
<foreground android:drawable="@mipmap/ic_launcher_foreground" />
|
|
</adaptive-icon>
|
|
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"
|