@nmmty/lazycanvas 0.4.0 → 0.5.0
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.
- package/dist/helpers/Filters.d.ts +10 -10
- package/dist/helpers/Fonts.d.ts +1 -1
- package/dist/helpers/FontsList.d.ts +1 -1
- package/dist/helpers/FontsList.js +19 -19
- package/dist/index.d.ts +11 -20
- package/dist/index.js +40 -47
- package/dist/structures/LazyCanvas.d.ts +126 -19
- package/dist/structures/LazyCanvas.js +100 -35
- package/dist/structures/components/BaseLayer.d.ts +188 -38
- package/dist/structures/components/BaseLayer.js +88 -41
- package/dist/structures/components/BezierLayer.d.ts +108 -21
- package/dist/structures/components/BezierLayer.js +73 -24
- package/dist/structures/components/ClearLayer.d.ts +120 -17
- package/dist/structures/components/ClearLayer.js +83 -22
- package/dist/structures/components/Group.d.ts +86 -18
- package/dist/structures/components/Group.js +69 -29
- package/dist/structures/components/ImageLayer.d.ts +85 -12
- package/dist/structures/components/ImageLayer.js +52 -39
- package/dist/structures/components/LineLayer.d.ts +111 -18
- package/dist/structures/components/LineLayer.js +58 -21
- package/dist/structures/components/MorphLayer.d.ts +109 -21
- package/dist/structures/components/MorphLayer.js +53 -25
- package/dist/structures/components/Path2DLayer.d.ts +191 -0
- package/dist/structures/components/Path2DLayer.js +318 -0
- package/dist/structures/components/QuadraticLayer.d.ts +108 -22
- package/dist/structures/components/QuadraticLayer.js +65 -30
- package/dist/structures/components/TextLayer.d.ts +201 -40
- package/dist/structures/components/TextLayer.js +99 -47
- package/dist/structures/components/index.d.ts +10 -0
- package/dist/structures/components/index.js +26 -0
- package/dist/structures/helpers/Exporter.d.ts +52 -0
- package/dist/structures/helpers/Exporter.js +168 -0
- package/dist/structures/helpers/Font.d.ts +64 -10
- package/dist/structures/helpers/Font.js +38 -11
- package/dist/structures/helpers/Gradient.d.ts +96 -9
- package/dist/structures/helpers/Gradient.js +48 -17
- package/dist/structures/helpers/Link.d.ts +52 -8
- package/dist/structures/helpers/Link.js +42 -11
- package/dist/structures/helpers/Pattern.d.ts +52 -7
- package/dist/structures/helpers/Pattern.js +45 -40
- package/dist/structures/helpers/index.d.ts +6 -0
- package/dist/structures/helpers/index.js +22 -0
- package/dist/structures/helpers/readers/JSONReader.d.ts +49 -0
- package/dist/structures/helpers/readers/JSONReader.js +172 -0
- package/dist/structures/helpers/readers/SVGReader.d.ts +20 -0
- package/dist/structures/helpers/readers/SVGReader.js +577 -0
- package/dist/structures/helpers/readers/YAMLReader.d.ts +0 -0
- package/dist/structures/helpers/readers/YAMLReader.js +1 -0
- package/dist/structures/managers/AnimationManager.d.ts +96 -20
- package/dist/structures/managers/AnimationManager.js +54 -26
- package/dist/structures/managers/FontsManager.d.ts +76 -32
- package/dist/structures/managers/FontsManager.js +70 -45
- package/dist/structures/managers/LayersManager.d.ts +84 -32
- package/dist/structures/managers/LayersManager.js +66 -28
- package/dist/structures/managers/RenderManager.d.ts +60 -6
- package/dist/structures/managers/RenderManager.js +120 -40
- package/dist/types/enum.d.ts +11 -6
- package/dist/types/enum.js +17 -12
- package/dist/types/index.d.ts +2 -19
- package/dist/types/index.js +17 -0
- package/dist/utils/LazyUtil.js +2 -2
- package/dist/utils/utils.d.ts +10 -9
- package/dist/utils/utils.js +159 -164
- package/package.json +4 -5
|
@@ -0,0 +1,577 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SVGReader = void 0;
|
|
4
|
+
const svgson_1 = require("svgson");
|
|
5
|
+
const fs_1 = require("fs");
|
|
6
|
+
const index_1 = require("../../../index");
|
|
7
|
+
class SVGReader {
|
|
8
|
+
static async parseSVG(svg) {
|
|
9
|
+
let loadedSVG = await fs_1.promises.readFile(svg);
|
|
10
|
+
return (0, svgson_1.parse)(loadedSVG.toString());
|
|
11
|
+
}
|
|
12
|
+
static async createImageLayer(svg) {
|
|
13
|
+
const imageLayer = new index_1.ImageLayer();
|
|
14
|
+
const src = svg.attributes['xlink:href'] || svg.attributes.href;
|
|
15
|
+
if (svg.attributes.id)
|
|
16
|
+
imageLayer.id = svg.attributes.id;
|
|
17
|
+
if (svg.attributes['fill-opacity'])
|
|
18
|
+
imageLayer.props.opacity = Number(svg.attributes['fill-opacity']);
|
|
19
|
+
if (src.startsWith('data:image')) {
|
|
20
|
+
const base64Data = src.replace(/^data:image\/\w+;base64,/, "");
|
|
21
|
+
const buffer = Buffer.from(base64Data, 'base64');
|
|
22
|
+
imageLayer.props.src = buffer;
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
imageLayer.props.src = src;
|
|
26
|
+
}
|
|
27
|
+
imageLayer.props.x = Number(svg.attributes.x) || 0;
|
|
28
|
+
imageLayer.props.y = Number(svg.attributes.y) || 0;
|
|
29
|
+
imageLayer.props.centring = 'start-top';
|
|
30
|
+
imageLayer.props.size.width = Number(svg.attributes.width);
|
|
31
|
+
imageLayer.props.size.height = Number(svg.attributes.height);
|
|
32
|
+
if (svg.attributes.transform) {
|
|
33
|
+
SVGReader.applyTransform(svg.attributes.transform, imageLayer);
|
|
34
|
+
}
|
|
35
|
+
return imageLayer;
|
|
36
|
+
}
|
|
37
|
+
static async createEllipseImageLayer(svg, path) {
|
|
38
|
+
const ellipseImageLayer = new index_1.ImageLayer();
|
|
39
|
+
const src = svg.attributes['xlink:href'] || svg.attributes.href;
|
|
40
|
+
ellipseImageLayer.data.id = svg.attributes.id;
|
|
41
|
+
if (svg.attributes['fill-opacity'])
|
|
42
|
+
ellipseImageLayer.data.alpha = Number(svg.attributes['fill-opacity']);
|
|
43
|
+
if (src.startsWith('data:image')) {
|
|
44
|
+
const base64Data = src.replace(/^data:image\/\w+;base64,/, "");
|
|
45
|
+
const buffer = Buffer.from(base64Data, 'base64');
|
|
46
|
+
ellipseImageLayer.data.image = buffer;
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
ellipseImageLayer.data.image = src;
|
|
50
|
+
}
|
|
51
|
+
ellipseImageLayer.data.x = Number(svg.attributes.x) || 0;
|
|
52
|
+
ellipseImageLayer.data.y = Number(svg.attributes.y) || 0;
|
|
53
|
+
ellipseImageLayer.data.centering = 'legacy';
|
|
54
|
+
ellipseImageLayer.data.width = Number(svg.attributes.width);
|
|
55
|
+
ellipseImageLayer.data.height = Number(svg.attributes.height);
|
|
56
|
+
ellipseImageLayer.data.path = path;
|
|
57
|
+
if (svg.attributes.transform) {
|
|
58
|
+
SVGReader.applyTransform(svg.attributes.transform, ellipseImageLayer);
|
|
59
|
+
}
|
|
60
|
+
ellipseImageLayer.data.fromSVG = true;
|
|
61
|
+
return ellipseImageLayer;
|
|
62
|
+
}
|
|
63
|
+
static async createRectLayer(svg, svgObject) {
|
|
64
|
+
let rectLayer = new index_1.MorphLayer();
|
|
65
|
+
if (svg.attributes.rx || svg.attributes.ry) {
|
|
66
|
+
rectLayer.props.size.radius = Math.min(Number(svg.attributes.rx) || 0, Number(svg.attributes.ry) || 0);
|
|
67
|
+
}
|
|
68
|
+
if (svg.attributes.id)
|
|
69
|
+
rectLayer.id = svg.attributes.id;
|
|
70
|
+
if (svg.attributes.fill && svg.attributes.fill !== 'none') {
|
|
71
|
+
rectLayer.props.fillStyle = await this.fillStyle(svg, svgObject);
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
rectLayer.props.fillStyle = svg.attributes.fill === 'none' ? svg.attributes.stroke : svg.attributes.fill || 'black';
|
|
75
|
+
}
|
|
76
|
+
rectLayer.props.filled = svg.attributes.fill !== 'none';
|
|
77
|
+
if (svg.attributes['fill-opacity'])
|
|
78
|
+
rectLayer.props.opacity = Number(svg.attributes['fill-opacity']);
|
|
79
|
+
rectLayer.props.x = Number(svg.attributes.x) || 0;
|
|
80
|
+
rectLayer.props.y = Number(svg.attributes.y) || 0;
|
|
81
|
+
rectLayer.props.centring = 'start-top';
|
|
82
|
+
rectLayer.props.size.width = Number(svg.attributes.width);
|
|
83
|
+
rectLayer.props.size.height = Number(svg.attributes.height);
|
|
84
|
+
if (svg.attributes.transform) {
|
|
85
|
+
SVGReader.applyTransform(svg.attributes.transform, rectLayer);
|
|
86
|
+
}
|
|
87
|
+
return rectLayer;
|
|
88
|
+
}
|
|
89
|
+
static async createEllipseLayer(svg, svgObject) {
|
|
90
|
+
const ellipseLayer = new index_1.MorphLayer();
|
|
91
|
+
if (svg.attributes.id)
|
|
92
|
+
ellipseLayer.id = svg.attributes.id;
|
|
93
|
+
if (svg.attributes.fill && svg.attributes.fill !== 'none') {
|
|
94
|
+
let id = SVGReader.extractIdFromUrl(svg.attributes.fill);
|
|
95
|
+
if (id) {
|
|
96
|
+
let element = SVGReader.findElementById(svgObject, id);
|
|
97
|
+
if (element.name === "pattern") {
|
|
98
|
+
ellipseLayer.props.fillStyle = await SVGReader.createPattern(element, svgObject, svg);
|
|
99
|
+
}
|
|
100
|
+
else if (['linearGradient', 'radialGradient'].includes(element.name)) {
|
|
101
|
+
ellipseLayer.props.fillStyle = await SVGReader.createGradient(element, svgObject, svg);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
ellipseLayer.props.fillStyle = svg.attributes.fill === 'none' ? svg.attributes.stroke : svg.attributes.fill || 'black';
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
ellipseLayer.data.color = svg.attributes.fill === 'none' ? svg.attributes.stroke : svg.attributes.fill || 'black';
|
|
110
|
+
}
|
|
111
|
+
ellipseLayer.data.fill = svg.attributes.fill !== 'none';
|
|
112
|
+
if (svg.attributes['fill-opacity'])
|
|
113
|
+
ellipseLayer.data.alpha = Number(svg.attributes['fill-opacity']);
|
|
114
|
+
ellipseLayer.data.x = Number(svg.attributes.x) || 0;
|
|
115
|
+
ellipseLayer.data.y = Number(svg.attributes.y) || 0;
|
|
116
|
+
ellipseLayer.data.centering = 'legacy';
|
|
117
|
+
ellipseLayer.data.width = Number(svg.attributes.width);
|
|
118
|
+
ellipseLayer.data.height = Number(svg.attributes.height);
|
|
119
|
+
if (svg.attributes.transform) {
|
|
120
|
+
SVGReader.applyTransform(svg.attributes.transform, ellipseLayer);
|
|
121
|
+
}
|
|
122
|
+
return ellipseLayer;
|
|
123
|
+
}
|
|
124
|
+
static async createCircleLayer(svg, svgObject) {
|
|
125
|
+
const circleLayer = new index_1.MorphLayer();
|
|
126
|
+
circleLayer.data.id = svg.attributes.id || `CircleLayer-${Math.random().toString(36).substring(2, 15)}`;
|
|
127
|
+
if (svg.attributes.fill && svg.attributes.fill !== 'none') {
|
|
128
|
+
let id = SVGReader.extractIdFromUrl(svg.attributes.fill);
|
|
129
|
+
if (id) {
|
|
130
|
+
let element = SVGReader.findElementById(svgObject, id);
|
|
131
|
+
if (element.name === "pattern") {
|
|
132
|
+
circleLayer.data.color = await SVGReader.createPattern(element, svgObject, svg);
|
|
133
|
+
}
|
|
134
|
+
else if (['linearGradient', 'radialGradient'].includes(element.name)) {
|
|
135
|
+
circleLayer.data.color = await SVGReader.createGradient(element, svgObject, svg);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
circleLayer.data.color = svg.attributes.fill === 'none' ? svg.attributes.stroke : svg.attributes.fill || 'black';
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
circleLayer.data.color = svg.attributes.fill === 'none' ? svg.attributes.stroke : svg.attributes.fill || 'black';
|
|
144
|
+
}
|
|
145
|
+
circleLayer.data.fill = svg.attributes.fill !== 'none';
|
|
146
|
+
if (svg.attributes['fill-opacity'])
|
|
147
|
+
circleLayer.data.alpha = Number(svg.attributes['fill-opacity']);
|
|
148
|
+
circleLayer.data.x = Number(svg.attributes.cx) || 0;
|
|
149
|
+
circleLayer.data.y = Number(svg.attributes.cy) || 0;
|
|
150
|
+
circleLayer.data.radius = Number(svg.attributes.r);
|
|
151
|
+
if (svg.attributes.transform) {
|
|
152
|
+
SVGReader.applyTransform(svg.attributes.transform, circleLayer);
|
|
153
|
+
}
|
|
154
|
+
return circleLayer;
|
|
155
|
+
}
|
|
156
|
+
static async createLineLayer(svg, svgObject) {
|
|
157
|
+
const lineLayer = new index_1.LineLayer();
|
|
158
|
+
lineLayer.data.id = svg.attributes.id || `LineLayer-${Math.random().toString(36).substring(2, 15)}`;
|
|
159
|
+
if (svg.attributes.fill && svg.attributes.fill !== 'none') {
|
|
160
|
+
let id = SVGReader.extractIdFromUrl(svg.attributes.fill);
|
|
161
|
+
if (id) {
|
|
162
|
+
let element = SVGReader.findElementById(svgObject, id);
|
|
163
|
+
if (element.name === "pattern") {
|
|
164
|
+
lineLayer.data.color = await SVGReader.createPattern(element, svgObject, svg);
|
|
165
|
+
}
|
|
166
|
+
else if (['linearGradient', 'radialGradient'].includes(element.name)) {
|
|
167
|
+
lineLayer.data.color = await SVGReader.createGradient(element, svgObject, svg);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
lineLayer.data.color = svg.attributes.fill === 'none' ? svg.attributes.stroke : svg.attributes.fill || 'black';
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
lineLayer.data.color = svg.attributes.fill === 'none' ? svg.attributes.stroke : svg.attributes.fill || 'black';
|
|
176
|
+
}
|
|
177
|
+
lineLayer.data.fill = svg.attributes.fill !== 'none';
|
|
178
|
+
if (svg.attributes['fill-opacity'])
|
|
179
|
+
lineLayer.data.alpha = Number(svg.attributes['fill-opacity']);
|
|
180
|
+
for (let i = 0; i < 2; i++) {
|
|
181
|
+
lineLayer.data.points.push({
|
|
182
|
+
x: Number(svg.attributes[`x${i + 1}`]),
|
|
183
|
+
y: Number(svg.attributes[`y${i + 1}`])
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
if (svg.attributes.transform) {
|
|
187
|
+
SVGReader.applyTransform(svg.attributes.transform, lineLayer);
|
|
188
|
+
}
|
|
189
|
+
return lineLayer;
|
|
190
|
+
}
|
|
191
|
+
static async createGradient(svg, svgObject, parent) {
|
|
192
|
+
const gradient = new index_1.Gradient();
|
|
193
|
+
gradient.data.id = svg.attributes.id || `Gradient-${Math.random().toString(36).substring(2, 15)}`;
|
|
194
|
+
gradient.data.gradientType = svg.name === 'linearGradient' ? 'linear' : 'radial';
|
|
195
|
+
let baseXOne = (parent.attributes.x !== undefined
|
|
196
|
+
? Number(parent.attributes.x)
|
|
197
|
+
: (parent.attributes.x1 !== undefined
|
|
198
|
+
? Number(parent.attributes.x1)
|
|
199
|
+
: Number(parent.attributes.cx) - Number(parent.attributes.r)));
|
|
200
|
+
let baseYOne = (parent.attributes.y !== undefined
|
|
201
|
+
? Number(parent.attributes.y)
|
|
202
|
+
: (parent.attributes.y1 !== undefined
|
|
203
|
+
? Number(parent.attributes.y1)
|
|
204
|
+
: Number(parent.attributes.cy) - Number(parent.attributes.r)));
|
|
205
|
+
let baseXTwo = (parent.attributes.x !== undefined
|
|
206
|
+
? Number(parent.attributes.x)
|
|
207
|
+
: (parent.attributes.x2 !== undefined
|
|
208
|
+
? Number(parent.attributes.x2)
|
|
209
|
+
: Number(parent.attributes.cx) - Number(parent.attributes.r)));
|
|
210
|
+
let baseYTwo = (parent.attributes.y !== undefined
|
|
211
|
+
? Number(parent.attributes.y)
|
|
212
|
+
: (parent.attributes.y2 !== undefined
|
|
213
|
+
? Number(parent.attributes.y2)
|
|
214
|
+
: Number(parent.attributes.cy) - Number(parent.attributes.r)));
|
|
215
|
+
gradient.data.points = [
|
|
216
|
+
{
|
|
217
|
+
x: baseXOne + (svg.attributes.x1 !== undefined
|
|
218
|
+
? (parent.attributes.width !== undefined ? parent.attributes.width * Number(svg.attributes.x1) : baseXOne * Number(svg.attributes.x1))
|
|
219
|
+
: Number(svg.attributes.fx) * (parent.attributes.width !== undefined ? Number(parent.attributes.width) : Number(parent.attributes.r) * 2)),
|
|
220
|
+
y: baseYOne + (svg.attributes.y1 !== undefined
|
|
221
|
+
? (parent.attributes.height !== undefined ? parent.attributes.height * Number(svg.attributes.y1) : baseYOne * Number(svg.attributes.y1))
|
|
222
|
+
: Number(svg.attributes.fy) * (parent.attributes.height !== undefined ? Number(parent.attributes.height) : Number(parent.attributes.r) * 2))
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
x: baseXTwo + (svg.attributes.x2 !== undefined
|
|
226
|
+
? (parent.attributes.width !== undefined ? parent.attributes.width * Number(svg.attributes.x2) : baseXTwo * Number(svg.attributes.x2))
|
|
227
|
+
: Number(svg.attributes.cx) * (parent.attributes.width !== undefined ? Number(parent.attributes.width) : Number(parent.attributes.r) * 2)),
|
|
228
|
+
y: baseYTwo + (svg.attributes.y2 !== undefined
|
|
229
|
+
? (parent.attributes.height !== undefined ? parent.attributes.height * Number(svg.attributes.y2) : baseYTwo * Number(svg.attributes.y2))
|
|
230
|
+
: Number(svg.attributes.cy) * (parent.attributes.height !== undefined ? Number(parent.attributes.height) : Number(parent.attributes.r) * 2))
|
|
231
|
+
}
|
|
232
|
+
];
|
|
233
|
+
if (svg.name === "radialGradient") {
|
|
234
|
+
gradient.data.radius = Number(parent.attributes.r) ? (Number(parent.attributes.r) * Number(svg.attributes.r)) * 2 : Math.min((Number(parent.attributes.width) * Number(svg.attributes.r)), (Number(parent.attributes.height) * Number(svg.attributes.r)));
|
|
235
|
+
}
|
|
236
|
+
for (const colorStop of svg.children) {
|
|
237
|
+
let color = colorStop.attributes['stop-color'];
|
|
238
|
+
let offset = colorStop.attributes['offset'].replace('%', '');
|
|
239
|
+
gradient.data.colorPoints.push({ color, position: Number(offset) / 100 });
|
|
240
|
+
}
|
|
241
|
+
return gradient;
|
|
242
|
+
}
|
|
243
|
+
static async createPattern(svg, svgObject, parent) {
|
|
244
|
+
const pattern = new index_1.Pattern();
|
|
245
|
+
pattern.data.id = svg.attributes.id || `Pattern-${Math.random().toString(36).substring(2, 15)}`;
|
|
246
|
+
pattern.data.patternType = index_1.PatternType.repeat;
|
|
247
|
+
let layers = [];
|
|
248
|
+
for (const child of svg.children) {
|
|
249
|
+
let layer;
|
|
250
|
+
switch (child.name) {
|
|
251
|
+
case 'image':
|
|
252
|
+
layer = await SVGReader.createImageLayer(child);
|
|
253
|
+
break;
|
|
254
|
+
case 'path':
|
|
255
|
+
layer = await SVGReader.createPath2DLayer(child, svgObject);
|
|
256
|
+
break;
|
|
257
|
+
case 'g':
|
|
258
|
+
const group = await SVGReader.createGroupLayer(child, svgObject);
|
|
259
|
+
layers.push(...group);
|
|
260
|
+
break;
|
|
261
|
+
case 'clipPath':
|
|
262
|
+
layer = await SVGReader.createClipPathLayer(child);
|
|
263
|
+
break;
|
|
264
|
+
case 'use':
|
|
265
|
+
layer = await SVGReader.handleUseElement(child, svgObject, svg);
|
|
266
|
+
break;
|
|
267
|
+
case 'rect':
|
|
268
|
+
layer = await SVGReader.createRectLayer(child, svgObject);
|
|
269
|
+
break;
|
|
270
|
+
case 'ellipse':
|
|
271
|
+
layer = await SVGReader.createEllipseLayer(child, svgObject);
|
|
272
|
+
break;
|
|
273
|
+
case 'circle':
|
|
274
|
+
layer = await SVGReader.createCircleLayer(child, svgObject);
|
|
275
|
+
break;
|
|
276
|
+
case 'line':
|
|
277
|
+
layer = await SVGReader.createLineLayer(child, svgObject);
|
|
278
|
+
break;
|
|
279
|
+
default:
|
|
280
|
+
console.warn(`Unsupported SVG element: ${child.name}`);
|
|
281
|
+
}
|
|
282
|
+
if (layer) {
|
|
283
|
+
layers.push(layer);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
let width = Number(svg.attributes['width']);
|
|
287
|
+
let height = Number(svg.attributes['height']);
|
|
288
|
+
width = width < 1 ? width * (Number(parent.attributes['width']) ? Number(parent.attributes['width']) : (Number(parent.attributes['r']) * 2)) : width;
|
|
289
|
+
height = height < 1 ? height * (Number(parent.attributes['height']) ? Number(parent.attributes['height']) : (Number(parent.attributes['r']) * 2)) : height;
|
|
290
|
+
pattern.data.pattern = {
|
|
291
|
+
data: new index_1.LazyCanvas()
|
|
292
|
+
.createNewCanvas(width, height)
|
|
293
|
+
.addLayers(...layers),
|
|
294
|
+
type: "canvas"
|
|
295
|
+
};
|
|
296
|
+
return pattern;
|
|
297
|
+
}
|
|
298
|
+
static async createPath2DLayer(svg, svgObject) {
|
|
299
|
+
const path2DLayer = new index_1.Path2DLayer(svg.attributes.d);
|
|
300
|
+
path2DLayer.data.id = svg.attributes.id || `Path2DLayer-${Math.random().toString(36).substring(2, 15)}`;
|
|
301
|
+
if (svg.attributes.fill && svg.attributes.fill !== 'none') {
|
|
302
|
+
let id = SVGReader.extractIdFromUrl(svg.attributes.fill);
|
|
303
|
+
if (id) {
|
|
304
|
+
let element = SVGReader.findElementById(svgObject, id);
|
|
305
|
+
if (element.name === "pattern") {
|
|
306
|
+
path2DLayer.data.color = await SVGReader.createPattern(element, svgObject, svg);
|
|
307
|
+
}
|
|
308
|
+
else if (['linearGradient', 'radialGradient'].includes(element.name)) {
|
|
309
|
+
path2DLayer.data.color = await SVGReader.createGradient(element, svgObject, svg);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
else {
|
|
313
|
+
path2DLayer.data.fillStyle = svg.attributes.fill === 'none' ? svg.attributes.stroke : svg.attributes.fill || 'black';
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
else {
|
|
317
|
+
path2DLayer.data.fillStyle = svg.attributes.fill === 'none' ? svg.attributes.stroke : svg.attributes.fill || 'black';
|
|
318
|
+
}
|
|
319
|
+
path2DLayer.data.filled = svg.attributes.fill !== 'none';
|
|
320
|
+
if (svg.attributes['fill-opacity'])
|
|
321
|
+
path2DLayer.data.alpha = Number(svg.attributes['fill-opacity']);
|
|
322
|
+
path2DLayer.data.lineWidth = svg.attributes['stroke-width'] ? Number(svg.attributes['stroke-width']) : 1;
|
|
323
|
+
if (svg.attributes.transform) {
|
|
324
|
+
SVGReader.applyTransform(svg.attributes.transform, path2DLayer);
|
|
325
|
+
}
|
|
326
|
+
return path2DLayer;
|
|
327
|
+
}
|
|
328
|
+
static async createClipPathLayer(svg) {
|
|
329
|
+
const clipPathLayer = new index_1.Path2DLayer(svg.children.map((child) => child.attributes.d).join(' '));
|
|
330
|
+
clipPathLayer.data.clipPath = true;
|
|
331
|
+
clipPathLayer.data.id = svg.attributes.id || `Path2DLayer-${Math.random().toString(36).substring(2, 15)}`;
|
|
332
|
+
if (svg.attributes.transform) {
|
|
333
|
+
SVGReader.applyTransform(svg.attributes.transform, clipPathLayer);
|
|
334
|
+
}
|
|
335
|
+
return clipPathLayer;
|
|
336
|
+
}
|
|
337
|
+
//private static async createTextLayer(svg: any, parent: any): Promise<any[] | TextLayer> {
|
|
338
|
+
// if (svg.children.length !== 0) {
|
|
339
|
+
// const textGroup = []
|
|
340
|
+
// for (const child of svg.children) {
|
|
341
|
+
// let layer;
|
|
342
|
+
// switch (child.name) {
|
|
343
|
+
// case 'text':
|
|
344
|
+
// layer = await SVGReader.createTextLayer(child, svg);
|
|
345
|
+
// break;
|
|
346
|
+
// case 'tspan':
|
|
347
|
+
// console.log(child)
|
|
348
|
+
// layer = await SVGReader.createTextLayer(child, svg);
|
|
349
|
+
// break;
|
|
350
|
+
// default:
|
|
351
|
+
// console.warn(`Unsupported SVG element: ${child.name}`);
|
|
352
|
+
// }
|
|
353
|
+
// if (layer) {
|
|
354
|
+
// // @ts-ignore
|
|
355
|
+
// textGroup.push(...layer);
|
|
356
|
+
// }
|
|
357
|
+
// }
|
|
358
|
+
// return textGroup
|
|
359
|
+
// } else {
|
|
360
|
+
// const textLayer = new TextLayer()
|
|
361
|
+
// textLayer.data.id = svg.attributes.id || `TextLayer-${Math.random().toString(36).substring(2, 15)}`;
|
|
362
|
+
// textLayer.data.x = svg.attributes.x || parent.attributes.x || 0
|
|
363
|
+
// textLayer.data.y = svg.attributes.y || parent.attributes.y || 0
|
|
364
|
+
// textLayer.data.size = svg.attributes['font-size'] || parent.attributes['font-size'] || 20
|
|
365
|
+
// textLayer.data.align = svg.attributes['anchor'] || parent.attributes['anchor'] || 'left'
|
|
366
|
+
//
|
|
367
|
+
// return textLayer
|
|
368
|
+
// }
|
|
369
|
+
//}
|
|
370
|
+
static async createGroupLayer(svg, svgObject) {
|
|
371
|
+
const groupLayers = [];
|
|
372
|
+
for (const child of svg.children) {
|
|
373
|
+
let layer;
|
|
374
|
+
switch (child.name) {
|
|
375
|
+
case 'image':
|
|
376
|
+
layer = await SVGReader.createImageLayer(child);
|
|
377
|
+
break;
|
|
378
|
+
case 'path':
|
|
379
|
+
layer = await SVGReader.createPath2DLayer(child, svgObject);
|
|
380
|
+
break;
|
|
381
|
+
case 'g':
|
|
382
|
+
const group = await SVGReader.createGroupLayer(child, svgObject);
|
|
383
|
+
groupLayers.push(...group);
|
|
384
|
+
break;
|
|
385
|
+
case 'clipPath':
|
|
386
|
+
layer = await SVGReader.createClipPathLayer(child);
|
|
387
|
+
break;
|
|
388
|
+
case 'use':
|
|
389
|
+
layer = await SVGReader.handleUseElement(child, svgObject, svg);
|
|
390
|
+
break;
|
|
391
|
+
case 'rect':
|
|
392
|
+
layer = await SVGReader.createRectLayer(child, svgObject);
|
|
393
|
+
break;
|
|
394
|
+
case 'ellipse':
|
|
395
|
+
layer = await SVGReader.createEllipseLayer(child, svgObject);
|
|
396
|
+
break;
|
|
397
|
+
case 'circle':
|
|
398
|
+
layer = await SVGReader.createCircleLayer(child, svgObject);
|
|
399
|
+
break;
|
|
400
|
+
case 'line':
|
|
401
|
+
layer = await SVGReader.createLineLayer(child, svgObject);
|
|
402
|
+
break;
|
|
403
|
+
default:
|
|
404
|
+
console.warn(`Unsupported SVG element: ${child.name}`);
|
|
405
|
+
}
|
|
406
|
+
if (layer) {
|
|
407
|
+
groupLayers.push(layer);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
return groupLayers;
|
|
411
|
+
}
|
|
412
|
+
static applyTransform(transform, layer) {
|
|
413
|
+
const matrixMatch = transform.match(/matrix\(([^)]+)\)/);
|
|
414
|
+
const scaleMatch = transform.match(/scale\(([^)]+)\)/);
|
|
415
|
+
const translateMatch = transform.match(/translate\(([^)]+)\)/);
|
|
416
|
+
const rotateMatch = transform.match(/rotate\(([^)]+)\)/);
|
|
417
|
+
if (matrixMatch) {
|
|
418
|
+
const [a, b, c, d, e, f] = matrixMatch[1].split(' ').map(Number);
|
|
419
|
+
layer.data.transform.matrix = { a, b, c, d, e, f };
|
|
420
|
+
layer.data.centering = 'legacy';
|
|
421
|
+
}
|
|
422
|
+
else if (scaleMatch) {
|
|
423
|
+
const [sx, sy] = scaleMatch[1].split(' ').map(Number);
|
|
424
|
+
layer.data.transform.scale = { x: sx, y: sy };
|
|
425
|
+
}
|
|
426
|
+
else if (translateMatch) {
|
|
427
|
+
const [tx, ty] = translateMatch[1].split(' ').map(Number);
|
|
428
|
+
layer.data.transform.translate = { x: tx, y: ty };
|
|
429
|
+
}
|
|
430
|
+
else if (rotateMatch) {
|
|
431
|
+
const [angle, cx, cy] = rotateMatch[1].split(' ').map(Number);
|
|
432
|
+
layer.data.transform.rotate = angle;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
static findElementById(svgObject, id) {
|
|
436
|
+
const queue = [svgObject];
|
|
437
|
+
while (queue.length > 0) {
|
|
438
|
+
const current = queue.shift();
|
|
439
|
+
if (current.attributes && current.attributes.id === id) {
|
|
440
|
+
return current;
|
|
441
|
+
}
|
|
442
|
+
if (current.children) {
|
|
443
|
+
queue.push(...current.children);
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
throw new Error(`Element with id ${id} not found`);
|
|
447
|
+
}
|
|
448
|
+
static extractIdFromUrl(url) {
|
|
449
|
+
const regex = /url\(#([^)]+)\)/;
|
|
450
|
+
const match = url.match(regex);
|
|
451
|
+
return match ? match[1] : null;
|
|
452
|
+
}
|
|
453
|
+
async fillStyle(svg, svgObject) {
|
|
454
|
+
let fill, style;
|
|
455
|
+
let id = SVGReader.extractIdFromUrl(svg.attributes.fill);
|
|
456
|
+
if (id) {
|
|
457
|
+
let element = SVGReader.findElementById(svgObject, id);
|
|
458
|
+
if (element.name === "pattern") {
|
|
459
|
+
fill = await SVGReader.createPattern(element, svgObject, svg);
|
|
460
|
+
}
|
|
461
|
+
else if (['linearGradient', 'radialGradient'].includes(element.name)) {
|
|
462
|
+
fill = await SVGReader.createGradient(element, svgObject, svg);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
else {
|
|
466
|
+
style = svg.attributes.fill === 'none' ? svg.attributes.stroke : svg.attributes.fill || 'black';
|
|
467
|
+
}
|
|
468
|
+
return { fill, style };
|
|
469
|
+
}
|
|
470
|
+
static async handleUseElement(svg, svgObject, from) {
|
|
471
|
+
const href = svg.attributes['xlink:href'] || svg.attributes.href;
|
|
472
|
+
const clipPath = from.attributes['clip-path'];
|
|
473
|
+
const id = href.replace('#', '');
|
|
474
|
+
const referencedElement = SVGReader.findElementById(svgObject, id);
|
|
475
|
+
let layer;
|
|
476
|
+
switch (referencedElement.name) {
|
|
477
|
+
case 'image':
|
|
478
|
+
if (clipPath) {
|
|
479
|
+
let id = SVGReader.extractIdFromUrl(from.attributes['clip-path']);
|
|
480
|
+
if (!id)
|
|
481
|
+
return console.warn(`Could not extract id from clipPath: ${from.attributes['clip-path']}`);
|
|
482
|
+
let element = SVGReader.findElementById(svgObject, id);
|
|
483
|
+
layer = await SVGReader.createEllipseImageLayer(referencedElement, element.children[0].attributes.d);
|
|
484
|
+
}
|
|
485
|
+
else {
|
|
486
|
+
layer = await SVGReader.createImageLayer(referencedElement);
|
|
487
|
+
}
|
|
488
|
+
break;
|
|
489
|
+
case 'path':
|
|
490
|
+
layer = await SVGReader.createPath2DLayer(referencedElement, svgObject);
|
|
491
|
+
break;
|
|
492
|
+
default:
|
|
493
|
+
throw new Error(`Unsupported element referenced by <use>: ${referencedElement.name}`);
|
|
494
|
+
}
|
|
495
|
+
if (svg.attributes.transform) {
|
|
496
|
+
SVGReader.applyTransform(svg.attributes.transform, layer);
|
|
497
|
+
}
|
|
498
|
+
return layer;
|
|
499
|
+
}
|
|
500
|
+
static async readSVG(svg) {
|
|
501
|
+
const svgObject = await SVGReader.parseSVG(svg);
|
|
502
|
+
const layers = [];
|
|
503
|
+
for (const svgElement of svgObject.children) {
|
|
504
|
+
let layer;
|
|
505
|
+
switch (svgElement.name) {
|
|
506
|
+
case 'defs':
|
|
507
|
+
for (const child of svgElement.children) {
|
|
508
|
+
if (child.name === 'image') {
|
|
509
|
+
layer = await SVGReader.createImageLayer(child);
|
|
510
|
+
}
|
|
511
|
+
else if (child.name === 'clipPath') {
|
|
512
|
+
layer = await SVGReader.createClipPathLayer(child);
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
break;
|
|
516
|
+
case 'path':
|
|
517
|
+
layer = await SVGReader.createPath2DLayer(svgElement, svgObject);
|
|
518
|
+
break;
|
|
519
|
+
case 'g':
|
|
520
|
+
const group = await SVGReader.createGroupLayer(svgElement, svgObject);
|
|
521
|
+
for (const element of group) {
|
|
522
|
+
let search = layers.find((l) => l.data.id === element.data.id);
|
|
523
|
+
if (!search)
|
|
524
|
+
layers.push(element);
|
|
525
|
+
else {
|
|
526
|
+
layers.splice(layers.indexOf(search), 1, element);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
break;
|
|
530
|
+
case 'clipPath':
|
|
531
|
+
layer = await SVGReader.createClipPathLayer(svgElement);
|
|
532
|
+
break;
|
|
533
|
+
case 'use':
|
|
534
|
+
layer = await SVGReader.handleUseElement(svgElement, svgObject, svgObject);
|
|
535
|
+
break;
|
|
536
|
+
case 'rect':
|
|
537
|
+
layer = await SVGReader.createRectLayer(svgElement, svgObject);
|
|
538
|
+
break;
|
|
539
|
+
case 'ellipse':
|
|
540
|
+
layer = await SVGReader.createEllipseLayer(svgElement, svgObject);
|
|
541
|
+
break;
|
|
542
|
+
case 'circle':
|
|
543
|
+
layer = await SVGReader.createCircleLayer(svgElement, svgObject);
|
|
544
|
+
break;
|
|
545
|
+
case 'line':
|
|
546
|
+
layer = await SVGReader.createLineLayer(svgElement, svgObject);
|
|
547
|
+
break;
|
|
548
|
+
//case 'text':
|
|
549
|
+
// const textGroup = await SVGReader.createTextLayer(svgElement, svgObject);
|
|
550
|
+
// if (Array.isArray(textGroup)) {
|
|
551
|
+
// for (const element of textGroup) {
|
|
552
|
+
// let search = layers.find((l) => l.data.id === element.data.id);
|
|
553
|
+
// if (!search) layers.push(element);
|
|
554
|
+
// else {
|
|
555
|
+
// layers.splice(layers.indexOf(search), 1, element);
|
|
556
|
+
// }
|
|
557
|
+
// }
|
|
558
|
+
// } else {
|
|
559
|
+
// layer = textGroup;
|
|
560
|
+
// }
|
|
561
|
+
// break;
|
|
562
|
+
default:
|
|
563
|
+
console.warn(`Unsupported SVG element: ${svgElement.name}`);
|
|
564
|
+
}
|
|
565
|
+
if (layer) {
|
|
566
|
+
let search = layers.find((l) => l.data.id === layer.data.id);
|
|
567
|
+
if (!search)
|
|
568
|
+
layers.push(layer);
|
|
569
|
+
else {
|
|
570
|
+
layers.splice(layers.indexOf(search), 1, layer);
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
return layers;
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
exports.SVGReader = SVGReader;
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";
|