-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstyles_path.py
272 lines (217 loc) · 7.2 KB
/
styles_path.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
"""
VI path styles
Converts non-text styles into svg styles.
"""
import colorsys
import xml.etree.ElementTree as ET
import tools_path as tp
def decode_stroke_style(stroke_style):
"""
Returns processed pathStrokeStyle.
fillRule/strokeType?
"basicStrokeStyle": {
"cap": 0, # ! 0: butt, 1: round, 2: square
"join": 1, # ! 0: miter, 1: round, 2: bevel
"position": 0 # ! -1: inner, 0: center, 1: outside not possible in SVG 1.1?
"dashPattern": [
26,
9,
16,
5
],
},
"""
basic_style = stroke_style.get("basicStrokeStyle")
color = stroke_style.get("color")
width = stroke_style.get("width")
stroke_style_result = {
"stroke": rgba_to_hex(color_to_rgb_tuple(color)),
"stroke-width": str(width),
"stroke-opacity": color_to_rgb_tuple(color)[3],
"stroke-linecap": cap_to_svg(basic_style.get("cap", 0)),
"stroke-dasharray": dash_pattern_to_svg(basic_style.get("dashPattern")),
"stroke-linejoin": join_to_svg(basic_style.get("join", 1))
}
return stroke_style_result
def decode_fill(fill):
color = fill.get("color", {}).get("_0")
gradient = fill.get("gradient", {}).get("_0")
if gradient is not None:
return gradient # pass through
elif color is not None:
return {
"fill": rgba_to_hex(color_to_rgb_tuple(color)),
"fill-opacity": color_to_rgb_tuple(color)[3]
}
def create_gradient_element(gradient_data, local_transform, id):
"""Create an SVG gradient element from data."""
gradient = gradient_data.get("gradient", {})
gradient_type = gradient.get("typeRawValue", 0) # 0: Linear, 1: Radial
transform = gradient_data.get("transform", {})
# Element and common attributes
gradient_element = ET.Element(str(gradient_type_to_svg(gradient_type)), {
"id": f"gradient{id}",
"xlink:href": f"#gradient{id}",
"gradientUnits": "userSpaceOnUse",
"gradientTransform": tp.create_group_transform(local_transform),
})
if gradient_type == 0: # Linear Gradient
gradient_element.attrib["x1"] = str(transform['start'][0])
gradient_element.attrib["y1"] = str(transform['start'][1])
gradient_element.attrib["x2"] = str(transform['end'][0])
gradient_element.attrib["y2"] = str(transform['end'][1])
elif gradient_type == 1: # Radial Gradient
cx = transform['start'][0]
cy = transform['start'][1]
fx = transform['end'][0]
fy = transform['end'][1]
# Calculate radius (r) from start and end points.
r = ((fx - cx)**2 + (fy - cy)**2)**0.5
gradient_element.attrib["cx"] = str(cx)
gradient_element.attrib["cy"] = str(cy)
gradient_element.attrib["r"] = str(r)
# Add color stops
for stop in gradient["stops"]:
color = color_to_rgb_tuple(stop.get("color"))
ratio = stop.get("ratio")
# Create style attribute
style_parts = [
f"stop-color:{rgba_to_hex(color)}",
f"stop-opacity:{color[3]}",
]
style = ";".join(style_parts)
stop_element = ET.Element("stop", {
"style": style,
"offset": f"{ratio}",
})
gradient_element.append(stop_element)
return gradient_element
def gradient_type_to_svg(blendmode):
"""
Returns gradient type (Linear / Radial).
"""
match blendmode:
case 0:
return "linearGradient"
case 1:
return "radialGradient"
case _:
return "linearGradient"
def blend_mode_to_svg(blendmode):
"""
Returns value for mix-blend-mode attribute.
Color Burn, Color Dodge, Soft Light, Hard Light do not exist in Linearity Curve.
"""
match blendmode:
case 0:
return "normal"
case 1:
return "multiply"
case 2:
return "screen"
case 3:
return "overlay"
case 4:
return "darken"
case 5:
return "lighten"
case 10:
return "difference"
case 11:
return "exclusion"
case 12:
return "hue"
case 13:
return "saturation"
case 14:
return "color"
case 15:
return "luminosity"
case _:
return "normal"
def cap_to_svg(cap):
"""Returns value for stroke-linecap attribute."""
match cap:
case 0:
return "butt"
case 1:
return "round"
case 2:
return "square"
case _:
return "butt"
def dash_pattern_to_svg(dash_pattern):
"""
Converts a dash pattern list to an SVG-compatible stroke-dasharray string.
Args:
dash_pattern (list): List of dash and gap lengths.
Returns:
str: A comma-separated string for SVG stroke-dasharray.
"""
if not dash_pattern:
return None # No dash pattern
return ", ".join(map(str, dash_pattern))
def join_to_svg(join):
"""Returns value for stroke-linejoin attribute."""
match join:
case 0:
return "miter"
case 1:
return "round"
case 2:
return "bevel"
case _:
return "miter"
def color_to_rgb_tuple(color):
"""Converts color into string."""
rgba = color.get("rgba")
hsba = color.get("hsba")
if rgba is not None:
return rgba_to_tuple(rgba)
elif hsba is not None:
return hsba_to_rgba(hsba)
def hsba_to_rgba(hsba):
"""
Converts an HSBA color to RGBA format.
Args:
hsba (dict): A dictionary with the keys "hue", "saturation", "brightness", and "alpha".
- "hue" (float): Hue value (0.0 to 1.0).
- "saturation" (float): Saturation value (0.0 to 1.0).
- "brightness" (float): Brightness value (0.0 to 1.0).
- "alpha" (float): Alpha value (0.0 to 1.0).
Returns:
tuple: A tuple of (red, green, blue, alpha), each as a float between 0.0 and 1.0.
"""
hue = hsba.get("hue", 0)
saturation = hsba.get("saturation", 0)
brightness = hsba.get("brightness", 0)
alpha = hsba.get("alpha", 1)
# Convert HSB to RGB
r, g, b = colorsys.hsv_to_rgb(hue, saturation, brightness)
# Return RGBA as tuple.
return r, g, b, alpha
def rgba_to_tuple(rgba):
"""
Converts an RGBA color to Tuple format.
Args:
hsba (dict): A dictionary with the keys "red", "green", "blue", and "alpha".
- "red" (float): Red value (0.0 to 1.0).
- "green" (float): Green value (0.0 to 1.0).
- "blue" (float): Blue value (0.0 to 1.0).
- "alpha" (float): Alpha value (0.0 to 1.0).
Returns:
tuple: A tuple of (red, green, blue, alpha), each as a float between 0.0 and 1.0.
"""
red = rgba.get("red", 0)
green = rgba.get("green", 0)
blue = rgba.get("blue", 0)
alpha = rgba.get("alpha", 1)
# Return RGBA as tuple.
return red, green, blue, alpha
def rgba_to_hex(rgba):
"""Converts RGBA tuple into str hex(#RRGGBB)."""
r, g, b, a = rgba
r = int(r * 255)
g = int(g * 255)
b = int(b * 255)
return f"#{r:02X}{g:02X}{b:02X}"