Metadata-Version: 2.4
Name: superwand
Version: 0.3.2
Summary: A tool for retheming images and CSS using color palettes and gradients.
Author: Julian Henry
License-Expression: MIT
Project-URL: Homepage, https://github.com/juleshenry/superwand
Project-URL: Bug Tracker, https://github.com/juleshenry/superwand/issues
Classifier: Programming Language :: Python :: 3
Classifier: Operating System :: OS Independent
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy
Requires-Dist: pillow
Requires-Dist: pillow-avif-plugin
Requires-Dist: scipy
Requires-Dist: matplotlib
Requires-Dist: scikit-learn
Requires-Dist: flask
Requires-Dist: werkzeug
Provides-Extra: test
Requires-Dist: pytest; extra == "test"
Requires-Dist: pytest-cov; extra == "test"
Dynamic: license-file

# superwand

![SuperWand Studio](https://raw.githubusercontent.com/juleshenry/superwand/main/examples/studio-preview.png)

Leverage magic wand to breath life to images, especially posterized and vector art images.

## Setup
```bash
pip install superwand
```
or, from a clone:
```bash
uv sync
```

![Every theme, one Charizard](https://raw.githubusercontent.com/juleshenry/superwand/main/examples/demos/charizard_themes.gif)

## SuperWand Studio

The SuperWand Studio provides an interactive web interface for real-time image retheming, CSS retheming, and gradient application.

### Running the Studio

Simply run the `superwand` command without applying a theme:
```bash
superwand
```

### Access the UI
Once the server is running, open your browser and navigate to `http://127.0.0.1:5001`. Use `--port` to pick another port and `--debug` for Flask debug mode.

## CLI Usage

### Apply a Theme
```bash
superwand examples/images/zebra.png -theme Urban
```

#### Arguments
- `image_path`: Path to the input image file (optional if starting studio).
- `-theme`: Theme to apply (Tropical, Urban, Winter, etc.).
- `-k`: Number of regions to identify (default: 4).
- `-tolerance`: Color matching tolerance (default: 50).
- `-flood`: Apply morphological flood filling (default: False).
- `-gradient`: Gradient style (none, auto, vertical, horizontal, radial, bottom-up, top-down, left-right, right-left) (default: none). When a theme is applied, the gradient transitions from the primary theme color of the region to the next color in the theme.
- `-polarity`: Where along the gradient the 50/50 blend lands (0.0 to 1.0, default: 0.5). 0.5 is linear; lower values reach the end color sooner, higher values hold the start color longer.
- `-match`: How regions are paired with palette colors. `order` (default for themes) maps the largest region to the first theme color; `luminance` (default for `-palette-from`) maps the darkest region to the darkest color, preserving light and shadow.
- `-palette-from`: Use the `k` dominant colors of another image as the theme.
- `-gif`: Write an animated GIF cycling through every theme (or only `-theme`).
- `-palette`: Print the image's `k` dominant colors as hex and exit.
- `-o`, `--output-dir`: Directory for output files (default: current directory).
- `--list-themes`: Print every theme with its hex colors.

Without `-theme`, `--headless` writes one image per theme.

### More examples
```bash
superwand examples/images/charizard.png -gif                     # charizard_themes.gif
superwand rocket.jpeg -palette-from mantis_shrimp.jpeg -k 6       # steal a photo's palette
superwand skyline.jpg -theme Midnight -k 5 -match luminance -o out/
superwand charizard.png -palette -k 4                             # print dominant colors
```

### Enforce Gradients
```bash
gradient-enforce examples/images/charizard.png --style radial --color1 "#FF0000" --color2 "#0000FF"
```

#### Arguments
- `image_path`: Path to the input image.
- `--style`: Direction of gradients (auto, vertical, horizontal, radial, bottom-up, top-down, left-right, right-left) (default: auto).
- `--completeness`: Impacted regions (auto, aggressive, filter) (default: auto).
- `--opacity`: Opacity handling (default: auto).
- `--polarity`: Gradient midpoint bias (0.0 to 1.0, default: 0.5).
- `--output`: Path to the output image (default: gradient_<style>_<filename>.png).
- `--color1`: Start color for the gradient (e.g., '255,0,0' or '#FF0000').
- `--color2`: End color for the gradient (e.g., '0,0,255' or '#0000FF').


> **Note on Colors**: By default, the start and end colors are automatically derived from each region's original color by adjusting its brightness. To explicitly define the gradient colors, use `--color1` and `--color2`. When provided, all prominent regions will be replaced with a gradient transitioning between these two colors.



## Python API
```python
from superwand import retheme, transfer_palette, extract_palette, theme_cycle_gif, css_retheme

img = retheme("charizard.png", "Vaporwave", k=6, gradient="radial")    # returns a PIL Image
img = retheme("charizard.png", [(255, 0, 128), (0, 255, 255), (20, 0, 40)])  # custom palette
img = transfer_palette("rocket.jpeg", "mantis_shrimp.jpeg", k=6)        # palette from a photo
colors = extract_palette("mantis_shrimp.jpeg", 6)                     # [(r, g, b), ...]
theme_cycle_gif("charizard.png", "charizard_themes.gif")
css = css_retheme("site.css", "Tropical")
```

## Demos
All demo images are regenerated by `uv run python scripts/generate_demos.py`.

### Choosing `k`
More regions means finer-grained recoloring.

![k sweep](https://raw.githubusercontent.com/juleshenry/superwand/main/examples/demos/k_sweep.png)

### Palette transfer
`-palette-from` extracts the dominant colors of a reference image and applies them with luminance matching, so dark stays dark and light stays light.

![palette transfer](https://raw.githubusercontent.com/juleshenry/superwand/main/examples/demos/palette_transfer.png)

### Matching by order vs. luminance
With `match=order` colors are assigned by region size, so the bright sunset sky turns dark navy. With `match=luminance` the sky gets the theme's lightest color and the silhouetted mountains its darkest.

![match modes](https://raw.githubusercontent.com/juleshenry/superwand/main/examples/demos/match_modes.png)

### Gradient polarity
![polarity sweep](https://raw.githubusercontent.com/juleshenry/superwand/main/examples/demos/polarity_sweep.png)

## Gradients
Included: `bottom-up`, `top-down`, `left-right`, `right-left`, `radial`

| | | | | |
| :---: | :---: | :---: | :---: | :---: |
| **bottom-up** <br> <img src="https://raw.githubusercontent.com/juleshenry/superwand/main/examples/charizards/gradient_bottom-up_charizard.png" width="200"> | **top-down** <br> <img src="https://raw.githubusercontent.com/juleshenry/superwand/main/examples/charizards/gradient_top-down_charizard.png" width="200"> | **left-right** <br> <img src="https://raw.githubusercontent.com/juleshenry/superwand/main/examples/charizards/gradient_left-right_charizard.png" width="200"> | **right-left** <br> <img src="https://raw.githubusercontent.com/juleshenry/superwand/main/examples/charizards/gradient_right-left_charizard.png" width="200"> | **radial** <br> <img src="https://raw.githubusercontent.com/juleshenry/superwand/main/examples/charizards/gradient_radial_charizard.png" width="200"> |

## CSS Retheming
Identify color schemes in CSS and replace with a theme. Every `#rgb`, `#rgba`, `#rrggbb`, `#rrggbbaa`, `rgb()` and `rgba()` value inside a declaration is clustered with KMeans and each cluster is mapped to a theme color; selectors, comments, formatting and alpha channels are left alone.

```bash
css-retheme examples/css/site.css Tropical -o site_tropical.css
```

| Before | After |
| :---: | :---: |
| ![before](https://raw.githubusercontent.com/juleshenry/superwand/main/examples/css/before.png) | ![after](https://raw.githubusercontent.com/juleshenry/superwand/main/examples/css/after_tropical.png) |
| ![menu](https://raw.githubusercontent.com/juleshenry/superwand/main/examples/css/menu.png) | ![menu_tropical](https://raw.githubusercontent.com/juleshenry/superwand/main/examples/css/menu_tropical.png) |

## Color Themes
Themes included:

| | | | | |
| :---: | :---: | :---: | :---: | :---: |
| **Spring** <br> ![Spring](https://raw.githubusercontent.com/juleshenry/superwand/main/src/superwand/assets/themes_jpgs/SpringTheme.jpg) | **Summer** <br> ![Summer](https://raw.githubusercontent.com/juleshenry/superwand/main/src/superwand/assets/themes_jpgs/SummerTheme.jpg) | **Winter** <br> ![Winter](https://raw.githubusercontent.com/juleshenry/superwand/main/src/superwand/assets/themes_jpgs/WinterTheme.jpg) | **Fall** <br> ![Fall](https://raw.githubusercontent.com/juleshenry/superwand/main/src/superwand/assets/themes_jpgs/FallTheme.jpg) | **Arctic** <br> ![Arctic](https://raw.githubusercontent.com/juleshenry/superwand/main/src/superwand/assets/themes_jpgs/ArcticTheme.jpg) |
| **Safari** <br> ![Safari](https://raw.githubusercontent.com/juleshenry/superwand/main/src/superwand/assets/themes_jpgs/SafariTheme.jpg) | **Urban** <br> ![Urban](https://raw.githubusercontent.com/juleshenry/superwand/main/src/superwand/assets/themes_jpgs/UrbanTheme.jpg) | **Neon** <br> ![Neon](https://raw.githubusercontent.com/juleshenry/superwand/main/src/superwand/assets/themes_jpgs/NeonTheme.jpg) | **Tropical** <br> ![Tropical](https://raw.githubusercontent.com/juleshenry/superwand/main/src/superwand/assets/themes_jpgs/TropicalTheme.jpg) | **Paixão** <br> ![Paixão](https://raw.githubusercontent.com/juleshenry/superwand/main/src/superwand/assets/themes_jpgs/Paix%C3%A3oTheme.jpg) |
| **Vaporwave** <br> ![Vaporwave](https://raw.githubusercontent.com/juleshenry/superwand/main/src/superwand/assets/themes_jpgs/VaporwaveTheme.jpg) | **Cyberpunk** <br> ![Cyberpunk](https://raw.githubusercontent.com/juleshenry/superwand/main/src/superwand/assets/themes_jpgs/CyberpunkTheme.jpg) | **Retro80s** <br> ![Retro80s](https://raw.githubusercontent.com/juleshenry/superwand/main/src/superwand/assets/themes_jpgs/Retro80sTheme.jpg) | **Sunset** <br> ![Sunset](https://raw.githubusercontent.com/juleshenry/superwand/main/src/superwand/assets/themes_jpgs/SunsetTheme.jpg) | **Midnight** <br> ![Midnight](https://raw.githubusercontent.com/juleshenry/superwand/main/src/superwand/assets/themes_jpgs/MidnightTheme.jpg) |
| **Forest** <br> ![Forest](https://raw.githubusercontent.com/juleshenry/superwand/main/src/superwand/assets/themes_jpgs/ForestTheme.jpg) | **Oceanic** <br> ![Oceanic](https://raw.githubusercontent.com/juleshenry/superwand/main/src/superwand/assets/themes_jpgs/OceanicTheme.jpg) | **Volcano** <br> ![Volcano](https://raw.githubusercontent.com/juleshenry/superwand/main/src/superwand/assets/themes_jpgs/VolcanoTheme.jpg) | | |

### Example: Charizard

| | | | | |
| :---: | :---: | :---: | :---: | :---: |
| **Spring** <br> <img src="https://raw.githubusercontent.com/juleshenry/superwand/main/examples/charizards/Spring_charizard.png" width="200"> | **Summer** <br> <img src="https://raw.githubusercontent.com/juleshenry/superwand/main/examples/charizards/Summer_charizard.png" width="200"> | **Fall** <br> <img src="https://raw.githubusercontent.com/juleshenry/superwand/main/examples/charizards/Fall_charizard.png" width="200"> | **Winter** <br> <img src="https://raw.githubusercontent.com/juleshenry/superwand/main/examples/charizards/Winter_charizard.png" width="200"> | **Arctic** <br> <img src="https://raw.githubusercontent.com/juleshenry/superwand/main/examples/charizards/Arctic_charizard.png" width="200"> |
| **Safari** <br> <img src="https://raw.githubusercontent.com/juleshenry/superwand/main/examples/charizards/Safari_charizard.png" width="200"> | **Urban** <br> <img src="https://raw.githubusercontent.com/juleshenry/superwand/main/examples/charizards/Urban_charizard.png" width="200"> | **Neon** <br> <img src="https://raw.githubusercontent.com/juleshenry/superwand/main/examples/charizards/Neon_charizard.png" width="200"> | **Tropical** <br> <img src="https://raw.githubusercontent.com/juleshenry/superwand/main/examples/charizards/Tropical_charizard.png" width="200"> | **Paixão** <br> <img src="https://raw.githubusercontent.com/juleshenry/superwand/main/examples/charizards/Paix%C3%A3o_charizard.png" width="200"> |
| **Vaporwave** <br> <img src="https://raw.githubusercontent.com/juleshenry/superwand/main/examples/charizards/Vaporwave_charizard.png" width="200"> | **Cyberpunk** <br> <img src="https://raw.githubusercontent.com/juleshenry/superwand/main/examples/charizards/Cyberpunk_charizard.png" width="200"> | **Retro80s** <br> <img src="https://raw.githubusercontent.com/juleshenry/superwand/main/examples/charizards/Retro80s_charizard.png" width="200"> | **Sunset** <br> <img src="https://raw.githubusercontent.com/juleshenry/superwand/main/examples/charizards/Sunset_charizard.png" width="200"> | **Midnight** <br> <img src="https://raw.githubusercontent.com/juleshenry/superwand/main/examples/charizards/Midnight_charizard.png" width="200"> |
| **Forest** <br> <img src="https://raw.githubusercontent.com/juleshenry/superwand/main/examples/charizards/Forest_charizard.png" width="200"> | **Oceanic** <br> <img src="https://raw.githubusercontent.com/juleshenry/superwand/main/examples/charizards/Oceanic_charizard.png" width="200"> | **Volcano** <br> <img src="https://raw.githubusercontent.com/juleshenry/superwand/main/examples/charizards/Volcano_charizard.png" width="200"> | | |

## Gallery

### Rio De Janeiro Skyline
| Original | Arctic | Fall | Neon | Tropical |
| :---: | :---: | :---: | :---: | :---: |
| ![Original](https://raw.githubusercontent.com/juleshenry/superwand/main/examples/gallery/erro_xota.jpg) | ![Arctic](https://raw.githubusercontent.com/juleshenry/superwand/main/examples/gallery/erro_xota_Arctic.png) | ![Fall](https://raw.githubusercontent.com/juleshenry/superwand/main/examples/gallery/erro_xota_Fall.png) | ![Neon](https://raw.githubusercontent.com/juleshenry/superwand/main/examples/gallery/erro_xota_Neon.png) | ![Tropical](https://raw.githubusercontent.com/juleshenry/superwand/main/examples/gallery/erro_xota_Tropical.png) |

### Austin Ladybird Lake Plankton rendered in [ZIT](https://github.com/juleshenry/zooplankton-image-tool)
| Original | Spring | Summer | Winter | Safari |
| :---: | :---: | :---: | :---: | :---: |
| ![Original](https://raw.githubusercontent.com/juleshenry/superwand/main/examples/gallery/plankt_oct19.jpg) | ![Spring](https://raw.githubusercontent.com/juleshenry/superwand/main/examples/gallery/plankt_oct19_Spring.png) | ![Summer](https://raw.githubusercontent.com/juleshenry/superwand/main/examples/gallery/plankt_oct19_Summer.png) | ![Winter](https://raw.githubusercontent.com/juleshenry/superwand/main/examples/gallery/plankt_oct19_Winter.png) | ![Safari](https://raw.githubusercontent.com/juleshenry/superwand/main/examples/gallery/plankt_oct19_Safari.png) |

### Me in Rio de Janeiro
| Original | Paixão | Urban | Arctic | Fall |
| :---: | :---: | :---: | :---: | :---: |
| ![Original](https://raw.githubusercontent.com/juleshenry/superwand/main/examples/gallery/rio07.jpg) | ![Paixão](https://raw.githubusercontent.com/juleshenry/superwand/main/examples/gallery/rio07_Paix%C3%A3o.png) | ![Urban](https://raw.githubusercontent.com/juleshenry/superwand/main/examples/gallery/rio07_Urban.png) | ![Arctic](https://raw.githubusercontent.com/juleshenry/superwand/main/examples/gallery/rio07_Arctic.png) | ![Fall](https://raw.githubusercontent.com/juleshenry/superwand/main/examples/gallery/rio07_Fall.png) |

### Night Portrait, December 2017

<p align="center"><img src="https://raw.githubusercontent.com/juleshenry/superwand/main/examples/gallery/night_portrait.jpg" width="180" alt="Original"><br><b>Original</b></p>

| | | | |
| :---: | :---: | :---: | :---: |
| **Spring** <br> <img src="https://raw.githubusercontent.com/juleshenry/superwand/main/examples/gallery/night_portrait_Spring.png" width="180" alt="Spring"> | **Summer** <br> <img src="https://raw.githubusercontent.com/juleshenry/superwand/main/examples/gallery/night_portrait_Summer.png" width="180" alt="Summer"> | **Winter** <br> <img src="https://raw.githubusercontent.com/juleshenry/superwand/main/examples/gallery/night_portrait_Winter.png" width="180" alt="Winter"> | **Fall** <br> <img src="https://raw.githubusercontent.com/juleshenry/superwand/main/examples/gallery/night_portrait_Fall.png" width="180" alt="Fall"> |
| **Safari** <br> <img src="https://raw.githubusercontent.com/juleshenry/superwand/main/examples/gallery/night_portrait_Safari.png" width="180" alt="Safari"> | **Urban** <br> <img src="https://raw.githubusercontent.com/juleshenry/superwand/main/examples/gallery/night_portrait_Urban.png" width="180" alt="Urban"> | **Neon** <br> <img src="https://raw.githubusercontent.com/juleshenry/superwand/main/examples/gallery/night_portrait_Neon.png" width="180" alt="Neon"> | **Tropical** <br> <img src="https://raw.githubusercontent.com/juleshenry/superwand/main/examples/gallery/night_portrait_Tropical.png" width="180" alt="Tropical"> |
| **Arctic** <br> <img src="https://raw.githubusercontent.com/juleshenry/superwand/main/examples/gallery/night_portrait_Arctic.png" width="180" alt="Arctic"> | **Paixão** <br> <img src="https://raw.githubusercontent.com/juleshenry/superwand/main/examples/gallery/night_portrait_Paix%C3%A3o.png" width="180" alt="Paixão"> | **Cyberpunk** <br> <img src="https://raw.githubusercontent.com/juleshenry/superwand/main/examples/gallery/night_portrait_Cyberpunk.png" width="180" alt="Cyberpunk"> | **Sunset** <br> <img src="https://raw.githubusercontent.com/juleshenry/superwand/main/examples/gallery/night_portrait_Sunset.png" width="180" alt="Sunset"> |
| **Oceanic** <br> <img src="https://raw.githubusercontent.com/juleshenry/superwand/main/examples/gallery/night_portrait_Oceanic.png" width="180" alt="Oceanic"> | **Vaporwave** <br> <img src="https://raw.githubusercontent.com/juleshenry/superwand/main/examples/gallery/night_portrait_Vaporwave.png" width="180" alt="Vaporwave"> | **Retro80s** <br> <img src="https://raw.githubusercontent.com/juleshenry/superwand/main/examples/gallery/night_portrait_Retro80s.png" width="180" alt="Retro80s"> | **Volcano** <br> <img src="https://raw.githubusercontent.com/juleshenry/superwand/main/examples/gallery/night_portrait_Volcano.png" width="180" alt="Volcano"> |
