Skip to content

Commit 0e497b5

Browse files
committed
update README
1 parent 3c17de2 commit 0e497b5

4 files changed

Lines changed: 85 additions & 54 deletions

File tree

README.md

Lines changed: 71 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,43 @@ It is built in reference with offical [typescript implementation](https://github
1313
Run file `tests/test_all.py` as:
1414

1515
```console
16-
python3 test_all.py <image path> <quality>
17-
16+
usage: test_all.py [-h] [--tonal-spot] [--expressive] [--fidelity] [--fruit-salad] [--monochrome] [--neutral] [--rainbow] [--vibrant]
17+
[--content] [--all] [--image IMAGE] [--quality QUALITY] [--method {pillow,cpp}]
18+
19+
Material You Color Scheme Test
20+
21+
options:
22+
-h, --help show this help message and exit
23+
--tonal-spot Print the tonal-spot dynamic scheme
24+
--expressive Print the expressive dynamic scheme
25+
--fidelity Print the fidelity dynamic scheme
26+
--fruit-salad Print the fruit-salad dynamic scheme
27+
--monochrome Print the monochrome dynamic scheme
28+
--neutral Print the neutral dynamic scheme
29+
--rainbow Print the rainbow dynamic scheme
30+
--vibrant Print the vibrant dynamic scheme
31+
--content Print the content dynamic scheme
32+
--all Print all dynamic schemes (default)
33+
--image IMAGE Path to an image file for color extraction
34+
--quality QUALITY Quality for image quantization (default: 5)
35+
--method {pillow,cpp}
36+
Method for color quantization (default: cpp)
1837
```
19-
Maximum quality is `1` that means use all pixels, and quality number more than `1` means how many pixels to skip in between while reading, also you can see it as compression.
2038

2139
<details>
2240
<summary>Click to view result</summary>
2341

2442
[Image Used, size was 8MB](https://unsplash.com/photos/zFMbpChjZGg/)
2543

26-
![image](https://github.com/T-Dynamos/materialyoucolor-pyhton/assets/68729523/9d5374c9-00b4-4b70-b82a-6792dd5c910f)
27-
![image](https://github.com/T-Dynamos/materialyoucolor-pyhton/assets/68729523/2edd819f-8600-4c82-a18a-3b759f63a552)
44+
<img width="666" height="516" alt="image" src="https://github.com/user-attachments/assets/68bc415b-3eb5-41d4-96e3-f36ced7411a8" />
45+
46+
47+
It is recommended to use the `cpp` backend, as the `pillow` backend is extremely memory-inefficient for large images.
48+
Newer Pillow APIs such as `Image.get_flattened_data()` eagerly materialize the entire image into a full list,
49+
so quality-based subsampling is applied only after full expansion and does not reduce memory usage.
50+
While `Image.getdata()` allows sampling during iteration, it is deprecated.
2851

52+
The `cpp` backend avoids these issues by operating directly on compact pixel buffers.
2953

3054
</details>
3155

@@ -50,7 +74,7 @@ pip3 install https://github.com/T-Dynamos/materialyoucolor-python/archive/master
5074
```
5175
### OS Specific
5276

53-
#### Arch Linux
77+
#### Arch Linux (OUTDATED)
5478

5579
```console
5680
yay -S python-materialyoucolor
@@ -62,7 +86,7 @@ Thanks :heart: to [@midn8hustlr](https://github.com/midn8hustlr) for this [AUR p
6286

6387
Ensure these lines in `buildozer.spec`:
6488
```python
65-
requirements = materialyoucolor
89+
requirements = materialyoucolor==3.0.0
6690
p4a.branch = develop
6791
```
6892

@@ -103,6 +127,7 @@ print(SchemeAndroid.dark(color).props)
103127
```python
104128
# Color in hue, chroma, tone form
105129
from materialyoucolor.hct import Hct
130+
from materialyoucolor.dynamiccolor.color_spec import COLOR_NAMES
106131
from materialyoucolor.dynamiccolor.material_dynamic_colors import MaterialDynamicColors
107132

108133
# There are 9 different variants of scheme.
@@ -114,60 +139,65 @@ scheme = SchemeTonalSpot( # choose any scheme here
114139
Hct.from_int(0xff4181EE), # source color in hct form
115140
True, # dark mode
116141
0.0, # contrast
142+
spec_version="2025"
117143
)
118144

119-
for color in vars(MaterialDynamicColors).keys():
120-
color_name = getattr(MaterialDynamicColors, color)
121-
if hasattr(color_name, "get_hct"): # is a color
122-
print(color, color_name.get_hct(scheme).to_rgba()) # print name of color and value in rgba format
123-
124-
# background [14, 20, 21, 255]
125-
# onBackground [222, 227, 229, 255]
126-
# surface [14, 20, 21, 255]
127-
# surfaceDim [14, 20, 21, 255]
128-
# ...
145+
mdc = MaterialDynamicColors(spec="2025")
146+
147+
for color in COLOR_NAMES:
148+
_color = getattr(mdc, color)
149+
print(color, _color.get_rgba(scheme), _color.get_hex(scheme))
150+
151+
# background [13, 14, 18, 255] #0D0E12FF
152+
# onBackground [227, 229, 240, 255] #E3E5F0FF
153+
# surface [13, 14, 18, 255] #0D0E12FF
154+
# surfaceDim [13, 14, 18, 255] #0D0E12FF
155+
# surfaceBright [41, 44, 52, 255] #292C34FF
156+
# surfaceContainerLowest [0, 0, 0, 255] #000000FF
157+
# surfaceContainerLow [17, 19, 24, 255] #111318FF
158+
# surfaceContainer [23, 25, 31, 255] #17191FFF
159+
# surfaceContainerHigh [29, 31, 38, 255] #1D1F26FF
160+
# surfaceContainerHighest [35, 38, 45, 255] #23262DFF
161+
# onSurface [227, 229, 240, 255] #E3E5F0FF
162+
# surfaceVariant [35, 38, 45, 255] #23262DFF
163+
# onSurfaceVariant [196, 198, 208, 255] #C4C6D0FF
164+
# outline [142, 144, 154, 255] #8E909AFF
165+
...
129166
```
130167

131168
- Generate and score colors from image
132169

133170
```python
134-
# Pillow is required to open image to array of pixels
135-
from PIL import Image
136-
# C++ QuantizeCelebi
137171
from materialyoucolor.quantize import QuantizeCelebi, ImageQuantizeCelebi
138-
# Material You's default scoring of colors
139172
from materialyoucolor.score.score import Score
140173

141-
# Open image
142-
image = Image.open("path_to_some_image.jpg")
143-
pixel_len = image.width * image.height
144-
image_data = image.getdata()
145-
146-
# Quality 1 means skip no pixels
174+
# Pixel subsampling factor (quality = 1 processes all pixels)
147175
quality = 1
148-
pixel_array = [image_data[_] for _ in range(0, pixel_len, quality)]
149-
150-
# Run algorithm
151-
result = QuantizeCelebi(pixel_array, 128) # 128 -> number desired colors, default 128
152176

153-
# Alternate C++ method
154-
# this is generally faster, but gives less control over image
155-
# result = ImageQuantizeCelebi("path_to_some_image.jpg", quality, 128)
177+
# Run Celebi color quantization on an image.
178+
# Returns a dict: {ARGB_color_int: population}
179+
result = ImageQuantizeCelebi(
180+
"example.jpg",
181+
quality,
182+
128, # maximum number of colors
183+
)
156184

157185
print(result)
158-
# {4278722365: 2320, 4278723396: 2405, 4278723657: 2366,...
159-
# result is a dict where key is
160-
# color in integer form (which you can convert later), and value is population
161186

162-
print(Score.score(result))
163-
# [4278722365, 4278723657]
164-
# list of selected colors in integer form
187+
# Rank and select the best theme colors.
188+
# Returns a list of ARGB color integers.
189+
selected_colors = Score.score(result)
165190

191+
print(selected_colors)
192+
# {4278911493: 276721,
193+
# 4280550664: 164247,
194+
# 4280683034: 144830,
195+
# ...
166196
```
167197
</details>
168198

169199
## FAQ
170200

171201
1. How it is different from `avanisubbiah/material-color-utilities`?
172202

173-
See https://github.com/T-Dynamos/materialyoucolor-python/issues/3
203+
This library is up to date, fast, and uses a hybrid system for image generation.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
from .dislike import DislikeAnalyzer
1+
from .dislike_analyzer import DislikeAnalyzer

materialyoucolor/scheme/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,5 @@
77
from .scheme_rainbow import SchemeRainbow
88
from .scheme_tonal_spot import SchemeTonalSpot
99
from .scheme_vibrant import SchemeVibrant
10+
from .scheme import Scheme
11+
from .scheme_android import SchemeAndroid

tests/test_all.py

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,24 @@
11
import argparse
22
import os
3+
import time
34

45
import psutil
56
from PIL import Image
67
from rich.console import Console
78
from rich.table import Table
89

10+
from materialyoucolor.dynamiccolor.color_spec import COLOR_NAMES
911
from materialyoucolor.dynamiccolor.material_dynamic_colors import MaterialDynamicColors
1012
from materialyoucolor.hct.hct import Hct
1113

12-
13-
# non-dynamic scheme
14-
from materialyoucolor.scheme.scheme import Scheme
15-
from materialyoucolor.scheme.scheme_android import SchemeAndroid
16-
1714
# dynamic schemes
1815
# import all schemes
1916
from materialyoucolor.scheme import *
2017

18+
# non-dynamic scheme
19+
from materialyoucolor.scheme.scheme import Scheme
20+
from materialyoucolor.scheme.scheme_android import SchemeAndroid
2121
from materialyoucolor.score.score import Score
22-
from materialyoucolor.dynamiccolor.color_spec import COLOR_NAMES
2322
from materialyoucolor.utils.color_utils import hex_from_rgba, rgba_from_argb
2423

2524

@@ -69,8 +68,8 @@ def get_current_rss_mb():
6968
"--method",
7069
type=str,
7170
choices=["pillow", "cpp"],
72-
default="pillow",
73-
help="Method for color quantization (default: pillow)",
71+
default="cpp",
72+
help="Method for color quantization (default: cpp)",
7473
)
7574
args = parser.parse_args()
7675

@@ -81,7 +80,7 @@ def get_current_rss_mb():
8180

8281
print("########## PILLOW METHOD ##########")
8382
initial_memory = get_current_rss_mb()
84-
start = default_timer()
83+
start = time.time()
8584
image = Image.open(args.image)
8685
pixel_len = image.width * image.height
8786
try:
@@ -91,7 +90,7 @@ def get_current_rss_mb():
9190
colors = QuantizeCelebi(
9291
[image_data[i] for i in range(0, pixel_len, args.quality)], MAX_COLOR
9392
)
94-
end = default_timer()
93+
end = time.time()
9594
final_memory = get_current_rss_mb()
9695
print(f"Color[pillow] generation took {end - start:.4f} secs")
9796
print(f"Peak RAM usage (Pillow): {final_memory - initial_memory:.2f} MB")
@@ -101,9 +100,9 @@ def get_current_rss_mb():
101100

102101
print("########## C++ Method ##########")
103102
initial_memory = get_current_rss_mb()
104-
start = default_timer()
103+
start = time.time()
105104
colors = ImageQuantizeCelebi(args.image, args.quality, MAX_COLOR)
106-
end = default_timer()
105+
end = time.time()
107106
final_memory = get_current_rss_mb()
108107
print(f"Color[stb_image] generation took {end - start:.4f} secs")
109108
print(f"Peak RAM usage (C++): {final_memory - initial_memory:.2f} MB")

0 commit comments

Comments
 (0)