rocket-welder-sdk 1.1.44__py3-none-any.whl → 1.1.45__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.
- rocket_welder_sdk/__init__.py +26 -0
- rocket_welder_sdk/graphics/__init__.py +42 -0
- rocket_welder_sdk/graphics/layer_canvas.py +157 -0
- rocket_welder_sdk/graphics/protocol.py +72 -0
- rocket_welder_sdk/graphics/rgb_color.py +109 -0
- rocket_welder_sdk/graphics/stage.py +494 -0
- rocket_welder_sdk/graphics/vector_graphics_encoder.py +575 -0
- rocket_welder_sdk/high_level/connection_strings.py +85 -0
- rocket_welder_sdk/rocket_welder_client.py +210 -12
- rocket_welder_sdk/session_id.py +1 -0
- {rocket_welder_sdk-1.1.44.dist-info → rocket_welder_sdk-1.1.45.dist-info}/METADATA +1 -1
- {rocket_welder_sdk-1.1.44.dist-info → rocket_welder_sdk-1.1.45.dist-info}/RECORD +14 -8
- {rocket_welder_sdk-1.1.44.dist-info → rocket_welder_sdk-1.1.45.dist-info}/WHEEL +1 -1
- {rocket_welder_sdk-1.1.44.dist-info → rocket_welder_sdk-1.1.45.dist-info}/top_level.txt +0 -0
rocket_welder_sdk/__init__.py
CHANGED
|
@@ -15,6 +15,19 @@ from .connection_string import ConnectionMode, ConnectionString, Protocol
|
|
|
15
15
|
from .controllers import DuplexShmController, IController, OneWayShmController
|
|
16
16
|
from .delta_frame import DeltaFrame
|
|
17
17
|
from .frame_metadata import FRAME_METADATA_SIZE, FrameMetadata, GstVideoFormat
|
|
18
|
+
from .graphics import (
|
|
19
|
+
FrameType,
|
|
20
|
+
ILayerCanvas,
|
|
21
|
+
IStageSink,
|
|
22
|
+
IStageWriter,
|
|
23
|
+
LayerEncoder,
|
|
24
|
+
OpType,
|
|
25
|
+
PropertyId,
|
|
26
|
+
RgbColor,
|
|
27
|
+
StageSink,
|
|
28
|
+
StageWriter,
|
|
29
|
+
VectorGraphicsEncoder,
|
|
30
|
+
)
|
|
18
31
|
from .gst_metadata import GstCaps, GstMetadata
|
|
19
32
|
from .keypoints_protocol import (
|
|
20
33
|
IKeyPointsSink,
|
|
@@ -38,6 +51,7 @@ from .segmentation_result import (
|
|
|
38
51
|
from .session_id import (
|
|
39
52
|
# Explicit URL environment variable names (set by rocket-welder2)
|
|
40
53
|
ACTIONS_SINK_URL_ENV,
|
|
54
|
+
GRAPHICS_SINK_URL_ENV,
|
|
41
55
|
KEYPOINTS_SINK_URL_ENV,
|
|
42
56
|
SEGMENTATION_SINK_URL_ENV,
|
|
43
57
|
# SessionId parsing
|
|
@@ -72,6 +86,7 @@ if _log_level:
|
|
|
72
86
|
__all__ = [
|
|
73
87
|
"ACTIONS_SINK_URL_ENV",
|
|
74
88
|
"FRAME_METADATA_SIZE",
|
|
89
|
+
"GRAPHICS_SINK_URL_ENV",
|
|
75
90
|
"KEYPOINTS_SINK_URL_ENV",
|
|
76
91
|
"SEGMENTATION_SINK_URL_ENV",
|
|
77
92
|
"BinaryFrameReader",
|
|
@@ -84,28 +99,39 @@ __all__ = [
|
|
|
84
99
|
"DeltaFrame",
|
|
85
100
|
"DuplexShmController",
|
|
86
101
|
"FrameMetadata",
|
|
102
|
+
"FrameType",
|
|
87
103
|
"GstCaps",
|
|
88
104
|
"GstMetadata",
|
|
89
105
|
"GstVideoFormat",
|
|
90
106
|
"IController",
|
|
91
107
|
"IKeyPointsSink",
|
|
92
108
|
"IKeyPointsWriter",
|
|
109
|
+
"ILayerCanvas",
|
|
93
110
|
"ISegmentationResultSink",
|
|
94
111
|
"ISegmentationResultSource",
|
|
95
112
|
"ISegmentationResultWriter",
|
|
113
|
+
"IStageSink",
|
|
114
|
+
"IStageWriter",
|
|
96
115
|
"KeyPointsSink",
|
|
97
116
|
"KeyPointsWriter",
|
|
117
|
+
"LayerEncoder",
|
|
98
118
|
"OneWayShmController",
|
|
119
|
+
"OpType",
|
|
99
120
|
"OpenCvController",
|
|
100
121
|
"PeriodicTimer",
|
|
101
122
|
"PeriodicTimerSync",
|
|
123
|
+
"PropertyId",
|
|
102
124
|
"Protocol",
|
|
125
|
+
"RgbColor",
|
|
103
126
|
"RocketWelderClient",
|
|
104
127
|
"SegmentationFrame",
|
|
105
128
|
"SegmentationProtocol",
|
|
106
129
|
"SegmentationResultSink",
|
|
107
130
|
"SegmentationResultSource",
|
|
108
131
|
"SegmentationResultWriter",
|
|
132
|
+
"StageSink",
|
|
133
|
+
"StageWriter",
|
|
134
|
+
"VectorGraphicsEncoder",
|
|
109
135
|
"get_session_id_from_env",
|
|
110
136
|
"parse_session_id",
|
|
111
137
|
]
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""
|
|
2
|
+
VectorGraphics module for streaming graphics overlays.
|
|
3
|
+
|
|
4
|
+
This module provides classes for encoding and streaming vector graphics
|
|
5
|
+
to the browser using Protocol V2.
|
|
6
|
+
|
|
7
|
+
Example:
|
|
8
|
+
from rocket_welder_sdk.graphics import StageSink, RgbColor
|
|
9
|
+
from rocket_welder_sdk.transport import UnixSocketFrameSink
|
|
10
|
+
|
|
11
|
+
# Create transport and sink
|
|
12
|
+
sink = UnixSocketFrameSink("/tmp/graphics.sock")
|
|
13
|
+
stage = StageSink(sink)
|
|
14
|
+
|
|
15
|
+
# Draw graphics for each frame
|
|
16
|
+
with stage.create_writer(frame_id) as writer:
|
|
17
|
+
writer[0].set_stroke(RgbColor.Red)
|
|
18
|
+
writer[0].draw_polygon([(0, 0), (100, 0), (100, 100)])
|
|
19
|
+
writer[1].draw_text("Hello", 10, 20)
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
from .layer_canvas import ILayerCanvas
|
|
23
|
+
from .protocol import END_MARKER_BYTE1, END_MARKER_BYTE2, FrameType, OpType, PropertyId
|
|
24
|
+
from .rgb_color import RgbColor
|
|
25
|
+
from .stage import IStageSink, IStageWriter, LayerEncoder, StageSink, StageWriter
|
|
26
|
+
from .vector_graphics_encoder import VectorGraphicsEncoder
|
|
27
|
+
|
|
28
|
+
__all__ = [
|
|
29
|
+
"END_MARKER_BYTE1",
|
|
30
|
+
"END_MARKER_BYTE2",
|
|
31
|
+
"FrameType",
|
|
32
|
+
"ILayerCanvas",
|
|
33
|
+
"IStageSink",
|
|
34
|
+
"IStageWriter",
|
|
35
|
+
"LayerEncoder",
|
|
36
|
+
"OpType",
|
|
37
|
+
"PropertyId",
|
|
38
|
+
"RgbColor",
|
|
39
|
+
"StageSink",
|
|
40
|
+
"StageWriter",
|
|
41
|
+
"VectorGraphicsEncoder",
|
|
42
|
+
]
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
"""
|
|
2
|
+
ILayerCanvas protocol - per-layer drawing interface.
|
|
3
|
+
|
|
4
|
+
Matches C# ILayerCanvas interface from BlazorBlaze.Server.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import TYPE_CHECKING, Protocol, Sequence, Tuple, runtime_checkable
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from .rgb_color import RgbColor
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@runtime_checkable
|
|
16
|
+
class ILayerCanvas(Protocol):
|
|
17
|
+
"""
|
|
18
|
+
Represents a single rendering layer with stateful context management.
|
|
19
|
+
|
|
20
|
+
Mirrors SkiaSharp's canvas API for familiar usage patterns.
|
|
21
|
+
This is a Protocol class (interface) matching C# ILayerCanvas.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
@property
|
|
25
|
+
def layer_id(self) -> int:
|
|
26
|
+
"""The layer ID (z-order index)."""
|
|
27
|
+
...
|
|
28
|
+
|
|
29
|
+
# ============== Layer Frame Type ==============
|
|
30
|
+
|
|
31
|
+
def master(self) -> None:
|
|
32
|
+
"""
|
|
33
|
+
Sets this layer to Master mode - clears and redraws with operations that follow.
|
|
34
|
+
|
|
35
|
+
This is the default mode when drawing operations are added.
|
|
36
|
+
"""
|
|
37
|
+
...
|
|
38
|
+
|
|
39
|
+
def remain(self) -> None:
|
|
40
|
+
"""
|
|
41
|
+
Sets this layer to Remain mode - keeps previous content unchanged.
|
|
42
|
+
|
|
43
|
+
No operations are sent for this layer, saving bandwidth.
|
|
44
|
+
"""
|
|
45
|
+
...
|
|
46
|
+
|
|
47
|
+
def clear(self) -> None:
|
|
48
|
+
"""
|
|
49
|
+
Sets this layer to Clear mode - clears to transparent with no redraw.
|
|
50
|
+
|
|
51
|
+
Use when you want to hide a layer without drawing new content.
|
|
52
|
+
"""
|
|
53
|
+
...
|
|
54
|
+
|
|
55
|
+
# ============== Context State - Styling ==============
|
|
56
|
+
|
|
57
|
+
def set_stroke(self, color: RgbColor) -> None:
|
|
58
|
+
"""Sets the stroke color for subsequent draw operations."""
|
|
59
|
+
...
|
|
60
|
+
|
|
61
|
+
def set_fill(self, color: RgbColor) -> None:
|
|
62
|
+
"""Sets the fill color for subsequent draw operations."""
|
|
63
|
+
...
|
|
64
|
+
|
|
65
|
+
def set_thickness(self, width: int) -> None:
|
|
66
|
+
"""Sets the stroke thickness in pixels."""
|
|
67
|
+
...
|
|
68
|
+
|
|
69
|
+
def set_font_size(self, size: int) -> None:
|
|
70
|
+
"""Sets the font size in pixels."""
|
|
71
|
+
...
|
|
72
|
+
|
|
73
|
+
def set_font_color(self, color: RgbColor) -> None:
|
|
74
|
+
"""Sets the font color for text operations."""
|
|
75
|
+
...
|
|
76
|
+
|
|
77
|
+
# ============== Context State - Transforms ==============
|
|
78
|
+
|
|
79
|
+
def translate(self, dx: float, dy: float) -> None:
|
|
80
|
+
"""Sets the translation offset for subsequent draw operations."""
|
|
81
|
+
...
|
|
82
|
+
|
|
83
|
+
def rotate(self, degrees: float) -> None:
|
|
84
|
+
"""Sets the rotation in degrees for subsequent draw operations."""
|
|
85
|
+
...
|
|
86
|
+
|
|
87
|
+
def scale(self, sx: float, sy: float) -> None:
|
|
88
|
+
"""Sets the scale factors for subsequent draw operations."""
|
|
89
|
+
...
|
|
90
|
+
|
|
91
|
+
def skew(self, kx: float, ky: float) -> None:
|
|
92
|
+
"""Sets the skew factors for subsequent draw operations."""
|
|
93
|
+
...
|
|
94
|
+
|
|
95
|
+
def set_matrix(
|
|
96
|
+
self,
|
|
97
|
+
scale_x: float,
|
|
98
|
+
skew_x: float,
|
|
99
|
+
trans_x: float,
|
|
100
|
+
skew_y: float,
|
|
101
|
+
scale_y: float,
|
|
102
|
+
trans_y: float,
|
|
103
|
+
) -> None:
|
|
104
|
+
"""
|
|
105
|
+
Sets a full transformation matrix for subsequent draw operations.
|
|
106
|
+
|
|
107
|
+
Takes precedence over individual transform properties.
|
|
108
|
+
|
|
109
|
+
Matrix layout matches SKMatrix:
|
|
110
|
+
| ScaleX SkewX TransX |
|
|
111
|
+
| SkewY ScaleY TransY |
|
|
112
|
+
"""
|
|
113
|
+
...
|
|
114
|
+
|
|
115
|
+
# ============== Context Stack ==============
|
|
116
|
+
|
|
117
|
+
def save(self) -> None:
|
|
118
|
+
"""
|
|
119
|
+
Pushes the current context state onto a stack.
|
|
120
|
+
|
|
121
|
+
Use with restore() for hierarchical transforms.
|
|
122
|
+
"""
|
|
123
|
+
...
|
|
124
|
+
|
|
125
|
+
def restore(self) -> None:
|
|
126
|
+
"""Pops and restores the most recently saved context state."""
|
|
127
|
+
...
|
|
128
|
+
|
|
129
|
+
def reset_context(self) -> None:
|
|
130
|
+
"""Resets the context to default values (black stroke, identity transform)."""
|
|
131
|
+
...
|
|
132
|
+
|
|
133
|
+
# ============== Draw Operations ==============
|
|
134
|
+
|
|
135
|
+
def draw_polygon(self, points: Sequence[Tuple[float, float]]) -> None:
|
|
136
|
+
"""Draws a polygon using the current context state."""
|
|
137
|
+
...
|
|
138
|
+
|
|
139
|
+
def draw_text(self, text: str, x: int, y: int) -> None:
|
|
140
|
+
"""Draws text at the specified position using the current context state."""
|
|
141
|
+
...
|
|
142
|
+
|
|
143
|
+
def draw_circle(self, center_x: int, center_y: int, radius: int) -> None:
|
|
144
|
+
"""Draws a circle using the current context state."""
|
|
145
|
+
...
|
|
146
|
+
|
|
147
|
+
def draw_rectangle(self, x: int, y: int, width: int, height: int) -> None:
|
|
148
|
+
"""Draws a rectangle using the current context state."""
|
|
149
|
+
...
|
|
150
|
+
|
|
151
|
+
def draw_line(self, x1: int, y1: int, x2: int, y2: int) -> None:
|
|
152
|
+
"""Draws a line using the current context state."""
|
|
153
|
+
...
|
|
154
|
+
|
|
155
|
+
def draw_jpeg(self, jpeg_data: bytes, x: int, y: int, width: int, height: int) -> None:
|
|
156
|
+
"""Draws a JPEG image at the specified position and size."""
|
|
157
|
+
...
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Protocol V2 enums and constants for VectorGraphics encoding.
|
|
3
|
+
|
|
4
|
+
Matches C# ProtocolV2 from BlazorBlaze.VectorGraphics.Protocol.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from enum import IntEnum
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class FrameType(IntEnum):
|
|
13
|
+
"""
|
|
14
|
+
Frame type for layer updates.
|
|
15
|
+
|
|
16
|
+
Matches C# FrameType enum.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
MASTER = 0x00 # Clear and redraw with operations
|
|
20
|
+
REMAIN = 0x01 # Keep previous content unchanged
|
|
21
|
+
CLEAR = 0x02 # Clear to transparent with no redraw
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class OpType(IntEnum):
|
|
25
|
+
"""
|
|
26
|
+
Operation type codes.
|
|
27
|
+
|
|
28
|
+
Matches C# OpType enum.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
# Draw operations (0x01-0x0F)
|
|
32
|
+
DRAW_POLYGON = 0x01
|
|
33
|
+
DRAW_TEXT = 0x02
|
|
34
|
+
DRAW_CIRCLE = 0x03
|
|
35
|
+
DRAW_RECT = 0x04
|
|
36
|
+
DRAW_LINE = 0x05
|
|
37
|
+
DRAW_JPEG = 0x07
|
|
38
|
+
|
|
39
|
+
# Context operations (0x10-0x1F)
|
|
40
|
+
SET_CONTEXT = 0x10
|
|
41
|
+
SAVE_CONTEXT = 0x11
|
|
42
|
+
RESTORE_CONTEXT = 0x12
|
|
43
|
+
RESET_CONTEXT = 0x13
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class PropertyId(IntEnum):
|
|
47
|
+
"""
|
|
48
|
+
Property IDs for SetContext operation.
|
|
49
|
+
|
|
50
|
+
Matches C# PropertyId enum.
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
# Styling properties (0x01-0x0F)
|
|
54
|
+
STROKE = 0x01
|
|
55
|
+
FILL = 0x02
|
|
56
|
+
THICKNESS = 0x03
|
|
57
|
+
FONT_SIZE = 0x04
|
|
58
|
+
FONT_COLOR = 0x05
|
|
59
|
+
|
|
60
|
+
# Transform properties (0x10-0x1F)
|
|
61
|
+
OFFSET = 0x10
|
|
62
|
+
ROTATION = 0x11
|
|
63
|
+
SCALE = 0x12
|
|
64
|
+
SKEW = 0x13
|
|
65
|
+
|
|
66
|
+
# Matrix (0x20)
|
|
67
|
+
MATRIX = 0x20
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
# Protocol constants
|
|
71
|
+
END_MARKER_BYTE1: int = 0xFF
|
|
72
|
+
END_MARKER_BYTE2: int = 0xFF
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"""
|
|
2
|
+
RgbColor - RGBA color representation.
|
|
3
|
+
|
|
4
|
+
Matches C# RgbColor readonly record struct from BlazorBlaze.VectorGraphics.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from dataclasses import dataclass
|
|
10
|
+
from typing import ClassVar
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass(frozen=True)
|
|
14
|
+
class RgbColor:
|
|
15
|
+
"""
|
|
16
|
+
Represents an RGBA color with byte components.
|
|
17
|
+
|
|
18
|
+
This is a frozen dataclass matching the C# `readonly record struct RgbColor`.
|
|
19
|
+
Each component is a byte (0-255).
|
|
20
|
+
|
|
21
|
+
Attributes:
|
|
22
|
+
r: Red component (0-255)
|
|
23
|
+
g: Green component (0-255)
|
|
24
|
+
b: Blue component (0-255)
|
|
25
|
+
a: Alpha component (0-255), defaults to 255 (opaque)
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
r: int
|
|
29
|
+
g: int
|
|
30
|
+
b: int
|
|
31
|
+
a: int = 255
|
|
32
|
+
|
|
33
|
+
# Pre-defined colors (class variables)
|
|
34
|
+
Transparent: ClassVar[RgbColor]
|
|
35
|
+
White: ClassVar[RgbColor]
|
|
36
|
+
Black: ClassVar[RgbColor]
|
|
37
|
+
Red: ClassVar[RgbColor]
|
|
38
|
+
Blue: ClassVar[RgbColor]
|
|
39
|
+
Green: ClassVar[RgbColor]
|
|
40
|
+
Gray: ClassVar[RgbColor]
|
|
41
|
+
|
|
42
|
+
def __post_init__(self) -> None:
|
|
43
|
+
"""Validate color components are in valid range."""
|
|
44
|
+
if not (0 <= self.r <= 255):
|
|
45
|
+
raise ValueError(f"Red component must be 0-255, got {self.r}")
|
|
46
|
+
if not (0 <= self.g <= 255):
|
|
47
|
+
raise ValueError(f"Green component must be 0-255, got {self.g}")
|
|
48
|
+
if not (0 <= self.b <= 255):
|
|
49
|
+
raise ValueError(f"Blue component must be 0-255, got {self.b}")
|
|
50
|
+
if not (0 <= self.a <= 255):
|
|
51
|
+
raise ValueError(f"Alpha component must be 0-255, got {self.a}")
|
|
52
|
+
|
|
53
|
+
def __str__(self) -> str:
|
|
54
|
+
"""Returns hex representation (#RRGGBB or #RRGGBBAA)."""
|
|
55
|
+
if self.a == 255:
|
|
56
|
+
return f"#{self.r:02X}{self.g:02X}{self.b:02X}"
|
|
57
|
+
return f"#{self.r:02X}{self.g:02X}{self.b:02X}{self.a:02X}"
|
|
58
|
+
|
|
59
|
+
def __repr__(self) -> str:
|
|
60
|
+
"""Returns debug representation."""
|
|
61
|
+
return f"RgbColor(r={self.r}, g={self.g}, b={self.b}, a={self.a})"
|
|
62
|
+
|
|
63
|
+
def to_bytes(self) -> bytes:
|
|
64
|
+
"""Returns RGBA as 4 bytes."""
|
|
65
|
+
return bytes([self.r, self.g, self.b, self.a])
|
|
66
|
+
|
|
67
|
+
@classmethod
|
|
68
|
+
def from_bytes(cls, data: bytes, offset: int = 0) -> RgbColor:
|
|
69
|
+
"""Creates RgbColor from 4 bytes (RGBA)."""
|
|
70
|
+
return cls(data[offset], data[offset + 1], data[offset + 2], data[offset + 3])
|
|
71
|
+
|
|
72
|
+
@classmethod
|
|
73
|
+
def from_hex(cls, hex_str: str) -> RgbColor:
|
|
74
|
+
"""
|
|
75
|
+
Creates RgbColor from hex string.
|
|
76
|
+
|
|
77
|
+
Supports formats: #RGB, #RGBA, #RRGGBB, #RRGGBBAA
|
|
78
|
+
"""
|
|
79
|
+
hex_str = hex_str.lstrip("#")
|
|
80
|
+
if len(hex_str) == 3:
|
|
81
|
+
# #RGB -> #RRGGBB
|
|
82
|
+
hex_str = "".join(c * 2 for c in hex_str)
|
|
83
|
+
elif len(hex_str) == 4:
|
|
84
|
+
# #RGBA -> #RRGGBBAA
|
|
85
|
+
hex_str = "".join(c * 2 for c in hex_str)
|
|
86
|
+
|
|
87
|
+
if len(hex_str) == 6:
|
|
88
|
+
r = int(hex_str[0:2], 16)
|
|
89
|
+
g = int(hex_str[2:4], 16)
|
|
90
|
+
b = int(hex_str[4:6], 16)
|
|
91
|
+
return cls(r, g, b)
|
|
92
|
+
elif len(hex_str) == 8:
|
|
93
|
+
r = int(hex_str[0:2], 16)
|
|
94
|
+
g = int(hex_str[2:4], 16)
|
|
95
|
+
b = int(hex_str[4:6], 16)
|
|
96
|
+
a = int(hex_str[6:8], 16)
|
|
97
|
+
return cls(r, g, b, a)
|
|
98
|
+
else:
|
|
99
|
+
raise ValueError(f"Invalid hex color format: #{hex_str}")
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
# Initialize class-level color constants
|
|
103
|
+
RgbColor.Transparent = RgbColor(0, 0, 0, 0)
|
|
104
|
+
RgbColor.White = RgbColor(255, 255, 255)
|
|
105
|
+
RgbColor.Black = RgbColor(0, 0, 0)
|
|
106
|
+
RgbColor.Red = RgbColor(255, 0, 0)
|
|
107
|
+
RgbColor.Blue = RgbColor(0, 0, 255)
|
|
108
|
+
RgbColor.Green = RgbColor(0, 255, 0)
|
|
109
|
+
RgbColor.Gray = RgbColor(128, 128, 128)
|