68 lines
2.8 KiB
Bash
Executable File
68 lines
2.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# ash-wallpaper.sh — turn a color photo into Ash-palette wallpapers:
|
|
# grayscale body tinted toward the Ash tones, with warm "ember" highlights
|
|
# (reds/oranges/golds) selectively preserved. Pleasantville-style.
|
|
#
|
|
# usage: tools/ash-wallpaper.sh INPUT [OUTBASE]
|
|
#
|
|
# By default BOTH variants are rendered:
|
|
# OUTBASE-dark.png (void -> chalk ramp)
|
|
# OUTBASE-light.png (stone -> paper ramp)
|
|
# Set DARK=1 to render only dark, LIGHT=1 to render only light.
|
|
# OUTBASE defaults to INPUT-without-extension + "-ash".
|
|
#
|
|
# tuning via environment (defaults shown):
|
|
# HUE_MAX=13% warm band: hue <= HUE_MAX
|
|
# HUE_MIN=94% ... or hue >= HUE_MIN (catches pure reds)
|
|
# SAT_MIN=12% below this saturation pixels lose the highlight
|
|
# SAT_MAX=45% at/above this saturation the highlight is full
|
|
# EMBER_BOOST=130 saturation multiplier (%) applied to highlight areas
|
|
# SENSITIVITY=8x45% sigmoidal contrast of the final mask
|
|
# BASE_LO= BASE_HI= override the grey ramp endpoints (applies to both
|
|
# rendered variants unless only one is generated)
|
|
set -euo pipefail
|
|
|
|
IN=${1:?usage: ash-wallpaper.sh INPUT [OUTBASE]}
|
|
OUTBASE=${2:-${IN%.*}-ash}
|
|
HUE_MAX=${HUE_MAX:-13%}
|
|
HUE_MIN=${HUE_MIN:-94%}
|
|
SAT_MIN=${SAT_MIN:-12%}
|
|
SAT_MAX=${SAT_MAX:-45%}
|
|
EMBER_BOOST=${EMBER_BOOST:-130}
|
|
SENSITIVITY=${SENSITIVITY:-8x45%}
|
|
|
|
if command -v magick >/dev/null; then IM=magick; else IM=convert; fi
|
|
|
|
if [[ ${DARK:-0} == 1 ]]; then VARIANTS=(dark)
|
|
elif [[ ${LIGHT:-0} == 1 ]]; then VARIANTS=(light)
|
|
else VARIANTS=(dark light); fi
|
|
|
|
TMP=$(mktemp -d)
|
|
trap 'rm -rf "$TMP"' EXIT
|
|
|
|
# warmth mask: (hue in warm band) x (saturation ramp)
|
|
"$IM" "$IN" -colorspace HSL -channel R -separate "$TMP/hue.png"
|
|
"$IM" "$IN" -colorspace HSL -channel G -separate "$TMP/sat.png"
|
|
"$IM" "$TMP/hue.png" -threshold "$HUE_MAX" -negate "$TMP/low.png"
|
|
"$IM" "$TMP/hue.png" -threshold "$HUE_MIN" "$TMP/high.png"
|
|
"$IM" "$TMP/low.png" "$TMP/high.png" -compose Lighten -composite "$TMP/band.png"
|
|
"$IM" "$TMP/sat.png" -level "$SAT_MIN","$SAT_MAX" "$TMP/satmask.png"
|
|
"$IM" "$TMP/band.png" "$TMP/satmask.png" -compose Multiply -composite \
|
|
-gaussian-blur 0x2 -sigmoidal-contrast "$SENSITIVITY" "$TMP/mask.png"
|
|
|
|
for preset in "${VARIANTS[@]}"; do
|
|
case "$preset" in
|
|
dark) lo=${BASE_LO:-#100f12}; hi=${BASE_HI:-#f3ede1} ;;
|
|
light) lo=${BASE_LO:-#b7ae98}; hi=${BASE_HI:-#f2ecdf} ;;
|
|
esac
|
|
# ash base + ember-touched highlights, joined by the mask
|
|
"$IM" "$IN" \
|
|
\( -clone 0 -modulate 100,0 +level-colors "$lo","$hi" \) \
|
|
\( -clone 0 -modulate "100,$EMBER_BOOST" \) \
|
|
-delete 0 \
|
|
\( +clone "$TMP/mask.png" -alpha off -compose CopyOpacity -composite \) \
|
|
-delete 1 -compose Over -composite \
|
|
-colorspace sRGB "$OUTBASE-$preset.png"
|
|
echo "wrote $OUTBASE-$preset.png"
|
|
done
|