307 lines
13 KiB
Markdown
307 lines
13 KiB
Markdown
# `ash-wallpaper.sh` — guide
|
||
|
||
Turns a color photo into an **Ash** wallpaper: the image is reduced to
|
||
Ash-tinted greys (dark variant), while warm *ember/gold* highlights (sunsets,
|
||
fire, lamps, skin tones) are selectively kept — the "Pleasantville" effect.
|
||
|
||
## Quick start
|
||
|
||
```sh
|
||
tools/ash-wallpaper.sh photo.jpg # -> photo-ash.png
|
||
tools/ash-wallpaper.sh photo.jpg out.png # custom output path
|
||
```
|
||
|
||
> **Be realistic about the defaults.** This is a ~50-line ImageMagick script,
|
||
> not an AI — it applies one fixed rule (*keep warm, high-saturation pixels;
|
||
> ash everything else*) to your photo. The default settings are tuned for the
|
||
> classic cases (fire, sunsets, lamps). For anything else, expect to tune: the
|
||
> samples below were all post-processed in 2–3 iterations of `HUE_MAX` /
|
||
> `SAT_MIN` / `SAT_MAX`. A motif with little warm colour (e.g. a whale) simply
|
||
> has little to keep — no parameter will invent highlights that aren't in the
|
||
> source.
|
||
|
||
Requirements: ImageMagick 6.9+ or 7 (`convert` / `magick`). 4K input takes ~10s.
|
||
All knobs are environment variables read once per run — tune one, rerun,
|
||
compare.
|
||
|
||
## How it works
|
||
|
||
1. **Hue band** — the photo's HSL hue channel is thresholded: pixels with
|
||
`hue ≤ HUE_MAX` or `hue ≥ HUE_MIN` form the "warm" band (reds, oranges,
|
||
golds; the wrap-around at HUE_MIN catches pure crimson reds).
|
||
2. **Saturation gate** — inside that band, a saturation ramp decides how much
|
||
of the pixel survives: nothing below `SAT_MIN`, everything from `SAT_MAX`.
|
||
This is what keeps dull, near-grey warmish pixels as ash.
|
||
3. **Softening** — the combined mask is blurred, then re-sharpened with
|
||
`SENSITIVITY` so highlights fade into the greys instead of showing hard
|
||
cut-out edges.
|
||
4. **Base** — a desaturated copy is tinted along the Ash dark ramp
|
||
(`BASE_LO` shadows → `BASE_HI` highlights, default void → chalk).
|
||
5. **Composite** — the original photo, with saturation multiplied by
|
||
`EMBER_BOOST`, is laid over the base through the mask.
|
||
|
||
## Parameters
|
||
|
||
| Variable | Default | Meaning |
|
||
|---|---|---|
|
||
| `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` | `#100f12` / `#f3ede1` | Endpoints of the grey ramp (void → chalk). Any colours work, e.g. `BASE_LO=#1c1b1f BASE_HI=#e6dfd1` for a flatter panel→bone ramp. |
|
||
|
||
### Where the Ash palette sits in the hue wheel
|
||
|
||
For reference when widening/narrowing the band (hue in IM percent ≈ degrees/360):
|
||
|
||
| Colour | Hex | Hue | In band at defaults? |
|
||
|---|---|---|---|
|
||
| blood | `#c15c46` | 11° (3%) | ✅ |
|
||
| rust | `#a86a48` | 21° (6%) | ✅ |
|
||
| ember | `#e0914f` | 27° (8%) | ✅ |
|
||
| gold | `#d6b46a` | 41° (11%) | ✅ |
|
||
| pure yellow | — | 60° (17%) | ❌ (needs `HUE_MAX=17%`) |
|
||
| moss | `#8f9a5c` | 69° (19%) | ❌ |
|
||
| steel | `#7c9aa1` | 187° (52%) | ❌ |
|
||
| 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; the originals are shown for
|
||
comparison and credit.
|
||
|
||
### Sunset over the sea
|
||
|
||
```sh
|
||
tools/ash-wallpaper.sh sunset.jpg
|
||
```
|
||
|
||
| Original | Ash |
|
||
|---|---|
|
||
|  |  |
|
||
|
||
Source: [“Leigh-on-Sea beach sunset (Unsplash)”](https://commons.wikimedia.org/wiki/File:Leigh-on-Sea_beach_sunset_(Unsplash).jpg)
|
||
by Joshua Fuller, CC0.
|
||
|
||
### Campfire close-up
|
||
|
||
```sh
|
||
tools/ash-wallpaper.sh campfire.jpg
|
||
```
|
||
|
||
| Original | Ash |
|
||
|---|---|
|
||
|  |  |
|
||
|
||
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 — warm-dominated scene
|
||
|
||
The whole park is bathed in warm orange, so ~90 % of the frame is "warm":
|
||
like the fireworks case below, the result stays close to the original. Narrow
|
||
the band (`HUE_MAX=8%`) to let only the saturated ember oranges through:
|
||
|
||
```sh
|
||
tools/ash-wallpaper.sh autumn.jpg
|
||
```
|
||
|
||
| Original | Ash |
|
||
|---|---|
|
||
|  |  |
|
||
|
||
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
|
||
```
|
||
|
||
| Original | Ash |
|
||
|---|---|
|
||
|  |  |
|
||
|
||
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
|
||
```
|
||
|
||
| Original | Ash |
|
||
|---|---|
|
||
|  |  |
|
||
|
||
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/).
|
||
|
||
### Candle light
|
||
|
||
A dark frame with a warm source — the ideal case; the flame and its glow stay,
|
||
everything else turns to ash:
|
||
|
||
```sh
|
||
EMBER_BOOST=120 tools/ash-wallpaper.sh candles.jpg
|
||
```
|
||
|
||
| Original | Ash |
|
||
|---|---|
|
||
|  |  |
|
||
|
||
Source: [“Alive”](https://commons.wikimedia.org/wiki/File:Alive_(61565557).jpeg)
|
||
by Ranit Sanyal, [CC BY 3.0](https://creativecommons.org/licenses/by/3.0/).
|
||
|
||
### Fairground at night
|
||
|
||
Neon rides: the white structure greys out, the warm cabin lighting and the red
|
||
LED strips survive. Uses the night recipe:
|
||
|
||
```sh
|
||
HUE_MAX=17% SAT_MIN=8% SAT_MAX=60% SENSITIVITY=4x50% \
|
||
tools/ash-wallpaper.sh kirmes.jpg
|
||
```
|
||
|
||
| Original | Ash |
|
||
|---|---|
|
||
|  |  |
|
||
|
||
Source: [“Nighttime ferris wheel gondolas … Pattaya fairground”](https://commons.wikimedia.org/wiki/File:DFC_4677_Nighttime_ferris_wheel_gondolas_glow_against_the_dark_sky_at_a_Pattaya_fairground_in_Nong_Pla_Lai_Bang_Lamung_District.jpg)
|
||
by PattayaPatrol, [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/).
|
||
|
||
### Rainy night in Moscow
|
||
|
||
Red neon and traffic-light reflections are all the colour left — the same
|
||
night recipe as above:
|
||
|
||
```sh
|
||
HUE_MAX=17% SAT_MIN=8% SAT_MAX=60% SENSITIVITY=4x50% \
|
||
tools/ash-wallpaper.sh rain.jpg
|
||
```
|
||
|
||
| Original | Ash |
|
||
|---|---|
|
||
|  |  |
|
||
|
||
Source: [“Late autumn rainy night in Moscow”](https://commons.wikimedia.org/wiki/File:Late_autumn_rainy_night_in_Moscow_(54889230493).jpg)
|
||
by kishjar?, [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/).
|
||
|
||
### Humpback whale — the low-highlight case
|
||
|
||
A daylight scene with almost no warm colour: only 0.4 % of the frame sits in
|
||
the warm band, so the result is (intentionally) almost fully grey. Nothing is
|
||
broken — there is simply little for the script to keep:
|
||
|
||
```sh
|
||
tools/ash-wallpaper.sh whale.jpg
|
||
```
|
||
|
||
| Original | Ash |
|
||
|---|---|
|
||
|  |  |
|
||
|
||
Source: [“Humpback Breaching”](https://commons.wikimedia.org/wiki/File:HIHWNMS_-_Humpback_Breaching_(33591142200).jpg)
|
||
by NOAA National Marine Sanctuaries — public domain.
|
||
|
||
### Fireworks — the negative case
|
||
|
||
Here the *whole* sky is lit red by smoke, so 96 % of the pixels are "warm" and
|
||
the mask covers everything: the image is barely greyscaled at all. When the
|
||
warm colour is the background rather than an accent, the effect has nothing to
|
||
work with. Pick a different shot, or narrow the band (`HUE_MAX=8%`) to keep
|
||
only the brightest sparks:
|
||
|
||
```sh
|
||
tools/ash-wallpaper.sh fireworks.jpg
|
||
```
|
||
|
||
| Original | Ash |
|
||
|---|---|
|
||
|  |  |
|
||
|
||
Source: [“Anjuna Beach, Goa, New Year's Eve, Fireworks in the sky”](https://commons.wikimedia.org/wiki/File:Anjuna_Beach,_Goa,_India,_New_Year%27s_Eve,_Fireworks_in_the_sky.jpg)
|
||
by Vyacheslav Argenberg, [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/).
|
||
|
||
### How much of each frame survived
|
||
|
||
The share of pixels the warmth mask keeps (measured with the **default** gate;
|
||
the night-recipe samples were run with a wider band). A quick way to read the
|
||
samples above, and a useful sanity check when tuning your own photo:
|
||
|
||
| Motif | Warm-pixel share (default) | Result |
|
||
|---|---|---|
|
||
| Humpback whale | 0.4 % | almost fully ash |
|
||
| Fairground | 4.2 % | ash with neon accents |
|
||
| City at night (ISS) | 17.0 % | ash with a glowing street grid |
|
||
| Rainy night Moscow | 17.2 % | ash with red neon |
|
||
| Sunset | 19.6 % | ash with a warm horizon |
|
||
| Campfire | 40.6 % | dark ash, glowing flames |
|
||
| Redhead portrait | 47.1 % | ash with warm hair/lips |
|
||
| Candle light | 73.2 % | dark ash with a glowing flame |
|
||
| Autumn foliage | 90.0 % | barely greyed — warm *is* the scene |
|
||
| Fireworks | 96.4 % | barely greyed — warm *is* the scene |
|
||
|
||
Rule of thumb: below ~25 % the effect is pronounced; above ~70 % the script
|
||
has little to grey out and you should narrow `HUE_MAX` or pick another frame.
|
||
|
||
## Recipes
|
||
|
||
```sh
|
||
# Warm sunset landscape, keep the drama
|
||
tools/ash-wallpaper.sh sunset.jpg
|
||
|
||
# Night city: street lamps are soft yellow-orange, need a wider + softer gate
|
||
HUE_MAX=17% SAT_MIN=8% SAT_MAX=60% SENSITIVITY=4x50% tools/ash-wallpaper.sh city.jpg
|
||
|
||
# Portrait: only eyes/lips/warm skin glow, everything else ash
|
||
SAT_MIN=18% EMBER_BOOST=150 tools/ash-wallpaper.sh portrait.jpg
|
||
|
||
# Almost pure grey with faint traces of ember
|
||
SAT_MIN=20% SAT_MAX=70% EMBER_BOOST=100 tools/ash-wallpaper.sh photo.jpg
|
||
|
||
# Flatter, dimmer base ramp
|
||
BASE_LO=#1c1b1f BASE_HI=#e6dfd1 tools/ash-wallpaper.sh photo.jpg
|
||
```
|
||
|
||
## Batch generation
|
||
|
||
```sh
|
||
for f in ~/Pictures/vacation/*.jpg; do
|
||
tools/ash-wallpaper.sh "$f"
|
||
done
|
||
```
|
||
|
||
## Using the results
|
||
|
||
Drop the generated files into the theme or user backgrounds folder — Omarchy
|
||
cycles through them with `Super+Ctrl+Space`:
|
||
|
||
```sh
|
||
mkdir -p ~/.config/omarchy/backgrounds/ash-dark
|
||
cp photo-ash.png ~/.config/omarchy/backgrounds/ash-dark/
|
||
```
|
||
|
||
## Troubleshooting
|
||
|
||
- **Highlights cut with hard edges** → lower the `SENSITIVITY` contrast
|
||
(first number), e.g. `4x45%`.
|
||
- **A warm object disappears** → its hue is outside the band (check the table
|
||
above) or its saturation is below `SAT_MIN`.
|
||
- **Grey areas look slightly tinted/brown** → those pixels are just inside the
|
||
band; raise `SAT_MIN`.
|
||
- **Fire/embers look clipped and neon** → lower `EMBER_BOOST` towards 100.
|
||
- **Image too bright/dark after tinting** → adjust `BASE_LO`/`BASE_HI` instead
|
||
of editing the photo.
|