Improved multichrome recoloring

This commit is contained in:
NicklasVraa
2023-08-10 22:03:58 +02:00
parent f4923aba6c
commit 96df4502e0
11 changed files with 45 additions and 21 deletions

View File

@@ -10,7 +10,7 @@ import os, ngtk, utils
def recolor(src_path, dest_path, name, replacement, progress_bar, status):
"""Recursively copies and converts a source folder into a destination, given a either a color or a palette."""
is_mono, new_colors = utils.get_input_colors(replacement)
new_colors, smooth, is_mono = utils.get_input_colors(replacement)
dest_path = utils.copy_pack(src_path, dest_path, name)
svg_paths = utils.get_paths(dest_path, [".svg"])
img_paths = utils.get_paths(dest_path, [".png", ".jpg", ".jpeg"])
@@ -40,7 +40,7 @@ def recolor(src_path, dest_path, name, replacement, progress_bar, status):
img = Image.open(path)
if is_mono: img = utils.monochrome_img(img, new_colors)
else: img = utils.multichrome_img(img, new_colors)
else: img = utils.multichrome_img(img, new_colors, smooth)
img.save(path)

View File

@@ -99,18 +99,18 @@ def load_palette_file(path:str) -> Dict[str,LabColor]:
palette = json.load(file)
return palette
def get_input_colors(resource) -> List[str]:
"""Returns an HSL tuple, or a list of colors, depending on the input, as well as a boolean indicating either."""
def get_input_colors(resource) -> Tuple[List[str],bool,bool]:
"""Returns an HSL tuple, or a list of colors, depending on the input, as well as a boolean indicating which one, as well as if the palettes specifies smoothing pngs/jpgs."""
if isinstance(resource, tuple) and len(resource) == 3:
return True, resource
return resource, False, True
elif type(resource) is str:
colors = load_palette_file(resource)["colors"]
return False, generate_palette_dict(colors)
palette_file = load_palette_file(resource)
return generate_palette_dict(palette_file["colors"]), palette_file["smooth"], False
else:
return False, generate_palette_dict(resource["colors"])
return generate_palette_dict(resource["colors"]), palette_file["smooth"], False
def get_svg_colors(svg:str) -> Set[str]:
"""Return a list of all unique colors within a given string
@@ -300,11 +300,13 @@ def monochrome_img(img:Image, hsl:Tuple[float,float,float]) -> Image:
return img
def multichrome_img(img:Image, new_colors:Dict[str,LabColor]) -> Image:
def multichrome_img(img:Image, new_colors:Dict[str,LabColor], smooth:bool) -> Image:
"""Replace colors in a given image with the closest match within a given
color palette."""
img = img.convert("P")
if smooth: img = img.convert("P", palette=Image.ADAPTIVE, colors=256)
else: img = img.convert("P")
palette = img.getpalette()
rgb_palette = [(palette[i], palette[i+1], palette[i+2]) for i in range(0, len(palette), 3)]
@@ -323,7 +325,7 @@ def multichrome_img(img:Image, new_colors:Dict[str,LabColor]) -> Image:
def recolor(src_path:str, dest_path:str, name:str, replacement) -> None:
"""Recursively copies and converts a source folder into a destination, given a either a color or a palette."""
is_mono, new_colors = get_input_colors(replacement)
new_colors, smooth, is_mono = get_input_colors(replacement)
dest_path = copy_pack(src_path, dest_path, name)
svg_paths = get_paths(dest_path, [".svg"])
img_paths = get_paths(dest_path, [".png", ".jpg", ".jpeg"])
@@ -344,6 +346,6 @@ def recolor(src_path:str, dest_path:str, name:str, replacement) -> None:
img = Image.open(path)
if is_mono: img = monochrome_img(img, new_colors)
else: img = multichrome_img(img, new_colors)
else: img = multichrome_img(img, new_colors, smooth)
img.save(path)

View File

@@ -1,6 +1,7 @@
{
"name": "Catppuccin Latte",
"desc": "Pastel theme that aims to be the middle ground between low and high contrast themes.",
"smooth": false,
"colors": [
"dc8a78",
"#dd7878",

View File

@@ -1,6 +1,7 @@
{
"name": "Dracula",
"desc": "Dark mode color scheme with vibrant and contrasting colors.",
"smooth": false,
"colors": [
"#44475a",
"#f8f8f2",

View File

@@ -1,6 +1,7 @@
{
"name": "Nord",
"desc": "An arctic, north-bluish color palette.",
"smooth": true,
"colors": [
"#434c5e",
"#4c566a",

View File

@@ -1,6 +1,7 @@
{
"name": "One Dark",
"desc": "Dark grey background with vibrant colors.",
"smooth": true,
"colors": [
"#282C34",
"#E06C75",

View File

@@ -6,12 +6,13 @@ Color Manager is a program for recoloring and manipulating existing icon packs,
![gui](resources/gui.png)
**Instanty recolor artwork such as wallpapers.**
**Instantly recolor artwork such as wallpapers.**
| Operation | Result |
| :---------: | ------ |
| Original | ![1](resources/original.png) |
| Monochrome: (0.6, 0.54, 0.5) | ![2](resources/mono.png) |
| Multichrome: dracula.json | ![3](resources/multi.png) |
| **Original** | ![1](resources/original.png) |
| **Monochrome**:<br> (0.6, 0.54, 0.5) | ![2](resources/mono.png) |
| **Multichrome**:<br> `nord.json`<br> `smooth=false` | ![3](resources/multi_accurate.png) |
| **Multichrome**:<br> `nord.json`<br> `smooth=true` | ![3](resources/multi_smooth.png) |
**GUI Demo**:
![demo](resources/demo.gif)
@@ -45,6 +46,7 @@ Speeds were recorded with an Intel i7-4770K CPU. Any asset can serve as the base
**Tip**: To increase the quality, i.e. decrease the perceived noise of multichromatic recolorings of pngs/jpgs, either...
- Increase the number of colors in the palette you provide to the program, e.g. populate it with slight variations of the existing colors
- Decrease the number of colors in your original image, e.g. using a function like `Image.quantize()` from `pillow`.
- Experiment with setting `smooth` to `true`/`false` in the palette json file.
Both will be implemented as optional automatic adjustments in the future.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 660 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 677 KiB

BIN
resources/multi_smooth.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 238 KiB

View File

@@ -2,7 +2,7 @@
"cells": [
{
"cell_type": "code",
"execution_count": null,
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
@@ -12,9 +12,25 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 21,
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"Processing svgs: 0%| | 0/6 [00:00<?, ?file/s]"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Processing svgs: 100%|██████████| 6/6 [00:00<00:00, 84.43file/s]\n",
"Processing imgs: 100%|██████████| 2/2 [00:01<00:00, 1.27file/s]\n"
]
}
],
"source": [
"from color_manager import utils\n",
"\n",
@@ -22,9 +38,9 @@
"name = \"my_pack2\"\n",
"dest = \"~/Downloads\"\n",
"hsl = (0.6, 0.54, 0.5) # = rc.normalize_hsl(180, 50, 50)\n",
"palette = \"palettes/dracula.json\"\n",
"palette = \"palettes/nord.json\"\n",
"\n",
"utils.recolor(src, dest, name, hsl) # hsl or palette"
"utils.recolor(src, dest, name, palette) # hsl or palette"
]
}
],