@nmmty/lazycanvas 0.3.6 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/dist/helpers/Filters.d.ts +10 -10
  2. package/dist/helpers/Fonts.d.ts +1 -1
  3. package/dist/helpers/FontsList.d.ts +1 -1
  4. package/dist/helpers/FontsList.js +19 -19
  5. package/dist/index.d.ts +11 -20
  6. package/dist/index.js +40 -45
  7. package/dist/structures/LazyCanvas.d.ts +126 -17
  8. package/dist/structures/LazyCanvas.js +101 -33
  9. package/dist/structures/components/BaseLayer.d.ts +188 -38
  10. package/dist/structures/components/BaseLayer.js +88 -41
  11. package/dist/structures/components/BezierLayer.d.ts +108 -21
  12. package/dist/structures/components/BezierLayer.js +73 -24
  13. package/dist/structures/components/ClearLayer.d.ts +142 -0
  14. package/dist/structures/components/ClearLayer.js +152 -0
  15. package/dist/structures/components/Group.d.ts +86 -18
  16. package/dist/structures/components/Group.js +69 -29
  17. package/dist/structures/components/ImageLayer.d.ts +85 -12
  18. package/dist/structures/components/ImageLayer.js +55 -42
  19. package/dist/structures/components/LineLayer.d.ts +111 -18
  20. package/dist/structures/components/LineLayer.js +58 -21
  21. package/dist/structures/components/MorphLayer.d.ts +109 -21
  22. package/dist/structures/components/MorphLayer.js +55 -27
  23. package/dist/structures/components/Path2DLayer.d.ts +191 -0
  24. package/dist/structures/components/Path2DLayer.js +318 -0
  25. package/dist/structures/components/QuadraticLayer.d.ts +108 -22
  26. package/dist/structures/components/QuadraticLayer.js +65 -30
  27. package/dist/structures/components/TextLayer.d.ts +201 -40
  28. package/dist/structures/components/TextLayer.js +101 -49
  29. package/dist/structures/components/index.d.ts +10 -0
  30. package/dist/structures/components/index.js +26 -0
  31. package/dist/structures/helpers/Exporter.d.ts +52 -0
  32. package/dist/structures/helpers/Exporter.js +168 -0
  33. package/dist/structures/helpers/Font.d.ts +64 -10
  34. package/dist/structures/helpers/Font.js +38 -11
  35. package/dist/structures/helpers/Gradient.d.ts +96 -9
  36. package/dist/structures/helpers/Gradient.js +48 -17
  37. package/dist/structures/helpers/Link.d.ts +52 -8
  38. package/dist/structures/helpers/Link.js +42 -11
  39. package/dist/structures/helpers/Pattern.d.ts +52 -7
  40. package/dist/structures/helpers/Pattern.js +45 -40
  41. package/dist/structures/helpers/index.d.ts +6 -0
  42. package/dist/structures/helpers/index.js +22 -0
  43. package/dist/structures/helpers/readers/JSONReader.d.ts +49 -0
  44. package/dist/structures/helpers/readers/JSONReader.js +172 -0
  45. package/dist/structures/helpers/readers/SVGReader.d.ts +20 -0
  46. package/dist/structures/helpers/readers/SVGReader.js +577 -0
  47. package/dist/structures/helpers/readers/YAMLReader.d.ts +0 -0
  48. package/dist/structures/helpers/readers/YAMLReader.js +1 -0
  49. package/dist/structures/managers/AnimationManager.d.ts +120 -0
  50. package/dist/structures/managers/AnimationManager.js +99 -0
  51. package/dist/structures/managers/FontsManager.d.ts +76 -32
  52. package/dist/structures/managers/FontsManager.js +70 -45
  53. package/dist/structures/managers/LayersManager.d.ts +84 -32
  54. package/dist/structures/managers/LayersManager.js +67 -29
  55. package/dist/structures/managers/RenderManager.d.ts +63 -6
  56. package/dist/structures/managers/RenderManager.js +162 -33
  57. package/dist/types/LazyCanvas.d.ts +2 -0
  58. package/dist/types/components/ClearLayer.d.ts +19 -0
  59. package/dist/types/enum.d.ts +20 -7
  60. package/dist/types/enum.js +24 -10
  61. package/dist/types/index.d.ts +2 -17
  62. package/dist/types/index.js +17 -0
  63. package/dist/types/managers/AnimationManager.d.ts +14 -0
  64. package/dist/types/types.d.ts +7 -3
  65. package/dist/utils/LazyUtil.js +2 -2
  66. package/dist/utils/utils.d.ts +10 -9
  67. package/dist/utils/utils.js +159 -164
  68. package/package.json +9 -5
@@ -1,74 +1,126 @@
1
1
  import { AnyLayer } from "../../types";
2
- import { ILayersManager } from "../../types";
3
- import { Group } from "../components/Group";
2
+ import { Group } from "../components";
3
+ /**
4
+ * Interface representing the LayersManager.
5
+ */
6
+ export interface ILayersManager {
7
+ /**
8
+ * A map storing layers or groups with their IDs as keys.
9
+ */
10
+ map: Map<string, AnyLayer | Group>;
11
+ /**
12
+ * Whether debugging is enabled.
13
+ */
14
+ debug: boolean;
15
+ }
16
+ /**
17
+ * Class representing a manager for handling layers and groups.
18
+ */
4
19
  export declare class LayersManager implements ILayersManager {
20
+ /**
21
+ * A map storing layers or groups with their IDs as keys.
22
+ */
5
23
  map: Map<string, AnyLayer | Group>;
24
+ /**
25
+ * Whether debugging is enabled.
26
+ */
6
27
  debug: boolean;
7
- constructor(debug?: boolean);
8
28
  /**
9
- * Add a layer to the map
10
- * @param layers {AnyLayer[]} - The `layer` or `group` to add to the map
29
+ * Constructs a new LayersManager instance.
30
+ * @param opts {Object} - Optional settings for the LayersManager.
31
+ * @param opts.debug {boolean} - Whether debugging is enabled.
32
+ */
33
+ constructor(opts?: {
34
+ debug?: boolean;
35
+ });
36
+ /**
37
+ * Adds layers or groups to the map.
38
+ * @param layers {Array<AnyLayer | Group>} - The layers or groups to add to the map.
39
+ * @returns {this} The current instance for chaining.
40
+ * @throws {LazyError} If a layer with the same ID already exists.
11
41
  */
12
- add(...layers: AnyLayer[]): this;
42
+ add(...layers: Array<AnyLayer | Group>): this;
13
43
  /**
14
- * Remove a layer from the map
15
- * @param ids {string[]} - The `id` of the layer or group to remove
44
+ * Removes layers or groups from the map by their IDs.
45
+ * @param ids {string[]} - The IDs of the layers or groups to remove.
46
+ * @returns {this} The current instance for chaining.
16
47
  */
17
48
  remove(...ids: string[]): this;
18
49
  /**
19
- * Clear all layers from the map
50
+ * Clears all layers and groups from the map.
51
+ * @returns {this} The current instance for chaining.
20
52
  */
21
53
  clear(): this;
22
54
  /**
23
- * Get a layer from the map
24
- * @param id {string} - The `id` of the layer or group to get
25
- * @param cross {boolean} - Whether to search in groups or not
55
+ * Retrieves a layer or group from the map by its ID.
56
+ * @param id {string} - The ID of the layer or group to retrieve.
57
+ * @param cross {boolean} - Whether to search within groups for the ID.
58
+ * @returns {AnyLayer | Group | undefined} The retrieved layer or group, or undefined if not found.
26
59
  */
27
- get(id: string, cross?: boolean): AnyLayer | undefined;
60
+ get(id: string, cross?: boolean): AnyLayer | Group | undefined;
28
61
  /**
29
- * Check if a layer exists in the map
30
- * @param id {string} - The `id` of the layer or group to check
62
+ * Checks if a layer or group exists in the map by its ID.
63
+ * @param id {string} - The ID of the layer or group to check.
64
+ * @returns {boolean} True if the layer or group exists, false otherwise.
31
65
  */
32
66
  has(id: string): boolean;
33
67
  /**
34
- * Get the size of the map
68
+ * Retrieves the number of layers and groups in the map.
69
+ * @returns {number} The size of the map.
35
70
  */
36
71
  size(): number;
37
72
  /**
38
- * Get the values of the map
73
+ * Retrieves the values (layers and groups) from the map.
74
+ * @returns {IterableIterator<AnyLayer | Group>} An iterator for the map values.
39
75
  */
40
- values(): IterableIterator<AnyLayer>;
76
+ values(): IterableIterator<AnyLayer | Group>;
41
77
  /**
42
- * Get the keys of the map
78
+ * Retrieves the keys (IDs) from the map.
79
+ * @returns {IterableIterator<string>} An iterator for the map keys.
43
80
  */
44
81
  keys(): IterableIterator<string>;
45
82
  /**
46
- * Get the entries of the map
83
+ * Retrieves the entries (key-value pairs) from the map.
84
+ * @returns {IterableIterator<[string, AnyLayer | Group]>} An iterator for the map entries.
47
85
  */
48
- entries(): IterableIterator<[string, AnyLayer]>;
86
+ entries(): IterableIterator<[string, AnyLayer | Group]>;
49
87
  /**
50
- * For each layer in the map
51
- * @param callbackfn {Function} - The `callback` function to execute
88
+ * Executes a callback function for each layer or group in the map.
89
+ * @param callbackfn {Function} - The callback function to execute.
90
+ * @returns {this} The current instance for chaining.
52
91
  */
53
- forEach(callbackfn: (value: AnyLayer, key: string, map: Map<string, AnyLayer>) => void): this;
92
+ forEach(callbackfn: (value: AnyLayer | Group, key: string, map: Map<string, AnyLayer | Group>) => void): this;
54
93
  /**
55
- * Convert the map to a JSON object
94
+ * Converts the map to a JSON object.
95
+ * @returns {object} The JSON representation of the map.
56
96
  */
57
97
  toJSON(): object;
58
98
  /**
59
- * Convert a JSON object to the map
60
- * @param json {object} - The `json` object to convert
99
+ * Populates the map from a JSON object.
100
+ * @param json {object} - The JSON object to populate the map from.
101
+ * @returns {this} The current instance for chaining.
61
102
  */
62
103
  fromJSON(json: object): this;
63
104
  /**
64
- * Convert the map to an array
105
+ * Converts the map to an array of layers and groups.
106
+ * @returns {Array<AnyLayer | Group>} An array of layers and groups.
65
107
  */
66
- toArray(): Array<AnyLayer>;
108
+ toArray(): Array<AnyLayer | Group>;
67
109
  /**
68
- * Convert an array to the map
69
- * @param array {Array<AnyLayer>} - The `array` to convert
110
+ * Populates the map from an array of layers and groups.
111
+ * @param array {Array<AnyLayer | Group>} - The array of layers and groups to populate the map from.
112
+ * @returns {this} The current instance for chaining.
113
+ */
114
+ fromArray(array: Array<AnyLayer | Group>): this;
115
+ /**
116
+ * Sorts the layers and groups in the map by their zIndex property.
117
+ * @returns {void}
70
118
  */
71
- fromArray(array: Array<AnyLayer>): this;
72
119
  sort(): void;
120
+ /**
121
+ * Searches for a layer or group by its ID, including within groups.
122
+ * @param id {string} - The ID of the layer or group to search for.
123
+ * @returns {AnyLayer | Group | undefined} The found layer or group, or undefined if not found.
124
+ */
73
125
  private crossSearch;
74
126
  }
@@ -1,18 +1,34 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.LayersManager = void 0;
4
- const Group_1 = require("../components/Group");
4
+ const components_1 = require("../components");
5
5
  const LazyUtil_1 = require("../../utils/LazyUtil");
6
+ /**
7
+ * Class representing a manager for handling layers and groups.
8
+ */
6
9
  class LayersManager {
10
+ /**
11
+ * A map storing layers or groups with their IDs as keys.
12
+ */
7
13
  map;
14
+ /**
15
+ * Whether debugging is enabled.
16
+ */
8
17
  debug;
9
- constructor(debug = false) {
18
+ /**
19
+ * Constructs a new LayersManager instance.
20
+ * @param opts {Object} - Optional settings for the LayersManager.
21
+ * @param opts.debug {boolean} - Whether debugging is enabled.
22
+ */
23
+ constructor(opts) {
10
24
  this.map = new Map();
11
- this.debug = debug;
25
+ this.debug = opts?.debug || false;
12
26
  }
13
27
  /**
14
- * Add a layer to the map
15
- * @param layers {AnyLayer[]} - The `layer` or `group` to add to the map
28
+ * Adds layers or groups to the map.
29
+ * @param layers {Array<AnyLayer | Group>} - The layers or groups to add to the map.
30
+ * @returns {this} The current instance for chaining.
31
+ * @throws {LazyError} If a layer with the same ID already exists.
16
32
  */
17
33
  add(...layers) {
18
34
  if (this.debug)
@@ -21,7 +37,7 @@ class LayersManager {
21
37
  layersArray = layersArray.filter(l => l !== undefined);
22
38
  for (const layer of layersArray) {
23
39
  if (this.debug)
24
- LazyUtil_1.LazyLog.log('none', `Data:`, layer.toJSON());
40
+ LazyUtil_1.LazyLog.log('none', `Data:`, 'toJSON' in layer ? layer.toJSON() : layer);
25
41
  if (this.map.has(layer.id))
26
42
  throw new LazyUtil_1.LazyError("Layer already exists");
27
43
  this.map.set(layer.id, layer);
@@ -30,8 +46,9 @@ class LayersManager {
30
46
  return this;
31
47
  }
32
48
  /**
33
- * Remove a layer from the map
34
- * @param ids {string[]} - The `id` of the layer or group to remove
49
+ * Removes layers or groups from the map by their IDs.
50
+ * @param ids {string[]} - The IDs of the layers or groups to remove.
51
+ * @returns {this} The current instance for chaining.
35
52
  */
36
53
  remove(...ids) {
37
54
  for (const id of ids) {
@@ -40,16 +57,18 @@ class LayersManager {
40
57
  return this;
41
58
  }
42
59
  /**
43
- * Clear all layers from the map
60
+ * Clears all layers and groups from the map.
61
+ * @returns {this} The current instance for chaining.
44
62
  */
45
63
  clear() {
46
64
  this.map.clear();
47
65
  return this;
48
66
  }
49
67
  /**
50
- * Get a layer from the map
51
- * @param id {string} - The `id` of the layer or group to get
52
- * @param cross {boolean} - Whether to search in groups or not
68
+ * Retrieves a layer or group from the map by its ID.
69
+ * @param id {string} - The ID of the layer or group to retrieve.
70
+ * @param cross {boolean} - Whether to search within groups for the ID.
71
+ * @returns {AnyLayer | Group | undefined} The retrieved layer or group, or undefined if not found.
53
72
  */
54
73
  get(id, cross = false) {
55
74
  if (cross)
@@ -58,81 +77,100 @@ class LayersManager {
58
77
  return this.map.get(id);
59
78
  }
60
79
  /**
61
- * Check if a layer exists in the map
62
- * @param id {string} - The `id` of the layer or group to check
80
+ * Checks if a layer or group exists in the map by its ID.
81
+ * @param id {string} - The ID of the layer or group to check.
82
+ * @returns {boolean} True if the layer or group exists, false otherwise.
63
83
  */
64
84
  has(id) {
65
85
  return this.map.has(id);
66
86
  }
67
87
  /**
68
- * Get the size of the map
88
+ * Retrieves the number of layers and groups in the map.
89
+ * @returns {number} The size of the map.
69
90
  */
70
91
  size() {
71
92
  return this.map.size;
72
93
  }
73
94
  /**
74
- * Get the values of the map
95
+ * Retrieves the values (layers and groups) from the map.
96
+ * @returns {IterableIterator<AnyLayer | Group>} An iterator for the map values.
75
97
  */
76
98
  values() {
77
99
  return this.map.values();
78
100
  }
79
101
  /**
80
- * Get the keys of the map
102
+ * Retrieves the keys (IDs) from the map.
103
+ * @returns {IterableIterator<string>} An iterator for the map keys.
81
104
  */
82
105
  keys() {
83
106
  return this.map.keys();
84
107
  }
85
108
  /**
86
- * Get the entries of the map
109
+ * Retrieves the entries (key-value pairs) from the map.
110
+ * @returns {IterableIterator<[string, AnyLayer | Group]>} An iterator for the map entries.
87
111
  */
88
112
  entries() {
89
113
  return this.map.entries();
90
114
  }
91
115
  /**
92
- * For each layer in the map
93
- * @param callbackfn {Function} - The `callback` function to execute
116
+ * Executes a callback function for each layer or group in the map.
117
+ * @param callbackfn {Function} - The callback function to execute.
118
+ * @returns {this} The current instance for chaining.
94
119
  */
95
120
  forEach(callbackfn) {
96
121
  this.map.forEach(callbackfn);
97
122
  return this;
98
123
  }
99
124
  /**
100
- * Convert the map to a JSON object
125
+ * Converts the map to a JSON object.
126
+ * @returns {object} The JSON representation of the map.
101
127
  */
102
128
  toJSON() {
103
129
  return Object.fromEntries(this.map);
104
130
  }
105
131
  /**
106
- * Convert a JSON object to the map
107
- * @param json {object} - The `json` object to convert
132
+ * Populates the map from a JSON object.
133
+ * @param json {object} - The JSON object to populate the map from.
134
+ * @returns {this} The current instance for chaining.
108
135
  */
109
136
  fromJSON(json) {
110
137
  this.map = new Map(Object.entries(json));
111
138
  return this;
112
139
  }
113
140
  /**
114
- * Convert the map to an array
141
+ * Converts the map to an array of layers and groups.
142
+ * @returns {Array<AnyLayer | Group>} An array of layers and groups.
115
143
  */
116
144
  toArray() {
117
145
  return Array.from(this.map.values());
118
146
  }
119
147
  /**
120
- * Convert an array to the map
121
- * @param array {Array<AnyLayer>} - The `array` to convert
148
+ * Populates the map from an array of layers and groups.
149
+ * @param array {Array<AnyLayer | Group>} - The array of layers and groups to populate the map from.
150
+ * @returns {this} The current instance for chaining.
122
151
  */
123
152
  fromArray(array) {
124
153
  this.map = new Map(array.map(l => [l.id, l]));
125
154
  return this;
126
155
  }
156
+ /**
157
+ * Sorts the layers and groups in the map by their zIndex property.
158
+ * @returns {void}
159
+ */
127
160
  sort() {
128
161
  this.fromArray(this.toArray().sort((a, b) => a.zIndex - b.zIndex));
129
162
  }
163
+ /**
164
+ * Searches for a layer or group by its ID, including within groups.
165
+ * @param id {string} - The ID of the layer or group to search for.
166
+ * @returns {AnyLayer | Group | undefined} The found layer or group, or undefined if not found.
167
+ */
130
168
  crossSearch(id) {
131
- for (const layer of this.map.values()) {
169
+ for (const layer of Array.from(this.map.values())) {
132
170
  if (layer.id === id)
133
171
  return layer;
134
- if (layer instanceof Group_1.Group) {
135
- const result = layer.components.find(l => l.id === id);
172
+ if (layer instanceof components_1.Group) {
173
+ const result = layer.layers.find(l => l.id === id);
136
174
  if (result)
137
175
  return result;
138
176
  }
@@ -1,15 +1,72 @@
1
1
  /// <reference types="node" />
2
2
  /// <reference types="node" />
3
- import { IRenderManager } from "../../types";
3
+ import { AnyExport } from "../../types";
4
4
  import { LazyCanvas } from "../LazyCanvas";
5
- import { SKRSContext2D } from "@napi-rs/canvas";
5
+ import { Canvas, SKRSContext2D, SvgCanvas } from "@napi-rs/canvas";
6
+ /**
7
+ * Interface representing the RenderManager.
8
+ */
9
+ export interface IRenderManager {
10
+ /**
11
+ * The LazyCanvas instance used for rendering.
12
+ */
13
+ lazyCanvas: LazyCanvas;
14
+ /**
15
+ * Whether debugging is enabled.
16
+ */
17
+ debug: boolean;
18
+ }
19
+ /**
20
+ * Class responsible for managing rendering operations, including static and animated exports.
21
+ */
6
22
  export declare class RenderManager implements IRenderManager {
23
+ /**
24
+ * The LazyCanvas instance used for rendering.
25
+ */
7
26
  lazyCanvas: LazyCanvas;
27
+ /**
28
+ * Whether debugging is enabled.
29
+ */
8
30
  debug: boolean;
9
- constructor(lazyCanvas: LazyCanvas, debug?: boolean);
10
31
  /**
11
- * This will render all the layers and return the rendered canvas buffer or ctx.
12
- * @returns {Promise<Buffer | SKRSContext2D>}
32
+ * Constructs a new RenderManager instance.
33
+ * @param lazyCanvas {LazyCanvas} - The LazyCanvas instance to use for rendering.
34
+ * @param opts {Object} - Optional settings for the RenderManager.
35
+ * @param opts.debug {boolean} - Whether debugging is enabled.
36
+ */
37
+ constructor(lazyCanvas: LazyCanvas, opts?: {
38
+ debug?: boolean;
39
+ });
40
+ /**
41
+ * Merges multiple ImageData objects into a single ImageData object.
42
+ * @param ctx {SKRSContext2D} - The canvas rendering context.
43
+ * @param imageDataList {ImageData[]} - The list of ImageData objects to merge.
44
+ * @param width {number} - The width of the resulting ImageData.
45
+ * @param height {number} - The height of the resulting ImageData.
46
+ * @returns {ImageData} The merged ImageData object.
47
+ */
48
+ private mergeImageData;
49
+ /**
50
+ * Renders a single layer or group of layers.
51
+ * @param layer {AnyLayer | Group} - The layer or group to render.
52
+ * @returns {Promise<SKRSContext2D>} The canvas rendering context after rendering.
53
+ */
54
+ private renderLayer;
55
+ /**
56
+ * Renders all layers statically and exports the result in the specified format.
57
+ * @param exportType {AnyExport} - The export format (e.g., buffer, SVG, or context).
58
+ * @returns {Promise<Buffer | SKRSContext2D | string>} The rendered output in the specified format.
59
+ */
60
+ private renderStatic;
61
+ /**
62
+ * Renders an animated sequence of layers and exports it as a GIF.
63
+ * @returns {Promise<Buffer>} The rendered animation as a Buffer.
64
+ */
65
+ private renderAnimation;
66
+ /**
67
+ * Renders all layers and exports the result in the specified format.
68
+ * @param format {AnyExport} - The export format (e.g., buffer, context, SVG, or canvas).
69
+ * @returns {Promise<Buffer | SKRSContext2D | Canvas | SvgCanvas | string>} The rendered output in the specified format.
13
70
  */
14
- render(): Promise<Buffer | SKRSContext2D>;
71
+ render(format: AnyExport): Promise<Buffer | SKRSContext2D | Canvas | SvgCanvas | string>;
15
72
  }
@@ -1,60 +1,189 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.RenderManager = void 0;
4
- const enum_1 = require("../../types/enum");
5
- const Group_1 = require("../components/Group");
4
+ const types_1 = require("../../types");
5
+ const components_1 = require("../components");
6
6
  const LazyUtil_1 = require("../../utils/LazyUtil");
7
+ // @ts-ignore
8
+ const gifenc_1 = require("gifenc");
9
+ /**
10
+ * Class responsible for managing rendering operations, including static and animated exports.
11
+ */
7
12
  class RenderManager {
13
+ /**
14
+ * The LazyCanvas instance used for rendering.
15
+ */
8
16
  lazyCanvas;
17
+ /**
18
+ * Whether debugging is enabled.
19
+ */
9
20
  debug;
10
- constructor(lazyCanvas, debug = false) {
21
+ /**
22
+ * Constructs a new RenderManager instance.
23
+ * @param lazyCanvas {LazyCanvas} - The LazyCanvas instance to use for rendering.
24
+ * @param opts {Object} - Optional settings for the RenderManager.
25
+ * @param opts.debug {boolean} - Whether debugging is enabled.
26
+ */
27
+ constructor(lazyCanvas, opts) {
11
28
  this.lazyCanvas = lazyCanvas;
12
- this.debug = debug;
29
+ this.debug = opts?.debug || false;
13
30
  }
14
31
  /**
15
- * This will render all the layers and return the rendered canvas buffer or ctx.
16
- * @returns {Promise<Buffer | SKRSContext2D>}
17
- */
18
- async render() {
19
- for (const layer of this.lazyCanvas.layers.toArray()) {
20
- if (this.debug)
21
- LazyUtil_1.LazyLog.log('info', `Rendering ${layer.id}...\nData:`, layer.toJSON());
22
- if (layer.visible) {
23
- if (layer instanceof Group_1.Group) {
24
- for (const subLayer of layer.components) {
25
- if (subLayer.visible) {
26
- if (!subLayer.props.globalComposite)
27
- this.lazyCanvas.ctx.globalCompositeOperation = 'source-over';
28
- else
29
- this.lazyCanvas.ctx.globalCompositeOperation = subLayer.props.globalComposite;
30
- await subLayer.draw(this.lazyCanvas.ctx, this.lazyCanvas.canvas, this.lazyCanvas.layers, this.debug);
32
+ * Merges multiple ImageData objects into a single ImageData object.
33
+ * @param ctx {SKRSContext2D} - The canvas rendering context.
34
+ * @param imageDataList {ImageData[]} - The list of ImageData objects to merge.
35
+ * @param width {number} - The width of the resulting ImageData.
36
+ * @param height {number} - The height of the resulting ImageData.
37
+ * @returns {ImageData} The merged ImageData object.
38
+ */
39
+ mergeImageData(ctx, imageDataList, width, height) {
40
+ const mergedData = ctx.createImageData(width, height);
41
+ const mergedPixels = mergedData.data;
42
+ for (const imageData of imageDataList) {
43
+ const pixels = imageData.data;
44
+ for (let i = 0; i < pixels.length; i += 4) {
45
+ const r = pixels[i];
46
+ const g = pixels[i + 1];
47
+ const b = pixels[i + 2];
48
+ const a = pixels[i + 3] / 255;
49
+ const existingAlpha = mergedPixels[i + 3] / 255;
50
+ const newAlpha = a + existingAlpha * (1 - a);
51
+ if (newAlpha > 0) {
52
+ mergedPixels[i] = (r * a + mergedPixels[i] * existingAlpha * (1 - a)) / newAlpha;
53
+ mergedPixels[i + 1] = (g * a + mergedPixels[i + 1] * existingAlpha * (1 - a)) / newAlpha;
54
+ mergedPixels[i + 2] = (b * a + mergedPixels[i + 2] * existingAlpha * (1 - a)) / newAlpha;
55
+ mergedPixels[i + 3] = newAlpha * 255;
56
+ }
57
+ }
58
+ }
59
+ return mergedData;
60
+ }
61
+ /**
62
+ * Renders a single layer or group of layers.
63
+ * @param layer {AnyLayer | Group} - The layer or group to render.
64
+ * @returns {Promise<SKRSContext2D>} The canvas rendering context after rendering.
65
+ */
66
+ async renderLayer(layer) {
67
+ if (this.debug)
68
+ LazyUtil_1.LazyLog.log('info', `Rendering ${layer.id}...\nData:`, layer.toJSON());
69
+ if (layer.visible) {
70
+ if (layer instanceof components_1.Group) {
71
+ for (const subLayer of layer.layers) {
72
+ if (subLayer.visible) {
73
+ if ('globalComposite' in subLayer.props && subLayer.props.globalComposite) {
74
+ this.lazyCanvas.ctx.globalCompositeOperation = subLayer.props.globalComposite;
75
+ }
76
+ else {
77
+ this.lazyCanvas.ctx.globalCompositeOperation = 'source-over';
31
78
  }
79
+ await subLayer.draw(this.lazyCanvas.ctx, this.lazyCanvas.canvas, this.lazyCanvas.manager.layers, this.debug);
32
80
  }
33
81
  }
82
+ }
83
+ else {
84
+ if ('globalComposite' in layer.props && layer.props.globalComposite) {
85
+ this.lazyCanvas.ctx.globalCompositeOperation = layer.props.globalComposite;
86
+ }
34
87
  else {
35
- if (!layer.props.globalComposite)
36
- this.lazyCanvas.ctx.globalCompositeOperation = 'source-over';
37
- else
38
- this.lazyCanvas.ctx.globalCompositeOperation = layer.props.globalComposite;
39
- await layer.draw(this.lazyCanvas.ctx, this.lazyCanvas.canvas, this.lazyCanvas.layers, this.debug);
88
+ this.lazyCanvas.ctx.globalCompositeOperation = 'source-over';
40
89
  }
41
- this.lazyCanvas.ctx.shadowColor = 'transparent';
90
+ await layer.draw(this.lazyCanvas.ctx, this.lazyCanvas.canvas, this.lazyCanvas.manager.layers, this.debug);
42
91
  }
92
+ this.lazyCanvas.ctx.shadowColor = 'transparent';
43
93
  }
44
- switch (this.lazyCanvas.exportType) {
45
- case enum_1.Export.Buffer:
94
+ return this.lazyCanvas.ctx;
95
+ }
96
+ /**
97
+ * Renders all layers statically and exports the result in the specified format.
98
+ * @param exportType {AnyExport} - The export format (e.g., buffer, SVG, or context).
99
+ * @returns {Promise<Buffer | SKRSContext2D | string>} The rendered output in the specified format.
100
+ */
101
+ async renderStatic(exportType) {
102
+ if (this.debug)
103
+ LazyUtil_1.LazyLog.log('info', `Rendering static...`);
104
+ for (const layer of this.lazyCanvas.manager.layers.toArray()) {
105
+ await this.renderLayer(layer);
106
+ }
107
+ switch (exportType) {
108
+ case types_1.Export.BUFFER:
46
109
  case "buffer":
110
+ case types_1.Export.SVG:
111
+ case "svg":
112
+ if ('getContent' in this.lazyCanvas.canvas) {
113
+ return this.lazyCanvas.canvas.getContent().toString('utf8');
114
+ }
47
115
  return this.lazyCanvas.canvas.toBuffer('image/png');
48
- case enum_1.Export.CTX:
116
+ case types_1.Export.CTX:
49
117
  case "ctx":
50
118
  return this.lazyCanvas.ctx;
51
- case enum_1.Export.SVG:
52
- case "svg":
53
- // @ts-ignore
54
- return this.lazyCanvas.canvas.getContent().toString('utf8');
55
119
  default:
120
+ if ('getContent' in this.lazyCanvas.canvas) {
121
+ return this.lazyCanvas.canvas.getContent().toString('utf8');
122
+ }
56
123
  return this.lazyCanvas.canvas.toBuffer('image/png');
57
124
  }
58
125
  }
126
+ /**
127
+ * Renders an animated sequence of layers and exports it as a GIF.
128
+ * @returns {Promise<Buffer>} The rendered animation as a Buffer.
129
+ */
130
+ async renderAnimation() {
131
+ const encoder = new gifenc_1.GIFEncoder();
132
+ if (this.debug)
133
+ LazyUtil_1.LazyLog.log('info', `Rendering animation...\nData:`, this.lazyCanvas.manager.animation.options);
134
+ const frameBuffer = [];
135
+ const { width, height } = this.lazyCanvas.options;
136
+ const delay = 1000 / this.lazyCanvas.manager.animation.options.frameRate;
137
+ const { loop, colorSpace, maxColors, transparency, utils } = this.lazyCanvas.manager.animation.options;
138
+ for (const layer of this.lazyCanvas.manager.layers.toArray()) {
139
+ const ctx = await this.renderLayer(layer);
140
+ frameBuffer.push(ctx.getImageData(0, 0, width, height));
141
+ if (frameBuffer.length > utils.buffer.size) {
142
+ frameBuffer.shift();
143
+ }
144
+ const mergeData = this.mergeImageData(ctx, frameBuffer, width, height);
145
+ const palette = (0, gifenc_1.quantize)(mergeData.data, maxColors, { format: colorSpace });
146
+ const index = (0, gifenc_1.applyPalette)(mergeData.data, palette, colorSpace);
147
+ encoder.writeFrame(index, width, height, {
148
+ palette,
149
+ transparent: transparency,
150
+ delay,
151
+ loop
152
+ });
153
+ if (utils.clear)
154
+ ctx.clearRect(0, 0, width, height);
155
+ }
156
+ encoder.finish();
157
+ return encoder.bytesView();
158
+ }
159
+ /**
160
+ * Renders all layers and exports the result in the specified format.
161
+ * @param format {AnyExport} - The export format (e.g., buffer, context, SVG, or canvas).
162
+ * @returns {Promise<Buffer | SKRSContext2D | Canvas | SvgCanvas | string>} The rendered output in the specified format.
163
+ */
164
+ async render(format) {
165
+ switch (format) {
166
+ case types_1.Export.BUFFER:
167
+ case "buffer":
168
+ if (this.lazyCanvas.options.animated) {
169
+ return await this.renderAnimation();
170
+ }
171
+ else {
172
+ return await this.renderStatic(types_1.Export.BUFFER);
173
+ }
174
+ case types_1.Export.CTX:
175
+ case "ctx":
176
+ return this.lazyCanvas.ctx;
177
+ case types_1.Export.SVG:
178
+ case "svg":
179
+ return this.renderStatic(types_1.Export.SVG);
180
+ case types_1.Export.CANVAS:
181
+ case "canvas":
182
+ await this.renderStatic(this.lazyCanvas.options.exportType === 'svg' ? types_1.Export.SVG : types_1.Export.BUFFER);
183
+ return this.lazyCanvas.canvas;
184
+ default:
185
+ return this.renderStatic(types_1.Export.BUFFER);
186
+ }
187
+ }
59
188
  }
60
189
  exports.RenderManager = RenderManager;