Last active
April 5, 2024 17:58
-
-
Save adamelliotfields/d41a7daca4ab35b7d4c05821f827111e to your computer and use it in GitHub Desktop.
Favicon and Webmanifest Script
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 | |
set -euo pipefail | |
# Generates favicons and a webmanifest from a single image | |
# https://evilmartians.com/chronicles/how-to-favicon-in-2021-six-files-that-fit-most-needs | |
# | |
# Usage: | |
# favicon.sh <file> [dir] [flags] | |
# | |
# Args: | |
# file: the input image file | |
# dir: the output directory (default: '.') | |
# | |
# Flags: | |
# -c,--color: the background color for the icons (default: #020617) | |
# -s,--sizes: comma-separated list of sizes for the icons (default: 192px) | |
# --no-manifest: do not generate a webmanifest | |
function favicon() { | |
local usage="usage: favicon.sh <file> [dir] [flags]" | |
local color="#020617" # slate-950 | |
local sizes='192' | |
local out_dir="." | |
local in_file="" | |
local no_manifest=false | |
local has_out_dir=false | |
# webmanifest | |
# could make all these flags if we wanted | |
local name='Example App' | |
local short_name='Example' | |
local description='A website with a description.' | |
local background_color="$color" | |
local theme_color="$color" | |
local display='minimal-ui' | |
local start_url='/' | |
local scope='/' | |
local icons='[]' | |
# no args | |
if [[ $# -eq 0 ]] ; then | |
echo "$usage" | |
return 1 | |
fi | |
# parse args | |
while [[ $# -gt 0 ]] ; do | |
case "$1" in | |
-c=*|--color=*) | |
color="${1#*=}" | |
shift ;; | |
-c|--color) | |
color="$2" | |
shift | |
shift ;; | |
-s=*|--sizes=*) | |
sizes="${1#*=}" | |
shift ;; | |
-s|--sizes) | |
sizes="$2" | |
shift | |
shift ;; | |
--no-manifest) | |
no_manifest=true | |
shift ;; | |
*) | |
if [[ -z $in_file ]] ; then | |
in_file="$1" | |
elif [[ $has_out_dir == false ]] ; then | |
out_dir="$1" | |
has_out_dir=true | |
fi | |
shift ;; | |
esac | |
done | |
# validate in_file | |
if [[ ! -f $in_file ]] ; then | |
echo "favicon: file ${in_file} does not exist" | |
return 1 | |
fi | |
# validate out_dir | |
if [[ ! -d $out_dir ]] ; then | |
mkdir -p "$out_dir" | |
fi | |
# build webmanifest | |
# shellcheck disable=SC2155 | |
local webmanifest=$(cat <<EOF | |
{ | |
"name": "$name", | |
"short_name": "$short_name", | |
"description": "$description", | |
"background_color": "$background_color", | |
"theme_color": "$theme_color", | |
"display": "$display", | |
"start_url": "$start_url", | |
"scope": "$scope", | |
"icons": $icons | |
} | |
EOF | |
) | |
# generate favicon | |
[[ -e "${out_dir}/favicon.ico" ]] && rm "${out_dir}/favicon.ico" | |
magick "$in_file" -resize "32x32" "${out_dir}/favicon.ico" | |
# generate apple-touch-icon (with 20px padding) | |
[[ -e "${out_dir}/apple-touch-icon.png" ]] && rm "${out_dir}/apple-touch-icon.png" | |
magick "$in_file" -resize "140x140" -gravity center -background "$color" -extent "180x180" -flatten "$out_dir/apple-touch-icon.png" | |
# generate icons | |
for size in $(echo "$sizes" | tr ',' '\n') ; do | |
# resize to add 20px padding | |
local resize=$((size - 40)) | |
[[ -e "${out_dir}/icon-${size}.png" ]] && rm "${out_dir}/icon-${size}.png" | |
magick "$in_file" \ | |
-resize "${resize}x${resize}" \ | |
-gravity center \ | |
-background "$color" \ | |
-extent "${size}x${size}" \ | |
-flatten "${out_dir}/icon-${size}.png" | |
# append each size to the webmanifest | |
webmanifest=$(echo "$webmanifest" | jq -c --arg size "$size" '.icons += [{ "src": "/icon-\($size).png", "type": "image/png", "sizes": "\($size)x\($size)" }]') | |
done | |
# unless the flag was set, write the webmanifest to the out_dir | |
if [[ $no_manifest == false ]] ; then | |
[[ -e "${out_dir}/manifest.webmanifest" ]] && rm "${out_dir}/manifest.webmanifest" | |
echo "$webmanifest" | tee "${out_dir}/manifest.webmanifest" >/dev/null | |
fi | |
} ; favicon "$@" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment