PGTKernelbasic 0.23.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- Kernel/ImageObj.py +52 -0
- Kernel/KernalInit.py +21 -0
- Kernel/KernelAudio.py +97 -0
- Kernel/KernelColor.py +420 -0
- Kernel/KernelEvent.py +129 -0
- Kernel/KernelLayout.py +58 -0
- Kernel/KernelPosition.py +231 -0
- Kernel/KernelRun.py +81 -0
- Kernel/KernelWidget.py +353 -0
- Kernel/ObjType.py +14 -0
- Kernel/PgRenderCompo/ButtonObj.py +192 -0
- Kernel/PgRenderCompo/LinkRenderfunc.py +71 -0
- Kernel/PgRenderCompo/RRender.py +84 -0
- Kernel/PgRenderCompo/Render.py +78 -0
- Kernel/PgRenderCompo/TextObj.py +127 -0
- Kernel/PgRenderCompo/__init__.py +5 -0
- Kernel/RFlags.py +63 -0
- Kernel/UFlags.py +18 -0
- Kernel/VFlags.py +29 -0
- Kernel/__init__.py +15 -0
- Kernel/geometry.py +117 -0
- pgtkernelbasic-0.23.0.dist-info/METADATA +12 -0
- pgtkernelbasic-0.23.0.dist-info/RECORD +25 -0
- pgtkernelbasic-0.23.0.dist-info/WHEEL +5 -0
- pgtkernelbasic-0.23.0.dist-info/top_level.txt +1 -0
Kernel/ImageObj.py
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import pygame
|
|
2
|
+
from Kernel.ObjType import RectTuple, PosTuple
|
|
3
|
+
import os
|
|
4
|
+
pygame_load = pygame.image.load
|
|
5
|
+
convert_alpha = pygame.Surface.convert_alpha
|
|
6
|
+
save = pygame.image.save
|
|
7
|
+
os_exists = os.path.exists
|
|
8
|
+
os_path_join = os.path.join
|
|
9
|
+
os_path_splitext = os.path.splitext
|
|
10
|
+
def is_image_file(path):
|
|
11
|
+
ext = os.path.splitext(path)[1].lower()
|
|
12
|
+
return ext in {'.png', '.jpg', '.jpeg', '.bmp', '.gif'}
|
|
13
|
+
class ImagePack:
|
|
14
|
+
def __init__(self, src: str, convert_alpha = True):
|
|
15
|
+
if os_exists(src) and is_image_file(src):
|
|
16
|
+
self.src = src
|
|
17
|
+
else:
|
|
18
|
+
raise ValueError("This is not a valid image path")
|
|
19
|
+
self.surface = pygame_load(src).convert_alpha() if convert_alpha else pygame_load(src)
|
|
20
|
+
def get_rect(self):
|
|
21
|
+
return self.surface.get_rect()
|
|
22
|
+
def get_size(self):
|
|
23
|
+
return self.surface.get_size()
|
|
24
|
+
def resize(self, size: PosTuple):
|
|
25
|
+
self.surface = pygame.transform.scale(self.surface, size)
|
|
26
|
+
return self
|
|
27
|
+
def scale_resize(self, scale):
|
|
28
|
+
w, h = self.get_size()
|
|
29
|
+
self.surface = pygame.transform.scale(self.surface, (w*scale, h * scale))
|
|
30
|
+
return self
|
|
31
|
+
def rotate(self, angle):
|
|
32
|
+
self.surface = pygame.transform.rotate(self.surface, angle)
|
|
33
|
+
return self
|
|
34
|
+
def crop(self, rect: RectTuple):
|
|
35
|
+
if (rect[0] < 0 or rect[1] < 0 or
|
|
36
|
+
rect[0] + rect[2] > self.surface.get_width() or
|
|
37
|
+
rect[1] + rect[3] > self.surface.get_height()):
|
|
38
|
+
raise ValueError("Crop rectangle out of image bounds")
|
|
39
|
+
else:
|
|
40
|
+
self.surface = self.surface.subsurface(rect)
|
|
41
|
+
return self
|
|
42
|
+
def take_from_crop(self, rect: RectTuple):
|
|
43
|
+
return self.surface.subsurface(rect).copy()
|
|
44
|
+
def get_image(self):
|
|
45
|
+
return self.surface
|
|
46
|
+
def flip(self, horizontal=False, vertical=False):
|
|
47
|
+
self.surface = pygame.transform.flip(self.surface, horizontal, vertical)
|
|
48
|
+
return self
|
|
49
|
+
def copy(self):
|
|
50
|
+
new_pack = ImagePack(self.src, convert_alpha=False)
|
|
51
|
+
new_pack.surface = self.surface.copy()
|
|
52
|
+
return new_pack
|
Kernel/KernalInit.py
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import pygame
|
|
2
|
+
init_state = False
|
|
3
|
+
_fill_mode = True
|
|
4
|
+
|
|
5
|
+
def set_fill_mode(mode=False):
|
|
6
|
+
global _fill_mode
|
|
7
|
+
_fill_mode = mode
|
|
8
|
+
|
|
9
|
+
def should_fill():
|
|
10
|
+
global _fill_mode
|
|
11
|
+
tfill = _fill_mode
|
|
12
|
+
_fill_mode = False
|
|
13
|
+
return tfill
|
|
14
|
+
def init():
|
|
15
|
+
global init_state
|
|
16
|
+
if not init_state:
|
|
17
|
+
pygame.init()
|
|
18
|
+
pygame.key.set_repeat(500, 50)
|
|
19
|
+
init_state = True
|
|
20
|
+
set_fill_mode(_fill_mode)
|
|
21
|
+
|
Kernel/KernelAudio.py
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import pygame
|
|
2
|
+
import miniaudio
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
class Audio:
|
|
6
|
+
def __init__(self, filepath: str):
|
|
7
|
+
ext = os.path.splitext(filepath)[1].lower()
|
|
8
|
+
valid_exts = ('.mp3', '.wav', '.ogg', '.flac', '.m4a', '.aac')
|
|
9
|
+
if not os.path.exists(filepath):
|
|
10
|
+
raise FileNotFoundError(f"Audio file not found: {filepath}")
|
|
11
|
+
if ext not in valid_exts:
|
|
12
|
+
raise ValueError(f"Unsupported format: {ext}. Supported: {valid_exts}")
|
|
13
|
+
self.filepath = filepath
|
|
14
|
+
self.backend = self._detect_backend()
|
|
15
|
+
self._load()
|
|
16
|
+
self._stream = None
|
|
17
|
+
self._paused = False
|
|
18
|
+
self._volume = 1.0
|
|
19
|
+
def _detect_backend(self):
|
|
20
|
+
try:
|
|
21
|
+
import miniaudio
|
|
22
|
+
return 'miniaudio'
|
|
23
|
+
except ImportError:
|
|
24
|
+
return 'pygame'
|
|
25
|
+
|
|
26
|
+
def _load(self):
|
|
27
|
+
if self.backend == 'miniaudio':
|
|
28
|
+
self._info = miniaudio.get_file_info(self.filepath)
|
|
29
|
+
self._stream = None
|
|
30
|
+
else: # pygame
|
|
31
|
+
self._sound = pygame.mixer.Sound(self.filepath)
|
|
32
|
+
|
|
33
|
+
def play(self, loop=False, volume=None):
|
|
34
|
+
play_volume = volume if volume is not None else self._volume
|
|
35
|
+
|
|
36
|
+
if self.backend == 'miniaudio':
|
|
37
|
+
self._stream = miniaudio.play_file(
|
|
38
|
+
self.filepath,
|
|
39
|
+
loop=loop,
|
|
40
|
+
volume=play_volume
|
|
41
|
+
)
|
|
42
|
+
else: # pygame
|
|
43
|
+
self._sound.set_volume(play_volume)
|
|
44
|
+
self._sound.play(-1 if loop else 0)
|
|
45
|
+
|
|
46
|
+
self._paused = False
|
|
47
|
+
def stop(self):
|
|
48
|
+
if self.backend == 'miniaudio' and self._stream:
|
|
49
|
+
self._stream.stop()
|
|
50
|
+
self._stream = None
|
|
51
|
+
else:
|
|
52
|
+
self._sound.stop()
|
|
53
|
+
|
|
54
|
+
@property
|
|
55
|
+
def duration(self):
|
|
56
|
+
if self.backend == 'miniaudio':
|
|
57
|
+
return self._info.duration
|
|
58
|
+
else:
|
|
59
|
+
return self._sound.get_length()
|
|
60
|
+
def pause(self):
|
|
61
|
+
if self.backend == 'miniaudio' and self._stream:
|
|
62
|
+
self._stream.pause()
|
|
63
|
+
self._paused = True
|
|
64
|
+
elif self.backend == 'pygame':
|
|
65
|
+
pygame.mixer.pause()
|
|
66
|
+
def resume(self):
|
|
67
|
+
if self.backend == 'miniaudio' and self._stream and self._paused:
|
|
68
|
+
self._stream.resume()
|
|
69
|
+
self._paused = False
|
|
70
|
+
elif self.backend == 'pygame':
|
|
71
|
+
pygame.mixer.unpause()
|
|
72
|
+
|
|
73
|
+
def set_volume(self, volume: float):
|
|
74
|
+
self._volume = max(0.0, min(1.0, volume))
|
|
75
|
+
|
|
76
|
+
if self.backend == 'miniaudio' and self._stream:
|
|
77
|
+
self._stream.volume = self._volume
|
|
78
|
+
elif self.backend == 'pygame' and hasattr(self, '_sound'):
|
|
79
|
+
self._sound.set_volume(self._volume)
|
|
80
|
+
|
|
81
|
+
def get_volume(self) -> float:
|
|
82
|
+
return self._volume
|
|
83
|
+
|
|
84
|
+
def fade_out(self, duration_ms: int):
|
|
85
|
+
if self.backend == 'miniaudio' and self._stream:
|
|
86
|
+
self._stream.fade_out(duration_ms)
|
|
87
|
+
elif self.backend == 'pygame':
|
|
88
|
+
self._sound.fadeout(duration_ms)
|
|
89
|
+
|
|
90
|
+
def fade_in(self, duration_ms: int, loop=False):
|
|
91
|
+
if self.backend == 'miniaudio':
|
|
92
|
+
self._stream = miniaudio.play_file(
|
|
93
|
+
self.filepath,
|
|
94
|
+
loop=loop,
|
|
95
|
+
volume=0.0
|
|
96
|
+
)
|
|
97
|
+
self._stream.fade_in(duration_ms, target_volume=self._volume)
|
Kernel/KernelColor.py
ADDED
|
@@ -0,0 +1,420 @@
|
|
|
1
|
+
import re
|
|
2
|
+
FLOAT_ERROR = 0.0000005
|
|
3
|
+
NAMES_TO_HEX = {
|
|
4
|
+
"aliceblue": "#f0f8ff",
|
|
5
|
+
"antiquewhite": "#faebd7",
|
|
6
|
+
"aqua": "#00ffff",
|
|
7
|
+
"aquamarine": "#7fffd4",
|
|
8
|
+
"azure": "#f0ffff",
|
|
9
|
+
"beige": "#f5f5dc",
|
|
10
|
+
"bisque": "#ffe4c4",
|
|
11
|
+
"black": "#000000",
|
|
12
|
+
"blanchedalmond": "#ffebcd",
|
|
13
|
+
"blue": "#0000ff",
|
|
14
|
+
"blueviolet": "#8a2be2",
|
|
15
|
+
"brown": "#a52a2a",
|
|
16
|
+
"burlywood": "#deb887",
|
|
17
|
+
"cadetblue": "#5f9ea0",
|
|
18
|
+
"chartreuse": "#7fff00",
|
|
19
|
+
"chocolate": "#d2691e",
|
|
20
|
+
"coral": "#ff7f50",
|
|
21
|
+
"cornflowerblue": "#6495ed",
|
|
22
|
+
"cornsilk": "#fff8dc",
|
|
23
|
+
"crimson": "#dc143c",
|
|
24
|
+
"cyan": "#00ffff",
|
|
25
|
+
"darkblue": "#00008b",
|
|
26
|
+
"darkcyan": "#008b8b",
|
|
27
|
+
"darkgoldenrod": "#b8860b",
|
|
28
|
+
"darkgray": "#a9a9a9",
|
|
29
|
+
"darkgrey": "#a9a9a9",
|
|
30
|
+
"darkgreen": "#006400",
|
|
31
|
+
"darkkhaki": "#bdb76b",
|
|
32
|
+
"darkmagenta": "#8b008b",
|
|
33
|
+
"darkolivegreen": "#556b2f",
|
|
34
|
+
"darkorange": "#ff8c00",
|
|
35
|
+
"darkorchid": "#9932cc",
|
|
36
|
+
"darkred": "#8b0000",
|
|
37
|
+
"darksalmon": "#e9967a",
|
|
38
|
+
"darkseagreen": "#8fbc8f",
|
|
39
|
+
"darkslateblue": "#483d8b",
|
|
40
|
+
"darkslategray": "#2f4f4f",
|
|
41
|
+
"darkslategrey": "#2f4f4f",
|
|
42
|
+
"darkturquoise": "#00ced1",
|
|
43
|
+
"darkviolet": "#9400d3",
|
|
44
|
+
"deeppink": "#ff1493",
|
|
45
|
+
"deepskyblue": "#00bfff",
|
|
46
|
+
"dimgray": "#696969",
|
|
47
|
+
"dimgrey": "#696969",
|
|
48
|
+
"dodgerblue": "#1e90ff",
|
|
49
|
+
"firebrick": "#b22222",
|
|
50
|
+
"floralwhite": "#fffaf0",
|
|
51
|
+
"forestgreen": "#228b22",
|
|
52
|
+
"fuchsia": "#ff00ff",
|
|
53
|
+
"gainsboro": "#dcdcdc",
|
|
54
|
+
"ghostwhite": "#f8f8ff",
|
|
55
|
+
"gold": "#ffd700",
|
|
56
|
+
"goldenrod": "#daa520",
|
|
57
|
+
"gray": "#808080",
|
|
58
|
+
"grey": "#808080",
|
|
59
|
+
"green": "#008000",
|
|
60
|
+
"greenyellow": "#adff2f",
|
|
61
|
+
"honeydew": "#f0fff0",
|
|
62
|
+
"hotpink": "#ff69b4",
|
|
63
|
+
"indianred": "#cd5c5c",
|
|
64
|
+
"indigo": "#4b0082",
|
|
65
|
+
"ivory": "#fffff0",
|
|
66
|
+
"khaki": "#f0e68c",
|
|
67
|
+
"lavender": "#e6e6fa",
|
|
68
|
+
"lavenderblush": "#fff0f5",
|
|
69
|
+
"lawngreen": "#7cfc00",
|
|
70
|
+
"lemonchiffon": "#fffacd",
|
|
71
|
+
"lightblue": "#add8e6",
|
|
72
|
+
"lightcoral": "#f08080",
|
|
73
|
+
"lightcyan": "#e0ffff",
|
|
74
|
+
"lightgoldenrodyellow": "#fafad2",
|
|
75
|
+
"lightgray": "#d3d3d3",
|
|
76
|
+
"lightgrey": "#d3d3d3",
|
|
77
|
+
"lightgreen": "#90ee90",
|
|
78
|
+
"lightpink": "#ffb6c1",
|
|
79
|
+
"lightsalmon": "#ffa07a",
|
|
80
|
+
"lightseagreen": "#20b2aa",
|
|
81
|
+
"lightskyblue": "#87cefa",
|
|
82
|
+
"lightslategray": "#778899",
|
|
83
|
+
"lightslategrey": "#778899",
|
|
84
|
+
"lightsteelblue": "#b0c4de",
|
|
85
|
+
"lightyellow": "#ffffe0",
|
|
86
|
+
"lime": "#00ff00",
|
|
87
|
+
"limegreen": "#32cd32",
|
|
88
|
+
"linen": "#faf0e6",
|
|
89
|
+
"magenta": "#ff00ff",
|
|
90
|
+
"maroon": "#800000",
|
|
91
|
+
"mediumaquamarine": "#66cdaa",
|
|
92
|
+
"mediumblue": "#0000cd",
|
|
93
|
+
"mediumorchid": "#ba55d3",
|
|
94
|
+
"mediumpurple": "#9370db",
|
|
95
|
+
"mediumseagreen": "#3cb371",
|
|
96
|
+
"mediumslateblue": "#7b68ee",
|
|
97
|
+
"mediumspringgreen": "#00fa9a",
|
|
98
|
+
"mediumturquoise": "#48d1cc",
|
|
99
|
+
"mediumvioletred": "#c71585",
|
|
100
|
+
"midnightblue": "#191970",
|
|
101
|
+
"mintcream": "#f5fffa",
|
|
102
|
+
"mistyrose": "#ffe4e1",
|
|
103
|
+
"moccasin": "#ffe4b5",
|
|
104
|
+
"navajowhite": "#ffdead",
|
|
105
|
+
"navy": "#000080",
|
|
106
|
+
"oldlace": "#fdf5e6",
|
|
107
|
+
"olive": "#808000",
|
|
108
|
+
"olivedrab": "#6b8e23",
|
|
109
|
+
"orange": "#ffa500",
|
|
110
|
+
"orangered": "#ff4500",
|
|
111
|
+
"orchid": "#da70d6",
|
|
112
|
+
"palegoldenrod": "#eee8aa",
|
|
113
|
+
"palegreen": "#98fb98",
|
|
114
|
+
"paleturquoise": "#afeeee",
|
|
115
|
+
"palevioletred": "#db7093",
|
|
116
|
+
"papayawhip": "#ffefd5",
|
|
117
|
+
"peachpuff": "#ffdab9",
|
|
118
|
+
"peru": "#cd853f",
|
|
119
|
+
"pink": "#ffc0cb",
|
|
120
|
+
"plum": "#dda0dd",
|
|
121
|
+
"powderblue": "#b0e0e6",
|
|
122
|
+
"purple": "#800080",
|
|
123
|
+
"red": "#ff0000",
|
|
124
|
+
"rosybrown": "#bc8f8f",
|
|
125
|
+
"royalblue": "#4169e1",
|
|
126
|
+
"saddlebrown": "#8b4513",
|
|
127
|
+
"salmon": "#fa8072",
|
|
128
|
+
"sandybrown": "#f4a460",
|
|
129
|
+
"seagreen": "#2e8b57",
|
|
130
|
+
"seashell": "#fff5ee",
|
|
131
|
+
"sienna": "#a0522d",
|
|
132
|
+
"silver": "#c0c0c0",
|
|
133
|
+
"skyblue": "#87ceeb",
|
|
134
|
+
"slateblue": "#6a5acd",
|
|
135
|
+
"slategray": "#708090",
|
|
136
|
+
"slategrey": "#708090",
|
|
137
|
+
"snow": "#fffafa",
|
|
138
|
+
"springgreen": "#00ff7f",
|
|
139
|
+
"steelblue": "#4682b4",
|
|
140
|
+
"tan": "#d2b48c",
|
|
141
|
+
"teal": "#008080",
|
|
142
|
+
"thistle": "#d8bfd8",
|
|
143
|
+
"tomato": "#ff6347",
|
|
144
|
+
"turquoise": "#40e0d0",
|
|
145
|
+
"violet": "#ee82ee",
|
|
146
|
+
"wheat": "#f5deb3",
|
|
147
|
+
"white": "#ffffff",
|
|
148
|
+
"whitesmoke": "#f5f5f5",
|
|
149
|
+
"yellow": "#ffff00",
|
|
150
|
+
"yellowgreen": "#9acd32",
|
|
151
|
+
}
|
|
152
|
+
class ColorTools:
|
|
153
|
+
def name_to_hex(self, name: str) -> str:
|
|
154
|
+
if hex_value := NAMES_TO_HEX.get(name.lower()):
|
|
155
|
+
return hex_value
|
|
156
|
+
raise ValueError(f'"{name}" is not defined as a named color in CSS3')
|
|
157
|
+
def hex_to_rgb(self, hex_value: str):
|
|
158
|
+
int_value = int(self.normalize_hex(hex_value)[1:], 16)
|
|
159
|
+
return int_value >> 16, int_value >> 8 & 0xFF, int_value & 0xFF
|
|
160
|
+
def name_to_rgb(self, name):
|
|
161
|
+
return self.hex_to_rgb(self.name_to_hex(name))
|
|
162
|
+
def normalize_hex(self, hex_value : str):
|
|
163
|
+
if (match := re.compile(r"^#([a-fA-F0-9]{3}|[a-fA-F0-9]{6})$").match(hex_value)) is None:
|
|
164
|
+
raise ValueError(f'"{hex_value}" is not a valid hexadecimal color value.')
|
|
165
|
+
hex_digits = match.group(1)
|
|
166
|
+
if len(hex_digits) == 3:
|
|
167
|
+
hex_digits = "".join(2 * s for s in hex_digits)
|
|
168
|
+
return f"#{hex_digits.lower()}"
|
|
169
|
+
|
|
170
|
+
def hue_to_rgb(self, v1, v2, vH):
|
|
171
|
+
|
|
172
|
+
while vH < 0: vH += 1
|
|
173
|
+
while vH > 1: vH -= 1
|
|
174
|
+
|
|
175
|
+
if 6 * vH < 1: return v1 + (v2 - v1) * 6 * vH
|
|
176
|
+
if 2 * vH < 1: return v2
|
|
177
|
+
if 3 * vH < 2: return v1 + (v2 - v1) * ((2.0 / 3) - vH) * 6
|
|
178
|
+
|
|
179
|
+
return v1
|
|
180
|
+
def hsl_to_rgb(self, hsl):
|
|
181
|
+
h, s, l = (float(v) for v in hsl)
|
|
182
|
+
|
|
183
|
+
if not (0.0 - FLOAT_ERROR <= s <= 1.0 + FLOAT_ERROR):
|
|
184
|
+
raise ValueError("Saturation must be between 0 and 1.")
|
|
185
|
+
if not (0.0 - FLOAT_ERROR <= l <= 1.0 + FLOAT_ERROR):
|
|
186
|
+
raise ValueError("Lightness must be between 0 and 1.")
|
|
187
|
+
|
|
188
|
+
if s == 0:
|
|
189
|
+
return l, l, l
|
|
190
|
+
|
|
191
|
+
if l < 0.5:
|
|
192
|
+
v2 = l * (1.0 + s)
|
|
193
|
+
else:
|
|
194
|
+
v2 = (l + s) - (s * l)
|
|
195
|
+
|
|
196
|
+
v1 = 2.0 * l - v2
|
|
197
|
+
|
|
198
|
+
r = self.hue_to_rgb(v1, v2, h + (1.0 / 3))
|
|
199
|
+
g = self.hue_to_rgb(v1, v2, h)
|
|
200
|
+
b = self.hue_to_rgb(v1, v2, h - (1.0 / 3))
|
|
201
|
+
|
|
202
|
+
return r, g, b
|
|
203
|
+
|
|
204
|
+
def rgb_to_hsl(self, rgb):
|
|
205
|
+
r, g, b = (float(v) for v in rgb)
|
|
206
|
+
|
|
207
|
+
for name, v in {'Red': r, 'Green': g, 'Blue': b}.items():
|
|
208
|
+
if not (0 - FLOAT_ERROR <= v <= 1 + FLOAT_ERROR):
|
|
209
|
+
raise ValueError("%s must be between 0 and 1. You provided %r."
|
|
210
|
+
% (name, v))
|
|
211
|
+
|
|
212
|
+
vmin = min(r, g, b) ## Min. value of RGB
|
|
213
|
+
vmax = max(r, g, b) ## Max. value of RGB
|
|
214
|
+
diff = vmax - vmin ## Delta RGB value
|
|
215
|
+
|
|
216
|
+
vsum = vmin + vmax
|
|
217
|
+
|
|
218
|
+
l = vsum / 2
|
|
219
|
+
|
|
220
|
+
if diff < FLOAT_ERROR:
|
|
221
|
+
return 0.0, 0.0, l
|
|
222
|
+
|
|
223
|
+
##
|
|
224
|
+
## Chromatic data...
|
|
225
|
+
##
|
|
226
|
+
|
|
227
|
+
## Saturation
|
|
228
|
+
if l < 0.5:
|
|
229
|
+
s = diff / vsum
|
|
230
|
+
else:
|
|
231
|
+
s = diff / (2.0 - vsum)
|
|
232
|
+
|
|
233
|
+
dr = (((vmax - r) / 6) + (diff / 2)) / diff
|
|
234
|
+
dg = (((vmax - g) / 6) + (diff / 2)) / diff
|
|
235
|
+
db = (((vmax - b) / 6) + (diff / 2)) / diff
|
|
236
|
+
|
|
237
|
+
if r == vmax:
|
|
238
|
+
h = db - dg
|
|
239
|
+
elif g == vmax:
|
|
240
|
+
h = (1.0 / 3) + dr - db
|
|
241
|
+
elif b == vmax:
|
|
242
|
+
h = (2.0 / 3) + dg - dr
|
|
243
|
+
|
|
244
|
+
if h < 0: h += 1
|
|
245
|
+
if h > 1: h -= 1
|
|
246
|
+
|
|
247
|
+
return h, s, l
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
class GradientGenerator:
|
|
251
|
+
def linear_gradient(self, color_start, color_end, steps):
|
|
252
|
+
gradient = []
|
|
253
|
+
for i in range(steps):
|
|
254
|
+
ratio = i / (steps - 1)
|
|
255
|
+
# Trộn màu
|
|
256
|
+
r = int(color_start[0] + (color_end[0] - color_start[0]) * ratio)
|
|
257
|
+
g = int(color_start[1] + (color_end[1] - color_start[1]) * ratio)
|
|
258
|
+
b = int(color_start[2] + (color_end[2] - color_start[2]) * ratio)
|
|
259
|
+
gradient.append((r, g, b))
|
|
260
|
+
return gradient
|
|
261
|
+
|
|
262
|
+
def multi_gradient(self, colors, steps):
|
|
263
|
+
gradient = []
|
|
264
|
+
segments = len(colors) - 1
|
|
265
|
+
steps_per_segment = steps // segments
|
|
266
|
+
|
|
267
|
+
for i in range(segments):
|
|
268
|
+
segment_grad = self.linear_gradient(
|
|
269
|
+
colors[i], colors[i + 1], steps_per_segment
|
|
270
|
+
)
|
|
271
|
+
gradient.extend(segment_grad)
|
|
272
|
+
|
|
273
|
+
return gradient
|
|
274
|
+
aliceblue = "#f0f8ff"
|
|
275
|
+
antiquewhite = "#faebd7"
|
|
276
|
+
aqua = "#00ffff"
|
|
277
|
+
aquamarine = "#7fffd4"
|
|
278
|
+
azure = "#f0ffff"
|
|
279
|
+
beige = "#f5f5dc"
|
|
280
|
+
bisque = "#ffe4c4"
|
|
281
|
+
black = "#000000"
|
|
282
|
+
blanchedalmond = "#ffebcd"
|
|
283
|
+
blue = "#0000ff"
|
|
284
|
+
blueviolet = "#8a2be2"
|
|
285
|
+
brown = "#a52a2a"
|
|
286
|
+
burlywood = "#deb887"
|
|
287
|
+
cadetblue = "#5f9ea0"
|
|
288
|
+
chartreuse = "#7fff00"
|
|
289
|
+
chocolate = "#d2691e"
|
|
290
|
+
coral = "#ff7f50"
|
|
291
|
+
cornflowerblue = "#6495ed"
|
|
292
|
+
cornsilk = "#fff8dc"
|
|
293
|
+
crimson = "#dc143c"
|
|
294
|
+
cyan = "#00ffff"
|
|
295
|
+
darkblue = "#00008b"
|
|
296
|
+
darkcyan = "#008b8b"
|
|
297
|
+
darkgoldenrod = "#b8860b"
|
|
298
|
+
darkgray = "#a9a9a9"
|
|
299
|
+
darkgrey = "#a9a9a9"
|
|
300
|
+
darkgreen = "#006400"
|
|
301
|
+
darkkhaki = "#bdb76b"
|
|
302
|
+
darkmagenta = "#8b008b"
|
|
303
|
+
darkolivegreen = "#556b2f"
|
|
304
|
+
darkorange = "#ff8c00"
|
|
305
|
+
darkorchid = "#9932cc"
|
|
306
|
+
darkred = "#8b0000"
|
|
307
|
+
darksalmon = "#e9967a"
|
|
308
|
+
darkseagreen = "#8fbc8f"
|
|
309
|
+
darkslateblue = "#483d8b"
|
|
310
|
+
darkslategray = "#2f4f4f"
|
|
311
|
+
darkslategrey = "#2f4f4f"
|
|
312
|
+
darkturquoise = "#00ced1"
|
|
313
|
+
darkviolet = "#9400d3"
|
|
314
|
+
deeppink = "#ff1493"
|
|
315
|
+
deepskyblue = "#00bfff"
|
|
316
|
+
dimgray = "#696969"
|
|
317
|
+
dimgrey = "#696969"
|
|
318
|
+
dodgerblue = "#1e90ff"
|
|
319
|
+
firebrick = "#b22222"
|
|
320
|
+
floralwhite = "#fffaf0"
|
|
321
|
+
forestgreen = "#228b22"
|
|
322
|
+
fuchsia = "#ff00ff"
|
|
323
|
+
gainsboro = "#dcdcdc"
|
|
324
|
+
ghostwhite = "#f8f8ff"
|
|
325
|
+
gold = "#ffd700"
|
|
326
|
+
goldenrod = "#daa520"
|
|
327
|
+
gray = "#808080"
|
|
328
|
+
grey = "#808080"
|
|
329
|
+
green = "#008000"
|
|
330
|
+
greenyellow = "#adff2f"
|
|
331
|
+
honeydew = "#f0fff0"
|
|
332
|
+
hotpink = "#ff69b4"
|
|
333
|
+
indianred = "#cd5c5c"
|
|
334
|
+
indigo = "#4b0082"
|
|
335
|
+
ivory = "#fffff0"
|
|
336
|
+
khaki = "#f0e68c"
|
|
337
|
+
lavender = "#e6e6fa"
|
|
338
|
+
lavenderblush = "#fff0f5"
|
|
339
|
+
lawngreen = "#7cfc00"
|
|
340
|
+
lemonchiffon = "#fffacd"
|
|
341
|
+
lightblue = "#add8e6"
|
|
342
|
+
lightcoral = "#f08080"
|
|
343
|
+
lightcyan = "#e0ffff"
|
|
344
|
+
lightgoldenrodyellow = "#fafad2"
|
|
345
|
+
lightgray = "#d3d3d3"
|
|
346
|
+
lightgrey = "#d3d3d3"
|
|
347
|
+
lightgreen = "#90ee90"
|
|
348
|
+
lightpink = "#ffb6c1"
|
|
349
|
+
lightsalmon = "#ffa07a"
|
|
350
|
+
lightseagreen = "#20b2aa"
|
|
351
|
+
lightskyblue = "#87cefa"
|
|
352
|
+
lightslategray = "#778899"
|
|
353
|
+
lightslategrey = "#778899"
|
|
354
|
+
lightsteelblue = "#b0c4de"
|
|
355
|
+
lightyellow = "#ffffe0"
|
|
356
|
+
lime = "#00ff00"
|
|
357
|
+
limegreen = "#32cd32"
|
|
358
|
+
linen = "#faf0e6"
|
|
359
|
+
magenta = "#ff00ff"
|
|
360
|
+
maroon = "#800000"
|
|
361
|
+
mediumaquamarine = "#66cdaa"
|
|
362
|
+
mediumblue = "#0000cd"
|
|
363
|
+
mediumorchid = "#ba55d3"
|
|
364
|
+
mediumpurple = "#9370db"
|
|
365
|
+
mediumseagreen = "#3cb371"
|
|
366
|
+
mediumslateblue = "#7b68ee"
|
|
367
|
+
mediumspringgreen = "#00fa9a"
|
|
368
|
+
mediumturquoise = "#48d1cc"
|
|
369
|
+
mediumvioletred = "#c71585"
|
|
370
|
+
midnightblue = "#191970"
|
|
371
|
+
mintcream = "#f5fffa"
|
|
372
|
+
mistyrose = "#ffe4e1"
|
|
373
|
+
moccasin = "#ffe4b5"
|
|
374
|
+
navajowhite = "#ffdead"
|
|
375
|
+
navy = "#000080"
|
|
376
|
+
oldlace = "#fdf5e6"
|
|
377
|
+
olive = "#808000"
|
|
378
|
+
olivedrab = "#6b8e23"
|
|
379
|
+
orange = "#ffa500"
|
|
380
|
+
orangered = "#ff4500"
|
|
381
|
+
orchid = "#da70d6"
|
|
382
|
+
palegoldenrod = "#eee8aa"
|
|
383
|
+
palegreen = "#98fb98"
|
|
384
|
+
paleturquoise = "#afeeee"
|
|
385
|
+
palevioletred = "#db7093"
|
|
386
|
+
papayawhip = "#ffefd5"
|
|
387
|
+
peachpuff = "#ffdab9"
|
|
388
|
+
peru = "#cd853f"
|
|
389
|
+
pink = "#ffc0cb"
|
|
390
|
+
plum = "#dda0dd"
|
|
391
|
+
powderblue = "#b0e0e6"
|
|
392
|
+
purple = "#800080"
|
|
393
|
+
red = "#ff0000"
|
|
394
|
+
rosybrown = "#bc8f8f"
|
|
395
|
+
royalblue = "#4169e1"
|
|
396
|
+
saddlebrown = "#8b4513"
|
|
397
|
+
salmon = "#fa8072"
|
|
398
|
+
sandybrown = "#f4a460"
|
|
399
|
+
seagreen = "#2e8b57"
|
|
400
|
+
seashell = "#fff5ee"
|
|
401
|
+
sienna = "#a0522d"
|
|
402
|
+
silver = "#c0c0c0"
|
|
403
|
+
skyblue = "#87ceeb"
|
|
404
|
+
slateblue = "#6a5acd"
|
|
405
|
+
slategray = "#708090"
|
|
406
|
+
slategrey = "#708090"
|
|
407
|
+
snow = "#fffafa"
|
|
408
|
+
springgreen = "#00ff7f"
|
|
409
|
+
steelblue = "#4682b4"
|
|
410
|
+
tan = "#d2b48c"
|
|
411
|
+
teal = "#008080"
|
|
412
|
+
thistle = "#d8bfd8"
|
|
413
|
+
tomato = "#ff6347"
|
|
414
|
+
turquoise = "#40e0d0"
|
|
415
|
+
violet = "#ee82ee"
|
|
416
|
+
wheat = "#f5deb3"
|
|
417
|
+
white = "#ffffff"
|
|
418
|
+
whitesmoke = "#f5f5f5"
|
|
419
|
+
yellow = "#ffff00"
|
|
420
|
+
yellowgreen = "#9acd32"
|