rocket-welder-sdk 1.1.44__py3-none-any.whl → 1.1.46__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.
@@ -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)