feat: render both variants by default (DARK/LIGHT to select one); add attributed Commons samples to guide
@@ -61,8 +61,9 @@ wallpaper: the image is reduced to Ash-tinted greys, while warm ember/gold
|
||||
highlights (sunset, fire, lights, skin tones) are selectively preserved.
|
||||
|
||||
```sh
|
||||
tools/ash-wallpaper.sh photo.jpg # -> photo-ash.png, dark base
|
||||
PRESET=light tools/ash-wallpaper.sh photo.jpg # light variant base
|
||||
tools/ash-wallpaper.sh photo.jpg # -> photo-ash-dark.png AND photo-ash-light.png
|
||||
DARK=1 tools/ash-wallpaper.sh photo.jpg # only dark
|
||||
LIGHT=1 tools/ash-wallpaper.sh photo.jpg # only light
|
||||
```
|
||||
|
||||
See **[tools/ash-wallpaper.md](tools/ash-wallpaper.md)** for the full
|
||||
|
||||
|
After Width: | Height: | Size: 283 KiB |
|
After Width: | Height: | Size: 284 KiB |
|
After Width: | Height: | Size: 70 KiB |
|
After Width: | Height: | Size: 120 KiB |
|
After Width: | Height: | Size: 178 KiB |
|
After Width: | Height: | Size: 146 KiB |
|
After Width: | Height: | Size: 86 KiB |
|
After Width: | Height: | Size: 88 KiB |
|
After Width: | Height: | Size: 78 KiB |
|
After Width: | Height: | Size: 47 KiB |
@@ -7,11 +7,13 @@ skin tones) are selectively kept — the "Pleasantville" effect.
|
||||
## Quick start
|
||||
|
||||
```sh
|
||||
tools/ash-wallpaper.sh photo.jpg # -> photo-ash.png (dark base)
|
||||
PRESET=light tools/ash-wallpaper.sh photo.jpg # -> light Ash base
|
||||
tools/ash-wallpaper.sh photo.jpg # -> photo-ash-dark.png AND photo-ash-light.png
|
||||
DARK=1 tools/ash-wallpaper.sh photo.jpg # only the dark variant
|
||||
LIGHT=1 tools/ash-wallpaper.sh photo.jpg # only the light variant
|
||||
```
|
||||
|
||||
Requirements: ImageMagick 6.9+ or 7 (`convert` / `magick`). 4K input takes ~1s.
|
||||
Requirements: ImageMagick 6.9+ or 7 (`convert` / `magick`). 4K input takes ~10s
|
||||
per run (the mask is computed once, both variants share it).
|
||||
All knobs are environment variables read once per run — tune one, rerun,
|
||||
compare.
|
||||
|
||||
@@ -35,14 +37,14 @@ compare.
|
||||
|
||||
| Variable | Default | Meaning |
|
||||
|---|---|---|
|
||||
| `PRESET` | `dark` | Grey ramp of the base. `dark` = `#100f12 → #f3ede1` (void→chalk), `light` = `#b7ae98 → #f2ecdf` (stone→paper). |
|
||||
| `DARK` / `LIGHT` | off | Set to `1` to render **only** that variant. Without them, both are written. |
|
||||
| `HUE_MAX` | `13%` | Upper edge of the warm band, in percent of the hue circle (360°). `13%` ≈ 47°, so reds, orange, ember and gold survive; yellows from ≈47° and all greens/blues fall out. |
|
||||
| `HUE_MIN` | `94%` | Lower edge of the wrap-around band (`≥ 338°`). Catches deep crimson/cherry reds whose hue sits just below 360°. |
|
||||
| `SAT_MIN` | `12%` | Saturation (HSL) below which a pixel becomes full grey, no matter its hue. Raise to make the image more monochrome (e.g. muted/desaturated photos: `18–25%`). |
|
||||
| `SAT_MAX` | `45%` | Saturation at which the highlight is fully kept. Pastel skies/candle-lit scenes peak below 45% — lower it (`25–35%`) to let soft colour through; raise it (`55–70%`) to keep only the most saturated embers. |
|
||||
| `SENSITIVITY` | `8x45%` | `-sigmoidal-contrast` applied to the mask: `contrast x midpoint`. Higher contrast → crisper, more cut-out-looking highlights; lower (e.g. `3x50%`) → dreamier, feathered bleed. The midpoint shifts the whole mask: `>50%` = only the most certain warm pixels, `<50%` = more generous. |
|
||||
| `EMBER_BOOST` | `130` | Saturation multiplier (%) on the surviving pixels, so the remaining embers read against all that ash. `100` = untouched colours, `160+` = intense glow. Applied to *all* channels of those pixels, so already-saturated fire can clip — reduce if it looks neon. |
|
||||
| `BASE_LO` / `BASE_HI` | from preset | Exact endpoints of the grey ramp. Any colour works, e.g. `BASE_LO=#1c1b1f BASE_HI=#e6dfd1` for a flatter panel→bone ramp. |
|
||||
| `BASE_LO` / `BASE_HI` | preset ramps | Exact endpoints of the grey ramp (dark: `#100f12 → #f3ede1`, light: `#b7ae98 → #f2ecdf`). Any colour works, e.g. `BASE_LO=#1c1b1f BASE_HI=#e6dfd1` for a flatter panel→bone ramp. |
|
||||
|
||||
### Where the Ash palette sits in the hue wheel
|
||||
|
||||
@@ -60,10 +62,86 @@ For reference when widening/narrowing the band (hue in IM percent ≈ degrees/36
|
||||
| rot | `#b47e99` | 330° (92%) | ❌ (needs `HUE_MIN=88%` — usually you *don't* want this) |
|
||||
| violet | `#a585ac` | 292° (81%) | ❌ |
|
||||
|
||||
## Samples
|
||||
|
||||
Freely-licensed photos from Wikimedia Commons, run through the script (900 px
|
||||
previews). Each entry lists the exact command; both variants come from a
|
||||
single run.
|
||||
|
||||
### Sunset over the sea
|
||||
|
||||
```sh
|
||||
tools/ash-wallpaper.sh sunset.jpg
|
||||
```
|
||||
|
||||
| Dark | Light |
|
||||
|---|---|
|
||||
|  |  |
|
||||
|
||||
Source: [“Leigh-on-Sea beach sunset (Unsplash)”](https://commons.wikimedia.org/wiki/File:Leigh-on-Sea_beach_sunset_(Unsplash).jpg)
|
||||
by Joshua Fuller, CC0 — no attribution required, given anyway.
|
||||
|
||||
### Campfire close-up
|
||||
|
||||
```sh
|
||||
tools/ash-wallpaper.sh campfire.jpg
|
||||
```
|
||||
|
||||
| Dark | Light |
|
||||
|---|---|
|
||||
|  |  |
|
||||
|
||||
Source: [“Closeup of raging flames in a large bonfire”](https://commons.wikimedia.org/wiki/File:Closeup_of_raging_flames_in_a_large_bonfire._-_Flickr_-_shixart1985.jpg)
|
||||
by Nenad Stojkovic, [CC BY 2.0](https://creativecommons.org/licenses/by/2.0/).
|
||||
|
||||
### Autumn foliage
|
||||
|
||||
```sh
|
||||
tools/ash-wallpaper.sh autumn.jpg
|
||||
```
|
||||
|
||||
| Dark | Light |
|
||||
|---|---|
|
||||
|  |  |
|
||||
|
||||
Source: [“Münster, Park Sentmaring – 2015 – 9923”](https://commons.wikimedia.org/wiki/File:M%C3%BCnster,_Park_Sentmaring_--_2015_--_9923.jpg)
|
||||
by Dietmar Rabich, [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/).
|
||||
|
||||
### City at night (ISS)
|
||||
|
||||
Street lamps glow soft yellow — the wide-band + soft-gate recipe from below:
|
||||
|
||||
```sh
|
||||
HUE_MAX=17% SAT_MIN=8% SAT_MAX=60% SENSITIVITY=4x50% \
|
||||
tools/ash-wallpaper.sh city.jpg
|
||||
```
|
||||
|
||||
| Dark | Light |
|
||||
|---|---|
|
||||
|  |  |
|
||||
|
||||
Source: [“Windy City of Lights (ISS070-E-105097)”](https://commons.wikimedia.org/wiki/File:Windy_City_of_Lights_(153622).jpg),
|
||||
astronaut photograph, NASA/JSC Crew Earth Observations — public domain.
|
||||
|
||||
### Redhead portrait
|
||||
|
||||
Only hair and lips keep their colour; skin stays close to bone:
|
||||
|
||||
```sh
|
||||
SAT_MIN=18% EMBER_BOOST=150 tools/ash-wallpaper.sh portrait.jpg
|
||||
```
|
||||
|
||||
| Dark | Light |
|
||||
|---|---|
|
||||
|  |  |
|
||||
|
||||
Source: [“Woman redhead natural portrait 1”](https://commons.wikimedia.org/wiki/File:Woman_redhead_natural_portrait_1.jpg)
|
||||
by dusdin (Flickr), cropped by Gridge, [CC BY 2.0](https://creativecommons.org/licenses/by/2.0/).
|
||||
|
||||
## Recipes
|
||||
|
||||
```sh
|
||||
# Warm sunset landscape, keep the drama (dark preset is the default)
|
||||
# Warm sunset landscape, keep the drama (writes BOTH dark and light)
|
||||
tools/ash-wallpaper.sh sunset.jpg
|
||||
|
||||
# Night city: street lamps are soft yellow-orange, need a wider + softer gate
|
||||
@@ -76,7 +154,7 @@ SAT_MIN=18% EMBER_BOOST=150 tools/ash-wallpaper.sh portrait.jpg
|
||||
SAT_MIN=20% SAT_MAX=70% EMBER_BOOST=100 tools/ash-wallpaper.sh photo.jpg
|
||||
|
||||
# Light-themed desktop
|
||||
PRESET=light tools/ash-wallpaper.sh beach.jpg
|
||||
LIGHT=1 tools/ash-wallpaper.sh beach.jpg
|
||||
```
|
||||
|
||||
## Batch generation
|
||||
@@ -94,7 +172,7 @@ cycles through them with `Super+Ctrl+Space`:
|
||||
|
||||
```sh
|
||||
mkdir -p ~/.config/omarchy/backgrounds/ash-dark
|
||||
cp photo-ash.png ~/.config/omarchy/backgrounds/ash-dark/
|
||||
cp photo-ash-dark.png photo-ash-light.png ~/.config/omarchy/backgrounds/ash-dark/
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
@@ -1,24 +1,29 @@
|
||||
#!/usr/bin/env bash
|
||||
# ash-wallpaper.sh — turn a color photo into an Ash-palette wallpaper:
|
||||
# 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 [OUTPUT]
|
||||
# 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):
|
||||
# PRESET=dark dark (void->chalk) | light (stone->paper)
|
||||
# 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 grayscale tint endpoints
|
||||
# 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 [OUTPUT]}
|
||||
OUT=${2:-${IN%.*}-ash.png}
|
||||
PRESET=${PRESET:-dark}
|
||||
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%}
|
||||
@@ -28,11 +33,9 @@ SENSITIVITY=${SENSITIVITY:-8x45%}
|
||||
|
||||
if command -v magick >/dev/null; then IM=magick; else IM=convert; fi
|
||||
|
||||
case "$PRESET" in
|
||||
dark) BASE_LO=${BASE_LO:-#100f12}; BASE_HI=${BASE_HI:-#f3ede1} ;;
|
||||
light) BASE_LO=${BASE_LO:-#b7ae98}; BASE_HI=${BASE_HI:-#f2ecdf} ;;
|
||||
*) echo "PRESET must be dark or light" >&2; exit 1 ;;
|
||||
esac
|
||||
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
|
||||
@@ -47,13 +50,18 @@ trap 'rm -rf "$TMP"' EXIT
|
||||
"$IM" "$TMP/band.png" "$TMP/satmask.png" -compose Multiply -composite \
|
||||
-gaussian-blur 0x2 -sigmoidal-contrast "$SENSITIVITY" "$TMP/mask.png"
|
||||
|
||||
# ash base + ember-touched highlights, joined by the mask
|
||||
"$IM" "$IN" \
|
||||
\( -clone 0 -modulate 100,0 +level-colors "$BASE_LO","$BASE_HI" \) \
|
||||
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 "$OUT"
|
||||
|
||||
echo "wrote $OUT"
|
||||
-colorspace sRGB "$OUTBASE-$preset.png"
|
||||
echo "wrote $OUTBASE-$preset.png"
|
||||
done
|
||||
|
||||