diff --git a/tools/make-store-assets.sh b/tools/make-store-assets.sh index 11186e6..099e9a6 100755 --- a/tools/make-store-assets.sh +++ b/tools/make-store-assets.sh @@ -38,4 +38,6 @@ render() { # echo "Writing store assets to $out" render "$here/store-assets/icon.svg" 512 512 icon-512.png keep-alpha render "$here/store-assets/feature-graphic.svg" 1024 500 feature-graphic-1024x500.png flatten -echo "Done. Screenshots: ./tools/make-store-screenshots.sh # reads store-assets/raw-screenshots/" +echo "Done. Screenshots: ./tools/make-store-screenshots.sh # reads store-assets/raw-screenshots/phone/" +echo " Tablets: FORM_FACTOR=tablet-7in ./tools/make-store-screenshots.sh" +echo " FORM_FACTOR=tablet-10in ./tools/make-store-screenshots.sh" diff --git a/tools/make-store-screenshots.sh b/tools/make-store-screenshots.sh index b5cf663..f6208a8 100755 --- a/tools/make-store-screenshots.sh +++ b/tools/make-store-screenshots.sh @@ -1,54 +1,94 @@ #!/usr/bin/env bash # -# Turns raw device screenshots into Play-legal store screenshots. +# Turns raw device screenshots into Play-legal store screenshots, one directory per form +# factor, because Play gives phones and each tablet size their own slot. # # ./tools/make-store-screenshots.sh [raw-dir] [output-dir] # -# Both paths default to inside the repo, never to $HOME: -# raw store-assets/raw-screenshots/ git-ignored staging for the `adb` captures -# output store-assets/screenshots/ the cropped files that get uploaded to Play +# FORM_FACTOR selects the Play Console slot the captures belong to +# (Main store listing > Graphics > Phone / 7-inch tablet / 10-inch tablet): # -# Why this exists: Play rejects a screenshot whose longer side is more than twice its -# shorter side ("your screenshot's maximum dimension can't be more than twice its minimum -# dimension"). A 1080 x 2400 phone capture is 2.22:1, so it has to become 1080 x 2160. +# FORM_FACTOR=phone (default) store-assets/raw-screenshots/phone/ -> store-assets/screenshots/phone/ +# FORM_FACTOR=tablet-7in store-assets/raw-screenshots/tablet-7in/ -> store-assets/screenshots/tablet-7in/ +# FORM_FACTOR=tablet-10in store-assets/raw-screenshots/tablet-10in/ -> store-assets/screenshots/tablet-10in/ # -# The crop removes system chrome only — the status bar at the top, the navigation bar at the -# bottom — never app content. Both heights were measured on the test device: +# Both paths are inside the repo, never in $HOME. Pass raw-dir / output-dir positionally to +# override them (that is what the tests and one-off captures use). # -# STATUS_BAR_PX ITYPE_STATUS_BAR frame height 93 px (1080 x 2400 @ 440 dpi) -# NAV_BAR_PX ITYPE_NAVIGATION_BAR bottom inset 130 px (same device) +# Why this exists: Play rejects a screenshot whose longer side is more than twice its shorter +# side ("The maximum dimension of your screenshot can't be more than twice as long as the +# minimum dimension"), and requires 24-bit PNG or JPEG without alpha, a shorter side of at +# least 320 px and a longer side of at most 3840 px. +# +# Phone A 1080 x 2400 capture is 2.22:1 and has to lose system chrome to reach the 2:1 +# cap. Both bar heights were measured on the test device: +# +# STATUS_BAR_PX ITYPE_STATUS_BAR frame height 93 px (1080 x 2400 @ 440 dpi) +# NAV_BAR_PX ITYPE_NAVIGATION_BAR bottom inset 130 px (same device) +# +# Tablet No tablet screen Android ships is anywhere near 2:1 — the 7" WSVGA profile is +# 1024 x 600 (1.71:1) and the 10-inch profiles (10.1" WXGA, Nexus 10, Medium +# Tablet, Pixel Tablet) are 1280 x 800 or 2560 x 1600 (1.60:1) — so a tablet frame +# is already legal and crops 0 px by default. Cropping chrome there is cosmetic +# only, so it is opt-in: measure on your device and pass the insets. +# +# Measure either device with (the bar heights are device- and OEM-specific, and MIUI is not +# AOSP: the AOSP defaults would have been 24 dp and 48 dp): # # adb shell dumpsys window displays | grep -oE 'ITYPE_STATUS_BAR frame=\[[^]]*\]\[[^]]*\]' # adb shell dumpsys window displays | grep -oE 'control type=ITYPE_NAVIGATION_BAR.*mInsetsHint=\{[^}]*\}' # -# Output is 24-bit PNG without alpha, which is what Play asks for. Captures are not shot by -# this script — take them yourself (the shot list is in docs/STORE_LISTING.md) and drop them -# into store-assets/raw-screenshots/, or pass the directory as the first argument. +# The crop removes system chrome only, never app content. Output is 24-bit PNG without alpha, +# which is what Play asks for. Captures are not shot by this script — take them yourself (the +# shot list is in docs/STORE_LISTING.md) and drop them into the raw directory, or pass that +# directory as the first argument. set -euo pipefail here="$(cd "$(dirname "$0")" && pwd)" repo="$(dirname "$here")" -raw="${1:-$repo/store-assets/raw-screenshots}" -out="${2:-$repo/store-assets/screenshots}" -status_bar="${STATUS_BAR_PX:-93}" -nav_bar="${NAV_BAR_PX:-130}" + +form_factor="${FORM_FACTOR:-phone}" +case "$form_factor" in + phone) default_status_bar=93; default_nav_bar=130 ;; + tablet-7in) default_status_bar=0; default_nav_bar=0 ;; + tablet-10in) default_status_bar=0; default_nav_bar=0 ;; + *) + echo "usage: FORM_FACTOR= $0 [raw-dir] [output-dir]" >&2 + echo "error: unknown FORM_FACTOR '$form_factor'" >&2 + exit 2 + ;; +esac + +raw="${1:-$repo/store-assets/raw-screenshots/$form_factor}" +out="${2:-$repo/store-assets/screenshots/$form_factor}" +status_bar="${STATUS_BAR_PX:-$default_status_bar}" +nav_bar="${NAV_BAR_PX:-$default_nav_bar}" if [ ! -d "$raw" ]; then - echo "usage: $0 [raw-screenshot-dir] [output-dir]" >&2 + echo "usage: FORM_FACTOR= $0 [raw-screenshot-dir] [output-dir]" >&2 echo "error: no such directory: $raw" >&2 echo " capture first, e.g. adb exec-out screencap -p > $raw/01-empty.png" >&2 exit 2 fi mkdir -p "$out" +echo "$form_factor: $raw -> $out (crop ${status_bar} px status bar + ${nav_bar} px navigation bar, clamp to 2:1)" shopt -s nullglob -for f in "$raw"/*.png; do +shots=("$raw"/*.png) +if [ ${#shots[@]} -eq 0 ]; then + echo "error: no .png captures in $raw" >&2 + echo " capture first, e.g. adb exec-out screencap -p > $raw/01-empty.png" >&2 + exit 2 +fi + +for f in "${shots[@]}"; do name="$(basename "$f")" width="$(identify -format '%w' "$f")" height="$(identify -format '%h' "$f")" - # Drop the two system bars, then clamp to a 2:1 portrait frame. + # Drop the two system bars (0 px for tablets, where the frame is already legal), then + # clamp to a 2:1 portrait frame. keep=$(( height - status_bar - nav_bar )) cap=$(( width * 2 )) if [ "$keep" -gt "$cap" ]; then @@ -57,6 +97,24 @@ for f in "$raw"/*.png; do magick "$f" -crop "${width}x${keep}+0+${status_bar}" +repage \ -background '#FFFBFE' -alpha remove -alpha off PNG24:"$out/$name" + + # Play's limits, checked on the file that actually gets uploaded rather than on the maths. + out_width="$(identify -format '%w' "$out/$name")" + out_height="$(identify -format '%h' "$out/$name")" + if [ "$out_width" -lt "$out_height" ]; then + short="$out_width"; long="$out_height" + else + short="$out_height"; long="$out_width" + fi + warn='' + if [ "$short" -lt 320 ]; then + warn="$warn ⚠️ shorter side under Play's 320 px minimum" + fi + if [ "$long" -gt 3840 ]; then + warn="$warn ⚠️ longer side over Play's 3840 px maximum" + fi + printf ' %s %s -> ' "$name" "$(identify -format '%wx%h' "$f")" - identify -format '%wx%h %[channels] %b\n' "$out/$name" + identify -format '%wx%h %[channels] %b' "$out/$name" + printf '%s\n' "$warn" done