@meonode/canvas 1.6.0 → 1.7.1
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/cjs/canvas/canvas.helper.d.ts +20 -1
- package/dist/cjs/canvas/canvas.helper.d.ts.map +1 -1
- package/dist/cjs/canvas/canvas.helper.js +230 -0
- package/dist/cjs/canvas/canvas.helper.js.map +1 -1
- package/dist/cjs/canvas/canvas.type.d.ts +19 -8
- package/dist/cjs/canvas/canvas.type.d.ts.map +1 -1
- package/dist/cjs/canvas/chart.canvas.util.d.ts +2 -2
- package/dist/cjs/canvas/chart.canvas.util.d.ts.map +1 -1
- package/dist/cjs/canvas/chart.canvas.util.js +101 -26
- package/dist/cjs/canvas/chart.canvas.util.js.map +1 -1
- package/dist/cjs/canvas/grid.canvas.util.d.ts +3 -3
- package/dist/cjs/canvas/grid.canvas.util.d.ts.map +1 -1
- package/dist/cjs/canvas/grid.canvas.util.js.map +1 -1
- package/dist/cjs/canvas/image.canvas.util.d.ts +40 -4
- package/dist/cjs/canvas/image.canvas.util.d.ts.map +1 -1
- package/dist/cjs/canvas/image.canvas.util.js +114 -4
- package/dist/cjs/canvas/image.canvas.util.js.map +1 -1
- package/dist/cjs/canvas/layout.canvas.util.d.ts +4 -4
- package/dist/cjs/canvas/layout.canvas.util.d.ts.map +1 -1
- package/dist/cjs/canvas/layout.canvas.util.js +1 -1
- package/dist/cjs/canvas/layout.canvas.util.js.map +1 -1
- package/dist/cjs/canvas/root.canvas.util.d.ts +5 -3
- package/dist/cjs/canvas/root.canvas.util.d.ts.map +1 -1
- package/dist/cjs/canvas/root.canvas.util.js +64 -43
- package/dist/cjs/canvas/root.canvas.util.js.map +1 -1
- package/dist/cjs/canvas/text.canvas.util.d.ts +2 -2
- package/dist/cjs/canvas/text.canvas.util.d.ts.map +1 -1
- package/dist/cjs/canvas/text.canvas.util.js +0 -1
- package/dist/cjs/canvas/text.canvas.util.js.map +1 -1
- package/dist/cjs/index.d.ts +1 -1
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +1 -0
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/canvas/canvas.helper.d.ts +20 -1
- package/dist/esm/canvas/canvas.helper.d.ts.map +1 -1
- package/dist/esm/canvas/canvas.helper.js +230 -1
- package/dist/esm/canvas/canvas.type.d.ts +19 -8
- package/dist/esm/canvas/canvas.type.d.ts.map +1 -1
- package/dist/esm/canvas/chart.canvas.util.d.ts +2 -2
- package/dist/esm/canvas/chart.canvas.util.d.ts.map +1 -1
- package/dist/esm/canvas/chart.canvas.util.js +102 -27
- package/dist/esm/canvas/grid.canvas.util.d.ts +3 -3
- package/dist/esm/canvas/grid.canvas.util.d.ts.map +1 -1
- package/dist/esm/canvas/image.canvas.util.d.ts +40 -4
- package/dist/esm/canvas/image.canvas.util.d.ts.map +1 -1
- package/dist/esm/canvas/image.canvas.util.js +112 -5
- package/dist/esm/canvas/layout.canvas.util.d.ts +4 -4
- package/dist/esm/canvas/layout.canvas.util.d.ts.map +1 -1
- package/dist/esm/canvas/layout.canvas.util.js +1 -1
- package/dist/esm/canvas/root.canvas.util.d.ts +5 -3
- package/dist/esm/canvas/root.canvas.util.d.ts.map +1 -1
- package/dist/esm/canvas/root.canvas.util.js +65 -44
- package/dist/esm/canvas/text.canvas.util.d.ts +2 -2
- package/dist/esm/canvas/text.canvas.util.d.ts.map +1 -1
- package/dist/esm/canvas/text.canvas.util.js +0 -1
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +1 -1
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { BaseProps, ImageProps,
|
|
1
|
+
import type { BaseProps, ImageProps, CanvasElement } from '../canvas/canvas.type.js';
|
|
2
2
|
import { type CanvasRenderingContext2D, Image as CanvasImage } from 'skia-canvas';
|
|
3
3
|
import { BoxNode } from '../canvas/layout.canvas.util.js';
|
|
4
4
|
/**
|
|
@@ -6,6 +6,36 @@ import { BoxNode } from '../canvas/layout.canvas.util.js';
|
|
|
6
6
|
* Scoped to a single RootNode.render() call; discarded after rendering.
|
|
7
7
|
*/
|
|
8
8
|
export type RenderImageCache = Map<string, Promise<CanvasImage>>;
|
|
9
|
+
/**
|
|
10
|
+
* A simple LRU cache for resolved `CanvasImage` objects.
|
|
11
|
+
*
|
|
12
|
+
* - Persists across render passes so repeated renders of the same tree don't
|
|
13
|
+
* re-fetch every image.
|
|
14
|
+
* - Bounded by `maxSize` entries; least-recently-used entries are evicted first.
|
|
15
|
+
* - Call `dispose()` to eagerly release all held images, or rely on the
|
|
16
|
+
* automatic `process.on('exit')` hook that clears the singleton.
|
|
17
|
+
*/
|
|
18
|
+
export declare class ImageLRUCache {
|
|
19
|
+
private readonly map;
|
|
20
|
+
readonly maxSize: number;
|
|
21
|
+
constructor(maxSize: number);
|
|
22
|
+
get(key: string): CanvasImage | undefined;
|
|
23
|
+
set(key: string, image: CanvasImage): void;
|
|
24
|
+
has(key: string): boolean;
|
|
25
|
+
get size(): number;
|
|
26
|
+
dispose(): void;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Returns the singleton `ImageLRUCache`, creating it on first access.
|
|
30
|
+
* Registers a one-time process cleanup hook to clear the cache
|
|
31
|
+
* so native image buffers are freed when the process shuts down.
|
|
32
|
+
*/
|
|
33
|
+
export declare function getImageCache(maxSize?: number): ImageLRUCache;
|
|
34
|
+
/**
|
|
35
|
+
* Explicitly disposes the global image cache.
|
|
36
|
+
* Useful in tests or when tearing down the rendering engine.
|
|
37
|
+
*/
|
|
38
|
+
export declare function disposeImageCache(): void;
|
|
9
39
|
/**
|
|
10
40
|
* Renders images with configurable sizing, positioning, and effects.
|
|
11
41
|
* Supports object-fit modes, positioning, border radius, and saturation filters.
|
|
@@ -24,8 +54,14 @@ export declare class ImageNode extends BoxNode {
|
|
|
24
54
|
*/
|
|
25
55
|
private _fetchCanvasImage;
|
|
26
56
|
/**
|
|
27
|
-
* Loads and processes an image
|
|
28
|
-
*
|
|
57
|
+
* Loads and processes an image.
|
|
58
|
+
*
|
|
59
|
+
* Resolution order:
|
|
60
|
+
* 1. Persistent LRU cache (cross-render) — instant hit, no I/O.
|
|
61
|
+
* 2. Per-render dedup cache — avoids duplicate in-flight fetches within a single render.
|
|
62
|
+
* 3. Fresh fetch via `_fetchCanvasImage()`.
|
|
63
|
+
*
|
|
64
|
+
* Resolved images are stored back into the LRU cache for future renders.
|
|
29
65
|
*/
|
|
30
66
|
private _loadImage;
|
|
31
67
|
getLoadingPromise(): Promise<void>;
|
|
@@ -38,5 +74,5 @@ export declare class ImageNode extends BoxNode {
|
|
|
38
74
|
/**
|
|
39
75
|
* Factory function to create ImageNode instances
|
|
40
76
|
*/
|
|
41
|
-
export declare const Image: (props: ImageProps) =>
|
|
77
|
+
export declare const Image: (props: ImageProps) => CanvasElement;
|
|
42
78
|
//# sourceMappingURL=image.canvas.util.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"image.canvas.util.d.ts","sourceRoot":"","sources":["../../../src/canvas/image.canvas.util.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,
|
|
1
|
+
{"version":3,"file":"image.canvas.util.d.ts","sourceRoot":"","sources":["../../../src/canvas/image.canvas.util.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAA;AACnF,OAAO,EAAE,KAAK,wBAAwB,EAAE,KAAK,IAAI,WAAW,EAAa,MAAM,aAAa,CAAA;AAC5F,OAAO,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAA;AAsBxD;;;GAGG;AACH,MAAM,MAAM,gBAAgB,GAAG,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC,CAAA;AAWhE;;;;;;;;GAQG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,GAAG,CAA8B;IAClD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;gBAEZ,OAAO,EAAE,MAAM;IAI3B,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS;IASzC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI;IAa1C,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIzB,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,OAAO,IAAI,IAAI;CAGhB;AAUD;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,OAAO,GAAE,MAA2B,GAAG,aAAa,CAejF;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,IAAI,CAGxC;AAED;;;GAGG;AACH,qBAAa,SAAU,SAAQ,OAAO;IAC5B,KAAK,EAAE,UAAU,GAAG,SAAS,CAAA;IACrC,OAAO,CAAC,WAAW,CAA2B;IAC9C,OAAO,CAAC,YAAY,CAAI;IACxB,OAAO,CAAC,aAAa,CAAI;IACzB,OAAO,CAAC,cAAc,CAA6B;gBAEvC,KAAK,EAAE,UAAU;IAYtB,IAAI,CAAC,KAAK,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAOpD;;;OAGG;YACW,iBAAiB;IAmE/B;;;;;;;;;OASG;IACH,OAAO,CAAC,UAAU;IAwEX,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC;IAIzC;;;OAGG;cACgB,cAAc,CAAC,GAAG,EAAE,wBAAwB,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CAoJrH;AAED;;GAEG;AACH,eAAO,MAAM,KAAK,GAAI,OAAO,UAAU,KAAG,aAGxC,CAAA"}
|
|
@@ -20,6 +20,86 @@ function calculateOffsetFromValue(positionValue, availableSpace) {
|
|
|
20
20
|
console.warn(`[ImageNode] Invalid objectPosition value format: ${value}. Defaulting to 50%.`);
|
|
21
21
|
return availableSpace * 0.5;
|
|
22
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* A simple LRU cache for resolved `CanvasImage` objects.
|
|
25
|
+
*
|
|
26
|
+
* - Persists across render passes so repeated renders of the same tree don't
|
|
27
|
+
* re-fetch every image.
|
|
28
|
+
* - Bounded by `maxSize` entries; least-recently-used entries are evicted first.
|
|
29
|
+
* - Call `dispose()` to eagerly release all held images, or rely on the
|
|
30
|
+
* automatic `process.on('exit')` hook that clears the singleton.
|
|
31
|
+
*/
|
|
32
|
+
class ImageLRUCache {
|
|
33
|
+
map = new Map();
|
|
34
|
+
maxSize;
|
|
35
|
+
constructor(maxSize) {
|
|
36
|
+
this.maxSize = maxSize;
|
|
37
|
+
}
|
|
38
|
+
get(key) {
|
|
39
|
+
const entry = this.map.get(key);
|
|
40
|
+
if (!entry)
|
|
41
|
+
return undefined;
|
|
42
|
+
// Move to end (most-recently used)
|
|
43
|
+
this.map.delete(key);
|
|
44
|
+
this.map.set(key, entry);
|
|
45
|
+
return entry.image;
|
|
46
|
+
}
|
|
47
|
+
set(key, image) {
|
|
48
|
+
// If key already exists, refresh it
|
|
49
|
+
if (this.map.has(key)) {
|
|
50
|
+
this.map.delete(key);
|
|
51
|
+
}
|
|
52
|
+
// Evict oldest if at capacity
|
|
53
|
+
while (this.map.size >= this.maxSize) {
|
|
54
|
+
const oldest = this.map.keys().next().value;
|
|
55
|
+
this.map.delete(oldest);
|
|
56
|
+
}
|
|
57
|
+
this.map.set(key, { image, key });
|
|
58
|
+
}
|
|
59
|
+
has(key) {
|
|
60
|
+
return this.map.has(key);
|
|
61
|
+
}
|
|
62
|
+
get size() {
|
|
63
|
+
return this.map.size;
|
|
64
|
+
}
|
|
65
|
+
dispose() {
|
|
66
|
+
this.map.clear();
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/** Module-level singleton — lazily created on first render. */
|
|
70
|
+
let _globalImageCache = null;
|
|
71
|
+
const DEFAULT_CACHE_SIZE = 128;
|
|
72
|
+
// Symbol key on process to track hook registration across module reloads (e.g. Jest resetModules)
|
|
73
|
+
const HOOK_KEY = Symbol.for('__meonode_canvas_image_cache_hook__');
|
|
74
|
+
/**
|
|
75
|
+
* Returns the singleton `ImageLRUCache`, creating it on first access.
|
|
76
|
+
* Registers a one-time process cleanup hook to clear the cache
|
|
77
|
+
* so native image buffers are freed when the process shuts down.
|
|
78
|
+
*/
|
|
79
|
+
function getImageCache(maxSize = DEFAULT_CACHE_SIZE) {
|
|
80
|
+
if (!_globalImageCache) {
|
|
81
|
+
_globalImageCache = new ImageLRUCache(maxSize);
|
|
82
|
+
}
|
|
83
|
+
if (!globalThis[HOOK_KEY]) {
|
|
84
|
+
globalThis[HOOK_KEY] = true;
|
|
85
|
+
const cleanup = () => {
|
|
86
|
+
_globalImageCache?.dispose();
|
|
87
|
+
_globalImageCache = null;
|
|
88
|
+
};
|
|
89
|
+
process.once('exit', cleanup);
|
|
90
|
+
process.once('SIGINT', cleanup);
|
|
91
|
+
process.once('SIGTERM', cleanup);
|
|
92
|
+
}
|
|
93
|
+
return _globalImageCache;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Explicitly disposes the global image cache.
|
|
97
|
+
* Useful in tests or when tearing down the rendering engine.
|
|
98
|
+
*/
|
|
99
|
+
function disposeImageCache() {
|
|
100
|
+
_globalImageCache?.dispose();
|
|
101
|
+
_globalImageCache = null;
|
|
102
|
+
}
|
|
23
103
|
/**
|
|
24
104
|
* Renders images with configurable sizing, positioning, and effects.
|
|
25
105
|
* Supports object-fit modes, positioning, border radius, and saturation filters.
|
|
@@ -111,8 +191,14 @@ class ImageNode extends BoxNode {
|
|
|
111
191
|
return loadImage(finalSource);
|
|
112
192
|
}
|
|
113
193
|
/**
|
|
114
|
-
* Loads and processes an image
|
|
115
|
-
*
|
|
194
|
+
* Loads and processes an image.
|
|
195
|
+
*
|
|
196
|
+
* Resolution order:
|
|
197
|
+
* 1. Persistent LRU cache (cross-render) — instant hit, no I/O.
|
|
198
|
+
* 2. Per-render dedup cache — avoids duplicate in-flight fetches within a single render.
|
|
199
|
+
* 3. Fresh fetch via `_fetchCanvasImage()`.
|
|
200
|
+
*
|
|
201
|
+
* Resolved images are stored back into the LRU cache for future renders.
|
|
116
202
|
*/
|
|
117
203
|
_loadImage(cache) {
|
|
118
204
|
if (!this.props.src) {
|
|
@@ -125,9 +211,26 @@ class ImageNode extends BoxNode {
|
|
|
125
211
|
return new Promise(resolve => {
|
|
126
212
|
const load = async () => {
|
|
127
213
|
try {
|
|
214
|
+
const lru = getImageCache();
|
|
215
|
+
const cacheKey = typeof this.props.src === 'string' ? (this.props.color ? `${this.props.src}|${this.props.color}` : this.props.src) : null;
|
|
216
|
+
// 1. Check persistent LRU cache
|
|
217
|
+
if (cacheKey) {
|
|
218
|
+
const cached = lru.get(cacheKey);
|
|
219
|
+
if (cached) {
|
|
220
|
+
this.loadedImage = cached;
|
|
221
|
+
this.naturalWidth = cached.width;
|
|
222
|
+
this.naturalHeight = cached.height;
|
|
223
|
+
const calculatedAspectRatio = cached.width > 0 && cached.height > 0 ? cached.width / cached.height : undefined;
|
|
224
|
+
const finalAspectRatio = typeof this.props.aspectRatio === 'number' && this.props.aspectRatio > 0 ? this.props.aspectRatio : calculatedAspectRatio;
|
|
225
|
+
this.node.setAspectRatio(finalAspectRatio);
|
|
226
|
+
this.props.onLoad?.();
|
|
227
|
+
resolve();
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
// 2. Per-render dedup cache or fresh fetch
|
|
128
232
|
let imagePromise;
|
|
129
|
-
if (cache &&
|
|
130
|
-
const cacheKey = this.props.color ? `${this.props.src}|${this.props.color}` : this.props.src;
|
|
233
|
+
if (cache && cacheKey) {
|
|
131
234
|
if (!cache.has(cacheKey)) {
|
|
132
235
|
cache.set(cacheKey, this._fetchCanvasImage());
|
|
133
236
|
}
|
|
@@ -137,6 +240,10 @@ class ImageNode extends BoxNode {
|
|
|
137
240
|
imagePromise = this._fetchCanvasImage();
|
|
138
241
|
}
|
|
139
242
|
const img = await imagePromise;
|
|
243
|
+
// 3. Store in persistent LRU cache
|
|
244
|
+
if (cacheKey) {
|
|
245
|
+
lru.set(cacheKey, img);
|
|
246
|
+
}
|
|
140
247
|
this.loadedImage = img;
|
|
141
248
|
this.naturalWidth = img.width;
|
|
142
249
|
this.naturalHeight = img.height;
|
|
@@ -317,4 +424,4 @@ const Image = (props) => ({
|
|
|
317
424
|
props: props,
|
|
318
425
|
});
|
|
319
426
|
|
|
320
|
-
export { Image, ImageNode };
|
|
427
|
+
export { Image, ImageLRUCache, ImageNode, disposeImageCache, getImageCache };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type CanvasRenderingContext2D } from 'skia-canvas';
|
|
2
|
-
import type { BaseProps, BoxProps,
|
|
2
|
+
import type { BaseProps, BoxProps, CanvasElement } from '../canvas/canvas.type.js';
|
|
3
3
|
import { Node } from '../constant/common.const.js';
|
|
4
4
|
/**
|
|
5
5
|
* @class BoxNode
|
|
@@ -92,7 +92,7 @@ export declare class BoxNode {
|
|
|
92
92
|
* @param {BoxProps} props Box properties and configuration.
|
|
93
93
|
* @returns {BoxNode} New BoxNode instance.
|
|
94
94
|
*/
|
|
95
|
-
export declare const Box: ({ children, ...rest }: BoxProps) =>
|
|
95
|
+
export declare const Box: ({ children, ...rest }: BoxProps) => CanvasElement;
|
|
96
96
|
/**
|
|
97
97
|
* @class ColumnNode
|
|
98
98
|
* Node class for vertical column layout
|
|
@@ -105,7 +105,7 @@ export declare class ColumnNode extends BoxNode {
|
|
|
105
105
|
* @param {BoxProps} props Column properties and configuration.
|
|
106
106
|
* @returns {ColumnNode} New ColumnNode instance.
|
|
107
107
|
*/
|
|
108
|
-
export declare const Column: ({ children, ...rest }: BoxProps) =>
|
|
108
|
+
export declare const Column: ({ children, ...rest }: BoxProps) => CanvasElement;
|
|
109
109
|
/**
|
|
110
110
|
* @class RowNode
|
|
111
111
|
* @classdesc Node class for horizontal row layout.
|
|
@@ -118,5 +118,5 @@ export declare class RowNode extends BoxNode {
|
|
|
118
118
|
* @param {BoxProps} props Row properties and configuration.
|
|
119
119
|
* @returns {RowNode} New RowNode instance.
|
|
120
120
|
*/
|
|
121
|
-
export declare const Row: ({ children, ...rest }: BoxProps) =>
|
|
121
|
+
export declare const Row: ({ children, ...rest }: BoxProps) => CanvasElement;
|
|
122
122
|
//# sourceMappingURL=layout.canvas.util.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"layout.canvas.util.d.ts","sourceRoot":"","sources":["../../../src/canvas/layout.canvas.util.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,wBAAwB,EAAE,MAAM,aAAa,CAAA;AAEnE,OAAO,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAkB,
|
|
1
|
+
{"version":3,"file":"layout.canvas.util.d.ts","sourceRoot":"","sources":["../../../src/canvas/layout.canvas.util.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,wBAAwB,EAAE,MAAM,aAAa,CAAA;AAEnE,OAAO,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAkB,aAAa,EAAE,MAAM,yBAAyB,CAAA;AAGjG,OAAa,EAAS,IAAI,EAAE,MAAM,4BAA4B,CAAA;AAE9D;;;;GAIG;AACH,qBAAa,OAAO;IAClB;;OAEG;IACH,YAAY,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAA;IAE/B;;OAEG;IACH,IAAI,EAAE,IAAI,CAAA;IAEV;;OAEG;IACH,QAAQ,EAAE,OAAO,EAAE,CAAA;IAEnB;;OAEG;IACH,KAAK,EAAE,QAAQ,GAAG,SAAS,CAAA;IAE3B;;OAEG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;IAEtB;;OAEG;IACH,GAAG,CAAC,EAAE,MAAM,CAAA;IAEZ;;;OAGG;gBACS,KAAK,GAAE,QAAQ,GAAG,SAAc;IAqB5C;;OAEG;IACI,sBAAsB;IAW7B;;;OAGG;IACH,SAAS,CAAC,sBAAsB,CAAC,WAAW,EAAE,QAAQ,GAAG,SAAS;IAkClE;;OAEG;IACH,SAAS,CAAC,aAAa,IAAI,IAAI;IAI/B;;;;OAIG;IACH,SAAS,CAAC,WAAW,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM;IAanD;;;OAGG;IACI,cAAc,IAAI,OAAO;IAiBhC;;OAEG;IACH,SAAS,CAAC,+BAA+B;IAIzC;;;OAGG;IACH,SAAS,CAAC,SAAS,CAAC,KAAK,EAAE,QAAQ;IAqInC;;;;;OAKG;IACH,MAAM,CAAC,GAAG,EAAE,wBAAwB,EAAE,OAAO,GAAE,MAAU,EAAE,OAAO,GAAE,MAAU;IA+J9E;;;;;;;;OAQG;IACH,SAAS,CAAC,cAAc,CAAC,GAAG,EAAE,wBAAwB,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CAoR5G;AAWD;;;;GAIG;AACH,eAAO,MAAM,GAAG,GAAI,uBAAuB,QAAQ,KAAG,aAIpD,CAAA;AAEF;;;GAGG;AACH,qBAAa,UAAW,SAAQ,OAAO;gBACzB,KAAK,GAAE,QAAQ,GAAG,SAAc;CAS7C;AAED;;;;GAIG;AACH,eAAO,MAAM,MAAM,GAAI,uBAAuB,QAAQ,KAAG,aAIvD,CAAA;AAEF;;;GAGG;AACH,qBAAa,OAAQ,SAAQ,OAAO;gBACtB,KAAK,GAAE,QAAQ,GAAG,SAAc;CAS7C;AAED;;;;GAIG;AACH,eAAO,MAAM,GAAG,GAAI,uBAAuB,QAAQ,KAAG,aAIpD,CAAA"}
|
|
@@ -719,7 +719,7 @@ class BoxNode {
|
|
|
719
719
|
}
|
|
720
720
|
}
|
|
721
721
|
/**
|
|
722
|
-
* Normalizes children into a flat
|
|
722
|
+
* Normalizes children into a flat CanvasElement array, filtering falsy values.
|
|
723
723
|
*/
|
|
724
724
|
function normalizeDescriptorChildren(children) {
|
|
725
725
|
if (children === undefined || children === null || children === false)
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { Canvas } from 'skia-canvas';
|
|
2
2
|
import { ColumnNode, BoxNode } from '../canvas/layout.canvas.util.js';
|
|
3
|
-
import type { BaseProps, RootProps,
|
|
3
|
+
import type { BaseProps, RootProps, CanvasElement } from '../canvas/canvas.type.js';
|
|
4
4
|
export declare const _clearRegisteredFonts: () => void;
|
|
5
5
|
export interface CanvasEngineConfig {
|
|
6
6
|
/** Run rendering in worker threads to avoid blocking the event loop (default: true) */
|
|
7
7
|
workerMode?: boolean;
|
|
8
8
|
/** Number of worker threads in the pool (default: os.cpus().length - 1) */
|
|
9
9
|
workers?: number;
|
|
10
|
+
/** Maximum number of resolved images to keep in the persistent LRU cache (default: 128) */
|
|
11
|
+
imageCacheSize?: number;
|
|
10
12
|
}
|
|
11
13
|
/**
|
|
12
14
|
* Configure the canvas rendering engine.
|
|
@@ -14,11 +16,11 @@ export interface CanvasEngineConfig {
|
|
|
14
16
|
*/
|
|
15
17
|
export declare function configure(options: CanvasEngineConfig): void;
|
|
16
18
|
/**
|
|
17
|
-
* Converts a
|
|
19
|
+
* Converts a CanvasElement tree into actual BoxNode instances.
|
|
18
20
|
* Used both for non-worker rendering (inline tree building) and inside
|
|
19
21
|
* the render worker (reconstructing the tree from serialized descriptors).
|
|
20
22
|
*/
|
|
21
|
-
export declare function buildTree(descriptor:
|
|
23
|
+
export declare function buildTree(descriptor: CanvasElement): BoxNode;
|
|
22
24
|
/**
|
|
23
25
|
* Root node that manages the canvas rendering context and coordinates overall layout and drawing.
|
|
24
26
|
* Inherits from ColumnNode to provide vertical layout capabilities.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"root.canvas.util.d.ts","sourceRoot":"","sources":["../../../src/canvas/root.canvas.util.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAA8C,MAAM,aAAa,CAAA;AAEhF,OAAO,EAAE,UAAU,EAAE,OAAO,EAAW,MAAM,gCAAgC,CAAA;AAC7E,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,
|
|
1
|
+
{"version":3,"file":"root.canvas.util.d.ts","sourceRoot":"","sources":["../../../src/canvas/root.canvas.util.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAA8C,MAAM,aAAa,CAAA;AAEhF,OAAO,EAAE,UAAU,EAAE,OAAO,EAAW,MAAM,gCAAgC,CAAA;AAC7E,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAA;AAkBlF,eAAO,MAAM,qBAAqB,YAEjC,CAAA;AAOD,MAAM,WAAW,kBAAkB;IACjC,uFAAuF;IACvF,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,2EAA2E;IAC3E,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,2FAA2F;IAC3F,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,kBAAkB,QAWpD;AA4LD;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,UAAU,EAAE,aAAa,GAAG,OAAO,CAmB5D;AAED;;;GAGG;AACH,qBAAa,QAAS,SAAQ,UAAU;IACtC,6CAA6C;IAC7C,OAAO,CAAC,MAAM,CAAoB;IAClC,8CAA8C;IAC9C,OAAO,CAAC,GAAG,CAAwC;IACnD,4CAA4C;IAC5C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAQ;IACpC,6CAA6C;IAC7C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAQ;IACrC,4DAA4D;IAC5D,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAQ;IAE9B;;;;OAIG;gBACS,KAAK,EAAE,SAAS,GAAG,SAAS;IAoDxC;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAazB;;;;OAIG;IACG,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC;CAmDhC;AAED;;;;;;GAMG;AACH,eAAO,MAAM,IAAI,GAAU,OAAO,SAAS,KAAG,OAAO,CAAC,MAAM,CAe3D,CAAA"}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { FontLibrary, Canvas } from 'skia-canvas';
|
|
2
2
|
import { ColumnNode, RowNode, BoxNode } from './layout.canvas.util.js';
|
|
3
|
-
import { ImageNode } from './image.canvas.util.js';
|
|
3
|
+
import { ImageNode, disposeImageCache, getImageCache } from './image.canvas.util.js';
|
|
4
4
|
import { TextNode } from './text.canvas.util.js';
|
|
5
5
|
import { ChartNode } from './chart.canvas.util.js';
|
|
6
6
|
import { GridItemNode, GridNode } from './grid.canvas.util.js';
|
|
7
7
|
import { Style } from '../constant/common.const.js';
|
|
8
|
+
import { WorkerPreProcessor } from './canvas.helper.js';
|
|
8
9
|
import * as path from 'node:path';
|
|
9
10
|
import * as fs from 'node:fs';
|
|
10
11
|
import { cpus } from 'node:os';
|
|
@@ -26,6 +27,11 @@ function configure(options) {
|
|
|
26
27
|
_workerMode = options.workerMode;
|
|
27
28
|
if (options.workers !== undefined)
|
|
28
29
|
_workerPoolSize = options.workers;
|
|
30
|
+
if (options.imageCacheSize !== undefined) {
|
|
31
|
+
// Dispose existing cache and create a new one with the specified size
|
|
32
|
+
disposeImageCache();
|
|
33
|
+
getImageCache(options.imageCacheSize);
|
|
34
|
+
}
|
|
29
35
|
if (_workerMode) {
|
|
30
36
|
_workerPool = new WorkerPool(_workerPoolSize);
|
|
31
37
|
}
|
|
@@ -150,16 +156,17 @@ class WorkerPool {
|
|
|
150
156
|
}
|
|
151
157
|
}
|
|
152
158
|
render(props) {
|
|
159
|
+
const sanitizedProps = WorkerPreProcessor.process(props);
|
|
153
160
|
return new Promise((resolve, reject) => {
|
|
154
161
|
const id = this.nextId++;
|
|
155
162
|
this.pending.set(id, { resolve: resolve, reject });
|
|
156
163
|
if (this.idle.length > 0) {
|
|
157
164
|
const worker = this.idle.pop();
|
|
158
|
-
const request = { type: 'render', taskId: id, props };
|
|
165
|
+
const request = { type: 'render', taskId: id, props: sanitizedProps };
|
|
159
166
|
worker.postMessage(request);
|
|
160
167
|
}
|
|
161
168
|
else {
|
|
162
|
-
this.queue.push({ id, props });
|
|
169
|
+
this.queue.push({ id, props: sanitizedProps });
|
|
163
170
|
}
|
|
164
171
|
});
|
|
165
172
|
}
|
|
@@ -180,7 +187,7 @@ class WorkerPool {
|
|
|
180
187
|
}
|
|
181
188
|
}
|
|
182
189
|
/**
|
|
183
|
-
* Converts a
|
|
190
|
+
* Converts a CanvasElement tree into actual BoxNode instances.
|
|
184
191
|
* Used both for non-worker rendering (inline tree building) and inside
|
|
185
192
|
* the render worker (reconstructing the tree from serialized descriptors).
|
|
186
193
|
*/
|
|
@@ -253,7 +260,7 @@ class RootNode extends ColumnNode {
|
|
|
253
260
|
this.targetWidth = props.width;
|
|
254
261
|
this.targetHeight = props.height;
|
|
255
262
|
this.node.setWidth(this.targetWidth);
|
|
256
|
-
// Convert any
|
|
263
|
+
// Convert any CanvasElement children to actual BoxNode instances
|
|
257
264
|
if (this.props.children) {
|
|
258
265
|
const childArray = Array.isArray(this.props.children) ? this.props.children : [this.props.children];
|
|
259
266
|
this.props.children = childArray.map(child => {
|
|
@@ -288,42 +295,49 @@ class RootNode extends ColumnNode {
|
|
|
288
295
|
* @returns Promise resolving to the rendered Canvas instance
|
|
289
296
|
*/
|
|
290
297
|
async render() {
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
// Step 3: Allow nodes to finalize their layout
|
|
309
|
-
const needRecalculate = this.finalizeLayout();
|
|
310
|
-
if (needRecalculate) {
|
|
298
|
+
try {
|
|
299
|
+
// Step 1: Load all images with a concurrency limit to avoid overwhelming remote sources.
|
|
300
|
+
// A per-render cache deduplicates identical src+color combinations within this render pass.
|
|
301
|
+
const imageNodes = this.findAllImageNodes();
|
|
302
|
+
if (imageNodes.length > 0) {
|
|
303
|
+
const imageCache = new Map();
|
|
304
|
+
const CONCURRENCY = 5;
|
|
305
|
+
const queue = [...imageNodes];
|
|
306
|
+
const workers = Array.from({ length: Math.min(CONCURRENCY, queue.length) }, async () => {
|
|
307
|
+
while (queue.length > 0) {
|
|
308
|
+
const node = queue.shift();
|
|
309
|
+
await node.load(imageCache);
|
|
310
|
+
}
|
|
311
|
+
});
|
|
312
|
+
await Promise.allSettled(workers);
|
|
313
|
+
}
|
|
314
|
+
// Step 2: Calculate initial layout
|
|
311
315
|
this.node.calculateLayout(this.targetWidth, undefined, Style.Direction.LTR);
|
|
316
|
+
// Step 3: Allow nodes to finalize their layout
|
|
317
|
+
const needRecalculate = this.finalizeLayout();
|
|
318
|
+
if (needRecalculate) {
|
|
319
|
+
this.node.calculateLayout(this.targetWidth, undefined, Style.Direction.LTR);
|
|
320
|
+
}
|
|
321
|
+
// Step 4: Create a canvas with calculated dimensions
|
|
322
|
+
const calculatedContentHeight = this.node.getComputedHeight();
|
|
323
|
+
const finalCanvasWidth = Math.ceil(this.targetWidth * this.scale);
|
|
324
|
+
const finalCanvasHeight = this.targetHeight ? Math.ceil(this.targetHeight * this.scale) : Math.max(1, Math.ceil(calculatedContentHeight * this.scale));
|
|
325
|
+
// Step 5: Set up canvas context
|
|
326
|
+
this.canvas = new Canvas(finalCanvasWidth, finalCanvasHeight);
|
|
327
|
+
this.ctx = this.canvas.getContext('2d');
|
|
328
|
+
this.ctx.scale(this.scale, this.scale);
|
|
329
|
+
// Step 6: Render content
|
|
330
|
+
super.render(this.ctx, 0, 0);
|
|
331
|
+
if (!this.canvas) {
|
|
332
|
+
throw new Error('Canvas not initialized');
|
|
333
|
+
}
|
|
334
|
+
return this.canvas;
|
|
312
335
|
}
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
// Step 5: Set up canvas context
|
|
318
|
-
this.canvas = new Canvas(finalCanvasWidth, finalCanvasHeight);
|
|
319
|
-
this.ctx = this.canvas.getContext('2d');
|
|
320
|
-
this.ctx.scale(this.scale, this.scale);
|
|
321
|
-
// Step 6: Render content
|
|
322
|
-
super.render(this.ctx, 0, 0);
|
|
323
|
-
if (!this.canvas) {
|
|
324
|
-
throw new Error('Canvas not initialized');
|
|
336
|
+
finally {
|
|
337
|
+
// Always clear the persistent image cache after render (success or error)
|
|
338
|
+
// so resolved CanvasImage references don't outlive the render pass.
|
|
339
|
+
disposeImageCache();
|
|
325
340
|
}
|
|
326
|
-
return this.canvas;
|
|
327
341
|
}
|
|
328
342
|
}
|
|
329
343
|
/**
|
|
@@ -334,14 +348,21 @@ class RootNode extends ColumnNode {
|
|
|
334
348
|
* @returns Promise resolving to the rendered Canvas (or WorkerCanvas in worker mode)
|
|
335
349
|
*/
|
|
336
350
|
const Root = async (props) => {
|
|
337
|
-
|
|
338
|
-
if (
|
|
339
|
-
|
|
351
|
+
try {
|
|
352
|
+
if (_workerMode) {
|
|
353
|
+
if (!_workerPool) {
|
|
354
|
+
_workerPool = new WorkerPool(_workerPoolSize);
|
|
355
|
+
}
|
|
356
|
+
const result = await _workerPool.render(props);
|
|
357
|
+
return new WorkerCanvas({ ...result, pool: _workerPool });
|
|
340
358
|
}
|
|
341
|
-
|
|
342
|
-
|
|
359
|
+
return await new RootNode(props).render();
|
|
360
|
+
}
|
|
361
|
+
catch (err) {
|
|
362
|
+
// Ensure cache is cleared even if Root-level orchestration fails
|
|
363
|
+
disposeImageCache();
|
|
364
|
+
throw err;
|
|
343
365
|
}
|
|
344
|
-
return new RootNode(props).render();
|
|
345
366
|
};
|
|
346
367
|
|
|
347
368
|
export { Root, RootNode, buildTree, configure };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { TextProps,
|
|
1
|
+
import type { TextProps, CanvasElement } from '../canvas/canvas.type.js';
|
|
2
2
|
import { type CanvasRenderingContext2D } from 'skia-canvas';
|
|
3
3
|
import { BoxNode } from '../canvas/layout.canvas.util.js';
|
|
4
4
|
/**
|
|
@@ -161,5 +161,5 @@ export declare class TextNode extends BoxNode {
|
|
|
161
161
|
/**
|
|
162
162
|
* Creates a new TextNode instance with rich text support
|
|
163
163
|
*/
|
|
164
|
-
export declare const Text: (text: number | string, props?: TextProps) =>
|
|
164
|
+
export declare const Text: (text: number | string, props?: TextProps) => CanvasElement;
|
|
165
165
|
//# sourceMappingURL=text.canvas.util.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"text.canvas.util.d.ts","sourceRoot":"","sources":["../../../src/canvas/text.canvas.util.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"text.canvas.util.d.ts","sourceRoot":"","sources":["../../../src/canvas/text.canvas.util.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAe,aAAa,EAAE,MAAM,yBAAyB,CAAA;AACpF,OAAO,EAAU,KAAK,wBAAwB,EAA2B,MAAM,aAAa,CAAA;AAC5F,OAAO,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAA;AAGxD;;;GAGG;AACH,qBAAa,QAAS,SAAQ,OAAO;IACnC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAoB;IAC7C,OAAO,CAAC,KAAK,CAAsB;IACnC,OAAO,CAAC,MAAM,CAAC,kBAAkB,CAAwC;IACzE,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAU;IACxC,OAAO,CAAC,WAAW,CAAe;IAClC,OAAO,CAAC,WAAW,CAAe;IAClC,OAAO,CAAC,kBAAkB,CAAe;IAEjC,KAAK,EAAE,SAAS,GAAG;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAA;gBAElC,IAAI,GAAE,MAAM,GAAG,MAAW,EAAE,KAAK,GAAE,SAAc;IAuB7D;;;;;;;;OAQG;WACW,gBAAgB,CAC5B,GAAG,EAAE,wBAAwB,EAC7B,IAAI,EAAE,MAAM,EACZ,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,KAAK,GAAE;QACL,UAAU,CAAC,EAAE,MAAM,CAAA;QACnB,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,UAAU,CAAC,EAAE,SAAS,CAAC,YAAY,CAAC,CAAA;QACpC,SAAS,CAAC,EAAE,SAAS,CAAC,WAAW,CAAC,CAAA;QAClC,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,SAAS,CAAC,EAAE,wBAAwB,CAAC,WAAW,CAAC,CAAA;QACjD,YAAY,CAAC,EAAE,wBAAwB,CAAC,cAAc,CAAC,CAAA;KACnD;cAwBW,aAAa,IAAI,IAAI;IAoDxC;;;;;;;;;;;;;;;;;OAiBG;IACH,OAAO,CAAC,sBAAsB;IA8B9B;;;;;;;;;;;;;;;;;OAiBG;IACH,OAAO,CAAC,aAAa;IA+ErB,OAAO,CAAC,aAAa;IAKrB,OAAO,CAAC,gBAAgB;IAyBxB;;;;OAIG;IACH,OAAO,CAAC,qBAAqB;IAM7B;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,aAAa;IAiCrB;;OAEG;IACH,OAAO,CAAC,yBAAyB;IAQjC;;;;;;;;;;;;;;OAcG;IACH,OAAO,CAAC,WAAW;IA+NnB;;;;;;;;;OASG;IACH,OAAO,CAAC,YAAY;IA6KpB;;;;;;;OAOG;IACH,OAAO,CAAC,aAAa;IAmErB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAQzB;;;;;;;;;;;;;;;;OAgBG;cACgB,cAAc,CAAC,GAAG,EAAE,wBAAwB,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CAkXrH;AAED;;GAEG;AACH,eAAO,MAAM,IAAI,GAAI,MAAM,MAAM,GAAG,MAAM,EAAE,QAAQ,SAAS,KAAG,aAI9D,CAAA"}
|
|
@@ -2,7 +2,6 @@ import { Canvas } from 'skia-canvas';
|
|
|
2
2
|
import { BoxNode } from './layout.canvas.util.js';
|
|
3
3
|
import { Style } from '../constant/common.const.js';
|
|
4
4
|
|
|
5
|
-
// TODO: Add comprehensive unit tests for this file.
|
|
6
5
|
/**
|
|
7
6
|
* Node for rendering text content with rich text styling support
|
|
8
7
|
* Supports color and weight variations through HTML-like tags
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export * from './constant/common.const.js';
|
|
2
2
|
export * from './canvas/canvas.type.js';
|
|
3
3
|
export { Box, Column, Row, type BoxNode } from './canvas/layout.canvas.util.js';
|
|
4
|
-
export { Image } from './canvas/image.canvas.util.js';
|
|
4
|
+
export { Image, disposeImageCache } from './canvas/image.canvas.util.js';
|
|
5
5
|
export { Text } from './canvas/text.canvas.util.js';
|
|
6
6
|
export { Root, configure } from './canvas/root.canvas.util.js';
|
|
7
7
|
export { GridItem } from './canvas/grid.canvas.util.js';
|
package/dist/esm/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,4BAA4B,CAAA;AAC1C,cAAc,yBAAyB,CAAA;AACvC,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,OAAO,EAAE,MAAM,gCAAgC,CAAA;AAC/E,OAAO,EAAE,KAAK,EAAE,MAAM,+BAA+B,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,4BAA4B,CAAA;AAC1C,cAAc,yBAAyB,CAAA;AACvC,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,OAAO,EAAE,MAAM,gCAAgC,CAAA;AAC/E,OAAO,EAAE,KAAK,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAA;AACxE,OAAO,EAAE,IAAI,EAAE,MAAM,8BAA8B,CAAA;AACnD,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAA;AAC9D,OAAO,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAA;AACvD,OAAO,EAAE,IAAI,EAAE,MAAM,8BAA8B,CAAA;AACnD,OAAO,EAAE,KAAK,EAAE,MAAM,+BAA+B,CAAA"}
|
package/dist/esm/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { Border, Style } from './constant/common.const.js';
|
|
2
2
|
export { Box, Column, Row } from './canvas/layout.canvas.util.js';
|
|
3
|
-
export { Image } from './canvas/image.canvas.util.js';
|
|
3
|
+
export { Image, disposeImageCache } from './canvas/image.canvas.util.js';
|
|
4
4
|
export { Text } from './canvas/text.canvas.util.js';
|
|
5
5
|
export { Root, configure } from './canvas/root.canvas.util.js';
|
|
6
6
|
export { Grid, GridItem } from './canvas/grid.canvas.util.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@meonode/canvas",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.1",
|
|
4
4
|
"description": "A declarative, component-based library for server-side canvas image generation. Write complex visuals with simple functions, similar to the composition style of @meonode/ui.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"canvas",
|