apexify.js 4.7.9 → 4.7.96

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 (41) hide show
  1. package/dist/cjs/ai/ApexAI.d.ts.map +1 -1
  2. package/dist/cjs/ai/ApexAI.js +41 -18
  3. package/dist/cjs/ai/ApexAI.js.map +1 -1
  4. package/dist/cjs/ai/buttons/tools.js +8 -8
  5. package/dist/cjs/ai/buttons/tools.js.map +1 -1
  6. package/dist/cjs/ai/modals-chat/groq/whisper.d.ts.map +1 -1
  7. package/dist/cjs/ai/modals-chat/groq/whisper.js +34 -33
  8. package/dist/cjs/ai/modals-chat/groq/whisper.js.map +1 -1
  9. package/dist/cjs/canvas/ApexPainter.d.ts +19 -14
  10. package/dist/cjs/canvas/ApexPainter.d.ts.map +1 -1
  11. package/dist/cjs/canvas/ApexPainter.js +132 -15
  12. package/dist/cjs/canvas/ApexPainter.js.map +1 -1
  13. package/dist/cjs/canvas/utils/types.d.ts +20 -12
  14. package/dist/cjs/canvas/utils/types.d.ts.map +1 -1
  15. package/dist/cjs/canvas/utils/types.js.map +1 -1
  16. package/dist/cjs/canvas/utils/utils.d.ts +2 -2
  17. package/dist/cjs/canvas/utils/utils.d.ts.map +1 -1
  18. package/dist/esm/ai/ApexAI.d.ts.map +1 -1
  19. package/dist/esm/ai/ApexAI.js +41 -18
  20. package/dist/esm/ai/ApexAI.js.map +1 -1
  21. package/dist/esm/ai/buttons/tools.js +8 -8
  22. package/dist/esm/ai/buttons/tools.js.map +1 -1
  23. package/dist/esm/ai/modals-chat/groq/whisper.d.ts.map +1 -1
  24. package/dist/esm/ai/modals-chat/groq/whisper.js +34 -33
  25. package/dist/esm/ai/modals-chat/groq/whisper.js.map +1 -1
  26. package/dist/esm/canvas/ApexPainter.d.ts +19 -14
  27. package/dist/esm/canvas/ApexPainter.d.ts.map +1 -1
  28. package/dist/esm/canvas/ApexPainter.js +132 -15
  29. package/dist/esm/canvas/ApexPainter.js.map +1 -1
  30. package/dist/esm/canvas/utils/types.d.ts +20 -12
  31. package/dist/esm/canvas/utils/types.d.ts.map +1 -1
  32. package/dist/esm/canvas/utils/types.js.map +1 -1
  33. package/dist/esm/canvas/utils/utils.d.ts +2 -2
  34. package/dist/esm/canvas/utils/utils.d.ts.map +1 -1
  35. package/lib/ai/ApexAI.ts +68 -44
  36. package/lib/ai/buttons/tools.ts +8 -8
  37. package/lib/ai/modals-chat/groq/whisper.ts +84 -83
  38. package/lib/canvas/ApexPainter.ts +180 -24
  39. package/lib/canvas/utils/types.ts +20 -13
  40. package/lib/canvas/utils/utils.ts +4 -2
  41. package/package.json +2 -2
@@ -3,13 +3,13 @@ import GIFEncoder from "gifencoder";
3
3
  import ffmpeg from 'fluent-ffmpeg';
4
4
  import { PassThrough} from "stream";
5
5
  import axios from 'axios';
6
- import fs from "fs";
6
+ import fs, { PathLike } from "fs";
7
7
  import path from "path";
8
8
  import { OutputFormat, CanvasConfig, TextObject, ImageProperties, GIFOptions, GIFResults, CustomOptions, cropOptions,
9
9
  drawBackgroundGradient, drawBackgroundColor, customBackground, customLines, applyRotation, applyStroke,
10
10
  applyShadow, imageRadius, drawShape, drawText, converter, resizingImg, applyColorFilters, imgEffects,verticalBarChart, pieChart,
11
11
  lineChart, cropInner, cropOuter, bgRemoval, detectColors, removeColor, dataURL, base64, arrayBuffer, blob, url, GradientConfig, Frame,
12
- PatternOptions, ExtractFramesOptions, backgroundRadius, applyZoom, ResizeOptions, applyPerspective
12
+ PatternOptions, ExtractFramesOptions, backgroundRadius, applyZoom, ResizeOptions, applyPerspective, MaskOptions, BlendOptions
13
13
  } from "./utils/utils";
14
14
 
15
15
  interface CanvasResults {
@@ -114,6 +114,7 @@ export class ApexPainter {
114
114
 
115
115
  const canvas = createCanvas(baseImage.width, baseImage.height);
116
116
  const ctx = canvas.getContext('2d') as SKRSContext2D | null;
117
+
117
118
  if (!ctx) {
118
119
  throw new Error('Unable to get 2D rendering context from canvas');
119
120
  }
@@ -164,7 +165,6 @@ export class ApexPainter {
164
165
  );
165
166
  }
166
167
 
167
- const size = { width: existingImage.width, height: existingImage.height };
168
168
  drawText(ctx, mergedTextOptions);
169
169
  }
170
170
 
@@ -336,24 +336,24 @@ async createGIF(gifFrames: { background: string; duration: number }[], options:
336
336
  return resizingImg(resizeOptions)
337
337
  }
338
338
 
339
- async imgConverter(imagePath: string, newExtension: string) {
340
- return converter(imagePath, newExtension)
339
+ async imgConverter(source: string, newExtension: string) {
340
+ return converter(source, newExtension)
341
341
  }
342
342
 
343
- async processImage(imagePath: string, filters: any[]) {
344
- return imgEffects(imagePath, filters)
343
+ async effects(source: string, filters: any[]) {
344
+ return imgEffects(source, filters)
345
345
  }
346
346
 
347
- async colorsFilter(imagePath: string, filterColor: any, opacity?: number) {
348
- return applyColorFilters(imagePath, filterColor, opacity)
347
+ async colorsFilter(source: string, filterColor: any, opacity?: number) {
348
+ return applyColorFilters(source, filterColor, opacity)
349
349
  }
350
350
 
351
- async colorAnalysis(imagePath: string) {
352
- return detectColors(imagePath)
351
+ async colorAnalysis(source: string) {
352
+ return detectColors(source)
353
353
  }
354
354
 
355
- async colorsRemover(imagePath: string, colorToRemove: { red: number, green: number, blue: number }) {
356
- return removeColor(imagePath, colorToRemove)
355
+ async colorsRemover(source: string, colorToRemove: { red: number, green: number, blue: number }) {
356
+ return removeColor(source, colorToRemove)
357
357
  }
358
358
 
359
359
  async removeBackground(imageURL: string, apiKey: string) {
@@ -623,7 +623,7 @@ async extractFrames(videoSource: string | Buffer, options: ExtractFramesOptions)
623
623
  * @param {Object} options - Options to customize the pattern.
624
624
  * @returns {Promise<Buffer>} - The adjusted image buffer.
625
625
  */
626
- async setPatternBackground(buffer:Buffer, options: PatternOptions) {
626
+ async patterns(buffer:Buffer, options: PatternOptions) {
627
627
 
628
628
  const img = await loadImage(buffer);
629
629
  const canvas = createCanvas(img.width, img.height);
@@ -663,6 +663,15 @@ async setPatternBackground(buffer:Buffer, options: PatternOptions) {
663
663
  case 'custom':
664
664
  await this.drawCustomPattern(ctx, width, height, options, x, y);
665
665
  break;
666
+ case 'noise':
667
+ await this.drawNoisePattern(ctx, width, height, x, y);
668
+ break;
669
+ case 'waves':
670
+ await this.drawWavePattern(ctx, width, height, options, x, y);
671
+ break;
672
+ case 'diagonal-checkerboard':
673
+ await this.drawDiagonalCheckerboardPattern(ctx, width, height, options, x, y);
674
+ break;
666
675
  default:
667
676
  throw new Error('Invalid pattern type specified.');
668
677
  }
@@ -682,7 +691,7 @@ async setPatternBackground(buffer:Buffer, options: PatternOptions) {
682
691
  * @param x The x offset of the area.
683
692
  * @param y The y offset of the area.
684
693
  */
685
- async fillWithGradient(
694
+ private async fillWithGradient(
686
695
  ctx: SKRSContext2D,
687
696
  width: number,
688
697
  height: number,
@@ -727,7 +736,7 @@ async setPatternBackground(buffer:Buffer, options: PatternOptions) {
727
736
  * @param x The x offset of the area.
728
737
  * @param y The y offset of the area.
729
738
  */
730
- async drawDotsPattern(
739
+ private async drawDotsPattern(
731
740
  ctx: SKRSContext2D,
732
741
  width: number,
733
742
  height: number,
@@ -759,7 +768,7 @@ async setPatternBackground(buffer:Buffer, options: PatternOptions) {
759
768
  * @param x The x offset of the area.
760
769
  * @param y The y offset of the area.
761
770
  */
762
- async drawStripesPattern(
771
+ private async drawStripesPattern(
763
772
  ctx: SKRSContext2D,
764
773
  width: number,
765
774
  height: number,
@@ -795,7 +804,7 @@ async setPatternBackground(buffer:Buffer, options: PatternOptions) {
795
804
  * @param x The x offset of the area.
796
805
  * @param y The y offset of the area.
797
806
  */
798
- async drawGridPattern(
807
+ private async drawGridPattern(
799
808
  ctx: SKRSContext2D,
800
809
  width: number,
801
810
  height: number,
@@ -833,7 +842,7 @@ async setPatternBackground(buffer:Buffer, options: PatternOptions) {
833
842
  * @param x The x offset of the area.
834
843
  * @param y The y offset of the area.
835
844
  */
836
- async drawCheckerboardPattern(
845
+ private async drawCheckerboardPattern(
837
846
  ctx: SKRSContext2D,
838
847
  width: number,
839
848
  height: number,
@@ -844,7 +853,7 @@ async setPatternBackground(buffer:Buffer, options: PatternOptions) {
844
853
  const color1 = options.color || 'black';
845
854
  const color2 = options.secondaryColor || 'white';
846
855
  const size = options.size || 20;
847
-
856
+
848
857
  for (let posY = y; posY < y + height; posY += size) {
849
858
  for (let posX = x; posX < x + width; posX += size) {
850
859
  ctx.fillStyle = (Math.floor(posX / size) + Math.floor(posY / size)) % 2 === 0 ? color1 : color2;
@@ -862,7 +871,7 @@ async setPatternBackground(buffer:Buffer, options: PatternOptions) {
862
871
  * @param x The x offset of the area.
863
872
  * @param y The y offset of the area.
864
873
  */
865
- async drawCustomPattern(
874
+ private async drawCustomPattern(
866
875
  ctx: SKRSContext2D,
867
876
  width: number,
868
877
  height: number,
@@ -881,7 +890,152 @@ async setPatternBackground(buffer:Buffer, options: PatternOptions) {
881
890
  ctx.fillRect(0, 0, width, height);
882
891
  ctx.resetTransform();
883
892
  }
893
+
894
+ private async drawWavePattern(ctx: SKRSContext2D, width: number, height: number, options: PatternOptions, x = 0, y = 0) {
895
+ const color = options.color || 'black';
896
+ const waveHeight = options.size || 10;
897
+ const frequency = options.spacing || 20;
898
+
899
+ ctx.strokeStyle = color;
900
+ ctx.lineWidth = 2;
901
+
902
+ for (let posY = y; posY < y + height; posY += frequency) {
903
+ ctx.beginPath();
904
+ for (let posX = x; posX < x + width; posX += 5) {
905
+ const waveY = posY + Math.sin(posX / frequency) * waveHeight;
906
+ ctx.lineTo(posX, waveY);
907
+ }
908
+ ctx.stroke();
909
+ }
910
+ }
911
+
912
+
913
+ private async drawNoisePattern(ctx: SKRSContext2D, width: number, height: number, x = 0, y = 0) {
914
+ const imageData = ctx.createImageData(width, height);
915
+ const data = imageData.data;
884
916
 
917
+ for (let i = 0; i < data.length; i += 4) {
918
+ const gray = Math.random() * 255;
919
+ data[i] = gray;
920
+ data[i + 1] = gray;
921
+ data[i + 2] = gray;
922
+ data[i + 3] = Math.random() * 255;
923
+ }
924
+
925
+ ctx.putImageData(imageData, x, y);
926
+ }
927
+
928
+
929
+ private async drawDiagonalCheckerboardPattern(ctx: SKRSContext2D, width: number, height: number, options: PatternOptions, x = 0, y = 0) {
930
+ const color1 = options.color || 'black';
931
+ const color2 = options.secondaryColor || 'white';
932
+ const size = options.size || 20;
933
+
934
+ ctx.save();
935
+ ctx.translate(x + width / 2, y + height / 2);
936
+ ctx.rotate(Math.PI / 4);
937
+ ctx.translate(-width / 2, -height / 2);
938
+
939
+ for (let posY = 0; posY < height; posY += size) {
940
+ for (let posX = 0; posX < width; posX += size) {
941
+ ctx.fillStyle = (Math.floor(posX / size) + Math.floor(posY / size)) % 2 === 0 ? color1 : color2;
942
+ ctx.fillRect(posX, posY, size, size);
943
+ }
944
+ }
945
+
946
+ ctx.restore();
947
+ }
948
+
949
+
950
+ async masking(
951
+ source: string | Buffer | PathLike | Uint8Array,
952
+ maskSource: string | Buffer | PathLike | Uint8Array,
953
+ options: MaskOptions = { type: "alpha" }
954
+ ): Promise<Buffer> {
955
+ const img = await loadImage(source);
956
+ const mask = await loadImage(maskSource);
957
+
958
+ const canvas = createCanvas(img.width, img.height);
959
+ const ctx = canvas.getContext("2d") as SKRSContext2D;
960
+
961
+ ctx.drawImage(img, 0, 0, img.width, img.height);
962
+
963
+ const maskCanvas = createCanvas(img.width, img.height);
964
+ const maskCtx = maskCanvas.getContext("2d") as SKRSContext2D;
965
+ maskCtx.drawImage(mask, 0, 0, img.width, img.height);
966
+
967
+ const maskData = maskCtx.getImageData(0, 0, img.width, img.height);
968
+ const imgData = ctx.getImageData(0, 0, img.width, img.height);
969
+
970
+ for (let i = 0; i < maskData.data.length; i += 4) {
971
+ let alphaValue = 255;
972
+
973
+ if (options.type === "grayscale") {
974
+ const grayscale = maskData.data[i] * 0.3 + maskData.data[i + 1] * 0.59 + maskData.data[i + 2] * 0.11;
975
+ alphaValue = grayscale >= (options.threshold ?? 128) ? 255 : 0;
976
+ } else if (options.type === "alpha") {
977
+ alphaValue = maskData.data[i + 3];
978
+ } else if (options.type === "color" && options.colorKey) {
979
+ const colorMatch =
980
+ maskData.data[i] === parseInt(options.colorKey.slice(1, 3), 16) &&
981
+ maskData.data[i + 1] === parseInt(options.colorKey.slice(3, 5), 16) &&
982
+ maskData.data[i + 2] === parseInt(options.colorKey.slice(5, 7), 16);
983
+ alphaValue = colorMatch ? 0 : 255;
984
+ }
985
+
986
+ if (options.invert) alphaValue = 255 - alphaValue;
987
+
988
+ imgData.data[i + 3] = alphaValue;
989
+ }
990
+
991
+ ctx.putImageData(imgData, 0, 0);
992
+
993
+ return canvas.toBuffer("image/png");
994
+ }
995
+
996
+ async gradientBlend(
997
+ source: string | Buffer | PathLike | Uint8Array,
998
+ options: BlendOptions
999
+ ): Promise<Buffer> {
1000
+ const img = await loadImage(source);
1001
+ const canvas = createCanvas(img.width, img.height);
1002
+ const ctx = canvas.getContext("2d") as SKRSContext2D;
1003
+
1004
+ ctx.drawImage(img, 0, 0, img.width, img.height);
1005
+
1006
+ let gradient: CanvasGradient;
1007
+ if (options.type === "linear") {
1008
+ const angle = options.angle ?? 0;
1009
+ const radians = (angle * Math.PI) / 180;
1010
+ const x1 = img.width / 2 - (Math.cos(radians) * img.width) / 2;
1011
+ const y1 = img.height / 2 - (Math.sin(radians) * img.height) / 2;
1012
+ const x2 = img.width / 2 + (Math.cos(radians) * img.width) / 2;
1013
+ const y2 = img.height / 2 + (Math.sin(radians) * img.height) / 2;
1014
+ gradient = ctx.createLinearGradient(x1, y1, x2, y2);
1015
+ } else if (options.type === "radial") {
1016
+ gradient = ctx.createRadialGradient(
1017
+ img.width / 2, img.height / 2, 0, img.width / 2, img.height / 2, Math.max(img.width, img.height)
1018
+ );
1019
+ } else {
1020
+ gradient = ctx.createConicGradient(Math.PI, img.width / 2, img.height / 2);
1021
+ }
1022
+
1023
+ options.colors.forEach(({ stop, color }) => gradient.addColorStop(stop, color));
1024
+ ctx.fillStyle = gradient;
1025
+
1026
+ ctx.globalCompositeOperation = options.blendMode ?? "multiply";
1027
+ ctx.fillRect(0, 0, img.width, img.height);
1028
+
1029
+ if (options.maskSource) {
1030
+ const mask = await loadImage(options.maskSource);
1031
+ ctx.globalCompositeOperation = "destination-in";
1032
+ ctx.drawImage(mask, 0, 0, img.width, img.height);
1033
+ }
1034
+
1035
+ ctx.globalCompositeOperation = "source-over";
1036
+
1037
+ return canvas.toBuffer("image/png");
1038
+ }
885
1039
 
886
1040
  async animate(
887
1041
  frames: Frame[],
@@ -967,7 +1121,7 @@ async animate(
967
1121
  }
968
1122
 
969
1123
  if (frame.pattern) {
970
- const patternImage = await loadImage(frame.pattern.imagePath);
1124
+ const patternImage = await loadImage(frame.pattern.source);
971
1125
  const pattern = ctx.createPattern(patternImage, frame.pattern.repeat || 'repeat');
972
1126
  fillStyle = pattern;
973
1127
  }
@@ -981,8 +1135,8 @@ async animate(
981
1135
  ctx.fillRect(0, 0, width, height);
982
1136
  }
983
1137
 
984
- if (frame.imagePath) {
985
- const image = await loadImage(frame.imagePath);
1138
+ if (frame.source) {
1139
+ const image = await loadImage(frame.source);
986
1140
  ctx.globalCompositeOperation = frame.blendMode || 'source-over';
987
1141
  ctx.drawImage(image, 0, 0, width, height);
988
1142
  }
@@ -1019,6 +1173,8 @@ async animate(
1019
1173
  return options?.gif ? undefined : buffers;
1020
1174
  }
1021
1175
 
1176
+
1177
+
1022
1178
  public validHex(hexColor: string): any {
1023
1179
  const hexPattern = /^#[0-9a-fA-F]{6}$/;
1024
1180
  if (!hexPattern.test(hexColor)) {
@@ -1,4 +1,5 @@
1
1
  import { Canvas, SKRSContext2D } from "@napi-rs/canvas"
2
+ import { PathLike } from "fs";
2
3
  /**
3
4
  * Configuration option to decide the outputformate from ApexPainter
4
5
  * @param {type} default - 'buffer', other formates: url, blob, base64, dataURL, arraybuffer.
@@ -502,10 +503,10 @@ export interface GradientConfig{
502
503
  backgroundColor?: string;
503
504
  gradient?: GradientConfig;
504
505
  pattern?: {
505
- imagePath: string;
506
+ source: string;
506
507
  repeat?: 'repeat' | 'repeat-x' | 'repeat-y' | 'no-repeat';
507
508
  };
508
- imagePath?: string;
509
+ source?: string;
509
510
  blendMode?: GlobalCompositeOperation;
510
511
  transformations?: {
511
512
  scaleX?: number;
@@ -522,7 +523,7 @@ export interface GradientConfig{
522
523
 
523
524
 
524
525
  export interface PatternOptions {
525
- type: 'dots' | 'stripes' | 'grid' | 'checkerboard' | 'custom';
526
+ type: 'dots' | 'stripes' | 'grid' | 'checkerboard' | 'noise' | 'waves' | 'diagonal-checkerboard' | 'custom';
526
527
  color?: string;
527
528
  secondaryColor?: string;
528
529
  x?: number;
@@ -552,21 +553,13 @@ export interface GradientConfig{
552
553
  * Options for resizing an image.
553
554
  */
554
555
  export interface ResizeOptions {
555
- /** The source image path or URL. */
556
556
  imagePath: string;
557
- /** Desired dimensions. If not provided, defaults are used. */
558
557
  size?: {
559
558
  width?: number;
560
559
  height?: number;
561
560
  };
562
- /**
563
- * If true, the image is resized to fit inside the provided dimensions while preserving the aspect ratio.
564
- * If false, the image is resized to fill the dimensions (which might distort the aspect ratio).
565
- */
566
561
  maintainAspectRatio?: boolean;
567
- /** Quality setting for the output image (0–100). Defaults to 90. */
568
562
  quality?: number;
569
- /** Output format for the resized image. Defaults to 'png'. */
570
563
  outputFormat?: 'png' | 'jpeg';
571
564
  }
572
565
 
@@ -578,7 +571,6 @@ export interface GradientConfig{
578
571
  export interface Coordinate {
579
572
  from: Point;
580
573
  to: Point;
581
- /** Optional tension for smoothing the curve. Default is 0. */
582
574
  tension?: number;
583
575
  }
584
576
 
@@ -587,4 +579,19 @@ export interface GradientConfig{
587
579
  coordinates: Coordinate[];
588
580
  crop: 'inner' | 'outer';
589
581
  radius?: number | "circular" | null;
590
- }
582
+ }
583
+
584
+ export interface MaskOptions {
585
+ type?: "alpha" | "grayscale" | "color";
586
+ threshold?: number;
587
+ invert?: boolean;
588
+ colorKey?: string;
589
+ }
590
+
591
+ export interface BlendOptions {
592
+ type?: "linear" | "radial" | "conic";
593
+ angle?: number;
594
+ colors: { stop: number; color: string }[];
595
+ blendMode?: "multiply" | "overlay" | "screen" | "darken" | "lighten" | "difference";
596
+ maskSource?: string | Buffer | PathLike | Uint8Array;
597
+ }
@@ -10,7 +10,7 @@
10
10
 
11
11
 
12
12
 
13
- import { OutputFormat, CanvasConfig, ImageProperties, TextObject, GIFOptions, GIFResults, CustomOptions, cropOptions, GradientConfig, Frame, PatternOptions, ExtractFramesOptions, ResizeOptions, CropOptions } from "./types";
13
+ import { OutputFormat, CanvasConfig, ImageProperties, TextObject, GIFOptions, GIFResults, CustomOptions, cropOptions, GradientConfig, Frame, PatternOptions, ExtractFramesOptions, ResizeOptions, CropOptions, MaskOptions, BlendOptions } from "./types";
14
14
  import { drawBackgroundColor, drawBackgroundGradient, customBackground, backgroundRadius } from "./Background/bg";
15
15
  import { applyRotation, imageRadius, applyStroke, applyZoom, applyShadow, objectRadius, drawShape, applyPerspective } from './Image/imageProperties'
16
16
  import { drawText, WrappedText } from "./Texts/textProperties";
@@ -66,5 +66,7 @@ export {
66
66
  ExtractFramesOptions,
67
67
  ResizeOptions,
68
68
  CropOptions,
69
- applyPerspective
69
+ applyPerspective,
70
+ MaskOptions,
71
+ BlendOptions
70
72
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apexify.js",
3
- "version": "4.7.9",
3
+ "version": "4.7.96",
4
4
  "description": "Unlimited AI models and Canvas library. Supports ts & js (supports front/back end).",
5
5
  "author": "zenith-79",
6
6
  "license": "MIT",
@@ -229,7 +229,7 @@
229
229
  "@discordjs/voice": "^0.18.0",
230
230
  "@google/generative-ai": "^0.22.0",
231
231
  "@napi-rs/canvas": "^0.1.53",
232
- "apexify.js": "^4.7.7",
232
+ "apexify.js": "^4.7.95",
233
233
  "axios": "^1.7.7",
234
234
  "discord.js": "^14.18.0",
235
235
  "fluent-ffmpeg": "^2.1.3",