apexify.js 4.9.26 → 4.9.28

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.
Files changed (108) hide show
  1. package/README.md +437 -47
  2. package/dist/cjs/Canvas/ApexPainter.d.ts +122 -78
  3. package/dist/cjs/Canvas/ApexPainter.d.ts.map +1 -1
  4. package/dist/cjs/Canvas/ApexPainter.js +461 -352
  5. package/dist/cjs/Canvas/ApexPainter.js.map +1 -1
  6. package/dist/cjs/Canvas/utils/Background/bg.d.ts +23 -11
  7. package/dist/cjs/Canvas/utils/Background/bg.d.ts.map +1 -1
  8. package/dist/cjs/Canvas/utils/Background/bg.js +174 -107
  9. package/dist/cjs/Canvas/utils/Background/bg.js.map +1 -1
  10. package/dist/cjs/Canvas/utils/Custom/customLines.js +2 -2
  11. package/dist/cjs/Canvas/utils/Custom/customLines.js.map +1 -1
  12. package/dist/cjs/Canvas/utils/Image/imageFilters.d.ts +11 -0
  13. package/dist/cjs/Canvas/utils/Image/imageFilters.d.ts.map +1 -0
  14. package/dist/cjs/Canvas/utils/Image/imageFilters.js +307 -0
  15. package/dist/cjs/Canvas/utils/Image/imageFilters.js.map +1 -0
  16. package/dist/cjs/Canvas/utils/Image/imageProperties.d.ts +47 -112
  17. package/dist/cjs/Canvas/utils/Image/imageProperties.d.ts.map +1 -1
  18. package/dist/cjs/Canvas/utils/Image/imageProperties.js +229 -560
  19. package/dist/cjs/Canvas/utils/Image/imageProperties.js.map +1 -1
  20. package/dist/cjs/Canvas/utils/Image/professionalImageFilters.d.ts +11 -0
  21. package/dist/cjs/Canvas/utils/Image/professionalImageFilters.d.ts.map +1 -0
  22. package/dist/cjs/Canvas/utils/Image/professionalImageFilters.js +351 -0
  23. package/dist/cjs/Canvas/utils/Image/professionalImageFilters.js.map +1 -0
  24. package/dist/cjs/Canvas/utils/Image/simpleProfessionalFilters.d.ts +11 -0
  25. package/dist/cjs/Canvas/utils/Image/simpleProfessionalFilters.d.ts.map +1 -0
  26. package/dist/cjs/Canvas/utils/Image/simpleProfessionalFilters.js +215 -0
  27. package/dist/cjs/Canvas/utils/Image/simpleProfessionalFilters.js.map +1 -0
  28. package/dist/cjs/Canvas/utils/Patterns/enhancedPatternRenderer.d.ts +71 -0
  29. package/dist/cjs/Canvas/utils/Patterns/enhancedPatternRenderer.d.ts.map +1 -0
  30. package/dist/cjs/Canvas/utils/Patterns/enhancedPatternRenderer.js +392 -0
  31. package/dist/cjs/Canvas/utils/Patterns/enhancedPatternRenderer.js.map +1 -0
  32. package/dist/cjs/Canvas/utils/Shapes/shapes.d.ts +29 -0
  33. package/dist/cjs/Canvas/utils/Shapes/shapes.d.ts.map +1 -0
  34. package/dist/cjs/Canvas/utils/Shapes/shapes.js +334 -0
  35. package/dist/cjs/Canvas/utils/Shapes/shapes.js.map +1 -0
  36. package/dist/cjs/Canvas/utils/Texts/enhancedTextRenderer.d.ts +127 -0
  37. package/dist/cjs/Canvas/utils/Texts/enhancedTextRenderer.d.ts.map +1 -0
  38. package/dist/cjs/Canvas/utils/Texts/enhancedTextRenderer.js +365 -0
  39. package/dist/cjs/Canvas/utils/Texts/enhancedTextRenderer.js.map +1 -0
  40. package/dist/cjs/Canvas/utils/types.d.ts +227 -131
  41. package/dist/cjs/Canvas/utils/types.d.ts.map +1 -1
  42. package/dist/cjs/Canvas/utils/types.js +0 -1
  43. package/dist/cjs/Canvas/utils/types.js.map +1 -1
  44. package/dist/cjs/Canvas/utils/utils.d.ts +7 -4
  45. package/dist/cjs/Canvas/utils/utils.d.ts.map +1 -1
  46. package/dist/cjs/Canvas/utils/utils.js +17 -7
  47. package/dist/cjs/Canvas/utils/utils.js.map +1 -1
  48. package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
  49. package/dist/esm/Canvas/ApexPainter.d.ts +122 -78
  50. package/dist/esm/Canvas/ApexPainter.d.ts.map +1 -1
  51. package/dist/esm/Canvas/ApexPainter.js +461 -352
  52. package/dist/esm/Canvas/ApexPainter.js.map +1 -1
  53. package/dist/esm/Canvas/utils/Background/bg.d.ts +23 -11
  54. package/dist/esm/Canvas/utils/Background/bg.d.ts.map +1 -1
  55. package/dist/esm/Canvas/utils/Background/bg.js +174 -107
  56. package/dist/esm/Canvas/utils/Background/bg.js.map +1 -1
  57. package/dist/esm/Canvas/utils/Custom/customLines.js +2 -2
  58. package/dist/esm/Canvas/utils/Custom/customLines.js.map +1 -1
  59. package/dist/esm/Canvas/utils/Image/imageFilters.d.ts +11 -0
  60. package/dist/esm/Canvas/utils/Image/imageFilters.d.ts.map +1 -0
  61. package/dist/esm/Canvas/utils/Image/imageFilters.js +307 -0
  62. package/dist/esm/Canvas/utils/Image/imageFilters.js.map +1 -0
  63. package/dist/esm/Canvas/utils/Image/imageProperties.d.ts +47 -112
  64. package/dist/esm/Canvas/utils/Image/imageProperties.d.ts.map +1 -1
  65. package/dist/esm/Canvas/utils/Image/imageProperties.js +229 -560
  66. package/dist/esm/Canvas/utils/Image/imageProperties.js.map +1 -1
  67. package/dist/esm/Canvas/utils/Image/professionalImageFilters.d.ts +11 -0
  68. package/dist/esm/Canvas/utils/Image/professionalImageFilters.d.ts.map +1 -0
  69. package/dist/esm/Canvas/utils/Image/professionalImageFilters.js +351 -0
  70. package/dist/esm/Canvas/utils/Image/professionalImageFilters.js.map +1 -0
  71. package/dist/esm/Canvas/utils/Image/simpleProfessionalFilters.d.ts +11 -0
  72. package/dist/esm/Canvas/utils/Image/simpleProfessionalFilters.d.ts.map +1 -0
  73. package/dist/esm/Canvas/utils/Image/simpleProfessionalFilters.js +215 -0
  74. package/dist/esm/Canvas/utils/Image/simpleProfessionalFilters.js.map +1 -0
  75. package/dist/esm/Canvas/utils/Patterns/enhancedPatternRenderer.d.ts +71 -0
  76. package/dist/esm/Canvas/utils/Patterns/enhancedPatternRenderer.d.ts.map +1 -0
  77. package/dist/esm/Canvas/utils/Patterns/enhancedPatternRenderer.js +392 -0
  78. package/dist/esm/Canvas/utils/Patterns/enhancedPatternRenderer.js.map +1 -0
  79. package/dist/esm/Canvas/utils/Shapes/shapes.d.ts +29 -0
  80. package/dist/esm/Canvas/utils/Shapes/shapes.d.ts.map +1 -0
  81. package/dist/esm/Canvas/utils/Shapes/shapes.js +334 -0
  82. package/dist/esm/Canvas/utils/Shapes/shapes.js.map +1 -0
  83. package/dist/esm/Canvas/utils/Texts/enhancedTextRenderer.d.ts +127 -0
  84. package/dist/esm/Canvas/utils/Texts/enhancedTextRenderer.d.ts.map +1 -0
  85. package/dist/esm/Canvas/utils/Texts/enhancedTextRenderer.js +365 -0
  86. package/dist/esm/Canvas/utils/Texts/enhancedTextRenderer.js.map +1 -0
  87. package/dist/esm/Canvas/utils/types.d.ts +227 -131
  88. package/dist/esm/Canvas/utils/types.d.ts.map +1 -1
  89. package/dist/esm/Canvas/utils/types.js +0 -1
  90. package/dist/esm/Canvas/utils/types.js.map +1 -1
  91. package/dist/esm/Canvas/utils/utils.d.ts +7 -4
  92. package/dist/esm/Canvas/utils/utils.d.ts.map +1 -1
  93. package/dist/esm/Canvas/utils/utils.js +17 -7
  94. package/dist/esm/Canvas/utils/utils.js.map +1 -1
  95. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  96. package/lib/Canvas/ApexPainter.ts +1325 -1218
  97. package/lib/Canvas/utils/Background/bg.ts +247 -173
  98. package/lib/Canvas/utils/Custom/customLines.ts +3 -3
  99. package/lib/Canvas/utils/Image/imageFilters.ts +356 -0
  100. package/lib/Canvas/utils/Image/imageProperties.ts +322 -775
  101. package/lib/Canvas/utils/Image/professionalImageFilters.ts +391 -0
  102. package/lib/Canvas/utils/Image/simpleProfessionalFilters.ts +229 -0
  103. package/lib/Canvas/utils/Patterns/enhancedPatternRenderer.ts +444 -0
  104. package/lib/Canvas/utils/Shapes/shapes.ts +528 -0
  105. package/lib/Canvas/utils/Texts/enhancedTextRenderer.ts +478 -0
  106. package/lib/Canvas/utils/types.ts +301 -117
  107. package/lib/Canvas/utils/utils.ts +85 -72
  108. package/package.json +106 -188
@@ -1,602 +1,271 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.buildPath = buildPath;
7
+ exports.applyRotation = applyRotation;
8
+ exports.createGradientFill = createGradientFill;
9
+ exports.fitInto = fitInto;
10
+ exports.loadImageCached = loadImageCached;
3
11
  exports.applyShadow = applyShadow;
4
- exports.applyZoom = applyZoom;
5
12
  exports.applyStroke = applyStroke;
6
- exports.drawShape = drawShape;
7
- exports.createGradient = createGradient;
8
- exports.applyRotation = applyRotation;
9
- exports.imageRadius = imageRadius;
10
- exports.objectRadius = objectRadius;
11
- exports.applyPerspective = applyPerspective;
12
- /**
13
- * Applies shadow to the canvas context.
14
- * @param ctx The canvas rendering context.
15
- * @param shadow The shadow properties.
16
- * @param x The x-coordinate of the shape.
17
- * @param y The y-coordinate of the shape.
18
- * @param width The width of the shape.
19
- * @param height The height of the shape.
20
- */
21
- function applyShadow(ctx, shadow, x, y, width, height) {
22
- ctx.save();
23
- if (shadow) {
24
- ctx.globalAlpha = shadow.opacity ?? 1;
25
- ctx.filter = `blur(${shadow.blur ?? 0}px)`;
26
- const shadowX = x + (shadow.offsetX ?? 0);
27
- const shadowY = y + (shadow.offsetY ?? 0);
28
- objectRadius(ctx, shadowX, shadowY, width, height, shadow.borderRadius ?? 2);
29
- ctx.fillStyle = shadow.gradient
30
- ? createGradient(ctx, shadow.gradient, shadowX, shadowY, shadowX + width, shadowY + height)
31
- : shadow.color || "transparent";
32
- ctx.fill();
13
+ exports.drawBoxBackground = drawBoxBackground;
14
+ function buildPath(ctx, x, y, w, h, radius = 0, borderPos = "all") {
15
+ ctx.beginPath();
16
+ if (radius === "circular") {
17
+ const r = Math.min(w, h) / 2;
18
+ ctx.arc(x + w / 2, y + h / 2, r, 0, Math.PI * 2);
19
+ ctx.closePath();
20
+ return;
33
21
  }
34
- ctx.filter = "none";
35
- ctx.globalAlpha = 1;
36
- ctx.restore();
22
+ if (!radius || radius <= 0) {
23
+ ctx.rect(x, y, w, h);
24
+ ctx.closePath();
25
+ return;
26
+ }
27
+ const br = Math.min(radius, w / 2, h / 2);
28
+ const sel = new Set(borderPos.toLowerCase().split(",").map(s => s.trim()));
29
+ const has = (name) => sel.has("all") || sel.has(name) ||
30
+ (name === "top-left" && (sel.has("top") || sel.has("left"))) ||
31
+ (name === "top-right" && (sel.has("top") || sel.has("right"))) ||
32
+ (name === "bottom-right" && (sel.has("bottom") || sel.has("right"))) ||
33
+ (name === "bottom-left" && (sel.has("bottom") || sel.has("left")));
34
+ const tl = has("top-left") ? br : 0;
35
+ const tr = has("top-right") ? br : 0;
36
+ const brR = has("bottom-right") ? br : 0;
37
+ const bl = has("bottom-left") ? br : 0;
38
+ ctx.moveTo(x + tl, y);
39
+ ctx.lineTo(x + w - tr, y);
40
+ if (tr)
41
+ ctx.arcTo(x + w, y, x + w, y + tr, tr);
42
+ ctx.lineTo(x + w, y + h - brR);
43
+ if (brR)
44
+ ctx.arcTo(x + w, y + h, x + w - brR, y + h, brR);
45
+ ctx.lineTo(x + bl, y + h);
46
+ if (bl)
47
+ ctx.arcTo(x, y + h, x, y + h - bl, bl);
48
+ ctx.lineTo(x, y + tl);
49
+ if (tl)
50
+ ctx.arcTo(x, y, x + tl, y, tl);
51
+ ctx.closePath();
37
52
  }
38
- /**
39
- * Applies zoom (scaling) to the canvas context around a specified point.
40
- * @param ctx The canvas rendering context.
41
- * @param zoom An object with scale (zoom factor) and the x/y coordinates that act as the zoom origin.
42
- */
43
- function applyZoom(ctx, zoom) {
44
- if (!zoom)
53
+ function applyRotation(ctx, deg, x, y, w, h) {
54
+ if (!deg)
45
55
  return;
46
- const scale = zoom.scale ?? 1;
47
- const zoomX = zoom.x ?? 0;
48
- const zoomY = zoom.y ?? 0;
49
- ctx.translate(zoomX, zoomY);
50
- ctx.scale(scale, scale);
51
- ctx.translate(-zoomX, -zoomY);
56
+ const cx = x + w / 2, cy = y + h / 2;
57
+ ctx.translate(cx, cy);
58
+ ctx.rotate((deg * Math.PI) / 180);
59
+ ctx.translate(-cx, -cy);
60
+ }
61
+ function rotatePoint(x, y, px, py, deg = 0) {
62
+ if (!deg)
63
+ return [x, y];
64
+ const a = (deg * Math.PI) / 180;
65
+ const dx = x - px, dy = y - py;
66
+ return [px + dx * Math.cos(a) - dy * Math.sin(a),
67
+ py + dx * Math.sin(a) + dy * Math.cos(a)];
52
68
  }
53
69
  /**
54
- * Applies stroke to the canvas context with support for selective side strokes.
55
- * Supports optional blur effect on the stroke.
56
- *
57
- * @param ctx The canvas rendering context.
58
- * @param stroke The stroke properties.
59
- * @param x The x-coordinate of the shape.
60
- * @param y The y-coordinate of the shape.
61
- * @param width The width of the shape.
62
- * @param height The height of the shape.
63
- * @param blur Optional blur effect on the stroke.
70
+ * Build a gradient in **rect-local coordinates**:
71
+ * - Defaults for coords use rect {w,h}
72
+ * - Rotation pivot defaults to rect center
73
+ * - Offsets are applied by adding rect.x/rect.y to all points
64
74
  */
65
- function applyStroke(ctx, stroke, x, y, width, height, shapeName) {
66
- if (!stroke)
67
- return;
68
- ctx.save();
69
- if (stroke.blur && stroke.blur > 0) {
70
- ctx.filter = `blur(${stroke.blur}px)`;
71
- }
72
- ctx.strokeStyle = stroke.gradient
73
- ? createGradient(ctx, stroke.gradient, x, y, x + width, y + height)
74
- : stroke.color || "transparent";
75
- ctx.lineWidth = stroke.width && stroke.width > 0 ? stroke.width : 2;
76
- ctx.beginPath();
77
- const borderPos = stroke.position || 0;
78
- // Adjust the bounding box by borderPos
79
- // - Positive borderPos moves stroke outward
80
- // - Negative borderPos moves stroke inward
81
- const offsetX = x - borderPos;
82
- const offsetY = y - borderPos;
83
- const offsetW = width + 2 * borderPos;
84
- const offsetH = height + 2 * borderPos;
85
- ctx.beginPath();
86
- // For known shapes (circle, star, etc.), re-draw with adjusted bounding box
87
- if ([
88
- "heart", "arrow", "circle", "star",
89
- "pentagon", "hexagon", "heptagon", "octagon",
90
- "diamond", "trapezoid", "kite",
91
- ].includes(shapeName)) {
92
- switch (shapeName) {
93
- case "circle":
94
- // Circle centered in the new bounding box
95
- ctx.arc(offsetX + offsetW / 2, offsetY + offsetH / 2, offsetW / 2, // radius
96
- 0, Math.PI * 2);
97
- break;
98
- case "star":
99
- drawStar(ctx, offsetX, offsetY, offsetW, offsetH);
100
- break;
101
- case "arrow":
102
- drawArrow(ctx, offsetX, offsetY, offsetW, offsetH);
103
- break;
104
- case "pentagon":
105
- case "hexagon":
106
- case "heptagon":
107
- case "octagon": {
108
- const sides = parseInt(shapeName.replace(/\D/g, ""), 10);
109
- drawPolygon(ctx, offsetX, offsetY, offsetW, offsetH, sides);
110
- break;
111
- }
112
- case "diamond":
113
- ctx.moveTo(offsetX + offsetW / 2, offsetY);
114
- ctx.lineTo(offsetX + offsetW, offsetY + offsetH / 2);
115
- ctx.lineTo(offsetX + offsetW / 2, offsetY + offsetH);
116
- ctx.lineTo(offsetX, offsetY + offsetH / 2);
117
- ctx.closePath();
118
- break;
119
- case "trapezoid": {
120
- const topWidth = offsetW * 0.6;
121
- const offsetVal = (offsetW - topWidth) / 2;
122
- ctx.moveTo(offsetX + offsetVal, offsetY);
123
- ctx.lineTo(offsetX + offsetVal + topWidth, offsetY);
124
- ctx.lineTo(offsetX + offsetW, offsetY + offsetH);
125
- ctx.lineTo(offsetX, offsetY + offsetH);
126
- ctx.closePath();
127
- break;
128
- }
129
- case "heart":
130
- drawHeart(ctx, offsetX, offsetY, offsetW, offsetH);
131
- break;
132
- case "kite":
133
- ctx.moveTo(offsetX + offsetW / 2, offsetY);
134
- ctx.lineTo(offsetX + offsetW, offsetY + offsetH / 2);
135
- ctx.lineTo(offsetX + offsetW / 2, offsetY + offsetH);
136
- ctx.lineTo(offsetX, offsetY + offsetH / 2);
137
- ctx.closePath();
138
- break;
139
- }
140
- }
141
- else {
142
- ctx.globalCompositeOperation = "source-atop";
143
- objectRadius(ctx, offsetX, offsetY, offsetW, offsetH, stroke.borderRadius || 2, stroke.borderPosition);
75
+ function createGradientFill(ctx, g, rect) {
76
+ const { x, y, w, h } = rect;
77
+ if (g.type === "linear") {
78
+ const { startX = 0, startY = 0, endX = w, endY = 0, rotate = 0, pivotX = w / 2, pivotY = h / 2, colors } = g;
79
+ const [sx, sy] = rotatePoint(startX, startY, pivotX, pivotY, rotate);
80
+ const [ex, ey] = rotatePoint(endX, endY, pivotX, pivotY, rotate);
81
+ const grad = ctx.createLinearGradient(x + sx, y + sy, x + ex, y + ey);
82
+ colors.forEach(cs => grad.addColorStop(cs.stop, cs.color));
83
+ return grad;
144
84
  }
145
- ctx.stroke();
146
- ctx.filter = "none";
147
- ctx.restore();
85
+ // radial
86
+ const { startX = w / 2, startY = h / 2, startRadius = 0, endX = w / 2, endY = h / 2, endRadius = Math.max(w, h) / 2, rotate = 0, pivotX = w / 2, pivotY = h / 2, colors } = g;
87
+ const [sx, sy] = rotatePoint(startX, startY, pivotX, pivotY, rotate);
88
+ const [ex, ey] = rotatePoint(endX, endY, pivotX, pivotY, rotate);
89
+ const grad = ctx.createRadialGradient(x + sx, y + sy, startRadius, x + ex, y + ey, endRadius);
90
+ colors.forEach(cs => grad.addColorStop(cs.stop, cs.color));
91
+ return grad;
148
92
  }
149
- function drawShape(ctx, shapeSettings) {
150
- const { source, x, y, width, height, opacity, rotation = 0, borderRadius = 0, borderPosition = 'all', stroke, shadow, isFilled = false, color = "transparent", gradient, filling, } = shapeSettings;
151
- const shapeName = source.toLowerCase();
152
- ctx.save();
153
- applyRotation(ctx, rotation, x, y, width, height);
154
- applyShadow(ctx, shadow, x, y, width, height);
155
- ctx.beginPath();
156
- ctx.globalAlpha = opacity;
157
- switch (shapeName) {
158
- case 'circle': {
159
- ctx.arc(x + width / 2, y + height / 2, width / 2, 0, Math.PI * 2);
160
- break;
161
- }
162
- case 'square': {
163
- ctx.rect(x, y, width, height);
93
+ function fitInto(boxX, boxY, boxW, boxH, imgW, imgH, fit = "fill", align = "center") {
94
+ let dx = boxX, dy = boxY, dw = boxW, dh = boxH, sx = 0, sy = 0, sw = imgW, sh = imgH;
95
+ if (fit === "fill") {
96
+ return { dx, dy, dw, dh, sx, sy, sw, sh };
97
+ }
98
+ const s = fit === "contain"
99
+ ? Math.min(boxW / imgW, boxH / imgH)
100
+ : Math.max(boxW / imgW, boxH / imgH);
101
+ dw = imgW * s;
102
+ dh = imgH * s;
103
+ const cx = boxX + (boxW - dw) / 2;
104
+ const cy = boxY + (boxH - dh) / 2;
105
+ switch (align) {
106
+ case "top-left":
107
+ dx = boxX;
108
+ dy = boxY;
164
109
  break;
165
- }
166
- case 'triangle': {
167
- ctx.moveTo(x + width / 2, y);
168
- ctx.lineTo(x, y + height);
169
- ctx.lineTo(x + width, y + height);
170
- ctx.closePath();
110
+ case "top":
111
+ dx = cx;
112
+ dy = boxY;
171
113
  break;
172
- }
173
- case 'pentagon':
174
- case 'hexagon':
175
- case 'heptagon':
176
- case 'octagon': {
177
- const sides = parseInt(shapeName.replace(/\D/g, ""), 10);
178
- drawPolygon(ctx, x, y, width, height, sides);
114
+ case "top-right":
115
+ dx = boxX + boxW - dw;
116
+ dy = boxY;
179
117
  break;
180
- }
181
- case 'star': {
182
- drawStar(ctx, x, y, width, height);
118
+ case "left":
119
+ dx = boxX;
120
+ dy = cy;
183
121
  break;
184
- }
185
- case 'kite': {
186
- ctx.moveTo(x + width / 2, y);
187
- ctx.lineTo(x + width, y + height / 2);
188
- ctx.lineTo(x + width / 2, y + height);
189
- ctx.lineTo(x, y + height / 2);
190
- ctx.closePath();
122
+ case "center":
123
+ dx = cx;
124
+ dy = cy;
191
125
  break;
192
- }
193
- case 'oval': {
194
- ctx.ellipse(x + width / 2, y + height / 2, width / 2, height / 2, 0, 0, Math.PI * 2);
126
+ case "right":
127
+ dx = boxX + boxW - dw;
128
+ dy = cy;
195
129
  break;
196
- }
197
- case 'arrow': {
198
- drawArrow(ctx, x, y, width, height);
130
+ case "bottom-left":
131
+ dx = boxX;
132
+ dy = boxY + boxH - dh;
199
133
  break;
200
- }
201
- case 'heart': {
202
- drawHeart(ctx, x, y, width, height);
134
+ case "bottom":
135
+ dx = cx;
136
+ dy = boxY + boxH - dh;
203
137
  break;
204
- }
205
- case 'diamond': {
206
- ctx.moveTo(x + width / 2, y);
207
- ctx.lineTo(x + width, y + height / 2);
208
- ctx.lineTo(x + width / 2, y + height);
209
- ctx.lineTo(x, y + height / 2);
210
- ctx.closePath();
138
+ case "bottom-right":
139
+ dx = boxX + boxW - dw;
140
+ dy = boxY + boxH - dh;
211
141
  break;
212
- }
213
- case 'trapezoid': {
214
- const topWidth = width * 0.6;
215
- const offset = (width - topWidth) / 2;
216
- ctx.moveTo(x + offset, y);
217
- ctx.lineTo(x + offset + topWidth, y);
218
- ctx.lineTo(x + width, y + height);
219
- ctx.lineTo(x, y + height);
220
- ctx.closePath();
142
+ default:
143
+ dx = cx;
144
+ dy = cy;
221
145
  break;
222
- }
223
- default: {
224
- ctx.restore();
225
- throw new Error(`Unsupported shape: ${shapeName}`);
226
- }
227
- }
228
- if (isFilled) {
229
- if (borderRadius && shapeName !== 'circle' && shapeName !== 'oval') {
230
- objectRadius(ctx, x, y, width, height, borderRadius, borderPosition);
231
- }
232
- let fillStyle = color;
233
- if (gradient) {
234
- fillStyle = createGradient(ctx, gradient, x, y, x + width, y + height);
235
- }
236
- if (filling && filling.percentage <= 100) {
237
- ctx.save();
238
- const isCustomShape = ["heart", "arrow", "star", "pentagon", "hexagon", "heptagon", "octagon", "diamond", "trapezoid", "kite", "oval", "circle"].includes(shapeName);
239
- if (isCustomShape) {
240
- ctx.clip();
241
- }
242
- let fillX = x;
243
- let fillY = y;
244
- let fillWidth = width;
245
- let fillHeight = height;
246
- switch (filling.rotation) {
247
- case 0:
248
- fillHeight = (filling.percentage / 100) * height;
249
- fillY = y + height - fillHeight;
250
- break;
251
- case 180:
252
- fillHeight = (filling.percentage / 100) * height;
253
- break;
254
- case 90:
255
- fillWidth = (filling.percentage / 100) * width;
256
- break;
257
- case 270:
258
- fillWidth = (filling.percentage / 100) * width;
259
- fillX = x + width - fillWidth;
260
- break;
261
- default:
262
- console.warn(`Unsupported filling rotation: ${filling.rotation}, defaulting to 0 (Bottom to Top).`);
263
- fillHeight = (filling.percentage / 100) * height;
264
- fillY = y + height - fillHeight;
265
- }
266
- ctx.beginPath();
267
- ctx.rect(fillX, fillY, fillWidth, fillHeight);
268
- ctx.fillStyle = fillStyle;
269
- ctx.fill();
270
- ctx.restore();
271
- }
272
- else {
273
- ctx.fillStyle = fillStyle;
274
- ctx.fill();
275
- }
276
146
  }
277
- ctx.globalAlpha = 1.0;
278
- if (stroke) {
279
- if (stroke?.opacity)
280
- ctx.globalAlpha = stroke.opacity;
281
- applyStroke(ctx, stroke, x, y, width, height, shapeName);
282
- ctx.globalAlpha = 1.0;
283
- }
284
- ctx.restore();
147
+ return { dx, dy, dw, dh, sx, sy, sw, sh };
285
148
  }
286
- function drawHeart(ctx, x, y, width, height) {
287
- ctx.beginPath();
288
- ctx.moveTo(x + width / 2, y + height * 0.9);
289
- ctx.bezierCurveTo(x + (width * 35) / 100, y + (height * 60) / 100, x + (width * 10) / 100, y + (height * 55) / 100, x + (width * 10) / 100, y + (height * 33.33) / 100);
290
- ctx.bezierCurveTo(x + (width * 10) / 100, y + (height * 10) / 100, x + (width * 50) / 100, y + (height * 5) / 100, x + (width * 50) / 100, y + (height * 33.33) / 100);
291
- ctx.bezierCurveTo(x + (width * 50) / 100, y + (height * 5) / 100, x + (width * 90) / 100, y + (height * 10) / 100, x + (width * 90) / 100, y + (height * 33.33) / 100);
292
- ctx.bezierCurveTo(x + (width * 90) / 100, y + (height * 55) / 100, x + (width * 65) / 100, y + (height * 60) / 100, x + width / 2, y + height * 0.9);
293
- ctx.closePath();
149
+ // utils/imageCache.ts
150
+ const canvas_1 = require("@napi-rs/canvas");
151
+ const path_1 = __importDefault(require("path"));
152
+ const cache = new Map();
153
+ function loadImageCached(src) {
154
+ if (Buffer.isBuffer(src))
155
+ return (0, canvas_1.loadImage)(src);
156
+ const key = src.startsWith("http") ? src : path_1.default.resolve(process.cwd(), src);
157
+ if (!cache.has(key))
158
+ cache.set(key, (0, canvas_1.loadImage)(key));
159
+ return cache.get(key);
294
160
  }
295
- /** Draws a polygon with a given number of sides */
296
- function drawPolygon(ctx, x, y, width, height, sides) {
297
- const cx = x + width / 2;
298
- const cy = y + height / 2;
299
- const radius = Math.min(width, height) / 2;
300
- ctx.moveTo(cx + radius, cy);
301
- for (let i = 1; i <= sides; i++) {
302
- const angle = (Math.PI * 2 * i) / sides;
303
- ctx.lineTo(cx + radius * Math.cos(angle), cy + radius * Math.sin(angle));
304
- }
305
- ctx.closePath();
306
- }
307
- function drawArrow(ctx, x, y, width, height) {
308
- const shaftWidth = width * 0.25;
309
- const headWidth = width * 0.5;
310
- const headHeight = height * 0.6;
311
- ctx.beginPath();
312
- ctx.moveTo(x, y + height / 2 - shaftWidth / 2);
313
- ctx.lineTo(x + width - headWidth, y + height / 2 - shaftWidth / 2);
314
- ctx.lineTo(x + width - headWidth, y);
315
- ctx.lineTo(x + width, y + height / 2);
316
- ctx.lineTo(x + width - headWidth, y + height);
317
- ctx.lineTo(x + width - headWidth, y + height / 2 + shaftWidth / 2);
318
- ctx.lineTo(x, y + height / 2 + shaftWidth / 2);
319
- ctx.closePath();
320
- }
321
- function drawStar(ctx, x, y, width, height) {
322
- const cx = x + width / 2;
323
- const cy = y + height / 2;
324
- const size = Math.min(width, height);
325
- const outerRadius = size / 2;
326
- const innerRadius = outerRadius * 0.5;
327
- const rotationOffset = -Math.PI / 2;
328
- ctx.beginPath();
329
- for (let i = 0; i < 5; i++) {
330
- let angle = (i * (Math.PI * 2)) / 5 + rotationOffset;
331
- ctx.lineTo(cx + outerRadius * Math.cos(angle), cy + outerRadius * Math.sin(angle));
332
- angle += Math.PI / 5;
333
- ctx.lineTo(cx + innerRadius * Math.cos(angle), cy + innerRadius * Math.sin(angle));
334
- }
335
- ctx.closePath();
336
- }
337
- function createGradient(ctx, gradientOptions, startX, startY, endX, endY) {
338
- if (!gradientOptions || !gradientOptions.type || !gradientOptions.colors) {
339
- throw new Error("Invalid gradient options. Provide a valid object with type and colors properties.");
340
- }
341
- if (!Array.isArray(gradientOptions.colors)) {
342
- throw new Error("Invalid gradient options. The colors property should be an array of color stops.");
343
- }
344
- if (gradientOptions.type === "linear") {
345
- if (typeof startX !== "number" ||
346
- typeof startY !== "number" ||
347
- typeof endX !== "number" ||
348
- typeof endY !== "number") {
349
- throw new Error("Invalid gradient options for linear gradient. Numeric values are required for startX, startY, endX, and endY.");
350
- }
351
- if (typeof gradientOptions.rotate === "number") {
352
- const centerX = (startX + endX) / 2;
353
- const centerY = (startY + endY) / 2;
354
- const dx = endX - startX;
355
- const dy = endY - startY;
356
- const length = Math.sqrt(dx * dx + dy * dy);
357
- const angleRad = (gradientOptions.rotate * Math.PI) / 180;
358
- startX = centerX - (length / 2) * Math.cos(angleRad);
359
- startY = centerY - (length / 2) * Math.sin(angleRad);
360
- endX = centerX + (length / 2) * Math.cos(angleRad);
361
- endY = centerY + (length / 2) * Math.sin(angleRad);
362
- }
363
- const gradient = ctx.createLinearGradient(startX, startY, endX, endY);
364
- for (const colorStop of gradientOptions.colors) {
365
- if (typeof colorStop.stop !== "number" ||
366
- typeof colorStop.color !== "string") {
367
- throw new Error("Invalid color stop. Each color stop should have a numeric stop value and a color string.");
368
- }
369
- gradient.addColorStop(colorStop.stop, colorStop.color);
370
- }
371
- return gradient;
372
- }
373
- else if (gradientOptions.type === "radial") {
374
- if (typeof gradientOptions.startX !== "number" ||
375
- typeof gradientOptions.startY !== "number" ||
376
- typeof gradientOptions.startRadius !== "number" ||
377
- typeof gradientOptions.endX !== "number" ||
378
- typeof gradientOptions.endY !== "number" ||
379
- typeof gradientOptions.endRadius !== "number") {
380
- throw new Error("Invalid gradient options for radial gradient. Numeric values are required for startX, startY, startRadius, endX, endY, and endRadius.");
381
- }
382
- const gradient = ctx.createRadialGradient(gradientOptions.startX, gradientOptions.startY, gradientOptions.startRadius, gradientOptions.endX, gradientOptions.endY, gradientOptions.endRadius);
383
- for (const colorStop of gradientOptions.colors) {
384
- if (typeof colorStop.stop !== "number" ||
385
- typeof colorStop.color !== "string") {
386
- throw new Error("Invalid color stop. Each color stop should have a numeric stop value and a color string.");
387
- }
388
- gradient.addColorStop(colorStop.stop, colorStop.color);
389
- }
390
- return gradient;
161
+ // Single implementation handling both
162
+ function applyShadow(ctx, a, b, c, d, e, f, g) {
163
+ let rect;
164
+ let shadow;
165
+ let radius;
166
+ let borderPos;
167
+ // Detect which overload we’re in
168
+ if (typeof a === "object" && "x" in a && "w" in a) {
169
+ // (ctx, rect, shadow)
170
+ rect = a;
171
+ shadow = b;
172
+ radius = shadow?.borderRadius ?? 0;
173
+ borderPos = shadow?.borderPosition ?? "all";
391
174
  }
392
175
  else {
393
- throw new Error('Unsupported gradient type. Use "linear" or "radial".');
176
+ // (ctx, shadow, x, y, w, h, radius?, borderPos?)
177
+ shadow = a;
178
+ rect = { x: b, y: c, w: d, h: e };
179
+ radius = f ?? shadow?.borderRadius ?? 0;
180
+ borderPos = g ?? shadow?.borderPosition ?? "all";
394
181
  }
395
- }
396
- /**
397
- * Applies rotation to the canvas context.
398
- * @param ctx The canvas rendering context.
399
- * @param rotation The rotation angle in degrees.
400
- * @param x The x-coordinate of the center of rotation.
401
- * @param y The y-coordinate of the center of rotation.
402
- * @param width The width of the shape.
403
- * @param height The height of the shape.
404
- */
405
- function applyRotation(ctx, rotation, x, y, width, height) {
406
- const rotationX = x + width / 2;
407
- const rotationY = y + height / 2;
408
- ctx.translate(rotationX, rotationY);
409
- ctx.rotate((rotation * Math.PI) / 180);
410
- ctx.translate(-rotationX, -rotationY);
411
- }
412
- /**
413
- * Applies border radius to the canvas context with selective corner support.
414
- *
415
- * @param ctx The canvas rendering context.
416
- * @param image The image to be drawn (will be drawn after clipping).
417
- * @param x The x-coordinate of the shape.
418
- * @param y The y-coordinate of the shape.
419
- * @param width The width of the shape.
420
- * @param height The height of the shape.
421
- * @param borderRadius The border radius value (number or "circular").
422
- * @param borderPosition The sides or corners to round.
423
- * Valid values include:
424
- * - "all"
425
- * - "top", "bottom", "left", "right"
426
- * - "top-left", "top-right", "bottom-left", "bottom-right"
427
- * - Or a comma‑separated list (e.g., "top, left, bottom")
428
- */
429
- function imageRadius(ctx, image, x, y, width, height, borderRadius, borderPosition = "all") {
182
+ if (!shadow)
183
+ return;
184
+ const { color = "rgba(0,0,0,1)", gradient, opacity = 0.4, offsetX = 0, offsetY = 0, blur = 20 } = shadow;
185
+ const r = { x: rect.x + offsetX, y: rect.y + offsetY, w: rect.w, h: rect.h };
430
186
  ctx.save();
431
- ctx.beginPath();
432
- if (borderRadius === "circular") {
433
- const circleRadius = Math.min(width, height) / 2;
434
- ctx.arc(x + width / 2, y + height / 2, circleRadius, 0, 2 * Math.PI);
435
- ctx.clip();
436
- }
437
- else if (typeof borderRadius === "number" && borderRadius > 0) {
438
- const br = Math.min(borderRadius, width / 2, height / 2);
439
- const selectedPositions = new Set(borderPosition.toLowerCase().split(",").map((s) => s.trim()));
440
- const roundTopLeft = selectedPositions.has("all") || selectedPositions.has("top-left") || (selectedPositions.has("top") && selectedPositions.has("left"));
441
- const roundTopRight = selectedPositions.has("all") || selectedPositions.has("top-right") || (selectedPositions.has("top") && selectedPositions.has("right"));
442
- const roundBottomRight = selectedPositions.has("all") || selectedPositions.has("bottom-right") || (selectedPositions.has("bottom") && selectedPositions.has("right"));
443
- const roundBottomLeft = selectedPositions.has("all") || selectedPositions.has("bottom-left") || (selectedPositions.has("bottom") && selectedPositions.has("left"));
444
- const tl = roundTopLeft ? br : 0;
445
- const tr = roundTopRight ? br : 0;
446
- const brR = roundBottomRight ? br : 0;
447
- const bl = roundBottomLeft ? br : 0;
448
- ctx.moveTo(x + tl, y);
449
- ctx.lineTo(x + width - tr, y);
450
- if (tr > 0)
451
- ctx.arc(x + width - tr, y + tr, tr, -Math.PI / 2, 0, false);
452
- ctx.lineTo(x + width, y + height - brR);
453
- if (brR > 0)
454
- ctx.arc(x + width - brR, y + height - brR, brR, 0, Math.PI / 2, false);
455
- ctx.lineTo(x + bl, y + height);
456
- if (bl > 0)
457
- ctx.arc(x + bl, y + height - bl, bl, Math.PI / 2, Math.PI, false);
458
- ctx.lineTo(x, y + tl);
459
- if (tl > 0)
460
- ctx.arc(x + tl, y + tl, tl, Math.PI, -Math.PI / 2, false);
461
- ctx.closePath();
462
- ctx.clip();
187
+ ctx.globalAlpha = opacity;
188
+ if (blur > 0)
189
+ ctx.filter = `blur(${blur}px)`;
190
+ buildPath(ctx, r.x, r.y, r.w, r.h, radius, borderPos);
191
+ if (gradient) {
192
+ const gfill = createGradientFill(ctx, gradient, r);
193
+ ctx.fillStyle = gfill;
463
194
  }
464
195
  else {
465
- ctx.rect(x, y, width, height);
466
- ctx.clip();
196
+ ctx.fillStyle = color;
467
197
  }
468
- ctx.drawImage(image, x, y, width, height);
198
+ ctx.fill();
199
+ ctx.filter = "none";
200
+ ctx.globalAlpha = 1;
469
201
  ctx.restore();
470
202
  }
471
- /**
472
- * Creates a rounded rectangle (or circular) path on the canvas context.
473
- *
474
- * @param ctx The canvas rendering context.
475
- * @param x The x-coordinate of the rectangle.
476
- * @param y The y-coordinate of the rectangle.
477
- * @param width The width of the rectangle.
478
- * @param height The height of the rectangle.
479
- * @param borderRadius The radius for rounding. Use a number (or string "circular" for a circle).
480
- * @param borderPosition Which sides/corners to round. Valid values include:
481
- * - "all" (default)
482
- * - "top", "bottom", "left", "right"
483
- * - "top-left", "top-right", "bottom-left", "bottom-right"
484
- * - Or a comma-separated list, e.g. "top-left, bottom-right" or "top, left, bottom"
485
- */
486
- function objectRadius(ctx, x, y, width, height, borderRadius = 0.1, borderPosition = "all") {
487
- ctx.beginPath();
488
- if (borderRadius === "circular") {
489
- // Draw a circular shape
490
- const circleRadius = Math.min(width, height) / 2;
491
- ctx.arc(x + width / 2, y + height / 2, circleRadius, 0, 2 * Math.PI);
492
- }
493
- else if (borderRadius > 0) {
494
- const br = Math.min(borderRadius, width / 2, height / 2);
495
- const selectedPositions = new Set(borderPosition.toLowerCase().split(",").map((s) => s.trim()));
496
- // **Correct Grouping**
497
- const roundTopLeft = selectedPositions.has("all") ||
498
- selectedPositions.has("top-left") ||
499
- selectedPositions.has("top") ||
500
- selectedPositions.has("left");
501
- const roundTopRight = selectedPositions.has("all") ||
502
- selectedPositions.has("top-right") ||
503
- selectedPositions.has("top") ||
504
- selectedPositions.has("right");
505
- const roundBottomRight = selectedPositions.has("all") ||
506
- selectedPositions.has("bottom-right") ||
507
- selectedPositions.has("bottom") ||
508
- selectedPositions.has("right");
509
- const roundBottomLeft = selectedPositions.has("all") ||
510
- selectedPositions.has("bottom-left") ||
511
- selectedPositions.has("bottom") ||
512
- selectedPositions.has("left");
513
- // **Assign correct radii**
514
- const tl = roundTopLeft ? br : 0;
515
- const tr = roundTopRight ? br : 0;
516
- const brR = roundBottomRight ? br : 0;
517
- const bl = roundBottomLeft ? br : 0;
518
- // **Draw rounded rectangle**
519
- ctx.moveTo(x + tl, y);
520
- ctx.lineTo(x + width - tr, y);
521
- if (tr > 0)
522
- ctx.arc(x + width - tr, y + tr, tr, -Math.PI / 2, 0, false);
523
- ctx.lineTo(x + width, y + height - brR);
524
- if (brR > 0)
525
- ctx.arc(x + width - brR, y + height - brR, brR, 0, Math.PI / 2, false);
526
- ctx.lineTo(x + bl, y + height);
527
- if (bl > 0)
528
- ctx.arc(x + bl, y + height - bl, bl, Math.PI / 2, Math.PI, false);
529
- ctx.lineTo(x, y + tl);
530
- if (tl > 0)
531
- ctx.arc(x + tl, y + tl, tl, Math.PI, -Math.PI / 2, false);
203
+ // Single implementation handling both
204
+ function applyStroke(ctx, a, b, c, d, e, f, g) {
205
+ let rect;
206
+ let stroke;
207
+ let radius;
208
+ let borderPos;
209
+ if (typeof a === "object" && "x" in a && "w" in a) {
210
+ // (ctx, rect, stroke)
211
+ rect = a;
212
+ stroke = b;
213
+ radius = stroke?.borderRadius ?? 0;
214
+ borderPos = stroke?.borderPosition ?? "all";
532
215
  }
533
216
  else {
534
- // Default: Draw normal rectangle
535
- ctx.rect(x, y, width, height);
217
+ // (ctx, stroke, x, y, w, h, radius?, borderPos?)
218
+ stroke = a;
219
+ rect = { x: b, y: c, w: d, h: e };
220
+ radius = f ?? stroke?.borderRadius ?? 0;
221
+ borderPos = g ?? stroke?.borderPosition ?? "all";
536
222
  }
537
- ctx.closePath();
538
- }
539
- /**
540
- * Performs bilinear interpolation on four corners.
541
- * @param corners The four corners (topLeft, topRight, bottomRight, bottomLeft).
542
- * @param t Horizontal interpolation factor (0 to 1).
543
- * @param u Vertical interpolation factor (0 to 1).
544
- * @returns The interpolated point.
545
- */
546
- function bilinearInterpolate(corners, t, u) {
547
- const top = {
548
- x: corners[0].x * (1 - t) + corners[1].x * t,
549
- y: corners[0].y * (1 - t) + corners[1].y * t,
550
- };
551
- const bottom = {
552
- x: corners[3].x * (1 - t) + corners[2].x * t,
553
- y: corners[3].y * (1 - t) + corners[2].y * t,
554
- };
555
- return {
556
- x: top.x * (1 - u) + bottom.x * u,
557
- y: top.y * (1 - u) + bottom.y * u,
223
+ if (!stroke)
224
+ return;
225
+ const { color = "#000", gradient, width = 2, position = 0, blur = 0, opacity = 1 } = stroke;
226
+ // expand/shrink by `position`
227
+ const r = {
228
+ x: rect.x - position,
229
+ y: rect.y - position,
230
+ w: rect.w + position * 2,
231
+ h: rect.h + position * 2
558
232
  };
233
+ ctx.save();
234
+ if (blur > 0)
235
+ ctx.filter = `blur(${blur}px)`;
236
+ ctx.globalAlpha = opacity;
237
+ buildPath(ctx, r.x, r.y, r.w, r.h, radius, borderPos);
238
+ ctx.lineWidth = width;
239
+ if (gradient) {
240
+ const gstroke = createGradientFill(ctx, gradient, r);
241
+ ctx.strokeStyle = gstroke;
242
+ }
243
+ else {
244
+ ctx.strokeStyle = color;
245
+ }
246
+ ctx.stroke();
247
+ ctx.filter = "none";
248
+ ctx.globalAlpha = 1;
249
+ ctx.restore();
559
250
  }
560
- /**
561
- * Applies a perspective warp to the given image by subdividing the source rectangle
562
- * and drawing each cell with an affine transform approximating the local perspective.
563
- *
564
- * @param ctx The canvas rendering context.
565
- * @param image The source image.
566
- * @param x The x-coordinate where the image is drawn.
567
- * @param y The y-coordinate where the image is drawn.
568
- * @param width The width of the region to draw.
569
- * @param height The height of the region to draw.
570
- * @param perspective An object containing four destination corners:
571
- * { topLeft, topRight, bottomRight, bottomLeft }.
572
- * @param gridCols Number of columns to subdivide (default: 10).
573
- * @param gridRows Number of rows to subdivide (default: 10).
574
- */
575
- async function applyPerspective(ctx, image, x, y, width, height, perspective, gridCols = 10, gridRows = 10) {
576
- const cellWidth = width / gridCols;
577
- const cellHeight = height / gridRows;
578
- for (let row = 0; row < gridRows; row++) {
579
- for (let col = 0; col < gridCols; col++) {
580
- const sx = x + col * cellWidth;
581
- const sy = y + row * cellHeight;
582
- const t0 = col / gridCols;
583
- const t1 = (col + 1) / gridCols;
584
- const u0 = row / gridRows;
585
- const u1 = (row + 1) / gridRows;
586
- const destTL = bilinearInterpolate([perspective.topLeft, perspective.topRight, perspective.bottomRight, perspective.bottomLeft], t0, u0);
587
- const destTR = bilinearInterpolate([perspective.topLeft, perspective.topRight, perspective.bottomRight, perspective.bottomLeft], t1, u0);
588
- const destBL = bilinearInterpolate([perspective.topLeft, perspective.topRight, perspective.bottomRight, perspective.bottomLeft], t0, u1);
589
- const a = (destTR.x - destTL.x) / cellWidth;
590
- const b = (destTR.y - destTL.y) / cellWidth;
591
- const c = (destBL.x - destTL.x) / cellHeight;
592
- const d = (destBL.y - destTL.y) / cellHeight;
593
- const e = destTL.x;
594
- const f = destTL.y;
595
- ctx.save();
596
- ctx.setTransform(a, b, c, d, e, f);
597
- ctx.drawImage(image, sx, sy, cellWidth, cellHeight, 0, 0, cellWidth, cellHeight);
598
- ctx.restore();
599
- }
251
+ /** Optional “box background” under the bitmap, inside the image clip */
252
+ function drawBoxBackground(ctx, rect, boxBg, borderRadius, borderPosition) {
253
+ if (!boxBg)
254
+ return;
255
+ const { color, gradient } = boxBg;
256
+ // clip to the box radius, then fill
257
+ ctx.save();
258
+ buildPath(ctx, rect.x, rect.y, rect.w, rect.h, borderRadius ?? 0, borderPosition ?? "all");
259
+ ctx.clip();
260
+ if (gradient) {
261
+ const g = createGradientFill(ctx, gradient, rect);
262
+ ctx.fillStyle = g;
263
+ ctx.fillRect(rect.x, rect.y, rect.w, rect.h);
600
264
  }
265
+ else if (color && color !== "transparent") {
266
+ ctx.fillStyle = color;
267
+ ctx.fillRect(rect.x, rect.y, rect.w, rect.h);
268
+ }
269
+ ctx.restore();
601
270
  }
602
271
  //# sourceMappingURL=imageProperties.js.map