@shotstack/shotstack-canvas 1.8.2 → 1.8.4
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/entry.node.cjs +499 -726
- package/dist/entry.node.d.cts +78 -186
- package/dist/entry.node.d.ts +78 -186
- package/dist/entry.node.js +493 -699
- package/dist/entry.web.d.ts +79 -186
- package/dist/entry.web.js +527 -711
- package/package.json +3 -1
package/dist/entry.web.js
CHANGED
|
@@ -2349,335 +2349,6 @@ var isGlyphFill2 = (op) => {
|
|
|
2349
2349
|
return op.op === "FillPath" && op.isShadow !== true;
|
|
2350
2350
|
};
|
|
2351
2351
|
|
|
2352
|
-
// src/core/shape-generators.ts
|
|
2353
|
-
var KAPPA = 0.5522847498307936;
|
|
2354
|
-
var DEG_TO_RAD = Math.PI / 180;
|
|
2355
|
-
function generateShapePath(params) {
|
|
2356
|
-
switch (params.shape) {
|
|
2357
|
-
case "rectangle":
|
|
2358
|
-
return generateRectanglePath(params);
|
|
2359
|
-
case "circle":
|
|
2360
|
-
return generateCirclePath(params);
|
|
2361
|
-
case "ellipse":
|
|
2362
|
-
return generateEllipsePath(params);
|
|
2363
|
-
case "line":
|
|
2364
|
-
return generateLinePath(params);
|
|
2365
|
-
case "triangle":
|
|
2366
|
-
return generateTrianglePath(params);
|
|
2367
|
-
case "polygon":
|
|
2368
|
-
return generatePolygonPath(params);
|
|
2369
|
-
case "star":
|
|
2370
|
-
return generateStarPath(params);
|
|
2371
|
-
case "arrow":
|
|
2372
|
-
return generateArrowPath(params);
|
|
2373
|
-
case "heart":
|
|
2374
|
-
return generateHeartPath(params);
|
|
2375
|
-
case "cross":
|
|
2376
|
-
return generateCrossPath(params);
|
|
2377
|
-
case "ring":
|
|
2378
|
-
return generateRingPath(params);
|
|
2379
|
-
}
|
|
2380
|
-
}
|
|
2381
|
-
function generateRectanglePath(params) {
|
|
2382
|
-
const { width, height, cornerRadius = 0 } = params;
|
|
2383
|
-
if (cornerRadius === 0) {
|
|
2384
|
-
return `M 0 0 L ${width} 0 L ${width} ${height} L 0 ${height} Z`;
|
|
2385
|
-
}
|
|
2386
|
-
const r = Math.min(cornerRadius, width / 2, height / 2);
|
|
2387
|
-
return [
|
|
2388
|
-
`M ${r} 0`,
|
|
2389
|
-
`L ${width - r} 0`,
|
|
2390
|
-
`Q ${width} 0 ${width} ${r}`,
|
|
2391
|
-
`L ${width} ${height - r}`,
|
|
2392
|
-
`Q ${width} ${height} ${width - r} ${height}`,
|
|
2393
|
-
`L ${r} ${height}`,
|
|
2394
|
-
`Q 0 ${height} 0 ${height - r}`,
|
|
2395
|
-
`L 0 ${r}`,
|
|
2396
|
-
`Q 0 0 ${r} 0`,
|
|
2397
|
-
"Z"
|
|
2398
|
-
].join(" ");
|
|
2399
|
-
}
|
|
2400
|
-
function generateCirclePath(params) {
|
|
2401
|
-
const { radius } = params;
|
|
2402
|
-
return generateEllipsePath({ radiusX: radius, radiusY: radius });
|
|
2403
|
-
}
|
|
2404
|
-
function generateEllipsePath(params) {
|
|
2405
|
-
const { radiusX, radiusY } = params;
|
|
2406
|
-
const kx = radiusX * KAPPA;
|
|
2407
|
-
const ky = radiusY * KAPPA;
|
|
2408
|
-
return [
|
|
2409
|
-
`M ${radiusX} 0`,
|
|
2410
|
-
`C ${radiusX} ${ky} ${kx} ${radiusY} 0 ${radiusY}`,
|
|
2411
|
-
`C ${-kx} ${radiusY} ${-radiusX} ${ky} ${-radiusX} 0`,
|
|
2412
|
-
`C ${-radiusX} ${-ky} ${-kx} ${-radiusY} 0 ${-radiusY}`,
|
|
2413
|
-
`C ${kx} ${-radiusY} ${radiusX} ${-ky} ${radiusX} 0`,
|
|
2414
|
-
"Z"
|
|
2415
|
-
].join(" ");
|
|
2416
|
-
}
|
|
2417
|
-
function generateLinePath(params) {
|
|
2418
|
-
const { length, thickness } = params;
|
|
2419
|
-
const halfThickness = thickness / 2;
|
|
2420
|
-
return [
|
|
2421
|
-
`M 0 ${-halfThickness}`,
|
|
2422
|
-
`L ${length} ${-halfThickness}`,
|
|
2423
|
-
`L ${length} ${halfThickness}`,
|
|
2424
|
-
`L 0 ${halfThickness}`,
|
|
2425
|
-
"Z"
|
|
2426
|
-
].join(" ");
|
|
2427
|
-
}
|
|
2428
|
-
function generateTrianglePath(params) {
|
|
2429
|
-
const { width, height } = params;
|
|
2430
|
-
const halfWidth = width / 2;
|
|
2431
|
-
return `M 0 ${height} L ${halfWidth} 0 L ${width} ${height} Z`;
|
|
2432
|
-
}
|
|
2433
|
-
function generatePolygonPath(params) {
|
|
2434
|
-
const { sides, radius } = params;
|
|
2435
|
-
const points = generatePolygonPoints(sides, radius);
|
|
2436
|
-
return pointsToPath(points, true);
|
|
2437
|
-
}
|
|
2438
|
-
function generatePolygonPoints(sides, radius) {
|
|
2439
|
-
const points = [];
|
|
2440
|
-
const angleStep = 2 * Math.PI / sides;
|
|
2441
|
-
const startAngle = -Math.PI / 2;
|
|
2442
|
-
for (let i = 0; i < sides; i++) {
|
|
2443
|
-
const angle = startAngle + i * angleStep;
|
|
2444
|
-
points.push({
|
|
2445
|
-
x: radius * Math.cos(angle),
|
|
2446
|
-
y: radius * Math.sin(angle)
|
|
2447
|
-
});
|
|
2448
|
-
}
|
|
2449
|
-
return points;
|
|
2450
|
-
}
|
|
2451
|
-
function generateStarPath(params) {
|
|
2452
|
-
const { points, outerRadius, innerRadius } = params;
|
|
2453
|
-
const starPoints = generateStarPoints(points, outerRadius, innerRadius);
|
|
2454
|
-
return pointsToPath(starPoints, true);
|
|
2455
|
-
}
|
|
2456
|
-
function generateStarPoints(pointCount, outerRadius, innerRadius) {
|
|
2457
|
-
const points = [];
|
|
2458
|
-
const totalPoints = pointCount * 2;
|
|
2459
|
-
const angleStep = Math.PI / pointCount;
|
|
2460
|
-
const startAngle = -Math.PI / 2;
|
|
2461
|
-
for (let i = 0; i < totalPoints; i++) {
|
|
2462
|
-
const radius = i % 2 === 0 ? outerRadius : innerRadius;
|
|
2463
|
-
const angle = startAngle + i * angleStep;
|
|
2464
|
-
points.push({
|
|
2465
|
-
x: radius * Math.cos(angle),
|
|
2466
|
-
y: radius * Math.sin(angle)
|
|
2467
|
-
});
|
|
2468
|
-
}
|
|
2469
|
-
return points;
|
|
2470
|
-
}
|
|
2471
|
-
function generateArrowPath(params) {
|
|
2472
|
-
const { length, headWidth, headLength, shaftWidth } = params;
|
|
2473
|
-
const halfShaft = shaftWidth / 2;
|
|
2474
|
-
const halfHead = headWidth / 2;
|
|
2475
|
-
const shaftLength = length - headLength;
|
|
2476
|
-
return [
|
|
2477
|
-
`M 0 ${-halfShaft}`,
|
|
2478
|
-
`L ${shaftLength} ${-halfShaft}`,
|
|
2479
|
-
`L ${shaftLength} ${-halfHead}`,
|
|
2480
|
-
`L ${length} 0`,
|
|
2481
|
-
`L ${shaftLength} ${halfHead}`,
|
|
2482
|
-
`L ${shaftLength} ${halfShaft}`,
|
|
2483
|
-
`L 0 ${halfShaft}`,
|
|
2484
|
-
"Z"
|
|
2485
|
-
].join(" ");
|
|
2486
|
-
}
|
|
2487
|
-
function generateHeartPath(params) {
|
|
2488
|
-
const { size } = params;
|
|
2489
|
-
const s = size / 2;
|
|
2490
|
-
return [
|
|
2491
|
-
`M 0 ${s * 0.3}`,
|
|
2492
|
-
`C 0 ${-s * 0.3} ${-s} ${-s * 0.3} ${-s} ${s * 0.3}`,
|
|
2493
|
-
`C ${-s} ${s * 0.7} 0 ${s} 0 ${s * 1.2}`,
|
|
2494
|
-
`C 0 ${s} ${s} ${s * 0.7} ${s} ${s * 0.3}`,
|
|
2495
|
-
`C ${s} ${-s * 0.3} 0 ${-s * 0.3} 0 ${s * 0.3}`,
|
|
2496
|
-
"Z"
|
|
2497
|
-
].join(" ");
|
|
2498
|
-
}
|
|
2499
|
-
function generateCrossPath(params) {
|
|
2500
|
-
const { width, height, thickness } = params;
|
|
2501
|
-
const halfThickness = thickness / 2;
|
|
2502
|
-
const halfWidth = width / 2;
|
|
2503
|
-
const halfHeight = height / 2;
|
|
2504
|
-
return [
|
|
2505
|
-
`M ${-halfThickness} ${-halfHeight}`,
|
|
2506
|
-
`L ${halfThickness} ${-halfHeight}`,
|
|
2507
|
-
`L ${halfThickness} ${-halfThickness}`,
|
|
2508
|
-
`L ${halfWidth} ${-halfThickness}`,
|
|
2509
|
-
`L ${halfWidth} ${halfThickness}`,
|
|
2510
|
-
`L ${halfThickness} ${halfThickness}`,
|
|
2511
|
-
`L ${halfThickness} ${halfHeight}`,
|
|
2512
|
-
`L ${-halfThickness} ${halfHeight}`,
|
|
2513
|
-
`L ${-halfThickness} ${halfThickness}`,
|
|
2514
|
-
`L ${-halfWidth} ${halfThickness}`,
|
|
2515
|
-
`L ${-halfWidth} ${-halfThickness}`,
|
|
2516
|
-
`L ${-halfThickness} ${-halfThickness}`,
|
|
2517
|
-
"Z"
|
|
2518
|
-
].join(" ");
|
|
2519
|
-
}
|
|
2520
|
-
function generateRingPath(params) {
|
|
2521
|
-
const { outerRadius, innerRadius } = params;
|
|
2522
|
-
const outerPath = generateCirclePath({ radius: outerRadius });
|
|
2523
|
-
const innerPath = generateCirclePath({ radius: innerRadius });
|
|
2524
|
-
return `${outerPath} ${reverseWindingOrder(innerPath)}`;
|
|
2525
|
-
}
|
|
2526
|
-
function pointsToPath(points, closed = true) {
|
|
2527
|
-
if (points.length === 0) return "";
|
|
2528
|
-
const commands = [`M ${points[0].x} ${points[0].y}`];
|
|
2529
|
-
for (let i = 1; i < points.length; i++) {
|
|
2530
|
-
commands.push(`L ${points[i].x} ${points[i].y}`);
|
|
2531
|
-
}
|
|
2532
|
-
if (closed) {
|
|
2533
|
-
commands.push("Z");
|
|
2534
|
-
}
|
|
2535
|
-
return commands.join(" ");
|
|
2536
|
-
}
|
|
2537
|
-
function reverseWindingOrder(path) {
|
|
2538
|
-
const commands = parsePathCommands(path);
|
|
2539
|
-
const reversed = [];
|
|
2540
|
-
const points = [];
|
|
2541
|
-
let currentX = 0;
|
|
2542
|
-
let currentY = 0;
|
|
2543
|
-
for (const cmd of commands) {
|
|
2544
|
-
if (cmd.type === "M" || cmd.type === "L") {
|
|
2545
|
-
points.push({ x: cmd.x, y: cmd.y });
|
|
2546
|
-
currentX = cmd.x;
|
|
2547
|
-
currentY = cmd.y;
|
|
2548
|
-
} else if (cmd.type === "C") {
|
|
2549
|
-
points.push({ x: cmd.x, y: cmd.y });
|
|
2550
|
-
currentX = cmd.x;
|
|
2551
|
-
currentY = cmd.y;
|
|
2552
|
-
}
|
|
2553
|
-
}
|
|
2554
|
-
if (points.length === 0) return path;
|
|
2555
|
-
points.reverse();
|
|
2556
|
-
reversed.push(`M ${points[0].x} ${points[0].y}`);
|
|
2557
|
-
for (let i = 1; i < points.length; i++) {
|
|
2558
|
-
reversed.push(`L ${points[i].x} ${points[i].y}`);
|
|
2559
|
-
}
|
|
2560
|
-
reversed.push("Z");
|
|
2561
|
-
return reversed.join(" ");
|
|
2562
|
-
}
|
|
2563
|
-
function parsePathCommands(path) {
|
|
2564
|
-
const commands = [];
|
|
2565
|
-
const regex = /([MLCQZ])\s*([^MLCQZ]*)/gi;
|
|
2566
|
-
let match;
|
|
2567
|
-
while ((match = regex.exec(path)) !== null) {
|
|
2568
|
-
const type = match[1].toUpperCase();
|
|
2569
|
-
const args = match[2].trim().split(/[\s,]+/).filter((s) => s.length > 0).map(parseFloat);
|
|
2570
|
-
if (type === "M" || type === "L") {
|
|
2571
|
-
commands.push({ type, x: args[0], y: args[1] });
|
|
2572
|
-
} else if (type === "C") {
|
|
2573
|
-
commands.push({
|
|
2574
|
-
type,
|
|
2575
|
-
x1: args[0],
|
|
2576
|
-
y1: args[1],
|
|
2577
|
-
x2: args[2],
|
|
2578
|
-
y2: args[3],
|
|
2579
|
-
x: args[4],
|
|
2580
|
-
y: args[5]
|
|
2581
|
-
});
|
|
2582
|
-
} else if (type === "Q") {
|
|
2583
|
-
commands.push({
|
|
2584
|
-
type,
|
|
2585
|
-
x1: args[0],
|
|
2586
|
-
y1: args[1],
|
|
2587
|
-
x: args[2],
|
|
2588
|
-
y: args[3]
|
|
2589
|
-
});
|
|
2590
|
-
} else if (type === "Z") {
|
|
2591
|
-
commands.push({ type });
|
|
2592
|
-
}
|
|
2593
|
-
}
|
|
2594
|
-
return commands;
|
|
2595
|
-
}
|
|
2596
|
-
function computePathBounds3(path) {
|
|
2597
|
-
const commands = parsePathCommands(path);
|
|
2598
|
-
let minX = Infinity;
|
|
2599
|
-
let minY = Infinity;
|
|
2600
|
-
let maxX = -Infinity;
|
|
2601
|
-
let maxY = -Infinity;
|
|
2602
|
-
const updateBounds = (x, y) => {
|
|
2603
|
-
minX = Math.min(minX, x);
|
|
2604
|
-
minY = Math.min(minY, y);
|
|
2605
|
-
maxX = Math.max(maxX, x);
|
|
2606
|
-
maxY = Math.max(maxY, y);
|
|
2607
|
-
};
|
|
2608
|
-
for (const cmd of commands) {
|
|
2609
|
-
if (cmd.x !== void 0 && cmd.y !== void 0) {
|
|
2610
|
-
updateBounds(cmd.x, cmd.y);
|
|
2611
|
-
}
|
|
2612
|
-
if (cmd.x1 !== void 0 && cmd.y1 !== void 0) {
|
|
2613
|
-
updateBounds(cmd.x1, cmd.y1);
|
|
2614
|
-
}
|
|
2615
|
-
if (cmd.x2 !== void 0 && cmd.y2 !== void 0) {
|
|
2616
|
-
updateBounds(cmd.x2, cmd.y2);
|
|
2617
|
-
}
|
|
2618
|
-
}
|
|
2619
|
-
if (minX === Infinity) {
|
|
2620
|
-
return { x: 0, y: 0, w: 0, h: 0 };
|
|
2621
|
-
}
|
|
2622
|
-
return {
|
|
2623
|
-
x: minX,
|
|
2624
|
-
y: minY,
|
|
2625
|
-
w: maxX - minX,
|
|
2626
|
-
h: maxY - minY
|
|
2627
|
-
};
|
|
2628
|
-
}
|
|
2629
|
-
function translatePath(path, dx, dy) {
|
|
2630
|
-
return path.replace(
|
|
2631
|
-
/(-?\d*\.?\d+(?:e[-+]?\d+)?)\s+(-?\d*\.?\d+(?:e[-+]?\d+)?)/gi,
|
|
2632
|
-
(match, x, y) => {
|
|
2633
|
-
const newX = parseFloat(x) + dx;
|
|
2634
|
-
const newY = parseFloat(y) + dy;
|
|
2635
|
-
return `${newX} ${newY}`;
|
|
2636
|
-
}
|
|
2637
|
-
);
|
|
2638
|
-
}
|
|
2639
|
-
function scalePath(path, sx, sy = sx) {
|
|
2640
|
-
return path.replace(
|
|
2641
|
-
/(-?\d*\.?\d+(?:e[-+]?\d+)?)\s+(-?\d*\.?\d+(?:e[-+]?\d+)?)/gi,
|
|
2642
|
-
(match, x, y) => {
|
|
2643
|
-
const newX = parseFloat(x) * sx;
|
|
2644
|
-
const newY = parseFloat(y) * sy;
|
|
2645
|
-
return `${newX} ${newY}`;
|
|
2646
|
-
}
|
|
2647
|
-
);
|
|
2648
|
-
}
|
|
2649
|
-
function rotatePath(path, angleDegrees) {
|
|
2650
|
-
const angleRadians = angleDegrees * DEG_TO_RAD;
|
|
2651
|
-
const cos = Math.cos(angleRadians);
|
|
2652
|
-
const sin = Math.sin(angleRadians);
|
|
2653
|
-
return path.replace(
|
|
2654
|
-
/(-?\d*\.?\d+(?:e[-+]?\d+)?)\s+(-?\d*\.?\d+(?:e[-+]?\d+)?)/gi,
|
|
2655
|
-
(match, x, y) => {
|
|
2656
|
-
const px = parseFloat(x);
|
|
2657
|
-
const py = parseFloat(y);
|
|
2658
|
-
const newX = px * cos - py * sin;
|
|
2659
|
-
const newY = px * sin + py * cos;
|
|
2660
|
-
return `${newX} ${newY}`;
|
|
2661
|
-
}
|
|
2662
|
-
);
|
|
2663
|
-
}
|
|
2664
|
-
function centerPath(path) {
|
|
2665
|
-
const bounds = computePathBounds3(path);
|
|
2666
|
-
const cx = bounds.x + bounds.w / 2;
|
|
2667
|
-
const cy = bounds.y + bounds.h / 2;
|
|
2668
|
-
return translatePath(path, -cx, -cy);
|
|
2669
|
-
}
|
|
2670
|
-
function normalizePathToSize(path, targetWidth, targetHeight) {
|
|
2671
|
-
const bounds = computePathBounds3(path);
|
|
2672
|
-
if (bounds.w === 0 || bounds.h === 0) return path;
|
|
2673
|
-
const scaleX = targetWidth / bounds.w;
|
|
2674
|
-
const scaleY = targetHeight / bounds.h;
|
|
2675
|
-
const scale = Math.min(scaleX, scaleY);
|
|
2676
|
-
let normalized = translatePath(path, -bounds.x, -bounds.y);
|
|
2677
|
-
normalized = scalePath(normalized, scale);
|
|
2678
|
-
return normalized;
|
|
2679
|
-
}
|
|
2680
|
-
|
|
2681
2352
|
// src/core/svg-path-utils.ts
|
|
2682
2353
|
var TAU = Math.PI * 2;
|
|
2683
2354
|
var PATH_COMMAND_REGEX = /([MmLlHhVvCcSsQqTtAaZz])([^MmLlHhVvCcSsQqTtAaZz]*)/g;
|
|
@@ -3074,109 +2745,212 @@ function quadraticToCubic(x0, y0, qx, qy, x, y) {
|
|
|
3074
2745
|
};
|
|
3075
2746
|
}
|
|
3076
2747
|
|
|
3077
|
-
// src/core/
|
|
3078
|
-
var
|
|
3079
|
-
var
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
const
|
|
3108
|
-
const
|
|
3109
|
-
const
|
|
3110
|
-
|
|
3111
|
-
}
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
|
|
3117
|
-
|
|
3118
|
-
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
navy: "#000080",
|
|
3135
|
-
teal: "#008080",
|
|
3136
|
-
olive: "#808000",
|
|
3137
|
-
maroon: "#800000",
|
|
3138
|
-
aqua: "#00FFFF",
|
|
3139
|
-
lime: "#00FF00",
|
|
3140
|
-
silver: "#C0C0C0",
|
|
3141
|
-
fuchsia: "#FF00FF"
|
|
2748
|
+
// src/core/resvg-renderer-web.ts
|
|
2749
|
+
var resvgWasmModule = null;
|
|
2750
|
+
var wasmInitialized = false;
|
|
2751
|
+
async function initResvgWasm() {
|
|
2752
|
+
if (resvgWasmModule && wasmInitialized) {
|
|
2753
|
+
return resvgWasmModule;
|
|
2754
|
+
}
|
|
2755
|
+
const wasmModule = await import("@resvg/resvg-wasm");
|
|
2756
|
+
resvgWasmModule = wasmModule;
|
|
2757
|
+
if (!wasmInitialized) {
|
|
2758
|
+
const wasmUrl = new URL("@resvg/resvg-wasm/index_bg.wasm", import.meta.url);
|
|
2759
|
+
const wasmResponse = await fetch(wasmUrl);
|
|
2760
|
+
const wasmBytes = await wasmResponse.arrayBuffer();
|
|
2761
|
+
const compiled = await WebAssembly.compile(wasmBytes);
|
|
2762
|
+
await resvgWasmModule.initWasm(compiled);
|
|
2763
|
+
wasmInitialized = true;
|
|
2764
|
+
}
|
|
2765
|
+
return resvgWasmModule;
|
|
2766
|
+
}
|
|
2767
|
+
async function initResvg(wasmBinary) {
|
|
2768
|
+
if (wasmInitialized) {
|
|
2769
|
+
return;
|
|
2770
|
+
}
|
|
2771
|
+
const wasmModule = await import("@resvg/resvg-wasm");
|
|
2772
|
+
resvgWasmModule = wasmModule;
|
|
2773
|
+
if (wasmBinary) {
|
|
2774
|
+
const compiled = await WebAssembly.compile(wasmBinary);
|
|
2775
|
+
await resvgWasmModule.initWasm(compiled);
|
|
2776
|
+
} else {
|
|
2777
|
+
const wasmUrl = new URL("@resvg/resvg-wasm/index_bg.wasm", import.meta.url);
|
|
2778
|
+
const wasmResponse = await fetch(wasmUrl);
|
|
2779
|
+
const wasmBytes = await wasmResponse.arrayBuffer();
|
|
2780
|
+
const compiled = await WebAssembly.compile(wasmBytes);
|
|
2781
|
+
await resvgWasmModule.initWasm(compiled);
|
|
2782
|
+
}
|
|
2783
|
+
wasmInitialized = true;
|
|
2784
|
+
}
|
|
2785
|
+
async function renderSvgToPng(svgString, options = {}) {
|
|
2786
|
+
const { Resvg } = await initResvgWasm();
|
|
2787
|
+
const resvgOptions = {};
|
|
2788
|
+
if (options.background) {
|
|
2789
|
+
resvgOptions.background = options.background;
|
|
2790
|
+
}
|
|
2791
|
+
if (options.fitTo) {
|
|
2792
|
+
resvgOptions.fitTo = options.fitTo;
|
|
2793
|
+
} else if (options.width) {
|
|
2794
|
+
resvgOptions.fitTo = { mode: "width", value: options.width };
|
|
2795
|
+
} else if (options.height) {
|
|
2796
|
+
resvgOptions.fitTo = { mode: "height", value: options.height };
|
|
2797
|
+
}
|
|
2798
|
+
const resvg = new Resvg(svgString, resvgOptions);
|
|
2799
|
+
const rendered = resvg.render();
|
|
2800
|
+
const png = rendered.asPng();
|
|
2801
|
+
return {
|
|
2802
|
+
png,
|
|
2803
|
+
width: rendered.width,
|
|
2804
|
+
height: rendered.height
|
|
3142
2805
|
};
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
2806
|
+
}
|
|
2807
|
+
function shapeToSvgString(asset, defaultWidth, defaultHeight) {
|
|
2808
|
+
if (!asset.shape) {
|
|
2809
|
+
throw new Error("Shape is required for shape mode");
|
|
2810
|
+
}
|
|
2811
|
+
const width = asset.width ?? defaultWidth;
|
|
2812
|
+
const height = asset.height ?? defaultHeight;
|
|
2813
|
+
const pathData = generateShapePathData(asset.shape);
|
|
2814
|
+
const bounds = computeSimplePathBounds(pathData);
|
|
2815
|
+
const centerX = width / 2;
|
|
2816
|
+
const centerY = height / 2;
|
|
2817
|
+
const pathCenterX = bounds.x + bounds.w / 2;
|
|
2818
|
+
const pathCenterY = bounds.y + bounds.h / 2;
|
|
2819
|
+
let offsetX = centerX - pathCenterX;
|
|
2820
|
+
let offsetY = centerY - pathCenterY;
|
|
2821
|
+
if (asset.transform) {
|
|
2822
|
+
offsetX += asset.transform.x ?? 0;
|
|
2823
|
+
offsetY += asset.transform.y ?? 0;
|
|
2824
|
+
}
|
|
2825
|
+
const elements = [];
|
|
2826
|
+
if (asset.shadow) {
|
|
2827
|
+
const shadowOffsetX = asset.shadow.offsetX ?? 4;
|
|
2828
|
+
const shadowOffsetY = asset.shadow.offsetY ?? 4;
|
|
2829
|
+
const shadowColor = asset.shadow.color ?? "#000000";
|
|
2830
|
+
const shadowOpacity = asset.shadow.opacity ?? 0.5;
|
|
2831
|
+
elements.push(
|
|
2832
|
+
`<path d="${pathData}" transform="translate(${offsetX + shadowOffsetX}, ${offsetY + shadowOffsetY})" fill="${shadowColor}" fill-opacity="${shadowOpacity}"/>`
|
|
2833
|
+
);
|
|
2834
|
+
}
|
|
2835
|
+
const pathAttrs = [`d="${pathData}"`, `transform="translate(${offsetX}, ${offsetY})"`];
|
|
2836
|
+
if (asset.fill) {
|
|
2837
|
+
const fillId = `fill-${Date.now()}`;
|
|
2838
|
+
const fillDef = generateFillDefinition(asset.fill, fillId, bounds);
|
|
2839
|
+
if (fillDef.defs) {
|
|
2840
|
+
elements.unshift(fillDef.defs);
|
|
2841
|
+
}
|
|
2842
|
+
pathAttrs.push(`fill="${fillDef.fill}"`);
|
|
2843
|
+
if (asset.fill.opacity !== void 0 && asset.fill.opacity !== 1) {
|
|
2844
|
+
pathAttrs.push(`fill-opacity="${asset.fill.opacity}"`);
|
|
2845
|
+
}
|
|
2846
|
+
} else {
|
|
2847
|
+
pathAttrs.push(`fill="none"`);
|
|
2848
|
+
}
|
|
2849
|
+
if (asset.stroke && asset.stroke.width && asset.stroke.width > 0) {
|
|
2850
|
+
pathAttrs.push(`stroke="${asset.stroke.color ?? "#000000"}"`);
|
|
2851
|
+
pathAttrs.push(`stroke-width="${asset.stroke.width}"`);
|
|
2852
|
+
if (asset.stroke.opacity !== void 0 && asset.stroke.opacity !== 1) {
|
|
2853
|
+
pathAttrs.push(`stroke-opacity="${asset.stroke.opacity}"`);
|
|
2854
|
+
}
|
|
2855
|
+
if (asset.stroke.dashArray && asset.stroke.dashArray.length > 0) {
|
|
2856
|
+
pathAttrs.push(`stroke-dasharray="${asset.stroke.dashArray.join(" ")}"`);
|
|
2857
|
+
}
|
|
2858
|
+
if (asset.stroke.lineCap) {
|
|
2859
|
+
pathAttrs.push(`stroke-linecap="${asset.stroke.lineCap}"`);
|
|
2860
|
+
}
|
|
2861
|
+
if (asset.stroke.lineJoin) {
|
|
2862
|
+
pathAttrs.push(`stroke-linejoin="${asset.stroke.lineJoin}"`);
|
|
2863
|
+
}
|
|
2864
|
+
}
|
|
2865
|
+
if (asset.opacity !== void 0 && asset.opacity !== 1) {
|
|
2866
|
+
pathAttrs.push(`opacity="${asset.opacity}"`);
|
|
3146
2867
|
}
|
|
3147
|
-
|
|
2868
|
+
elements.push(`<path ${pathAttrs.join(" ")}/>`);
|
|
2869
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}">${elements.join(
|
|
2870
|
+
""
|
|
2871
|
+
)}</svg>`;
|
|
3148
2872
|
}
|
|
3149
|
-
function
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
}
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
if (
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
}
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
const
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
2873
|
+
function generateFillDefinition(fill, id, _bounds) {
|
|
2874
|
+
if (fill.type === "solid") {
|
|
2875
|
+
return { fill: fill.color };
|
|
2876
|
+
}
|
|
2877
|
+
if (fill.type === "linear") {
|
|
2878
|
+
const angle = fill.angle ?? 0;
|
|
2879
|
+
const rad = angle * Math.PI / 180;
|
|
2880
|
+
const x1 = 50 - Math.cos(rad) * 50;
|
|
2881
|
+
const y1 = 50 - Math.sin(rad) * 50;
|
|
2882
|
+
const x2 = 50 + Math.cos(rad) * 50;
|
|
2883
|
+
const y2 = 50 + Math.sin(rad) * 50;
|
|
2884
|
+
const stops = fill.stops.map((s) => `<stop offset="${s.offset * 100}%" stop-color="${s.color}"/>`).join("");
|
|
2885
|
+
const defs = `<defs><linearGradient id="${id}" x1="${x1}%" y1="${y1}%" x2="${x2}%" y2="${y2}%">${stops}</linearGradient></defs>`;
|
|
2886
|
+
return { fill: `url(#${id})`, defs };
|
|
2887
|
+
}
|
|
2888
|
+
if (fill.type === "radial") {
|
|
2889
|
+
const stops = fill.stops.map((s) => `<stop offset="${s.offset * 100}%" stop-color="${s.color}"/>`).join("");
|
|
2890
|
+
const defs = `<defs><radialGradient id="${id}" cx="50%" cy="50%" r="50%">${stops}</radialGradient></defs>`;
|
|
2891
|
+
return { fill: `url(#${id})`, defs };
|
|
2892
|
+
}
|
|
2893
|
+
return { fill: "#000000" };
|
|
2894
|
+
}
|
|
2895
|
+
function generateShapePathData(shape) {
|
|
2896
|
+
const shapeType = shape.type;
|
|
2897
|
+
switch (shapeType) {
|
|
2898
|
+
case "rectangle": {
|
|
2899
|
+
const s = shape;
|
|
2900
|
+
return generateRectanglePath(s.width, s.height, s.cornerRadius ?? 0);
|
|
2901
|
+
}
|
|
2902
|
+
case "circle": {
|
|
2903
|
+
const s = shape;
|
|
2904
|
+
return generateCirclePath(s.radius);
|
|
2905
|
+
}
|
|
2906
|
+
case "ellipse": {
|
|
2907
|
+
const s = shape;
|
|
2908
|
+
return generateEllipsePath(s.radiusX, s.radiusY);
|
|
2909
|
+
}
|
|
2910
|
+
case "line": {
|
|
2911
|
+
const s = shape;
|
|
2912
|
+
return generateLinePath(s.length, s.thickness ?? 2);
|
|
2913
|
+
}
|
|
2914
|
+
case "polygon": {
|
|
2915
|
+
const s = shape;
|
|
2916
|
+
return generatePolygonPath(s.sides, s.radius);
|
|
2917
|
+
}
|
|
2918
|
+
case "star": {
|
|
2919
|
+
const s = shape;
|
|
2920
|
+
return generateStarPath(s.points, s.outerRadius, s.innerRadius);
|
|
2921
|
+
}
|
|
2922
|
+
case "arrow": {
|
|
2923
|
+
const s = shape;
|
|
2924
|
+
return generateArrowPath(s.length, s.headWidth ?? 30, s.headLength ?? 25, s.shaftWidth ?? 10);
|
|
2925
|
+
}
|
|
2926
|
+
case "heart": {
|
|
2927
|
+
const s = shape;
|
|
2928
|
+
return generateHeartPath(s.size);
|
|
2929
|
+
}
|
|
2930
|
+
case "cross": {
|
|
2931
|
+
const s = shape;
|
|
2932
|
+
return generateCrossPath(s.width, s.height, s.thickness);
|
|
2933
|
+
}
|
|
2934
|
+
case "ring": {
|
|
2935
|
+
const s = shape;
|
|
2936
|
+
return generateRingPath(s.outerRadius, s.innerRadius);
|
|
2937
|
+
}
|
|
2938
|
+
case "path": {
|
|
2939
|
+
const s = shape;
|
|
2940
|
+
return s.d;
|
|
2941
|
+
}
|
|
2942
|
+
default:
|
|
2943
|
+
throw new Error(`Unknown shape type: ${shapeType}`);
|
|
2944
|
+
}
|
|
2945
|
+
}
|
|
2946
|
+
var KAPPA = 0.5522847498307936;
|
|
2947
|
+
function generateRectanglePath(width, height, cornerRadius) {
|
|
2948
|
+
const x = -width / 2;
|
|
2949
|
+
const y = -height / 2;
|
|
2950
|
+
const r = Math.min(cornerRadius, width / 2, height / 2);
|
|
2951
|
+
if (r === 0) {
|
|
3177
2952
|
return `M ${x} ${y} L ${x + width} ${y} L ${x + width} ${y + height} L ${x} ${y + height} Z`;
|
|
3178
2953
|
}
|
|
3179
|
-
const r = Math.min(rx, ry, width / 2, height / 2);
|
|
3180
2954
|
return [
|
|
3181
2955
|
`M ${x + r} ${y}`,
|
|
3182
2956
|
`L ${x + width - r} ${y}`,
|
|
@@ -3190,288 +2964,350 @@ function rectToPath(attrs) {
|
|
|
3190
2964
|
"Z"
|
|
3191
2965
|
].join(" ");
|
|
3192
2966
|
}
|
|
3193
|
-
function
|
|
3194
|
-
const
|
|
3195
|
-
const cy = parseNumber(extractAttribute(attrs, "cy")) || 0;
|
|
3196
|
-
const r = parseNumber(extractAttribute(attrs, "r")) || 0;
|
|
3197
|
-
if (r === 0) return "";
|
|
3198
|
-
const KAPPA2 = 0.5522847498307936;
|
|
3199
|
-
const k = r * KAPPA2;
|
|
2967
|
+
function generateCirclePath(radius) {
|
|
2968
|
+
const k = radius * KAPPA;
|
|
3200
2969
|
return [
|
|
3201
|
-
`M ${
|
|
3202
|
-
`C ${
|
|
3203
|
-
`C ${
|
|
3204
|
-
`C ${
|
|
3205
|
-
`C ${
|
|
2970
|
+
`M ${radius} 0`,
|
|
2971
|
+
`C ${radius} ${k} ${k} ${radius} 0 ${radius}`,
|
|
2972
|
+
`C ${-k} ${radius} ${-radius} ${k} ${-radius} 0`,
|
|
2973
|
+
`C ${-radius} ${-k} ${-k} ${-radius} 0 ${-radius}`,
|
|
2974
|
+
`C ${k} ${-radius} ${radius} ${-k} ${radius} 0`,
|
|
3206
2975
|
"Z"
|
|
3207
2976
|
].join(" ");
|
|
3208
2977
|
}
|
|
3209
|
-
function
|
|
3210
|
-
const
|
|
3211
|
-
const cy = parseNumber(extractAttribute(attrs, "cy")) || 0;
|
|
3212
|
-
const rx = parseNumber(extractAttribute(attrs, "rx")) || 0;
|
|
3213
|
-
const ry = parseNumber(extractAttribute(attrs, "ry")) || 0;
|
|
3214
|
-
if (rx === 0 || ry === 0) return "";
|
|
3215
|
-
const KAPPA2 = 0.5522847498307936;
|
|
3216
|
-
const kx = rx * KAPPA2;
|
|
3217
|
-
const ky = ry * KAPPA2;
|
|
2978
|
+
function generateCirclePathReversed(radius) {
|
|
2979
|
+
const k = radius * KAPPA;
|
|
3218
2980
|
return [
|
|
3219
|
-
`M ${
|
|
3220
|
-
`C ${
|
|
3221
|
-
`C ${
|
|
3222
|
-
`C ${
|
|
3223
|
-
`C ${
|
|
2981
|
+
`M ${radius} 0`,
|
|
2982
|
+
`C ${radius} ${-k} ${k} ${-radius} 0 ${-radius}`,
|
|
2983
|
+
`C ${-k} ${-radius} ${-radius} ${-k} ${-radius} 0`,
|
|
2984
|
+
`C ${-radius} ${k} ${-k} ${radius} 0 ${radius}`,
|
|
2985
|
+
`C ${k} ${radius} ${radius} ${k} ${radius} 0`,
|
|
2986
|
+
"Z"
|
|
2987
|
+
].join(" ");
|
|
2988
|
+
}
|
|
2989
|
+
function generateEllipsePath(radiusX, radiusY) {
|
|
2990
|
+
const kx = radiusX * KAPPA;
|
|
2991
|
+
const ky = radiusY * KAPPA;
|
|
2992
|
+
return [
|
|
2993
|
+
`M ${radiusX} 0`,
|
|
2994
|
+
`C ${radiusX} ${ky} ${kx} ${radiusY} 0 ${radiusY}`,
|
|
2995
|
+
`C ${-kx} ${radiusY} ${-radiusX} ${ky} ${-radiusX} 0`,
|
|
2996
|
+
`C ${-radiusX} ${-ky} ${-kx} ${-radiusY} 0 ${-radiusY}`,
|
|
2997
|
+
`C ${kx} ${-radiusY} ${radiusX} ${-ky} ${radiusX} 0`,
|
|
3224
2998
|
"Z"
|
|
3225
2999
|
].join(" ");
|
|
3226
3000
|
}
|
|
3227
|
-
function
|
|
3228
|
-
const
|
|
3229
|
-
const
|
|
3230
|
-
|
|
3231
|
-
|
|
3232
|
-
|
|
3233
|
-
|
|
3234
|
-
|
|
3235
|
-
const points =
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
|
|
3001
|
+
function generateLinePath(length, thickness) {
|
|
3002
|
+
const halfLen = length / 2;
|
|
3003
|
+
const halfThick = thickness / 2;
|
|
3004
|
+
return `M ${-halfLen} ${-halfThick} L ${halfLen} ${-halfThick} L ${halfLen} ${halfThick} L ${-halfLen} ${halfThick} Z`;
|
|
3005
|
+
}
|
|
3006
|
+
function generatePolygonPath(sides, radius) {
|
|
3007
|
+
const angleStep = 2 * Math.PI / sides;
|
|
3008
|
+
const startAngle = -Math.PI / 2;
|
|
3009
|
+
const points = [];
|
|
3010
|
+
for (let i = 0; i < sides; i++) {
|
|
3011
|
+
const angle = startAngle + i * angleStep;
|
|
3012
|
+
const x = Math.cos(angle) * radius;
|
|
3013
|
+
const y = Math.sin(angle) * radius;
|
|
3014
|
+
points.push(i === 0 ? `M ${x} ${y}` : `L ${x} ${y}`);
|
|
3015
|
+
}
|
|
3016
|
+
points.push("Z");
|
|
3017
|
+
return points.join(" ");
|
|
3018
|
+
}
|
|
3019
|
+
function generateStarPath(points, outerRadius, innerRadius) {
|
|
3020
|
+
const angleStep = Math.PI / points;
|
|
3021
|
+
const startAngle = -Math.PI / 2;
|
|
3239
3022
|
const pathParts = [];
|
|
3240
|
-
for (let i = 0; i <
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
|
|
3245
|
-
|
|
3246
|
-
}
|
|
3247
|
-
}
|
|
3023
|
+
for (let i = 0; i < points * 2; i++) {
|
|
3024
|
+
const angle = startAngle + i * angleStep;
|
|
3025
|
+
const radius = i % 2 === 0 ? outerRadius : innerRadius;
|
|
3026
|
+
const x = Math.cos(angle) * radius;
|
|
3027
|
+
const y = Math.sin(angle) * radius;
|
|
3028
|
+
pathParts.push(i === 0 ? `M ${x} ${y}` : `L ${x} ${y}`);
|
|
3248
3029
|
}
|
|
3030
|
+
pathParts.push("Z");
|
|
3249
3031
|
return pathParts.join(" ");
|
|
3250
3032
|
}
|
|
3251
|
-
function
|
|
3252
|
-
const
|
|
3253
|
-
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
|
|
3259
|
-
|
|
3260
|
-
|
|
3261
|
-
|
|
3262
|
-
|
|
3263
|
-
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
let styleFill = fill;
|
|
3267
|
-
let styleStroke = stroke;
|
|
3268
|
-
let styleStrokeWidth = strokeWidth;
|
|
3269
|
-
let styleOpacity = opacity;
|
|
3270
|
-
if (style) {
|
|
3271
|
-
const fillMatch = style.match(/fill\s*:\s*([^;]+)/i);
|
|
3272
|
-
if (fillMatch) styleFill = fillMatch[1].trim();
|
|
3273
|
-
const strokeMatch = style.match(/stroke\s*:\s*([^;]+)/i);
|
|
3274
|
-
if (strokeMatch) styleStroke = strokeMatch[1].trim();
|
|
3275
|
-
const strokeWidthMatch = style.match(/stroke-width\s*:\s*([^;]+)/i);
|
|
3276
|
-
if (strokeWidthMatch) styleStrokeWidth = parseNumber(strokeWidthMatch[1].trim());
|
|
3277
|
-
const opacityMatch = style.match(/opacity\s*:\s*([^;]+)/i);
|
|
3278
|
-
if (opacityMatch) styleOpacity = parseNumber(opacityMatch[1].trim());
|
|
3279
|
-
}
|
|
3280
|
-
return {
|
|
3281
|
-
d,
|
|
3282
|
-
fill: styleFill,
|
|
3283
|
-
fillOpacity,
|
|
3284
|
-
stroke: styleStroke,
|
|
3285
|
-
strokeWidth: styleStrokeWidth,
|
|
3286
|
-
strokeOpacity,
|
|
3287
|
-
opacity: styleOpacity,
|
|
3288
|
-
transform
|
|
3289
|
-
};
|
|
3033
|
+
function generateArrowPath(length, headWidth, headLength, shaftWidth) {
|
|
3034
|
+
const halfShaft = shaftWidth / 2;
|
|
3035
|
+
const halfHead = headWidth / 2;
|
|
3036
|
+
const shaftLength = length - headLength;
|
|
3037
|
+
const startX = -length / 2;
|
|
3038
|
+
return [
|
|
3039
|
+
`M ${startX} ${-halfShaft}`,
|
|
3040
|
+
`L ${startX + shaftLength} ${-halfShaft}`,
|
|
3041
|
+
`L ${startX + shaftLength} ${-halfHead}`,
|
|
3042
|
+
`L ${startX + length} 0`,
|
|
3043
|
+
`L ${startX + shaftLength} ${halfHead}`,
|
|
3044
|
+
`L ${startX + shaftLength} ${halfShaft}`,
|
|
3045
|
+
`L ${startX} ${halfShaft}`,
|
|
3046
|
+
"Z"
|
|
3047
|
+
].join(" ");
|
|
3290
3048
|
}
|
|
3291
|
-
function
|
|
3292
|
-
const
|
|
3293
|
-
|
|
3294
|
-
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
|
|
3299
|
-
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
const viewBox = parseViewBox(viewBoxAttr);
|
|
3307
|
-
if (viewBox && (!width || !height)) {
|
|
3308
|
-
width = width || viewBox.width;
|
|
3309
|
-
height = height || viewBox.height;
|
|
3310
|
-
}
|
|
3311
|
-
const paths = [];
|
|
3312
|
-
let match;
|
|
3313
|
-
PATH_TAG_REGEX.lastIndex = 0;
|
|
3314
|
-
while ((match = PATH_TAG_REGEX.exec(svgString)) !== null) {
|
|
3315
|
-
const pathAttrs = extractPathAttributes(match[1]);
|
|
3316
|
-
if (pathAttrs.d) {
|
|
3317
|
-
paths.push(pathAttrs);
|
|
3318
|
-
}
|
|
3319
|
-
}
|
|
3320
|
-
RECT_TAG_REGEX.lastIndex = 0;
|
|
3321
|
-
while ((match = RECT_TAG_REGEX.exec(svgString)) !== null) {
|
|
3322
|
-
const path = extractShapeAsPath(match[1], rectToPath);
|
|
3323
|
-
if (path) paths.push(path);
|
|
3324
|
-
}
|
|
3325
|
-
CIRCLE_TAG_REGEX.lastIndex = 0;
|
|
3326
|
-
while ((match = CIRCLE_TAG_REGEX.exec(svgString)) !== null) {
|
|
3327
|
-
const path = extractShapeAsPath(match[1], circleToPath);
|
|
3328
|
-
if (path) paths.push(path);
|
|
3329
|
-
}
|
|
3330
|
-
ELLIPSE_TAG_REGEX.lastIndex = 0;
|
|
3331
|
-
while ((match = ELLIPSE_TAG_REGEX.exec(svgString)) !== null) {
|
|
3332
|
-
const path = extractShapeAsPath(match[1], ellipseToPath);
|
|
3333
|
-
if (path) paths.push(path);
|
|
3334
|
-
}
|
|
3335
|
-
LINE_TAG_REGEX.lastIndex = 0;
|
|
3336
|
-
while ((match = LINE_TAG_REGEX.exec(svgString)) !== null) {
|
|
3337
|
-
const path = extractShapeAsPath(match[1], lineToPath);
|
|
3338
|
-
if (path) paths.push(path);
|
|
3339
|
-
}
|
|
3340
|
-
POLYLINE_TAG_REGEX.lastIndex = 0;
|
|
3341
|
-
while ((match = POLYLINE_TAG_REGEX.exec(svgString)) !== null) {
|
|
3342
|
-
const path = extractShapeAsPath(match[1], polylineToPath);
|
|
3343
|
-
if (path) paths.push(path);
|
|
3344
|
-
}
|
|
3345
|
-
POLYGON_TAG_REGEX.lastIndex = 0;
|
|
3346
|
-
while ((match = POLYGON_TAG_REGEX.exec(svgString)) !== null) {
|
|
3347
|
-
const path = extractShapeAsPath(match[1], polygonToPath);
|
|
3348
|
-
if (path) paths.push(path);
|
|
3349
|
-
}
|
|
3350
|
-
return {
|
|
3351
|
-
width,
|
|
3352
|
-
height,
|
|
3353
|
-
viewBox,
|
|
3354
|
-
paths
|
|
3355
|
-
};
|
|
3049
|
+
function generateHeartPath(size) {
|
|
3050
|
+
const scale = size / 32;
|
|
3051
|
+
const points = [
|
|
3052
|
+
"M 0 6",
|
|
3053
|
+
"C -0.5 -3 -12 -3 -12 6",
|
|
3054
|
+
"C -12 12 0 18 0 24",
|
|
3055
|
+
"C 0 18 12 12 12 6",
|
|
3056
|
+
"C 12 -3 0.5 -3 0 6",
|
|
3057
|
+
"Z"
|
|
3058
|
+
];
|
|
3059
|
+
return points.map((cmd) => {
|
|
3060
|
+
return cmd.replace(/-?\d+(\.\d+)?/g, (match) => {
|
|
3061
|
+
return String(parseFloat(match) * scale);
|
|
3062
|
+
});
|
|
3063
|
+
}).join(" ");
|
|
3356
3064
|
}
|
|
3357
|
-
function
|
|
3358
|
-
const
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
}
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3065
|
+
function generateCrossPath(width, height, thickness) {
|
|
3066
|
+
const hw = width / 2;
|
|
3067
|
+
const hh = height / 2;
|
|
3068
|
+
const ht = thickness / 2;
|
|
3069
|
+
return [
|
|
3070
|
+
`M ${-ht} ${-hh}`,
|
|
3071
|
+
`L ${ht} ${-hh}`,
|
|
3072
|
+
`L ${ht} ${-ht}`,
|
|
3073
|
+
`L ${hw} ${-ht}`,
|
|
3074
|
+
`L ${hw} ${ht}`,
|
|
3075
|
+
`L ${ht} ${ht}`,
|
|
3076
|
+
`L ${ht} ${hh}`,
|
|
3077
|
+
`L ${-ht} ${hh}`,
|
|
3078
|
+
`L ${-ht} ${ht}`,
|
|
3079
|
+
`L ${-hw} ${ht}`,
|
|
3080
|
+
`L ${-hw} ${-ht}`,
|
|
3081
|
+
`L ${-ht} ${-ht}`,
|
|
3082
|
+
"Z"
|
|
3083
|
+
].join(" ");
|
|
3374
3084
|
}
|
|
3375
|
-
function
|
|
3376
|
-
const
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
};
|
|
3389
|
-
if (path.fillOpacity !== void 0 && path.fillOpacity !== 1) {
|
|
3390
|
-
asset.fill.opacity = path.fillOpacity;
|
|
3391
|
-
}
|
|
3392
|
-
}
|
|
3393
|
-
const strokeColor = parseColor(path.stroke);
|
|
3394
|
-
if (strokeColor && path.strokeWidth && path.strokeWidth > 0) {
|
|
3395
|
-
asset.stroke = {
|
|
3396
|
-
color: strokeColor,
|
|
3397
|
-
width: path.strokeWidth
|
|
3398
|
-
};
|
|
3399
|
-
if (path.strokeOpacity !== void 0 && path.strokeOpacity !== 1) {
|
|
3400
|
-
asset.stroke.opacity = path.strokeOpacity;
|
|
3085
|
+
function generateRingPath(outerRadius, innerRadius) {
|
|
3086
|
+
const outerPath = generateCirclePath(outerRadius);
|
|
3087
|
+
const innerPath = generateCirclePathReversed(innerRadius);
|
|
3088
|
+
return `${outerPath} ${innerPath}`;
|
|
3089
|
+
}
|
|
3090
|
+
function computeSimplePathBounds(d) {
|
|
3091
|
+
const numberRegex = /-?(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?/g;
|
|
3092
|
+
const numbers = [];
|
|
3093
|
+
let match;
|
|
3094
|
+
while ((match = numberRegex.exec(d)) !== null) {
|
|
3095
|
+
const num = parseFloat(match[0]);
|
|
3096
|
+
if (!isNaN(num) && isFinite(num)) {
|
|
3097
|
+
numbers.push(num);
|
|
3401
3098
|
}
|
|
3402
3099
|
}
|
|
3403
|
-
if (
|
|
3404
|
-
|
|
3405
|
-
}
|
|
3406
|
-
if (width > 0) {
|
|
3407
|
-
asset.width = width;
|
|
3100
|
+
if (numbers.length < 2) {
|
|
3101
|
+
return { x: 0, y: 0, w: 0, h: 0 };
|
|
3408
3102
|
}
|
|
3409
|
-
|
|
3410
|
-
|
|
3103
|
+
let minX = Infinity;
|
|
3104
|
+
let minY = Infinity;
|
|
3105
|
+
let maxX = -Infinity;
|
|
3106
|
+
let maxY = -Infinity;
|
|
3107
|
+
let currentX = 0;
|
|
3108
|
+
let currentY = 0;
|
|
3109
|
+
const commands = d.match(/[MmLlHhVvCcSsQqTtAaZz]/g) || [];
|
|
3110
|
+
let cmdIndex = 0;
|
|
3111
|
+
let numIndex = 0;
|
|
3112
|
+
while (cmdIndex < commands.length) {
|
|
3113
|
+
const cmd = commands[cmdIndex];
|
|
3114
|
+
switch (cmd) {
|
|
3115
|
+
case "M":
|
|
3116
|
+
case "L":
|
|
3117
|
+
case "T":
|
|
3118
|
+
if (numIndex + 1 < numbers.length) {
|
|
3119
|
+
currentX = numbers[numIndex++];
|
|
3120
|
+
currentY = numbers[numIndex++];
|
|
3121
|
+
minX = Math.min(minX, currentX);
|
|
3122
|
+
maxX = Math.max(maxX, currentX);
|
|
3123
|
+
minY = Math.min(minY, currentY);
|
|
3124
|
+
maxY = Math.max(maxY, currentY);
|
|
3125
|
+
}
|
|
3126
|
+
break;
|
|
3127
|
+
case "m":
|
|
3128
|
+
case "l":
|
|
3129
|
+
case "t":
|
|
3130
|
+
if (numIndex + 1 < numbers.length) {
|
|
3131
|
+
currentX += numbers[numIndex++];
|
|
3132
|
+
currentY += numbers[numIndex++];
|
|
3133
|
+
minX = Math.min(minX, currentX);
|
|
3134
|
+
maxX = Math.max(maxX, currentX);
|
|
3135
|
+
minY = Math.min(minY, currentY);
|
|
3136
|
+
maxY = Math.max(maxY, currentY);
|
|
3137
|
+
}
|
|
3138
|
+
break;
|
|
3139
|
+
case "H":
|
|
3140
|
+
if (numIndex < numbers.length) {
|
|
3141
|
+
currentX = numbers[numIndex++];
|
|
3142
|
+
minX = Math.min(minX, currentX);
|
|
3143
|
+
maxX = Math.max(maxX, currentX);
|
|
3144
|
+
}
|
|
3145
|
+
break;
|
|
3146
|
+
case "h":
|
|
3147
|
+
if (numIndex < numbers.length) {
|
|
3148
|
+
currentX += numbers[numIndex++];
|
|
3149
|
+
minX = Math.min(minX, currentX);
|
|
3150
|
+
maxX = Math.max(maxX, currentX);
|
|
3151
|
+
}
|
|
3152
|
+
break;
|
|
3153
|
+
case "V":
|
|
3154
|
+
if (numIndex < numbers.length) {
|
|
3155
|
+
currentY = numbers[numIndex++];
|
|
3156
|
+
minY = Math.min(minY, currentY);
|
|
3157
|
+
maxY = Math.max(maxY, currentY);
|
|
3158
|
+
}
|
|
3159
|
+
break;
|
|
3160
|
+
case "v":
|
|
3161
|
+
if (numIndex < numbers.length) {
|
|
3162
|
+
currentY += numbers[numIndex++];
|
|
3163
|
+
minY = Math.min(minY, currentY);
|
|
3164
|
+
maxY = Math.max(maxY, currentY);
|
|
3165
|
+
}
|
|
3166
|
+
break;
|
|
3167
|
+
case "C":
|
|
3168
|
+
if (numIndex + 5 < numbers.length) {
|
|
3169
|
+
for (let j = 0; j < 3; j++) {
|
|
3170
|
+
const x = numbers[numIndex++];
|
|
3171
|
+
const y = numbers[numIndex++];
|
|
3172
|
+
minX = Math.min(minX, x);
|
|
3173
|
+
maxX = Math.max(maxX, x);
|
|
3174
|
+
minY = Math.min(minY, y);
|
|
3175
|
+
maxY = Math.max(maxY, y);
|
|
3176
|
+
if (j === 2) {
|
|
3177
|
+
currentX = x;
|
|
3178
|
+
currentY = y;
|
|
3179
|
+
}
|
|
3180
|
+
}
|
|
3181
|
+
}
|
|
3182
|
+
break;
|
|
3183
|
+
case "c":
|
|
3184
|
+
if (numIndex + 5 < numbers.length) {
|
|
3185
|
+
for (let j = 0; j < 3; j++) {
|
|
3186
|
+
const x = currentX + numbers[numIndex++];
|
|
3187
|
+
const y = currentY + numbers[numIndex++];
|
|
3188
|
+
minX = Math.min(minX, x);
|
|
3189
|
+
maxX = Math.max(maxX, x);
|
|
3190
|
+
minY = Math.min(minY, y);
|
|
3191
|
+
maxY = Math.max(maxY, y);
|
|
3192
|
+
if (j === 2) {
|
|
3193
|
+
currentX = x;
|
|
3194
|
+
currentY = y;
|
|
3195
|
+
}
|
|
3196
|
+
}
|
|
3197
|
+
}
|
|
3198
|
+
break;
|
|
3199
|
+
case "S":
|
|
3200
|
+
case "Q":
|
|
3201
|
+
if (numIndex + 3 < numbers.length) {
|
|
3202
|
+
for (let j = 0; j < 2; j++) {
|
|
3203
|
+
const x = numbers[numIndex++];
|
|
3204
|
+
const y = numbers[numIndex++];
|
|
3205
|
+
minX = Math.min(minX, x);
|
|
3206
|
+
maxX = Math.max(maxX, x);
|
|
3207
|
+
minY = Math.min(minY, y);
|
|
3208
|
+
maxY = Math.max(maxY, y);
|
|
3209
|
+
if (j === 1) {
|
|
3210
|
+
currentX = x;
|
|
3211
|
+
currentY = y;
|
|
3212
|
+
}
|
|
3213
|
+
}
|
|
3214
|
+
}
|
|
3215
|
+
break;
|
|
3216
|
+
case "s":
|
|
3217
|
+
case "q":
|
|
3218
|
+
if (numIndex + 3 < numbers.length) {
|
|
3219
|
+
for (let j = 0; j < 2; j++) {
|
|
3220
|
+
const x = currentX + numbers[numIndex++];
|
|
3221
|
+
const y = currentY + numbers[numIndex++];
|
|
3222
|
+
minX = Math.min(minX, x);
|
|
3223
|
+
maxX = Math.max(maxX, x);
|
|
3224
|
+
minY = Math.min(minY, y);
|
|
3225
|
+
maxY = Math.max(maxY, y);
|
|
3226
|
+
if (j === 1) {
|
|
3227
|
+
currentX = x;
|
|
3228
|
+
currentY = y;
|
|
3229
|
+
}
|
|
3230
|
+
}
|
|
3231
|
+
}
|
|
3232
|
+
break;
|
|
3233
|
+
case "A":
|
|
3234
|
+
if (numIndex + 6 < numbers.length) {
|
|
3235
|
+
numIndex += 5;
|
|
3236
|
+
currentX = numbers[numIndex++];
|
|
3237
|
+
currentY = numbers[numIndex++];
|
|
3238
|
+
minX = Math.min(minX, currentX);
|
|
3239
|
+
maxX = Math.max(maxX, currentX);
|
|
3240
|
+
minY = Math.min(minY, currentY);
|
|
3241
|
+
maxY = Math.max(maxY, currentY);
|
|
3242
|
+
}
|
|
3243
|
+
break;
|
|
3244
|
+
case "a":
|
|
3245
|
+
if (numIndex + 6 < numbers.length) {
|
|
3246
|
+
numIndex += 5;
|
|
3247
|
+
currentX += numbers[numIndex++];
|
|
3248
|
+
currentY += numbers[numIndex++];
|
|
3249
|
+
minX = Math.min(minX, currentX);
|
|
3250
|
+
maxX = Math.max(maxX, currentX);
|
|
3251
|
+
minY = Math.min(minY, currentY);
|
|
3252
|
+
maxY = Math.max(maxY, currentY);
|
|
3253
|
+
}
|
|
3254
|
+
break;
|
|
3255
|
+
case "Z":
|
|
3256
|
+
case "z":
|
|
3257
|
+
break;
|
|
3258
|
+
}
|
|
3259
|
+
cmdIndex++;
|
|
3411
3260
|
}
|
|
3412
|
-
|
|
3413
|
-
}
|
|
3414
|
-
function svgToSingleAsset(svgString) {
|
|
3415
|
-
const parsed = parseSvgMarkup(svgString);
|
|
3416
|
-
if (parsed.paths.length === 0) {
|
|
3417
|
-
return {
|
|
3418
|
-
type: "svg",
|
|
3419
|
-
shape: {
|
|
3420
|
-
type: "path",
|
|
3421
|
-
d: ""
|
|
3422
|
-
},
|
|
3423
|
-
width: parsed.width || void 0,
|
|
3424
|
-
height: parsed.height || void 0
|
|
3425
|
-
};
|
|
3261
|
+
if (minX === Infinity) {
|
|
3262
|
+
return { x: 0, y: 0, w: 0, h: 0 };
|
|
3426
3263
|
}
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
shape: {
|
|
3433
|
-
type: "path",
|
|
3434
|
-
d: combinedD
|
|
3435
|
-
}
|
|
3264
|
+
return {
|
|
3265
|
+
x: minX,
|
|
3266
|
+
y: minY,
|
|
3267
|
+
w: maxX - minX,
|
|
3268
|
+
h: maxY - minY
|
|
3436
3269
|
};
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3270
|
+
}
|
|
3271
|
+
async function renderSvgAssetToPng(asset, options = {}) {
|
|
3272
|
+
const defaultWidth = options.defaultWidth ?? 1920;
|
|
3273
|
+
const defaultHeight = options.defaultHeight ?? 1080;
|
|
3274
|
+
let svgString;
|
|
3275
|
+
let targetWidth;
|
|
3276
|
+
let targetHeight;
|
|
3277
|
+
if (asset.src) {
|
|
3278
|
+
svgString = asset.src;
|
|
3279
|
+
const dimensions = extractSvgDimensions(svgString);
|
|
3280
|
+
targetWidth = dimensions.width || defaultWidth;
|
|
3281
|
+
targetHeight = dimensions.height || defaultHeight;
|
|
3282
|
+
} else if (asset.shape) {
|
|
3283
|
+
targetWidth = asset.width ?? defaultWidth;
|
|
3284
|
+
targetHeight = asset.height ?? defaultHeight;
|
|
3285
|
+
svgString = shapeToSvgString(asset, targetWidth, targetHeight);
|
|
3286
|
+
} else {
|
|
3287
|
+
throw new Error("Either 'src' or 'shape' must be provided");
|
|
3448
3288
|
}
|
|
3449
|
-
|
|
3450
|
-
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
|
|
3289
|
+
return renderSvgToPng(svgString, {
|
|
3290
|
+
width: targetWidth,
|
|
3291
|
+
height: targetHeight,
|
|
3292
|
+
background: options.background
|
|
3293
|
+
});
|
|
3294
|
+
}
|
|
3295
|
+
function extractSvgDimensions(svgString) {
|
|
3296
|
+
const widthMatch = svgString.match(/width\s*=\s*["']?(\d+(?:\.\d+)?)/i);
|
|
3297
|
+
const heightMatch = svgString.match(/height\s*=\s*["']?(\d+(?:\.\d+)?)/i);
|
|
3298
|
+
let width = widthMatch ? parseFloat(widthMatch[1]) : 0;
|
|
3299
|
+
let height = heightMatch ? parseFloat(heightMatch[1]) : 0;
|
|
3300
|
+
if (!width || !height) {
|
|
3301
|
+
const viewBoxMatch = svgString.match(/viewBox\s*=\s*["']([^"']+)["']/i);
|
|
3302
|
+
if (viewBoxMatch) {
|
|
3303
|
+
const parts = viewBoxMatch[1].trim().split(/[\s,]+/).map(parseFloat);
|
|
3304
|
+
if (parts.length === 4) {
|
|
3305
|
+
width = width || parts[2];
|
|
3306
|
+
height = height || parts[3];
|
|
3458
3307
|
}
|
|
3459
3308
|
}
|
|
3460
3309
|
}
|
|
3461
|
-
|
|
3462
|
-
if (firstPathWithOpacity) {
|
|
3463
|
-
asset.opacity = firstPathWithOpacity.opacity;
|
|
3464
|
-
}
|
|
3465
|
-
if (parsed.width > 0) {
|
|
3466
|
-
asset.width = parsed.width;
|
|
3467
|
-
}
|
|
3468
|
-
if (parsed.height > 0) {
|
|
3469
|
-
asset.height = parsed.height;
|
|
3470
|
-
}
|
|
3471
|
-
return asset;
|
|
3472
|
-
}
|
|
3473
|
-
function importSvg(svgString) {
|
|
3474
|
-
return svgToSingleAsset(svgString);
|
|
3310
|
+
return { width, height };
|
|
3475
3311
|
}
|
|
3476
3312
|
|
|
3477
3313
|
// src/env/entry.web.ts
|
|
@@ -3738,38 +3574,21 @@ export {
|
|
|
3738
3574
|
CanvasRichTextAssetSchema,
|
|
3739
3575
|
CanvasSvgAssetSchema,
|
|
3740
3576
|
arcToCubicBeziers,
|
|
3741
|
-
centerPath,
|
|
3742
3577
|
commandsToPathString,
|
|
3743
|
-
|
|
3578
|
+
computeSimplePathBounds,
|
|
3744
3579
|
createTextEngine,
|
|
3745
3580
|
createWebPainter,
|
|
3746
|
-
|
|
3747
|
-
|
|
3748
|
-
generateCrossPath,
|
|
3749
|
-
generateEllipsePath,
|
|
3750
|
-
generateHeartPath,
|
|
3751
|
-
generateLinePath,
|
|
3752
|
-
generatePolygonPath,
|
|
3753
|
-
generatePolygonPoints,
|
|
3754
|
-
generateRectanglePath,
|
|
3755
|
-
generateRingPath,
|
|
3756
|
-
generateShapePath,
|
|
3757
|
-
generateStarPath,
|
|
3758
|
-
generateStarPoints,
|
|
3759
|
-
generateTrianglePath,
|
|
3760
|
-
importSvg,
|
|
3581
|
+
generateShapePathData,
|
|
3582
|
+
initResvg,
|
|
3761
3583
|
isGlyphFill2 as isGlyphFill,
|
|
3762
3584
|
isShadowFill2 as isShadowFill,
|
|
3763
3585
|
normalizePath,
|
|
3764
3586
|
normalizePathString,
|
|
3765
|
-
normalizePathToSize,
|
|
3766
|
-
parseSvgMarkup,
|
|
3767
3587
|
parseSvgPath,
|
|
3768
|
-
pointsToPath,
|
|
3769
3588
|
quadraticToCubic,
|
|
3770
|
-
|
|
3771
|
-
|
|
3772
|
-
|
|
3589
|
+
renderSvgAssetToPng,
|
|
3590
|
+
renderSvgToPng,
|
|
3591
|
+
shapeToSvgString,
|
|
3773
3592
|
svgAssetSchema,
|
|
3774
3593
|
svgGradientStopSchema,
|
|
3775
3594
|
svgLinearGradientFillSchema,
|
|
@@ -3778,8 +3597,5 @@ export {
|
|
|
3778
3597
|
svgShapeSchema,
|
|
3779
3598
|
svgSolidFillSchema,
|
|
3780
3599
|
svgStrokeSchema,
|
|
3781
|
-
|
|
3782
|
-
svgToSingleAsset,
|
|
3783
|
-
svgTransformSchema,
|
|
3784
|
-
translatePath
|
|
3600
|
+
svgTransformSchema
|
|
3785
3601
|
};
|