Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

29 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Paletteer banner

Recolor PNG, JPEG and WEBP wallpapers with built-in or custom color palettes while mapping each image's continuous lightness into the theme's tonal range.

See PALETTES.md for the supported palette and its colors.

Built-in themes: everforest-dark-medium, catppuccin-mocha, tokyo-night, gruvbox-dark-medium, nord, dracula, and rose-pine-moon.

Examples

Show example galleries

Derived previews use --palette-name-only; their current settings are defined in scripts/regenerate-readme-images.sh and can be applied with make readme-images without changing these paths.

Built-in palette comparison

OriginalEverforest Dark Medium
Original DSC 1657DSC 1657 recolored with Everforest Dark Medium
Catppuccin MochaTokyo Night
DSC 1657 recolored with Catppuccin MochaDSC 1657 recolored with Tokyo Night
Gruvbox Dark MediumNord
DSC 1657 recolored with Gruvbox Dark MediumDSC 1657 recolored with Nord
DraculaRosé Pine Moon
DSC 1657 recolored with DraculaDSC 1657 recolored with Rosé Pine Moon

Everforest Dark Medium Comparison

OriginalEverforest Dark MediumEverforest (accents ignored)
Original DSC 1255Everforest DSC 1255Everforest neutral DSC 1255
Original DSC 1261Everforest DSC 1261Everforest neutral DSC 1261
Original DSC 1275Everforest DSC 1275Everforest neutral DSC 1275
Original DSC 1321Everforest DSC 1321Everforest neutral DSC 1321
Original DSC 1340Everforest DSC 1340Everforest neutral DSC 1340
Original DSC 1344Everforest DSC 1344Everforest neutral DSC 1344
Original DSC 1383Everforest DSC 1383Everforest neutral DSC 1383
Original DSC 1484Everforest DSC 1484Everforest neutral DSC 1484
Original DSC 1571Everforest DSC 1571Everforest neutral DSC 1571
Original DSC 1629Everforest DSC 1629Everforest neutral DSC 1629
Original DSC 1657Everforest DSC 1657Everforest neutral DSC 1657
Original DSC 1719Everforest DSC 1719Everforest neutral DSC 1719
Original DSC 1806Everforest DSC 1806Everforest neutral DSC 1806
Original DSC 1812Everforest DSC 1812Everforest neutral DSC 1812
Original DSC 1915Everforest DSC 1915Everforest neutral DSC 1915
Original DSC 2080Everforest DSC 2080Everforest neutral DSC 2080
Original DSC 2311Everforest DSC 2311Everforest neutral DSC 2311
Original DSC 2316Everforest DSC 2316Everforest neutral DSC 2316
Original DSC 2357Everforest DSC 2357Everforest neutral DSC 2357

Installation

cargo install --path .

Usage

paletteer [OPTIONS] <--theme <THEME>|--theme-file <FILE>> <INPUT>...
Argument Required / default Effect Use case
<INPUT>... Required; one or more Recolors PNG, JPG, JPEG, or WebP files. Accepts individual files, directories, and expanded or quoted globs. Directories include immediate supported files only. Process one image, batch a folder, or select files recursively with a quoted glob such as '**/*-forest.jpg'.
-t, --theme <THEME> No default; required unless --theme-file is used Selects one of the built-in color palettes. Use a bundled palette without maintaining a separate file.
--theme-file <FILE> No default; required unless --theme is used Loads a custom TOML palette. Cannot be combined with --theme. Recolor with your own base and accent colors.
-n, --normalize-name Optional; off Lowercases the generated output stem and restricts it to a-z, 0-9, and -. Produce predictable, shell-friendly filenames from names containing spaces, punctuation, or uppercase characters.
--palette-name-only Optional; off Omits neutral, lambda, and mix settings from the output filename, leaving only the palette suffix. Keep filenames short when settings are tracked elsewhere. Different settings then resolve to the same output path.
-f, --format <FORMAT> Optional; png Selects png, webp, or jpg output. PNG is lossless; JPEG discards alpha. Choose lossless output, smaller WebP files, or broadly compatible JPEG files.
-q, --quality <1-100> Optional; 80 for WebP/JPEG Sets lossy encoding quality. Using it with PNG is an error. Trade output size for visual quality when writing WebP or JPEG.
--neutral-only Optional; off Excludes accent colors and adds -neutral to the output filename. Produce a deliberately subdued, near-monochrome result.
--lambda <0-1> Optional; 0.25 Weights the mapped theme lightness when selecting the nearest palette color. Non-default values add -lambda-<value> to the filename. Use 0 for hue/chroma-only matching or increase toward 1 to make palette lightness influence color assignment.
--mix <0-1> Optional; 1 Blends the original Oklab color with the recolored result, including its theme-mapped lightness. Non-default values add -mix-<value> to the output filename. Use 0 for the original colors, an intermediate value such as 0.5 for a subtler result, or 1 for the full theme tonal range and chroma remap.
-o, --overwrite Optional; off Replaces an existing output only after the new image encodes successfully. Regenerate images without deleting old outputs manually.
-h, --help Optional Prints the built-in CLI reference. Check available arguments from the installed binary.

Custom palettes

Pass a TOML file with --theme-file:

name = "forest-dusk"
colors = ["#1b2428", "#556b62", "#d8c9aa"]
accents = ["#e67e80", "#a7c080", "#7fbbb3"]

name becomes the output filename suffix and must contain only lowercase letters, digits, and single hyphens. colors must contain at least one #RRGGBB color. accents is optional and participates by default; use --neutral-only to exclude it.

paletteer --theme-file examples/forest-dusk.toml --mix 0.9 wallpaper.jpg

Quote recursive globs for consistent behavior across shells. Files whose names already carry a built-in or currently selected custom palette suffix (optionally followed by -neutral, -lambda-<value>, and -mix-<value>) are skipped to prevent repeat recoloring.

How it works

Recoloring runs entirely in the Oklab perceptual color space (via the palette crate), where Euclidean distance approximates perceived color difference. Each opaque pixel is converted from sRGB to Oklab, remapped, and converted back; fully transparent pixels are skipped, and the per-pixel work is parallelized with rayon.

The remap has two independent stages.

1. Lightness range mapping. The image's own lightness range — the minimum and maximum Oklab L over all opaque pixels — is affine-mapped onto the palette's lightness range. Every pixel's lightness is stretched or compressed by the same linear transform, so a dark theme pulls the whole image dark and the tonal contrast becomes the palette's. This is what makes a result feel like it belongs to the theme. Because the transform is continuous, gradients stay smooth and free of banding.

2. Chroma mapping. For each pixel the two nearest palette colors to its mapped-lightness / original-chroma point are found using a lightness-weighted squared distance λ·ΔL² + Δa² + Δb², where --lambda sets how much lightness influences the match. The pixel's chroma (a, b) is then linearly interpolated between those two palette colors by projecting it onto the segment between them. Snapping to a single nearest color would posterize smooth hue gradients into hard contours; interpolating between the nearest two keeps the transition continuous while staying within the palette's colors.

The output pixel takes its lightness from stage 1 and its chroma from stage 2, and --mix then linearly blends between the original Oklab color and this recolored one (0 = original, 1 = full remap).

Acknoledgements

This project was developed with assistance from AI coding tools. The resulting code was reviewed and tested by the maintainer.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages