diff --git a/README.md b/README.md index 17a90e2..1bb89b8 100644 --- a/README.md +++ b/README.md @@ -61,9 +61,7 @@ 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-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 +tools/ash-wallpaper.sh photo.jpg # -> photo-ash.png ``` See **[tools/ash-wallpaper.md](tools/ash-wallpaper.md)** for the full diff --git a/images/samples/ash-autumn-dark.jpg b/images/samples/ash-autumn-dark.jpg deleted file mode 100644 index 3715081..0000000 Binary files a/images/samples/ash-autumn-dark.jpg and /dev/null differ diff --git a/images/samples/ash-autumn-light.jpg b/images/samples/ash-autumn-light.jpg deleted file mode 100644 index 18820d3..0000000 Binary files a/images/samples/ash-autumn-light.jpg and /dev/null differ diff --git a/images/samples/ash-autumn.jpg b/images/samples/ash-autumn.jpg new file mode 100644 index 0000000..78b0b66 Binary files /dev/null and b/images/samples/ash-autumn.jpg differ diff --git a/images/samples/ash-campfire-dark.jpg b/images/samples/ash-campfire-dark.jpg deleted file mode 100644 index facbac1..0000000 Binary files a/images/samples/ash-campfire-dark.jpg and /dev/null differ diff --git a/images/samples/ash-campfire-light.jpg b/images/samples/ash-campfire-light.jpg deleted file mode 100644 index d5f9fa2..0000000 Binary files a/images/samples/ash-campfire-light.jpg and /dev/null differ diff --git a/images/samples/ash-campfire.jpg b/images/samples/ash-campfire.jpg new file mode 100644 index 0000000..41bb9d5 Binary files /dev/null and b/images/samples/ash-campfire.jpg differ diff --git a/images/samples/ash-city-light.jpg b/images/samples/ash-city-light.jpg deleted file mode 100644 index 20fab3c..0000000 Binary files a/images/samples/ash-city-light.jpg and /dev/null differ diff --git a/images/samples/ash-city-dark.jpg b/images/samples/ash-city.jpg similarity index 100% rename from images/samples/ash-city-dark.jpg rename to images/samples/ash-city.jpg diff --git a/images/samples/ash-redhead-light.jpg b/images/samples/ash-redhead-light.jpg deleted file mode 100644 index ebc8807..0000000 Binary files a/images/samples/ash-redhead-light.jpg and /dev/null differ diff --git a/images/samples/ash-redhead-dark.jpg b/images/samples/ash-redhead.jpg similarity index 100% rename from images/samples/ash-redhead-dark.jpg rename to images/samples/ash-redhead.jpg diff --git a/images/samples/ash-sunset-dark.jpg b/images/samples/ash-sunset-dark.jpg deleted file mode 100644 index e170a49..0000000 Binary files a/images/samples/ash-sunset-dark.jpg and /dev/null differ diff --git a/images/samples/ash-sunset-light.jpg b/images/samples/ash-sunset-light.jpg deleted file mode 100644 index 1d81b1c..0000000 Binary files a/images/samples/ash-sunset-light.jpg and /dev/null differ diff --git a/images/samples/ash-sunset.jpg b/images/samples/ash-sunset.jpg new file mode 100644 index 0000000..7463014 Binary files /dev/null and b/images/samples/ash-sunset.jpg differ diff --git a/images/samples/autumn-original.jpg b/images/samples/autumn-original.jpg new file mode 100644 index 0000000..1de5c65 Binary files /dev/null and b/images/samples/autumn-original.jpg differ diff --git a/images/samples/campfire-original.jpg b/images/samples/campfire-original.jpg new file mode 100644 index 0000000..16e5fca Binary files /dev/null and b/images/samples/campfire-original.jpg differ diff --git a/images/samples/city-original.jpg b/images/samples/city-original.jpg new file mode 100644 index 0000000..3ba4829 Binary files /dev/null and b/images/samples/city-original.jpg differ diff --git a/images/samples/redhead-original.jpg b/images/samples/redhead-original.jpg new file mode 100644 index 0000000..7218383 Binary files /dev/null and b/images/samples/redhead-original.jpg differ diff --git a/images/samples/sunset-original.jpg b/images/samples/sunset-original.jpg new file mode 100644 index 0000000..f13ab0d Binary files /dev/null and b/images/samples/sunset-original.jpg differ diff --git a/tools/ash-wallpaper.md b/tools/ash-wallpaper.md index a6a9cd5..ab876b3 100644 --- a/tools/ash-wallpaper.md +++ b/tools/ash-wallpaper.md @@ -1,19 +1,17 @@ # `ash-wallpaper.sh` — guide Turns a color photo into an **Ash** wallpaper: the image is reduced to -Ash-tinted greys, while warm *ember/gold* highlights (sunsets, fire, lamps, -skin tones) are selectively kept — the "Pleasantville" effect. +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-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 +tools/ash-wallpaper.sh photo.jpg # -> photo-ash.png +tools/ash-wallpaper.sh photo.jpg out.png # custom output path ``` -Requirements: ImageMagick 6.9+ or 7 (`convert` / `magick`). 4K input takes ~10s -per run (the mask is computed once, both variants share it). +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. @@ -28,8 +26,8 @@ compare. 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 grey ramp - (`BASE_LO` shadows → `BASE_HI` highlights). +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. @@ -37,14 +35,13 @@ compare. | Variable | Default | Meaning | |---|---|---| -| `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` | 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. | +| `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 @@ -65,8 +62,8 @@ For reference when widening/narrowing the band (hue in IM percent ≈ degrees/36 ## 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. +previews). Each entry lists the exact command; the originals are shown for +comparison and credit. ### Sunset over the sea @@ -74,12 +71,12 @@ single run. tools/ash-wallpaper.sh sunset.jpg ``` -| Dark | Light | +| Original | Ash | |---|---| -| ![sunset dark](../images/samples/ash-sunset-dark.jpg) | ![sunset light](../images/samples/ash-sunset-light.jpg) | +| ![sunset original](../images/samples/sunset-original.jpg) | ![sunset ash](../images/samples/ash-sunset.jpg) | 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. +by Joshua Fuller, CC0. ### Campfire close-up @@ -87,9 +84,9 @@ by Joshua Fuller, CC0 — no attribution required, given anyway. tools/ash-wallpaper.sh campfire.jpg ``` -| Dark | Light | +| Original | Ash | |---|---| -| ![campfire dark](../images/samples/ash-campfire-dark.jpg) | ![campfire light](../images/samples/ash-campfire-light.jpg) | +| ![campfire original](../images/samples/campfire-original.jpg) | ![campfire ash](../images/samples/ash-campfire.jpg) | 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/). @@ -100,9 +97,9 @@ by Nenad Stojkovic, [CC BY 2.0](https://creativecommons.org/licenses/by/2.0/). tools/ash-wallpaper.sh autumn.jpg ``` -| Dark | Light | +| Original | Ash | |---|---| -| ![autumn dark](../images/samples/ash-autumn-dark.jpg) | ![autumn light](../images/samples/ash-autumn-light.jpg) | +| ![autumn original](../images/samples/autumn-original.jpg) | ![autumn ash](../images/samples/ash-autumn.jpg) | 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/). @@ -116,9 +113,9 @@ HUE_MAX=17% SAT_MIN=8% SAT_MAX=60% SENSITIVITY=4x50% \ tools/ash-wallpaper.sh city.jpg ``` -| Dark | Light | +| Original | Ash | |---|---| -| ![city dark](../images/samples/ash-city-dark.jpg) | ![city light](../images/samples/ash-city-light.jpg) | +| ![city original](../images/samples/city-original.jpg) | ![city ash](../images/samples/ash-city.jpg) | 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. @@ -131,9 +128,9 @@ Only hair and lips keep their colour; skin stays close to bone: SAT_MIN=18% EMBER_BOOST=150 tools/ash-wallpaper.sh portrait.jpg ``` -| Dark | Light | +| Original | Ash | |---|---| -| ![portrait dark](../images/samples/ash-redhead-dark.jpg) | ![portrait light](../images/samples/ash-redhead-light.jpg) | +| ![portrait original](../images/samples/redhead-original.jpg) | ![portrait ash](../images/samples/ash-redhead.jpg) | 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/). @@ -141,7 +138,7 @@ by dusdin (Flickr), cropped by Gridge, [CC BY 2.0](https://creativecommons.org/l ## Recipes ```sh -# Warm sunset landscape, keep the drama (writes BOTH dark and light) +# 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 @@ -153,8 +150,8 @@ 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 -# Light-themed desktop -LIGHT=1 tools/ash-wallpaper.sh beach.jpg +# Flatter, dimmer base ramp +BASE_LO=#1c1b1f BASE_HI=#e6dfd1 tools/ash-wallpaper.sh photo.jpg ``` ## Batch generation @@ -172,7 +169,7 @@ cycles through them with `Super+Ctrl+Space`: ```sh mkdir -p ~/.config/omarchy/backgrounds/ash-dark -cp photo-ash-dark.png photo-ash-light.png ~/.config/omarchy/backgrounds/ash-dark/ +cp photo-ash.png ~/.config/omarchy/backgrounds/ash-dark/ ``` ## Troubleshooting diff --git a/tools/ash-wallpaper.sh b/tools/ash-wallpaper.sh index 2cc8a52..5801685 100755 --- a/tools/ash-wallpaper.sh +++ b/tools/ash-wallpaper.sh @@ -1,15 +1,11 @@ #!/usr/bin/env bash -# ash-wallpaper.sh — turn a color photo into Ash-palette wallpapers: +# ash-wallpaper.sh — turn a color photo into an Ash-palette wallpaper: # 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] +# usage: tools/ash-wallpaper.sh INPUT [OUTPUT] # -# 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". +# OUTPUT defaults to INPUT-without-extension + "-ash.png". # # tuning via environment (defaults shown): # HUE_MAX=13% warm band: hue <= HUE_MAX @@ -18,25 +14,22 @@ # 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) +# BASE_LO= BASE_HI= grey ramp endpoints (void -> chalk) set -euo pipefail -IN=${1:?usage: ash-wallpaper.sh INPUT [OUTBASE]} -OUTBASE=${2:-${IN%.*}-ash} +IN=${1:?usage: ash-wallpaper.sh INPUT [OUTPUT]} +OUT=${2:-${IN%.*}-ash.png} 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%} +BASE_LO=${BASE_LO:-#100f12} +BASE_HI=${BASE_HI:-#f3ede1} 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 @@ -50,18 +43,13 @@ trap 'rm -rf "$TMP"' EXIT "$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 +# ash base + ember-touched highlights, joined by the mask +"$IM" "$IN" \ + \( -clone 0 -modulate 100,0 +level-colors "$BASE_LO","$BASE_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"