mirror of
https://github.com/NicklasVraa/Color-manager.git
synced 2026-01-18 17:27:20 +01:00
Improved multichrome recoloring
This commit is contained in:
@@ -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)
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"name": "Dracula",
|
||||
"desc": "Dark mode color scheme with vibrant and contrasting colors.",
|
||||
"smooth": false,
|
||||
"colors": [
|
||||
"#44475a",
|
||||
"#f8f8f2",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"name": "Nord",
|
||||
"desc": "An arctic, north-bluish color palette.",
|
||||
"smooth": true,
|
||||
"colors": [
|
||||
"#434c5e",
|
||||
"#4c566a",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"name": "One Dark",
|
||||
"desc": "Dark grey background with vibrant colors.",
|
||||
"smooth": true,
|
||||
"colors": [
|
||||
"#282C34",
|
||||
"#E06C75",
|
||||
|
||||
10
readme.md
10
readme.md
@@ -6,12 +6,13 @@ Color Manager is a program for recoloring and manipulating existing icon packs,
|
||||
|
||||

|
||||
|
||||
**Instanty recolor artwork such as wallpapers.**
|
||||
**Instantly recolor artwork such as wallpapers.**
|
||||
| Operation | Result |
|
||||
| :---------: | ------ |
|
||||
| Original |  |
|
||||
| Monochrome: (0.6, 0.54, 0.5) |  |
|
||||
| Multichrome: dracula.json |  |
|
||||
| **Original** |  |
|
||||
| **Monochrome**:<br> (0.6, 0.54, 0.5) |  |
|
||||
| **Multichrome**:<br> `nord.json`<br> `smooth=false` |  |
|
||||
| **Multichrome**:<br> `nord.json`<br> `smooth=true` |  |
|
||||
|
||||
**GUI Demo**:
|
||||

|
||||
@@ -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 |
BIN
resources/multi_accurate.png
Normal file
BIN
resources/multi_accurate.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 677 KiB |
BIN
resources/multi_smooth.png
Normal file
BIN
resources/multi_smooth.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 238 KiB |
26
test.ipynb
26
test.ipynb
@@ -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"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user