Last active
June 27, 2025 05:01
-
-
Save nberlette/66f6e8104ab50386da41a57204d79c00 to your computer and use it in GitHub Desktop.
Apple .icns conversion helper
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
# helper function for constructing escape sequences | |
# this does NOT include the CSI character by default. | |
# for that, see the [`csi`] function below this. | |
function esc() { | |
local -r escape="\x1b" | |
local -a args=() | |
local delim=";" prefix="" suffix="" code="" | |
# parse the arguments: | |
# - allow overrides for prefix, delim, and suffix. | |
# - e.g. `--prefix="["`, `-d,` or `--delim=,`, `--suffix=m]` | |
# - !!! equals sign is optional, e.g. `--prefix [` | |
# - short options are allowed, e.g. `-p[`, `-d,`, `-s]` | |
# - all remaining arguments are treated as codes. | |
# - respect the `--` argument terminator to indicate the end of options. | |
# - respect the order of all positional arguments. | |
while [[ $# -gt 0 ]]; do | |
local arg="$1" | |
# end of options, break the loop | |
[[ "$arg" == "--" ]] && break; | |
# handle options | |
case "$arg" in | |
# handle short opts, and long options with equals sign | |
(--prefix=*|-p*) prefix="${arg#*=}" ;; | |
(--prefix|-p) shift; prefix="$1"; shift ;; | |
(--delim=*|-d*) delim="${arg#*=}" ;; | |
(--delim|-d) shift; delim="$1"; shift ;; | |
(--suffix=*|-s*) suffix="${arg#*=}" ;; | |
(--suffix|-s) shift; suffix="$1"; shift ;; | |
(--) shift; continue;; # end of options | |
(--*|-*) echo "Unknown option: $arg" >&2; return 1 ;; | |
(*) { | |
# if the argument is not an option, treat it as a code | |
[[ "$arg" =~ ^[0-9]+$ ]] && code+="${arg}" || { | |
# if the argument is not a number, treat it as a string | |
# and escape it to remove non-pri ntable characters | |
if [[ -n "$code" ]]; then | |
code+="$delim" | |
fi | |
} | |
code+="$(printf '%s' "$arg" | sed 's/[^[:print:]]//g')" | |
continue | |
} ;; | |
(*) args+=("$arg") | |
;; | |
esac | |
shift | |
done | |
} | |
function main () { | |
# show the usage page if no args are given, or if passed any derivation of "-h" "--help" "-?" etc | |
if [ $# -eq 0 ] || [[ "$1" =~ ^[-]{0,2}(h(elp)?|[?])$ ]]; then | |
local bold undl ital dark reset | |
bold=$(printf '\033[1m') | |
dark=$(printf '\033[2m') | |
ital=$(printf '\033[3m') | |
undl=$(printf '\033[4m') | |
reset=$(printf '\033[0m') | |
cat<<EOL | |
${bold}icns.sh${reset}${dark} - automated macOS .icns conversion helper${reset} | |
${bold}${undl}USAGE${reset} | |
./icns.sh <${bold}${undl}${ital}source.png${reset}> <${bold}${undl}${ital}destination.icns${reset}> | |
${bold}${undl}SUMMARY${reset} | |
Resizes ${bold}${undl}${ital}source.png${reset} to the required sizes, formatted into one file, | |
output to ${bold}${undl}${ital}destination.icns${reset} in Apple .icns, in these resolutions: | |
16x16 32x32 128x128 256x256 512x512 | |
16x16${dark}@2x${reset} 32x32${dark}@2x${reset} 128x128${dark}@2x${reset} 256x256${dark}@2x${reset} 512x512${dark}@2x${reset} | |
${bold}${undl}RECOMMENDATIONS${reset} | |
o Use a ${bold}${undl}${ital}source.png${reset} >= 1024x1024 resolution. | |
o Use absolute paths for ${bold}${undl}${ital}source.png${reset} and ${bold}${undl}${ital}destination.icns${reset} | |
${dark}(reduces the chance of a file mishap during conversion)${reset} | |
${bold}${undl}LICENSE${reset}: MIT © ${ital}Nicholas Berlette${reset} <${dark}${ital}${undl}https://github.com/nberlette${reset}> | |
EOL | |
# non-zero exit code if no arguments are provided | |
[ $# = 0 ] && return 1 || return 0; | |
else | |
# main program | |
local input output iconset | |
input=${1:-"./AppIcon.png"} | |
output=${2:-"./icon.icns"} | |
iconset="$(dirname "$output")/$(basename "$output" | cut -d. -f1).iconset" | |
# outputpng="$(dirname "$output")/icon.png" | |
mkdir -p "$iconset" >&/dev/null | |
local xy | |
for xy in 16 32 128 256 512; do | |
sips -z $xy $xy "$input" --out "${iconset}/icon_${xy}x${xy}.png" > /dev/null | |
sips -z $((xy * 2)) $((xy * 2)) "$input" --out "${iconset}/icon_${xy}x${xy}@2x.png" > /dev/null | |
done | |
iconutil -c icns "$iconset" && rm -rf "$iconset" | |
fi | |
} | |
{ main "$@" && unset -f main; } || exit $?; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.