apexify.js 4.5.25 → 4.5.31
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/ai/modals-chat/electronHub/chatmodels.d.ts.map +1 -1
- package/dist/ai/modals-chat/electronHub/chatmodels.js +6 -0
- package/dist/ai/modals-chat/electronHub/chatmodels.js.map +1 -1
- package/dist/canvas/ApexPainter.d.ts +94 -7
- package/dist/canvas/ApexPainter.d.ts.map +1 -1
- package/dist/canvas/ApexPainter.js +443 -119
- package/dist/canvas/ApexPainter.js.map +1 -1
- package/dist/canvas/utils/bg.d.ts +3 -3
- package/dist/canvas/utils/bg.d.ts.map +1 -1
- package/dist/canvas/utils/bg.js +35 -15
- package/dist/canvas/utils/bg.js.map +1 -1
- package/dist/canvas/utils/customLines.d.ts +2 -1
- package/dist/canvas/utils/customLines.d.ts.map +1 -1
- package/dist/canvas/utils/customLines.js +67 -31
- package/dist/canvas/utils/customLines.js.map +1 -1
- package/dist/canvas/utils/general functions.d.ts +2 -2
- package/dist/canvas/utils/general functions.d.ts.map +1 -1
- package/dist/canvas/utils/general functions.js +52 -15
- package/dist/canvas/utils/general functions.js.map +1 -1
- package/dist/canvas/utils/types.d.ts +68 -0
- package/dist/canvas/utils/types.d.ts.map +1 -1
- package/dist/canvas/utils/types.js +2 -4
- package/dist/canvas/utils/types.js.map +1 -1
- package/dist/canvas/utils/utils.d.ts +2 -2
- package/dist/canvas/utils/utils.d.ts.map +1 -1
- package/examples/barchart.txt +71 -0
- package/examples/linechart.txt +93 -0
- package/examples/piechart.txt +67 -0
- package/lib/ai/modals-chat/electronHub/chatmodels.ts +6 -0
- package/lib/canvas/ApexPainter.ts +665 -262
- package/lib/canvas/utils/bg.ts +42 -16
- package/lib/canvas/utils/customLines.ts +88 -43
- package/lib/canvas/utils/general functions.ts +98 -41
- package/lib/canvas/utils/types.ts +77 -1
- package/lib/canvas/utils/utils.ts +6 -2
- package/package.json +19 -6
package/lib/canvas/utils/bg.ts
CHANGED
|
@@ -1,40 +1,63 @@
|
|
|
1
1
|
import { loadImage } from "@napi-rs/canvas";
|
|
2
2
|
import { CanvasConfig } from './types';
|
|
3
|
-
import fs from 'fs';
|
|
4
3
|
import path from 'path';
|
|
5
4
|
|
|
6
5
|
/**
|
|
7
6
|
* Draws a solid background color on the canvas.
|
|
7
|
+
* Applies zoom scaling and positioning adjustments.
|
|
8
8
|
* @param ctx The canvas rendering context.
|
|
9
9
|
* @param canvas The canvas configuration object.
|
|
10
|
-
* @returns A Promise that resolves once the background color is drawn.
|
|
11
10
|
*/
|
|
12
11
|
export async function drawBackgroundColor(ctx: any, canvas: CanvasConfig): Promise<void> {
|
|
12
|
+
const zoomScale = canvas.zoom?.scale || 1;
|
|
13
|
+
const zoomX = canvas.zoom?.x || 0;
|
|
14
|
+
const zoomY = canvas.zoom?.y || 0;
|
|
15
|
+
|
|
16
|
+
const canvasWidth = canvas.width || 500;
|
|
17
|
+
const canvasHeight = canvas.height || 500;
|
|
18
|
+
|
|
19
|
+
const newWidth = canvasWidth * zoomScale;
|
|
20
|
+
const newHeight = canvasHeight * zoomScale;
|
|
21
|
+
|
|
22
|
+
const drawX = (canvasWidth - newWidth) / 2 - zoomX;
|
|
23
|
+
const drawY = (canvasHeight - newHeight) / 2 - zoomY;
|
|
24
|
+
|
|
13
25
|
if (canvas.colorBg !== 'transparent') {
|
|
14
26
|
ctx.fillStyle = canvas.colorBg;
|
|
15
|
-
ctx.fillRect(
|
|
27
|
+
ctx.fillRect(drawX, drawY, newWidth, newHeight);
|
|
16
28
|
}
|
|
17
29
|
}
|
|
18
30
|
|
|
19
31
|
/**
|
|
20
32
|
* Draws a gradient background on the canvas.
|
|
33
|
+
* Applies zoom scaling and positioning adjustments.
|
|
21
34
|
* @param ctx The canvas rendering context.
|
|
22
35
|
* @param canvas The canvas configuration object.
|
|
23
|
-
* @returns A Promise that resolves once the gradient background is drawn.
|
|
24
36
|
*/
|
|
25
37
|
export async function drawBackgroundGradient(ctx: any, canvas: CanvasConfig): Promise<void> {
|
|
26
38
|
if (canvas.gradientBg) {
|
|
27
|
-
const { type, startX, startY, endX, endY, startRadius, endRadius, colors } = canvas.gradientBg;
|
|
39
|
+
const { type, startX = 0, startY = 0, endX = canvas.width || 500, endY = canvas.height || 500, startRadius = 0, endRadius = 0, colors } = canvas.gradientBg;
|
|
28
40
|
|
|
29
41
|
if (!colors || colors.length === 0) {
|
|
30
42
|
throw new Error('You need to provide colors for the gradient.');
|
|
31
43
|
}
|
|
32
44
|
|
|
33
45
|
let gradient;
|
|
46
|
+
const zoomScale = canvas.zoom?.scale || 1;
|
|
47
|
+
const zoomX = canvas.zoom?.x || 0;
|
|
48
|
+
const zoomY = canvas.zoom?.y || 0;
|
|
49
|
+
|
|
50
|
+
const newStartX = startX * zoomScale - zoomX;
|
|
51
|
+
const newStartY = startY * zoomScale - zoomY;
|
|
52
|
+
const newEndX = endX * zoomScale - zoomX;
|
|
53
|
+
const newEndY = endY * zoomScale - zoomY;
|
|
54
|
+
|
|
34
55
|
if (type === 'linear' || type === undefined) {
|
|
35
|
-
gradient = ctx.createLinearGradient(
|
|
56
|
+
gradient = ctx.createLinearGradient(newStartX, newStartY, newEndX, newEndY);
|
|
36
57
|
} else if (type === 'radial') {
|
|
37
|
-
|
|
58
|
+
const newStartRadius = startRadius * zoomScale;
|
|
59
|
+
const newEndRadius = endRadius * zoomScale;
|
|
60
|
+
gradient = ctx.createRadialGradient(newStartX, newStartY, newStartRadius, newEndX, newEndY, newEndRadius);
|
|
38
61
|
} else {
|
|
39
62
|
throw new Error('Unsupported gradient type.');
|
|
40
63
|
}
|
|
@@ -43,16 +66,21 @@ export async function drawBackgroundGradient(ctx: any, canvas: CanvasConfig): Pr
|
|
|
43
66
|
gradient.addColorStop(stop, color);
|
|
44
67
|
}
|
|
45
68
|
|
|
69
|
+
const newWidth = (canvas.width || 500) * zoomScale;
|
|
70
|
+
const newHeight = (canvas.height || 500) * zoomScale;
|
|
71
|
+
const drawX = ((canvas.width || 500) - newWidth) / 2 - zoomX;
|
|
72
|
+
const drawY = ((canvas.height || 500) - newHeight) / 2 - zoomY;
|
|
73
|
+
|
|
46
74
|
ctx.fillStyle = gradient;
|
|
47
|
-
ctx.fillRect(
|
|
75
|
+
ctx.fillRect(drawX, drawY, newWidth, newHeight);
|
|
48
76
|
}
|
|
49
77
|
}
|
|
50
78
|
|
|
51
79
|
/**
|
|
52
80
|
* Draws a custom background image on the canvas.
|
|
81
|
+
* Zoom logic is applied to scale and position the image.
|
|
53
82
|
* @param ctx The canvas rendering context.
|
|
54
83
|
* @param canvas The canvas configuration object.
|
|
55
|
-
* @returns A Promise that resolves once the custom background image is drawn.
|
|
56
84
|
*/
|
|
57
85
|
export async function customBackground(ctx: any, canvas: CanvasConfig): Promise<void> {
|
|
58
86
|
if (canvas.customBg) {
|
|
@@ -68,22 +96,20 @@ export async function customBackground(ctx: any, canvas: CanvasConfig): Promise<
|
|
|
68
96
|
const image = await loadImage(imageBuffer);
|
|
69
97
|
const zoomScale = canvas.zoom?.scale || 1;
|
|
70
98
|
|
|
71
|
-
if (zoomScale < 0) throw new Error("Invalid scale. Scale can't be a
|
|
99
|
+
if (zoomScale < 0) throw new Error("Invalid scale. Scale can't be a negative integer.");
|
|
72
100
|
|
|
73
101
|
const zoomX = canvas.zoom?.x || 0;
|
|
74
102
|
const zoomY = canvas.zoom?.y || 0;
|
|
75
103
|
const moveX = canvas.x || 0;
|
|
76
104
|
const moveY = canvas.y || 0;
|
|
77
105
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
canvas.width = image.width;
|
|
81
|
-
}
|
|
106
|
+
const canvasWidth = canvas.width || image.width;
|
|
107
|
+
const canvasHeight = canvas.height || image.height;
|
|
82
108
|
|
|
83
109
|
const newWidth = image.width * zoomScale;
|
|
84
110
|
const newHeight = image.height * zoomScale;
|
|
85
|
-
const drawX = moveX + (
|
|
86
|
-
const drawY = moveY + (
|
|
111
|
+
const drawX = moveX + (canvasWidth - newWidth) / 2 - zoomX;
|
|
112
|
+
const drawY = moveY + (canvasHeight - newHeight) / 2 - zoomY;
|
|
87
113
|
|
|
88
114
|
ctx.drawImage(image, drawX, drawY, newWidth, newHeight);
|
|
89
115
|
|
|
@@ -1,49 +1,94 @@
|
|
|
1
|
+
import { CustomOptions } from "./types";
|
|
1
2
|
|
|
2
|
-
export function customLines
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
ctx.lineTo(customOption.endCoordinates.x, customOption.endCoordinates.y);
|
|
7
|
-
ctx.lineWidth = customOption.lineStyle.width || 1;
|
|
8
|
-
ctx.strokeStyle = customOption.lineStyle.color || 'black';
|
|
9
|
-
|
|
10
|
-
if (typeof customOption.lineStyle.lineRadius === 'number') {
|
|
11
|
-
const borderRadius = customOption.lineStyle.lineRadius;
|
|
12
|
-
const dx = customOption.endCoordinates.x - customOption.startCoordinates.x;
|
|
13
|
-
const dy = customOption.endCoordinates.y - customOption.startCoordinates.y;
|
|
14
|
-
const angle = Math.atan2(dy, dx);
|
|
15
|
-
const offsetX = Math.cos(angle) * borderRadius;
|
|
16
|
-
const offsetY = Math.sin(angle) * borderRadius;
|
|
17
|
-
ctx.moveTo(customOption.startCoordinates.x + offsetX, customOption.startCoordinates.y + offsetY);
|
|
18
|
-
ctx.lineTo(customOption.endCoordinates.x - offsetX, customOption.endCoordinates.y - offsetY);
|
|
19
|
-
} else if (customOption.lineStyle.lineRadius === 'circular') {
|
|
20
|
-
const dx = customOption.endCoordinates.x - customOption.startCoordinates.x;
|
|
21
|
-
const dy = customOption.endCoordinates.y - customOption.startCoordinates.y;
|
|
22
|
-
const length = Math.sqrt(dx * dx + dy * dy);
|
|
23
|
-
const angle = Math.atan2(dy, dx);
|
|
24
|
-
const halfWidth = customOption.lineStyle.width ? customOption.lineStyle.width / 2 : 1;
|
|
25
|
-
ctx.moveTo(customOption.startCoordinates.x + Math.cos(angle - Math.PI / 2) * halfWidth, customOption.startCoordinates.y + Math.sin(angle - Math.PI / 2) * halfWidth);
|
|
26
|
-
ctx.arc(customOption.startCoordinates.x, customOption.startCoordinates.y, length / 2, angle - Math.PI / 2, angle + Math.PI / 2);
|
|
27
|
-
ctx.lineTo(customOption.endCoordinates.x + Math.cos(angle + Math.PI / 2) * halfWidth, customOption.endCoordinates.y + Math.sin(angle + Math.PI / 2) * halfWidth);
|
|
28
|
-
ctx.arc(customOption.endCoordinates.x, customOption.endCoordinates.y, length / 2, angle + Math.PI / 2, angle - Math.PI / 2, true);
|
|
29
|
-
ctx.closePath();
|
|
30
|
-
}
|
|
3
|
+
export function customLines(ctx: any, options: CustomOptions[]) {
|
|
4
|
+
let previousEndCoordinates = null;
|
|
5
|
+
let currentStyle = null;
|
|
6
|
+
let inSingleLineSequence = false;
|
|
31
7
|
|
|
32
|
-
|
|
8
|
+
for (let i = 0; i < options.length; i++) {
|
|
9
|
+
const customOption = options[i];
|
|
10
|
+
const { startCoordinates, endCoordinates, lineStyle } = customOption;
|
|
11
|
+
const isSingleLine = lineStyle?.singleLine;
|
|
33
12
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
13
|
+
if (isSingleLine && !inSingleLineSequence) {
|
|
14
|
+
currentStyle = lineStyle;
|
|
15
|
+
inSingleLineSequence = true;
|
|
16
|
+
ctx.beginPath();
|
|
17
|
+
ctx.moveTo(startCoordinates.x, startCoordinates.y);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (!isSingleLine && inSingleLineSequence) {
|
|
21
|
+
ctx.stroke();
|
|
22
|
+
applyAdditionalStroke(ctx, currentStyle);
|
|
23
|
+
inSingleLineSequence = false;
|
|
24
|
+
currentStyle = null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const start = inSingleLineSequence && previousEndCoordinates
|
|
28
|
+
? previousEndCoordinates
|
|
29
|
+
: startCoordinates;
|
|
30
|
+
|
|
31
|
+
if (!inSingleLineSequence) {
|
|
32
|
+
ctx.beginPath();
|
|
33
|
+
ctx.moveTo(start.x, start.y);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
ctx.lineTo(endCoordinates.x, endCoordinates.y);
|
|
37
|
+
|
|
38
|
+
const appliedStyle = inSingleLineSequence ? currentStyle : lineStyle;
|
|
39
|
+
ctx.lineWidth = appliedStyle?.width || 1;
|
|
40
|
+
ctx.strokeStyle = appliedStyle?.color || 'black';
|
|
41
|
+
ctx.lineJoin = appliedStyle?.lineJoin || 'miter';
|
|
42
|
+
ctx.lineCap = appliedStyle?.lineCap || 'butt';
|
|
43
|
+
|
|
44
|
+
if (appliedStyle?.lineDash) {
|
|
45
|
+
ctx.setLineDash(appliedStyle.lineDash.dashArray || []);
|
|
46
|
+
ctx.lineDashOffset = appliedStyle.lineDash.offset || 0;
|
|
47
|
+
} else {
|
|
48
|
+
ctx.setLineDash([]);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (typeof appliedStyle?.lineRadius === 'number') {
|
|
52
|
+
const borderRadius = appliedStyle.lineRadius;
|
|
53
|
+
const dx = endCoordinates.x - start.x;
|
|
54
|
+
const dy = endCoordinates.y - start.y;
|
|
55
|
+
const angle = Math.atan2(dy, dx);
|
|
56
|
+
const offsetX = Math.cos(angle) * borderRadius;
|
|
57
|
+
const offsetY = Math.sin(angle) * borderRadius;
|
|
58
|
+
ctx.moveTo(start.x + offsetX, start.y + offsetY);
|
|
59
|
+
ctx.lineTo(endCoordinates.x - offsetX, endCoordinates.y - offsetY);
|
|
60
|
+
} else if (appliedStyle?.lineRadius === 'circular') {
|
|
61
|
+
const dx = endCoordinates.x - start.x;
|
|
62
|
+
const dy = endCoordinates.y - start.y;
|
|
63
|
+
const length = Math.sqrt(dx * dx + dy * dy);
|
|
64
|
+
const angle = Math.atan2(dy, dx);
|
|
65
|
+
const halfWidth = appliedStyle.width ? appliedStyle.width / 2 : 1;
|
|
66
|
+
ctx.moveTo(start.x + Math.cos(angle - Math.PI / 2) * halfWidth, start.y + Math.sin(angle - Math.PI / 2) * halfWidth);
|
|
67
|
+
ctx.arc(start.x, start.y, length / 2, angle - Math.PI / 2, angle + Math.PI / 2);
|
|
68
|
+
ctx.lineTo(endCoordinates.x + Math.cos(angle + Math.PI / 2) * halfWidth, endCoordinates.y + Math.sin(angle + Math.PI / 2) * halfWidth);
|
|
69
|
+
ctx.arc(endCoordinates.x, endCoordinates.y, length / 2, angle + Math.PI / 2, angle - Math.PI / 2, true);
|
|
70
|
+
ctx.closePath();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (!inSingleLineSequence || i === options.length - 1) {
|
|
74
|
+
ctx.stroke();
|
|
75
|
+
applyAdditionalStroke(ctx, appliedStyle);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
previousEndCoordinates = endCoordinates;
|
|
79
|
+
|
|
80
|
+
if (!isSingleLine) {
|
|
81
|
+
currentStyle = null;
|
|
82
|
+
inSingleLineSequence = false;
|
|
83
|
+
}
|
|
39
84
|
}
|
|
85
|
+
}
|
|
40
86
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
ctx.
|
|
45
|
-
ctx.
|
|
46
|
-
ctx.
|
|
87
|
+
function applyAdditionalStroke(ctx: any, style: any) {
|
|
88
|
+
if (style.stroke) {
|
|
89
|
+
const { color, width } = style.stroke;
|
|
90
|
+
ctx.strokeStyle = color || 'black';
|
|
91
|
+
ctx.lineWidth = width || 1;
|
|
92
|
+
ctx.stroke();
|
|
47
93
|
}
|
|
48
|
-
|
|
49
|
-
}
|
|
94
|
+
}
|
|
@@ -27,38 +27,38 @@ export async function loadImages(imagePath: string) {
|
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
export async function resizingImg(resizeOptions: any): Promise<
|
|
30
|
+
export async function resizingImg(resizeOptions: any): Promise<Buffer> {
|
|
31
31
|
try {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
let absoluteImagePath: string;
|
|
37
|
-
|
|
38
|
-
if (resizeOptions.imagePath.startsWith("http")) {
|
|
39
|
-
|
|
40
|
-
absoluteImagePath = resizeOptions.imagePath;
|
|
41
|
-
} else {
|
|
32
|
+
if (!resizeOptions.imagePath) {
|
|
33
|
+
throw new Error("Image path is required for resizing.");
|
|
34
|
+
}
|
|
42
35
|
|
|
43
|
-
|
|
44
|
-
|
|
36
|
+
let absoluteImagePath;
|
|
37
|
+
|
|
38
|
+
if (resizeOptions.imagePath.startsWith("http")) {
|
|
39
|
+
absoluteImagePath = resizeOptions.imagePath;
|
|
40
|
+
} else {
|
|
41
|
+
absoluteImagePath = path.join(process.cwd(), resizeOptions.imagePath);
|
|
42
|
+
}
|
|
45
43
|
|
|
46
|
-
|
|
47
|
-
const canvas = createCanvas(resizeOptions.size?.width || 500, resizeOptions.size?.height || 500);
|
|
48
|
-
const ctx = canvas.getContext('2d');
|
|
44
|
+
let image = sharp(absoluteImagePath);
|
|
49
45
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
46
|
+
const resizeOptionsForSharp = {
|
|
47
|
+
width: resizeOptions.size?.width || 500,
|
|
48
|
+
height: resizeOptions.size?.height || 500,
|
|
49
|
+
fit: resizeOptions.maintainAspectRatio ? sharp.fit.inside : sharp.fit.fill
|
|
50
|
+
};
|
|
53
51
|
|
|
54
|
-
|
|
52
|
+
const resizedBuffer = await image
|
|
53
|
+
.resize(resizeOptionsForSharp)
|
|
54
|
+
.png()
|
|
55
|
+
.toBuffer();
|
|
55
56
|
|
|
56
|
-
|
|
57
|
+
return resizedBuffer;
|
|
57
58
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
throw new Error("Failed to resize image");
|
|
59
|
+
} catch (error) {
|
|
60
|
+
console.error("Error resizing image:", error);
|
|
61
|
+
throw new Error("Failed to resize image");
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
64
|
|
|
@@ -97,36 +97,93 @@ export async function converter(imagePath: string, newExtension: string) {
|
|
|
97
97
|
}
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
-
export async function applyColorFilters(imagePath: string,
|
|
101
|
-
|
|
102
|
-
try {
|
|
100
|
+
export async function applyColorFilters(imagePath: string, gradientOptions?: any, opacity: number = 1) {
|
|
101
|
+
try {
|
|
103
102
|
let image: any;
|
|
104
103
|
|
|
105
104
|
if (imagePath.startsWith("http")) {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
image = sharp(pngBuffer);
|
|
105
|
+
const pngBuffer = await converter(imagePath, "png");
|
|
106
|
+
image = sharp(pngBuffer);
|
|
109
107
|
} else {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
image = sharp(imagePathResolved);
|
|
108
|
+
const imagePathResolved = path.join(process.cwd(), imagePath);
|
|
109
|
+
image = await sharp(imagePathResolved);
|
|
113
110
|
}
|
|
114
111
|
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
throw new Error("Invalid color format. Only hex colors are supported.");
|
|
118
|
-
}
|
|
112
|
+
const metadata = await image.metadata();
|
|
113
|
+
let gradientImage: Buffer;
|
|
119
114
|
|
|
120
|
-
|
|
115
|
+
if (typeof gradientOptions === 'string') {
|
|
116
|
+
gradientImage = createSolidColorImage(metadata.width, metadata.height, gradientOptions, opacity);
|
|
117
|
+
} else {
|
|
118
|
+
gradientImage = createGradientImage(metadata.width, metadata.height, gradientOptions, opacity);
|
|
119
|
+
}
|
|
121
120
|
|
|
122
|
-
const outputBuffer = await image
|
|
121
|
+
const outputBuffer = await image
|
|
122
|
+
.composite([{ input: gradientImage, blend: 'over' }])
|
|
123
|
+
.toBuffer();
|
|
124
|
+
|
|
123
125
|
return outputBuffer;
|
|
124
|
-
} catch (error) {
|
|
126
|
+
} catch (error) {
|
|
125
127
|
console.error("Error applying color filter:", error);
|
|
126
128
|
throw new Error("Failed to apply color filter");
|
|
127
129
|
}
|
|
128
130
|
}
|
|
129
131
|
|
|
132
|
+
function createSolidColorImage(width: number, height: number, color: string, opacity: number) {
|
|
133
|
+
const solidColorCanvas = createCanvas(width, height);
|
|
134
|
+
const ctx = solidColorCanvas.getContext('2d');
|
|
135
|
+
|
|
136
|
+
ctx.globalAlpha = opacity;
|
|
137
|
+
|
|
138
|
+
ctx.fillStyle = color;
|
|
139
|
+
ctx.fillRect(0, 0, width, height);
|
|
140
|
+
|
|
141
|
+
return solidColorCanvas.toBuffer('image/png');
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function createGradientImage(width: number, height: number, options: any, opacity: number) {
|
|
145
|
+
const { type, colors } = options;
|
|
146
|
+
|
|
147
|
+
const gradientCanvas = createCanvas(width, height);
|
|
148
|
+
const ctx = gradientCanvas.getContext('2d');
|
|
149
|
+
|
|
150
|
+
if (type === 'linear') {
|
|
151
|
+
const gradient = ctx.createLinearGradient(
|
|
152
|
+
options.startX || 0,
|
|
153
|
+
options.startY || 0,
|
|
154
|
+
options.endX || width,
|
|
155
|
+
options.endY || height
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
colors.forEach(({ stop, color }: any) => {
|
|
159
|
+
gradient.addColorStop(stop, color);
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
ctx.fillStyle = gradient;
|
|
163
|
+
} else if (type === 'radial') {
|
|
164
|
+
const gradient = ctx.createRadialGradient(
|
|
165
|
+
options.startX || width / 2,
|
|
166
|
+
options.startY || height / 2,
|
|
167
|
+
options.startRadius || 0,
|
|
168
|
+
options.endX || width / 2,
|
|
169
|
+
options.endY || height / 2,
|
|
170
|
+
options.endRadius || Math.max(width, height)
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
colors.forEach(({ stop, color }: any) => {
|
|
174
|
+
gradient.addColorStop(stop, color);
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
ctx.fillStyle = gradient;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
ctx.globalAlpha = opacity;
|
|
181
|
+
|
|
182
|
+
ctx.fillRect(0, 0, width, height);
|
|
183
|
+
|
|
184
|
+
return gradientCanvas.toBuffer('image/png');
|
|
185
|
+
}
|
|
186
|
+
|
|
130
187
|
export async function imgEffects(imagePath: string, filters: any[]) {
|
|
131
188
|
try {
|
|
132
189
|
let jimpImage;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Canvas } from "@napi-rs/canvas"
|
|
1
2
|
/**
|
|
2
3
|
* Configuration option to decide the outputformate from ApexPainter
|
|
3
4
|
* @param {type} default - 'buffer', other formates: url, blob, base64, dataURL, arraybuffer.
|
|
@@ -50,6 +51,7 @@ export interface CanvasConfig {
|
|
|
50
51
|
offsetY?: number;
|
|
51
52
|
blur?: number;
|
|
52
53
|
opacity?: number;
|
|
54
|
+
borderRadius?: number | "circular";
|
|
53
55
|
};
|
|
54
56
|
rotation?: number;
|
|
55
57
|
borderRadius?: number | "circular";
|
|
@@ -260,6 +262,13 @@ export interface CustomOptions {
|
|
|
260
262
|
width?: number;
|
|
261
263
|
color?: string;
|
|
262
264
|
lineRadius?: number | string;
|
|
265
|
+
lineJoin?: 'round' | 'bevel' | 'miter';
|
|
266
|
+
lineCap?: 'butt' | 'round' | 'square';
|
|
267
|
+
singleLine?: boolean;
|
|
268
|
+
lineDash?: {
|
|
269
|
+
dashArray?: number[];
|
|
270
|
+
offset?: number;
|
|
271
|
+
};
|
|
263
272
|
stroke?: {
|
|
264
273
|
color?: string;
|
|
265
274
|
width?: number;
|
|
@@ -475,4 +484,71 @@ export interface cropOptions {
|
|
|
475
484
|
imageSource: string;
|
|
476
485
|
crop: 'inner' | 'outer';
|
|
477
486
|
radius: number | "circular"
|
|
478
|
-
}
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
|
|
490
|
+
export interface GradientConfig{
|
|
491
|
+
type: 'linear' | 'radial';
|
|
492
|
+
startX?: number;
|
|
493
|
+
startY?: number;
|
|
494
|
+
endX?: number;
|
|
495
|
+
endY?: number;
|
|
496
|
+
startRadius?: number;
|
|
497
|
+
endRadius?: number;
|
|
498
|
+
angle?: number; // Optional: angle-based linear gradients
|
|
499
|
+
colors: {
|
|
500
|
+
stop: number;
|
|
501
|
+
color: string;
|
|
502
|
+
}[];
|
|
503
|
+
};
|
|
504
|
+
|
|
505
|
+
export interface Frame{
|
|
506
|
+
backgroundColor?: string; // Static color
|
|
507
|
+
gradient?: GradientConfig;
|
|
508
|
+
pattern?: {
|
|
509
|
+
imagePath: string; // Path to the pattern image
|
|
510
|
+
repeat?: 'repeat' | 'repeat-x' | 'repeat-y' | 'no-repeat'; // Pattern repetition options
|
|
511
|
+
};
|
|
512
|
+
imagePath?: string; // Path to the image file
|
|
513
|
+
blendMode?: GlobalCompositeOperation; // Blending mode
|
|
514
|
+
transformations?: {
|
|
515
|
+
scaleX?: number;
|
|
516
|
+
scaleY?: number;
|
|
517
|
+
rotate?: number; // Rotation in degrees
|
|
518
|
+
translateX?: number;
|
|
519
|
+
translateY?: number;
|
|
520
|
+
};
|
|
521
|
+
duration?: number; // Custom duration for this frame
|
|
522
|
+
width?: number; // Custom width for the canvas
|
|
523
|
+
height?: number; // Custom height for the canvas
|
|
524
|
+
onDrawCustom?: (ctx: CanvasRenderingContext2D, canvas: Canvas) => void; // Custom draw callback
|
|
525
|
+
};
|
|
526
|
+
|
|
527
|
+
|
|
528
|
+
export interface PatternOptions {
|
|
529
|
+
type: 'dots' | 'stripes' | 'grid' | 'checkerboard' | 'custom';
|
|
530
|
+
color?: string; // Base color for the pattern
|
|
531
|
+
secondaryColor?: string;
|
|
532
|
+
x?: number;
|
|
533
|
+
y?: number;
|
|
534
|
+
width?: number;
|
|
535
|
+
height?: number;
|
|
536
|
+
size?: number; // Size of the pattern (e.g., dot radius, stripe width)
|
|
537
|
+
spacing?: number; // Spacing between patterns
|
|
538
|
+
angle?: number; // Angle for stripes (degrees)
|
|
539
|
+
customPatternImage?: string; // Path to a custom pattern image
|
|
540
|
+
backgroundColor?: string; // Single background color to fill the canvas
|
|
541
|
+
gradient?: GradientConfig; // Gradient options for background
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
|
|
545
|
+
export interface ExtractFramesOptions {
|
|
546
|
+
interval: number;
|
|
547
|
+
outputFormat?: 'jpg' | 'png';
|
|
548
|
+
frameSelection?: {
|
|
549
|
+
start?: number;
|
|
550
|
+
end?: number;
|
|
551
|
+
};
|
|
552
|
+
watermark?: string;
|
|
553
|
+
}
|
|
554
|
+
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
import { OutputFormat, CanvasConfig, ImageProperties, TextObject, ImageObject, GIFOptions, GIFResults, CustomOptions, cropOptions } from "./types";
|
|
13
|
+
import { OutputFormat, CanvasConfig, ImageProperties, TextObject, ImageObject, GIFOptions, GIFResults, CustomOptions, cropOptions, GradientConfig, Frame, PatternOptions, ExtractFramesOptions } from "./types";
|
|
14
14
|
import { radiusBorder } from "./radius";
|
|
15
15
|
import { circularBorder } from "./circular";
|
|
16
16
|
import { drawBackgroundColor, drawBackgroundGradient, customBackground } from "./bg";
|
|
@@ -62,5 +62,9 @@ export {
|
|
|
62
62
|
cropOuter,
|
|
63
63
|
detectColors,
|
|
64
64
|
removeColor,
|
|
65
|
-
bgRemoval
|
|
65
|
+
bgRemoval,
|
|
66
|
+
GradientConfig,
|
|
67
|
+
Frame,
|
|
68
|
+
PatternOptions,
|
|
69
|
+
ExtractFramesOptions
|
|
66
70
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "apexify.js",
|
|
3
|
-
"version": "4.5.
|
|
3
|
+
"version": "4.5.31",
|
|
4
4
|
"description": "Unlimited AI models and Canvas library. Supports ts & js (supports front/back end).",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"author": "zenith-79",
|
|
@@ -14,7 +14,8 @@
|
|
|
14
14
|
},
|
|
15
15
|
"files": [
|
|
16
16
|
"lib",
|
|
17
|
-
"dist"
|
|
17
|
+
"dist",
|
|
18
|
+
"examples"
|
|
18
19
|
],
|
|
19
20
|
"keywords": [
|
|
20
21
|
"chat bot",
|
|
@@ -189,6 +190,17 @@
|
|
|
189
190
|
"image converter",
|
|
190
191
|
"converter",
|
|
191
192
|
"canvas-filters",
|
|
193
|
+
"image mask",
|
|
194
|
+
"image animate",
|
|
195
|
+
"animate",
|
|
196
|
+
"gif",
|
|
197
|
+
"masks",
|
|
198
|
+
"mask",
|
|
199
|
+
"blend",
|
|
200
|
+
"image blend",
|
|
201
|
+
"custom drawing",
|
|
202
|
+
"frames",
|
|
203
|
+
"extract frames",
|
|
192
204
|
"apexify",
|
|
193
205
|
"apexify.js"
|
|
194
206
|
],
|
|
@@ -196,11 +208,11 @@
|
|
|
196
208
|
"@google/generative-ai": "^0.14.1",
|
|
197
209
|
"@iamtraction/google-translate": "^2.0.1",
|
|
198
210
|
"@napi-rs/canvas": "^0.1.53",
|
|
199
|
-
"apexify.js": "^4.5.23",
|
|
200
211
|
"api": "^6.1.2",
|
|
201
212
|
"compromise": "^14.14.0",
|
|
202
213
|
"csv-parse": "^5.5.6",
|
|
203
214
|
"discord.js": "^14.15.3",
|
|
215
|
+
"fluent-ffmpeg": "^2.1.3",
|
|
204
216
|
"gifencoder": "^2.0.1",
|
|
205
217
|
"groq-sdk": "^0.5.0",
|
|
206
218
|
"hercai": "^12.3.2",
|
|
@@ -209,13 +221,14 @@
|
|
|
209
221
|
"pdf-parse": "^1.1.1",
|
|
210
222
|
"sharp": "^0.33.4",
|
|
211
223
|
"tesseract.js": "^5.1.0",
|
|
212
|
-
"ts-node": "^10.9.2",
|
|
213
|
-
"typescript": "^5.5.3",
|
|
214
224
|
"verse.db": "^2.2.15"
|
|
215
225
|
},
|
|
216
226
|
"devDependencies": {
|
|
227
|
+
"@types/fluent-ffmpeg": "^2.1.26",
|
|
217
228
|
"@types/gifencoder": "^2.0.3",
|
|
218
229
|
"@types/node": "^22.5.4",
|
|
219
|
-
"@types/pdf-parse": "^1.1.4"
|
|
230
|
+
"@types/pdf-parse": "^1.1.4",
|
|
231
|
+
"ts-node": "^10.9.2",
|
|
232
|
+
"typescript": "^5.6.2"
|
|
220
233
|
}
|
|
221
234
|
}
|