pyblend2d 0.21.2__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.
- blend2d/__init__.py +284 -0
- blend2d/_bin/blend2d_fx.lib +0 -0
- blend2d/_bin/blend2d_geo.lib +0 -0
- blend2d/_bin/blend2d_motion.lib +0 -0
- blend2d/_bin/blend2d_perspective.lib +0 -0
- blend2d/_bin/blend2d_video.lib +0 -0
- blend2d/_bin/libblend2d.dll +0 -0
- blend2d/_bin/libblend2d.so +0 -0
- blend2d/_bin/libblend2d_fx.dll +0 -0
- blend2d/_bin/libblend2d_fx.pdb +0 -0
- blend2d/_bin/libblend2d_geo.dll +0 -0
- blend2d/_bin/libblend2d_geo.pdb +0 -0
- blend2d/_bin/libblend2d_motion.dll +0 -0
- blend2d/_bin/libblend2d_motion.pdb +0 -0
- blend2d/_bin/libblend2d_perspective.dll +0 -0
- blend2d/_bin/libblend2d_perspective.pdb +0 -0
- blend2d/_bin/libblend2d_video.dll +0 -0
- blend2d/_bin/libblend2d_video.pdb +0 -0
- blend2d/color.py +202 -0
- blend2d/context.py +1439 -0
- blend2d/diagnostics.py +201 -0
- blend2d/enums.py +272 -0
- blend2d/ffi.py +1301 -0
- blend2d/font.py +251 -0
- blend2d/fx/__init__.py +55 -0
- blend2d/fx/_ffi.py +74 -0
- blend2d/fx/blur.py +39 -0
- blend2d/fx/color_grade.py +73 -0
- blend2d/fx/glitch.py +61 -0
- blend2d/fx/glow.py +104 -0
- blend2d/fx/lens.py +98 -0
- blend2d/fx/pipeline.py +105 -0
- blend2d/geometry.py +242 -0
- blend2d/image.py +349 -0
- blend2d/matrix.py +153 -0
- blend2d/motion/__init__.py +74 -0
- blend2d/motion/easing.py +410 -0
- blend2d/motion/particles.py +345 -0
- blend2d/motion/path_anim.py +303 -0
- blend2d/motion/perspective.py +426 -0
- blend2d/motion/scene.py +237 -0
- blend2d/motion/timeline.py +208 -0
- blend2d/path.py +582 -0
- blend2d/py.typed +1 -0
- blend2d/shapgeo.py +705 -0
- blend2d/shapgeo_downloader.py +159 -0
- blend2d/shapgeo_io.py +303 -0
- blend2d/shapgeo_proj.py +242 -0
- blend2d/style.py +210 -0
- blend2d/svg.py +383 -0
- blend2d/video.py +498 -0
- blend2d-src/blend2d-version.py +23 -0
- pyblend2d-0.21.2.dist-info/METADATA +318 -0
- pyblend2d-0.21.2.dist-info/RECORD +56 -0
- pyblend2d-0.21.2.dist-info/WHEEL +5 -0
- pyblend2d-0.21.2.dist-info/top_level.txt +2 -0
blend2d/__init__.py
ADDED
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
"""
|
|
2
|
+
PyBlend: High-Performance 2D Vector Graphics Engine for Python powered by Blend2D.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from blend2d.enums import (
|
|
6
|
+
Format,
|
|
7
|
+
CompOp,
|
|
8
|
+
FillRule,
|
|
9
|
+
GeometryType,
|
|
10
|
+
ExtendMode,
|
|
11
|
+
GradientType,
|
|
12
|
+
StrokeCap,
|
|
13
|
+
StrokeCapPosition,
|
|
14
|
+
StrokeJoin,
|
|
15
|
+
StrokeTransformOrder,
|
|
16
|
+
TransformOp,
|
|
17
|
+
ClipOp,
|
|
18
|
+
FlattenMode,
|
|
19
|
+
RenderingEngine,
|
|
20
|
+
ResultCode,
|
|
21
|
+
ContextHint,
|
|
22
|
+
RenderingQuality,
|
|
23
|
+
GradientQuality,
|
|
24
|
+
PatternQuality,
|
|
25
|
+
RuntimeInfoType,
|
|
26
|
+
RuntimeCpuArch,
|
|
27
|
+
RuntimeCpuFeatures,
|
|
28
|
+
)
|
|
29
|
+
from blend2d.ffi import Blend2DError
|
|
30
|
+
from blend2d.geometry import (
|
|
31
|
+
Point,
|
|
32
|
+
PointI,
|
|
33
|
+
Size,
|
|
34
|
+
SizeI,
|
|
35
|
+
Rect,
|
|
36
|
+
RectI,
|
|
37
|
+
Box,
|
|
38
|
+
BoxI,
|
|
39
|
+
Circle,
|
|
40
|
+
Ellipse,
|
|
41
|
+
RoundRect,
|
|
42
|
+
Triangle,
|
|
43
|
+
Arc,
|
|
44
|
+
Line,
|
|
45
|
+
)
|
|
46
|
+
from blend2d.matrix import Matrix2D
|
|
47
|
+
from blend2d.color import (
|
|
48
|
+
Rgba32,
|
|
49
|
+
Rgba,
|
|
50
|
+
parse_color,
|
|
51
|
+
NAMED_COLORS,
|
|
52
|
+
)
|
|
53
|
+
from blend2d.image import Image
|
|
54
|
+
from blend2d.path import Path
|
|
55
|
+
from blend2d.style import (
|
|
56
|
+
Gradient,
|
|
57
|
+
LinearGradient,
|
|
58
|
+
RadialGradient,
|
|
59
|
+
ConicGradient,
|
|
60
|
+
Pattern,
|
|
61
|
+
)
|
|
62
|
+
from blend2d.font import (
|
|
63
|
+
FontFace,
|
|
64
|
+
Font,
|
|
65
|
+
FontMetrics,
|
|
66
|
+
TextMetrics,
|
|
67
|
+
)
|
|
68
|
+
from blend2d.context import Context
|
|
69
|
+
from blend2d.diagnostics import (
|
|
70
|
+
diagnose_environment,
|
|
71
|
+
print_diagnostic_report,
|
|
72
|
+
get_error_details,
|
|
73
|
+
get_runtime_info,
|
|
74
|
+
)
|
|
75
|
+
from blend2d import svg
|
|
76
|
+
from blend2d.svg import SvgContext, export_svg
|
|
77
|
+
from blend2d import video
|
|
78
|
+
from blend2d.video import (
|
|
79
|
+
VideoWriter,
|
|
80
|
+
VideoReader,
|
|
81
|
+
record_animation,
|
|
82
|
+
detect_hardware_encoders,
|
|
83
|
+
VideoError,
|
|
84
|
+
CodecNotFoundError,
|
|
85
|
+
FrameFormatError,
|
|
86
|
+
)
|
|
87
|
+
from blend2d import shapgeo
|
|
88
|
+
from blend2d.shapgeo import (
|
|
89
|
+
GeoCanvas,
|
|
90
|
+
GeoTransform,
|
|
91
|
+
from_shapely,
|
|
92
|
+
from_geojson,
|
|
93
|
+
from_wkt,
|
|
94
|
+
render_gdf,
|
|
95
|
+
auto_bounds,
|
|
96
|
+
read_file,
|
|
97
|
+
read_shapefile,
|
|
98
|
+
read_geojson,
|
|
99
|
+
proj,
|
|
100
|
+
Transformer,
|
|
101
|
+
to_web_mercator,
|
|
102
|
+
to_wgs84,
|
|
103
|
+
reproject_gdf,
|
|
104
|
+
downloader,
|
|
105
|
+
download_dataset,
|
|
106
|
+
load_dataset,
|
|
107
|
+
register_dataset,
|
|
108
|
+
)
|
|
109
|
+
from blend2d import motion
|
|
110
|
+
from blend2d.motion import (
|
|
111
|
+
Timeline,
|
|
112
|
+
Easing,
|
|
113
|
+
Spring,
|
|
114
|
+
CubicBezier,
|
|
115
|
+
trim_path,
|
|
116
|
+
PathFollower,
|
|
117
|
+
PathMorph,
|
|
118
|
+
ParticleSystem,
|
|
119
|
+
Camera2D,
|
|
120
|
+
PerspectiveCamera,
|
|
121
|
+
render_globe,
|
|
122
|
+
Node,
|
|
123
|
+
Layer,
|
|
124
|
+
Scene,
|
|
125
|
+
)
|
|
126
|
+
from blend2d import fx
|
|
127
|
+
from blend2d.fx import (
|
|
128
|
+
FXPipeline,
|
|
129
|
+
gaussian_blur,
|
|
130
|
+
box_blur,
|
|
131
|
+
bloom,
|
|
132
|
+
neon_glow,
|
|
133
|
+
drop_shadow,
|
|
134
|
+
chromatic_aberration,
|
|
135
|
+
vignette,
|
|
136
|
+
film_grain,
|
|
137
|
+
color_grade,
|
|
138
|
+
grayscale,
|
|
139
|
+
invert,
|
|
140
|
+
sepia,
|
|
141
|
+
scanlines,
|
|
142
|
+
glitch_displacement,
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
# Alias geo -> shapgeo for developer convenience
|
|
146
|
+
geo = shapgeo
|
|
147
|
+
|
|
148
|
+
__version__ = "0.21.2"
|
|
149
|
+
__author__ = "Islam Arifi, PyBlend Team, Blend2D Authors"
|
|
150
|
+
|
|
151
|
+
__all__ = [
|
|
152
|
+
# Core
|
|
153
|
+
"Image",
|
|
154
|
+
"Context",
|
|
155
|
+
"Path",
|
|
156
|
+
"Blend2DError",
|
|
157
|
+
# Post-Processing FX Engine
|
|
158
|
+
"fx",
|
|
159
|
+
"FXPipeline",
|
|
160
|
+
"gaussian_blur",
|
|
161
|
+
"box_blur",
|
|
162
|
+
"bloom",
|
|
163
|
+
"neon_glow",
|
|
164
|
+
"drop_shadow",
|
|
165
|
+
"chromatic_aberration",
|
|
166
|
+
"vignette",
|
|
167
|
+
"film_grain",
|
|
168
|
+
"color_grade",
|
|
169
|
+
"grayscale",
|
|
170
|
+
"invert",
|
|
171
|
+
"sepia",
|
|
172
|
+
"scanlines",
|
|
173
|
+
"glitch_displacement",
|
|
174
|
+
# Motion Graphics & Animation Engine
|
|
175
|
+
"motion",
|
|
176
|
+
"Timeline",
|
|
177
|
+
"Easing",
|
|
178
|
+
"Spring",
|
|
179
|
+
"CubicBezier",
|
|
180
|
+
"trim_path",
|
|
181
|
+
"PathFollower",
|
|
182
|
+
"PathMorph",
|
|
183
|
+
"ParticleSystem",
|
|
184
|
+
"Camera2D",
|
|
185
|
+
"PerspectiveCamera",
|
|
186
|
+
"render_globe",
|
|
187
|
+
"Node",
|
|
188
|
+
"Layer",
|
|
189
|
+
"Scene",
|
|
190
|
+
# Geospatial (GeoPandas & Shapely C++ Engine)
|
|
191
|
+
"shapgeo",
|
|
192
|
+
"geo",
|
|
193
|
+
"GeoCanvas",
|
|
194
|
+
"GeoTransform",
|
|
195
|
+
"from_shapely",
|
|
196
|
+
"from_geojson",
|
|
197
|
+
"from_wkt",
|
|
198
|
+
"render_gdf",
|
|
199
|
+
"auto_bounds",
|
|
200
|
+
"read_file",
|
|
201
|
+
"read_shapefile",
|
|
202
|
+
"read_geojson",
|
|
203
|
+
"proj",
|
|
204
|
+
"Transformer",
|
|
205
|
+
"to_web_mercator",
|
|
206
|
+
"to_wgs84",
|
|
207
|
+
"reproject_gdf",
|
|
208
|
+
"downloader",
|
|
209
|
+
"download_dataset",
|
|
210
|
+
"load_dataset",
|
|
211
|
+
# Video & Native FFmpeg Engine
|
|
212
|
+
"video",
|
|
213
|
+
"VideoWriter",
|
|
214
|
+
"VideoReader",
|
|
215
|
+
"record_animation",
|
|
216
|
+
"detect_hardware_encoders",
|
|
217
|
+
"VideoError",
|
|
218
|
+
"CodecNotFoundError",
|
|
219
|
+
"FrameFormatError",
|
|
220
|
+
# SVG Vector Export
|
|
221
|
+
"svg",
|
|
222
|
+
"SvgContext",
|
|
223
|
+
"export_svg",
|
|
224
|
+
# Diagnostics & Troubleshooting
|
|
225
|
+
"diagnose_environment",
|
|
226
|
+
"print_diagnostic_report",
|
|
227
|
+
"get_error_details",
|
|
228
|
+
"get_runtime_info",
|
|
229
|
+
# Styles
|
|
230
|
+
"Gradient",
|
|
231
|
+
"LinearGradient",
|
|
232
|
+
"RadialGradient",
|
|
233
|
+
"ConicGradient",
|
|
234
|
+
"Pattern",
|
|
235
|
+
# Colors
|
|
236
|
+
"Rgba32",
|
|
237
|
+
"Rgba",
|
|
238
|
+
"parse_color",
|
|
239
|
+
"NAMED_COLORS",
|
|
240
|
+
# Typography
|
|
241
|
+
"FontFace",
|
|
242
|
+
"Font",
|
|
243
|
+
"FontMetrics",
|
|
244
|
+
"TextMetrics",
|
|
245
|
+
# Geometry
|
|
246
|
+
"Point",
|
|
247
|
+
"PointI",
|
|
248
|
+
"Size",
|
|
249
|
+
"SizeI",
|
|
250
|
+
"Rect",
|
|
251
|
+
"RectI",
|
|
252
|
+
"Box",
|
|
253
|
+
"BoxI",
|
|
254
|
+
"Circle",
|
|
255
|
+
"Ellipse",
|
|
256
|
+
"RoundRect",
|
|
257
|
+
"Triangle",
|
|
258
|
+
"Arc",
|
|
259
|
+
"Line",
|
|
260
|
+
"Matrix2D",
|
|
261
|
+
# Enums
|
|
262
|
+
"Format",
|
|
263
|
+
"CompOp",
|
|
264
|
+
"FillRule",
|
|
265
|
+
"GeometryType",
|
|
266
|
+
"ExtendMode",
|
|
267
|
+
"GradientType",
|
|
268
|
+
"StrokeCap",
|
|
269
|
+
"StrokeCapPosition",
|
|
270
|
+
"StrokeJoin",
|
|
271
|
+
"StrokeTransformOrder",
|
|
272
|
+
"TransformOp",
|
|
273
|
+
"ClipOp",
|
|
274
|
+
"FlattenMode",
|
|
275
|
+
"RenderingEngine",
|
|
276
|
+
"ResultCode",
|
|
277
|
+
"ContextHint",
|
|
278
|
+
"RenderingQuality",
|
|
279
|
+
"GradientQuality",
|
|
280
|
+
"PatternQuality",
|
|
281
|
+
"RuntimeInfoType",
|
|
282
|
+
"RuntimeCpuArch",
|
|
283
|
+
"RuntimeCpuFeatures",
|
|
284
|
+
]
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
blend2d/color.py
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Color Representation and Utilities for Blend2D.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
from typing import Union, Tuple, Sequence
|
|
8
|
+
from blend2d.ffi import BLRgba32, BLRgba64, BLRgba
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
NAMED_COLORS = {
|
|
12
|
+
"black": 0xFF000000,
|
|
13
|
+
"white": 0xFFFFFFFF,
|
|
14
|
+
"red": 0xFFFF0000,
|
|
15
|
+
"green": 0xFF008000,
|
|
16
|
+
"lime": 0xFF00FF00,
|
|
17
|
+
"blue": 0xFF0000FF,
|
|
18
|
+
"yellow": 0xFFFFFF00,
|
|
19
|
+
"cyan": 0xFF00FFFF,
|
|
20
|
+
"aqua": 0xFF00FFFF,
|
|
21
|
+
"magenta": 0xFFFF00FF,
|
|
22
|
+
"fuchsia": 0xFFFF00FF,
|
|
23
|
+
"transparent": 0x00000000,
|
|
24
|
+
"gray": 0xFF808080,
|
|
25
|
+
"grey": 0xFF808080,
|
|
26
|
+
"darkgray": 0xFFA9A9A9,
|
|
27
|
+
"darkgrey": 0xFFA9A9A9,
|
|
28
|
+
"lightgray": 0xFFD3D3D3,
|
|
29
|
+
"lightgrey": 0xFFD3D3D3,
|
|
30
|
+
"orange": 0xFFFFA500,
|
|
31
|
+
"coral": 0xFFFF7F50,
|
|
32
|
+
"purple": 0xFF800080,
|
|
33
|
+
"pink": 0xFFFFC0CB,
|
|
34
|
+
"navy": 0xFF000080,
|
|
35
|
+
"teal": 0xFF008080,
|
|
36
|
+
"olive": 0xFF808000,
|
|
37
|
+
"maroon": 0xFF800000,
|
|
38
|
+
"silver": 0xFFC0C0C0,
|
|
39
|
+
"gold": 0xFFFFD700,
|
|
40
|
+
"indigo": 0xFF4B0082,
|
|
41
|
+
"violet": 0xFFEE82EE,
|
|
42
|
+
"brown": 0xFFA52A2A,
|
|
43
|
+
"khaki": 0xFFF0E68C,
|
|
44
|
+
"lavender": 0xFFE6E6FA,
|
|
45
|
+
"salmon": 0xFFFA8072,
|
|
46
|
+
"plum": 0xFFDDA0DD,
|
|
47
|
+
"turquoise": 0xFF40E0D0,
|
|
48
|
+
"crimson": 0xFFDC143C,
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@dataclass
|
|
53
|
+
class Rgba32:
|
|
54
|
+
"""32-bit ARGB color (uint32)."""
|
|
55
|
+
value: int = 0xFF000000
|
|
56
|
+
|
|
57
|
+
def __init__(
|
|
58
|
+
self,
|
|
59
|
+
r_or_value: Union[int, Sequence[int]] = 0xFF000000,
|
|
60
|
+
g: Optional[int] = None,
|
|
61
|
+
b: Optional[int] = None,
|
|
62
|
+
a: Optional[int] = None
|
|
63
|
+
):
|
|
64
|
+
if isinstance(r_or_value, (tuple, list)):
|
|
65
|
+
vals = r_or_value
|
|
66
|
+
r = vals[0]
|
|
67
|
+
g = vals[1]
|
|
68
|
+
b = vals[2]
|
|
69
|
+
a = vals[3] if len(vals) > 3 else 255
|
|
70
|
+
self.value = ((int(a) & 0xFF) << 24) | ((int(r) & 0xFF) << 16) | ((int(g) & 0xFF) << 8) | (int(b) & 0xFF)
|
|
71
|
+
elif g is not None or b is not None or a is not None:
|
|
72
|
+
r = int(r_or_value)
|
|
73
|
+
g_val = int(g) if g is not None else 0
|
|
74
|
+
b_val = int(b) if b is not None else 0
|
|
75
|
+
a_val = int(a) if a is not None else 255
|
|
76
|
+
self.value = ((a_val & 0xFF) << 24) | ((r & 0xFF) << 16) | ((g_val & 0xFF) << 8) | (b_val & 0xFF)
|
|
77
|
+
else:
|
|
78
|
+
self.value = int(r_or_value) & 0xFFFFFFFF
|
|
79
|
+
|
|
80
|
+
@property
|
|
81
|
+
def a(self) -> int:
|
|
82
|
+
return (self.value >> 24) & 0xFF
|
|
83
|
+
|
|
84
|
+
@property
|
|
85
|
+
def r(self) -> int:
|
|
86
|
+
return (self.value >> 16) & 0xFF
|
|
87
|
+
|
|
88
|
+
@property
|
|
89
|
+
def g(self) -> int:
|
|
90
|
+
return (self.value >> 8) & 0xFF
|
|
91
|
+
|
|
92
|
+
@property
|
|
93
|
+
def b(self) -> int:
|
|
94
|
+
return self.value & 0xFF
|
|
95
|
+
|
|
96
|
+
def to_c(self) -> BLRgba32:
|
|
97
|
+
return BLRgba32(self.value)
|
|
98
|
+
|
|
99
|
+
@classmethod
|
|
100
|
+
def from_c(cls, c: BLRgba32) -> Rgba32:
|
|
101
|
+
return cls(c.value)
|
|
102
|
+
|
|
103
|
+
@classmethod
|
|
104
|
+
def from_rgba(cls, r: int, g: int, b: int, a: int = 255) -> Rgba32:
|
|
105
|
+
val = ((int(a) & 0xFF) << 24) | ((int(r) & 0xFF) << 16) | ((int(g) & 0xFF) << 8) | (int(b) & 0xFF)
|
|
106
|
+
return cls(val)
|
|
107
|
+
|
|
108
|
+
@classmethod
|
|
109
|
+
def from_hex(cls, hex_str: str) -> Rgba32:
|
|
110
|
+
s = hex_str.strip().lstrip("#")
|
|
111
|
+
try:
|
|
112
|
+
if len(s) == 3: # RGB
|
|
113
|
+
r = int(s[0] * 2, 16)
|
|
114
|
+
g = int(s[1] * 2, 16)
|
|
115
|
+
b = int(s[2] * 2, 16)
|
|
116
|
+
return cls.from_rgba(r, g, b, 255)
|
|
117
|
+
elif len(s) == 4: # RGBA
|
|
118
|
+
r = int(s[0] * 2, 16)
|
|
119
|
+
g = int(s[1] * 2, 16)
|
|
120
|
+
b = int(s[2] * 2, 16)
|
|
121
|
+
a = int(s[3] * 2, 16)
|
|
122
|
+
return cls.from_rgba(r, g, b, a)
|
|
123
|
+
elif len(s) == 6: # RRGGBB
|
|
124
|
+
r = int(s[0:2], 16)
|
|
125
|
+
g = int(s[2:4], 16)
|
|
126
|
+
b = int(s[4:6], 16)
|
|
127
|
+
return cls.from_rgba(r, g, b, 255)
|
|
128
|
+
elif len(s) == 8: # RRGGBBAA
|
|
129
|
+
r = int(s[0:2], 16)
|
|
130
|
+
g = int(s[2:4], 16)
|
|
131
|
+
b = int(s[4:6], 16)
|
|
132
|
+
a = int(s[6:8], 16)
|
|
133
|
+
return cls.from_rgba(r, g, b, a)
|
|
134
|
+
except ValueError:
|
|
135
|
+
pass
|
|
136
|
+
raise ValueError(f"Invalid hex color string: '{hex_str}'")
|
|
137
|
+
|
|
138
|
+
def __repr__(self) -> str:
|
|
139
|
+
return f"Rgba32(r={self.r}, g={self.g}, b={self.b}, a={self.a}, hex=#{self.value:08X})"
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
@dataclass
|
|
143
|
+
class Rgba:
|
|
144
|
+
"""Floating point RGBA color (0.0 - 1.0)."""
|
|
145
|
+
r: float = 0.0
|
|
146
|
+
g: float = 0.0
|
|
147
|
+
b: float = 0.0
|
|
148
|
+
a: float = 1.0
|
|
149
|
+
|
|
150
|
+
def to_c(self) -> BLRgba:
|
|
151
|
+
return BLRgba(float(self.r), float(self.g), float(self.b), float(self.a))
|
|
152
|
+
|
|
153
|
+
@classmethod
|
|
154
|
+
def from_c(cls, c: BLRgba) -> Rgba:
|
|
155
|
+
return cls(c.r, c.g, c.b, c.a)
|
|
156
|
+
|
|
157
|
+
def to_rgba32(self) -> Rgba32:
|
|
158
|
+
return Rgba32.from_rgba(
|
|
159
|
+
int(min(max(self.r, 0.0), 1.0) * 255),
|
|
160
|
+
int(min(max(self.g, 0.0), 1.0) * 255),
|
|
161
|
+
int(min(max(self.b, 0.0), 1.0) * 255),
|
|
162
|
+
int(min(max(self.a, 0.0), 1.0) * 255),
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
ColorLike = Union[Rgba32, Rgba, int, str, Tuple[int, int, int], Tuple[int, int, int, int], Sequence[float]]
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def parse_color(color: ColorLike) -> Rgba32:
|
|
170
|
+
"""Universal color parser returning a 32-bit Rgba32 instance."""
|
|
171
|
+
if isinstance(color, Rgba32):
|
|
172
|
+
return color
|
|
173
|
+
if isinstance(color, Rgba):
|
|
174
|
+
return color.to_rgba32()
|
|
175
|
+
if isinstance(color, int):
|
|
176
|
+
return Rgba32(color)
|
|
177
|
+
if isinstance(color, str):
|
|
178
|
+
color_lower = color.lower().strip()
|
|
179
|
+
if color_lower in NAMED_COLORS:
|
|
180
|
+
return Rgba32(NAMED_COLORS[color_lower])
|
|
181
|
+
if color.startswith("#"):
|
|
182
|
+
return Rgba32.from_hex(color)
|
|
183
|
+
# Try hex even without # if 6 or 8 hex digits
|
|
184
|
+
if len(color) in (3, 4, 6, 8) and all(c in "0123456789abcdefABCDEF" for c in color):
|
|
185
|
+
return Rgba32.from_hex(color)
|
|
186
|
+
raise ValueError(f"Unknown color name or invalid hex string: '{color}'")
|
|
187
|
+
if isinstance(color, (tuple, list)):
|
|
188
|
+
if all(isinstance(x, float) and 0.0 <= x <= 1.0 for x in color):
|
|
189
|
+
# Float normalized colors
|
|
190
|
+
r = int(color[0] * 255)
|
|
191
|
+
g = int(color[1] * 255)
|
|
192
|
+
b = int(color[2] * 255)
|
|
193
|
+
a = int(color[3] * 255) if len(color) > 3 else 255
|
|
194
|
+
return Rgba32.from_rgba(r, g, b, a)
|
|
195
|
+
else:
|
|
196
|
+
r = int(color[0])
|
|
197
|
+
g = int(color[1])
|
|
198
|
+
b = int(color[2])
|
|
199
|
+
a = int(color[3]) if len(color) > 3 else 255
|
|
200
|
+
return Rgba32.from_rgba(r, g, b, a)
|
|
201
|
+
|
|
202
|
+
raise TypeError(f"Cannot convert type {type(color)} to a valid Blend2D Color.")
|