@nmmty/lazycanvas 0.6.5 → 1.0.0-dev.4
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/ReadMe.md +1 -1
- package/biome.json +41 -0
- package/dist/core/Interpolation.d.ts +30 -0
- package/dist/core/Interpolation.js +200 -0
- package/dist/core/Scene.d.ts +96 -0
- package/dist/core/Scene.js +172 -0
- package/dist/core/Signal.d.ts +133 -0
- package/dist/core/Signal.js +255 -0
- package/dist/core/SignalUtils.d.ts +133 -0
- package/dist/core/SignalUtils.js +333 -0
- package/dist/core/ThreadScheduler.d.ts +38 -0
- package/dist/core/ThreadScheduler.js +74 -0
- package/dist/helpers/Filters.js +1 -1
- package/dist/helpers/FontsList.js +18 -18
- package/dist/helpers/Utlis.d.ts +3 -3
- package/dist/helpers/Utlis.js +15 -18
- package/dist/helpers/index.d.ts +3 -3
- package/dist/index.d.ts +10 -0
- package/dist/index.js +10 -0
- package/dist/jsx-runtime.d.ts +17 -0
- package/dist/jsx-runtime.js +111 -0
- package/dist/structures/LazyCanvas.d.ts +3 -45
- package/dist/structures/LazyCanvas.js +11 -74
- package/dist/structures/components/BaseLayer.d.ts +34 -12
- package/dist/structures/components/BaseLayer.js +68 -35
- package/dist/structures/components/BezierLayer.d.ts +16 -37
- package/dist/structures/components/BezierLayer.js +83 -46
- package/dist/structures/components/{Group.d.ts → Div.d.ts} +22 -16
- package/dist/structures/components/{Group.js → Div.js} +38 -39
- package/dist/structures/components/ImageLayer.d.ts +1 -1
- package/dist/structures/components/ImageLayer.js +27 -26
- package/dist/structures/components/LineLayer.d.ts +11 -37
- package/dist/structures/components/LineLayer.js +42 -42
- package/dist/structures/components/MorphLayer.d.ts +3 -32
- package/dist/structures/components/MorphLayer.js +35 -47
- package/dist/structures/components/Path2DLayer.d.ts +4 -32
- package/dist/structures/components/Path2DLayer.js +28 -33
- package/dist/structures/components/PolygonLayer.d.ts +2 -31
- package/dist/structures/components/PolygonLayer.js +35 -38
- package/dist/structures/components/QuadraticLayer.d.ts +16 -33
- package/dist/structures/components/QuadraticLayer.js +80 -42
- package/dist/structures/components/TextLayer.d.ts +4 -33
- package/dist/structures/components/TextLayer.js +60 -62
- package/dist/structures/components/index.d.ts +10 -11
- package/dist/structures/components/index.js +1 -2
- package/dist/structures/helpers/Exporter.d.ts +13 -4
- package/dist/structures/helpers/Exporter.js +80 -43
- package/dist/structures/helpers/Font.js +1 -17
- package/dist/structures/helpers/Gradient.js +32 -45
- package/dist/structures/helpers/Link.js +2 -14
- package/dist/structures/helpers/Pattern.js +9 -17
- package/dist/structures/helpers/index.d.ts +7 -7
- package/dist/structures/helpers/readers/JSONReader.d.ts +4 -4
- package/dist/structures/helpers/readers/JSONReader.js +34 -42
- package/dist/structures/helpers/readers/YAMLReader.js +7 -7
- package/dist/structures/managers/FontsManager.js +9 -18
- package/dist/structures/managers/LayersManager.d.ts +18 -28
- package/dist/structures/managers/LayersManager.js +14 -36
- package/dist/structures/managers/RenderManager.d.ts +1 -15
- package/dist/structures/managers/RenderManager.js +17 -110
- package/dist/structures/managers/index.d.ts +3 -5
- package/dist/structures/managers/index.js +0 -2
- package/dist/types/enum.d.ts +1 -2
- package/dist/types/enum.js +1 -2
- package/dist/types/index.d.ts +1 -1
- package/dist/types/types.d.ts +232 -107
- package/dist/utils/APNGEncoder.d.ts +67 -0
- package/dist/utils/APNGEncoder.js +205 -0
- package/dist/utils/DrawUtils.d.ts +9 -0
- package/dist/utils/DrawUtils.js +42 -0
- package/dist/utils/LazyUtil.js +1 -2
- package/dist/utils/utils.d.ts +4 -7
- package/dist/utils/utils.js +136 -77
- package/package.json +60 -59
- package/dist/structures/components/ClearLayer.d.ts +0 -147
- package/dist/structures/components/ClearLayer.js +0 -158
- package/dist/structures/managers/AnimationManager.d.ts +0 -120
- package/dist/structures/managers/AnimationManager.js +0 -99
- package/dist/structures/managers/PluginManager.d.ts +0 -230
- package/dist/structures/managers/PluginManager.js +0 -182
package/dist/types/types.d.ts
CHANGED
|
@@ -1,107 +1,232 @@
|
|
|
1
|
-
import { Gradient, Link, Pattern } from "../structures/helpers";
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
export type
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
export type
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
export type
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
export
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
1
|
+
import { Gradient, Link, Pattern } from "../structures/helpers";
|
|
2
|
+
import {
|
|
3
|
+
MorphLayer,
|
|
4
|
+
ImageLayer,
|
|
5
|
+
TextLayer,
|
|
6
|
+
BezierLayer,
|
|
7
|
+
QuadraticLayer,
|
|
8
|
+
LineLayer,
|
|
9
|
+
Path2DLayer,
|
|
10
|
+
IMorphLayer,
|
|
11
|
+
IBezierLayer,
|
|
12
|
+
IImageLayer,
|
|
13
|
+
ITextLayer,
|
|
14
|
+
IQuadraticLayer,
|
|
15
|
+
ILineLayer,
|
|
16
|
+
IPath2DLayer,
|
|
17
|
+
IPolygonLayer,
|
|
18
|
+
PolygonLayer,
|
|
19
|
+
} from "../structures/components";
|
|
20
|
+
import {
|
|
21
|
+
FontWeight,
|
|
22
|
+
GradientType,
|
|
23
|
+
TextAlign,
|
|
24
|
+
TextBaseline,
|
|
25
|
+
TextDirection,
|
|
26
|
+
LineCap,
|
|
27
|
+
LineJoin,
|
|
28
|
+
Export,
|
|
29
|
+
Centring,
|
|
30
|
+
PatternType,
|
|
31
|
+
LinkType,
|
|
32
|
+
GlobalCompositeOperation,
|
|
33
|
+
ColorSpace,
|
|
34
|
+
} from "./enum";
|
|
35
|
+
import {
|
|
36
|
+
Signal,
|
|
37
|
+
ThreadGenerator,
|
|
38
|
+
SignalOptions,
|
|
39
|
+
TweenConfig,
|
|
40
|
+
unwrap,
|
|
41
|
+
isSignal,
|
|
42
|
+
} from "../core/Signal";
|
|
43
|
+
|
|
44
|
+
// Utility type for signal-enabled values
|
|
45
|
+
export type Signalable<T> = T | Signal<T>;
|
|
46
|
+
|
|
47
|
+
// Re-export for convenience
|
|
48
|
+
export type { ThreadGenerator, SignalOptions, TweenConfig };
|
|
49
|
+
export { unwrap, isSignal };
|
|
50
|
+
|
|
51
|
+
// Core types with Signal support
|
|
52
|
+
export type ScaleType =
|
|
53
|
+
| `link-w-${string}-${number}`
|
|
54
|
+
| `link-h-${string}-${number}`
|
|
55
|
+
| `link-x-${string}-${number}`
|
|
56
|
+
| `link-y-${string}-${number}`
|
|
57
|
+
| `${number}%`
|
|
58
|
+
| `${number}px`
|
|
59
|
+
| number
|
|
60
|
+
| "vw"
|
|
61
|
+
| "vh"
|
|
62
|
+
| "vmin"
|
|
63
|
+
| "vmax"
|
|
64
|
+
| Link
|
|
65
|
+
| Signal<number>;
|
|
66
|
+
|
|
67
|
+
export type StringColorType =
|
|
68
|
+
| `rgba(${number}, ${number}, ${number}, ${number})`
|
|
69
|
+
| `rgb(${number}, ${number}, ${number})`
|
|
70
|
+
| `hsl(${number}, ${number}%, ${number}%)`
|
|
71
|
+
| `hsla(${number}, ${number}%, ${number}%, ${number})`
|
|
72
|
+
| `#${string}`
|
|
73
|
+
| string
|
|
74
|
+
| Signal<string>;
|
|
75
|
+
|
|
76
|
+
export type ColorType = Gradient | Pattern | StringColorType;
|
|
77
|
+
|
|
78
|
+
export type JSONLayer =
|
|
79
|
+
| IMorphLayer
|
|
80
|
+
| IImageLayer
|
|
81
|
+
| ITextLayer
|
|
82
|
+
| IBezierLayer
|
|
83
|
+
| IQuadraticLayer
|
|
84
|
+
| ILineLayer
|
|
85
|
+
| IPath2DLayer
|
|
86
|
+
| IPolygonLayer;
|
|
87
|
+
|
|
88
|
+
export type AnyLayer =
|
|
89
|
+
| MorphLayer
|
|
90
|
+
| ImageLayer
|
|
91
|
+
| TextLayer
|
|
92
|
+
| BezierLayer
|
|
93
|
+
| QuadraticLayer
|
|
94
|
+
| LineLayer
|
|
95
|
+
| Path2DLayer
|
|
96
|
+
| PolygonLayer;
|
|
97
|
+
|
|
98
|
+
export type AnyWeight = FontWeight | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | 950;
|
|
99
|
+
|
|
100
|
+
export type AnyGradientType = GradientType | "linear" | "radial" | "conic";
|
|
101
|
+
|
|
102
|
+
export type AnyTextAlign = TextAlign | "left" | "right" | "center" | "start" | "end";
|
|
103
|
+
|
|
104
|
+
export type AnyTextBaseline =
|
|
105
|
+
| TextBaseline
|
|
106
|
+
| "top"
|
|
107
|
+
| "hanging"
|
|
108
|
+
| "middle"
|
|
109
|
+
| "alphabetic"
|
|
110
|
+
| "ideographic"
|
|
111
|
+
| "bottom";
|
|
112
|
+
|
|
113
|
+
export type AnyTextDirection = TextDirection | "ltr" | "rtl" | "inherit";
|
|
114
|
+
|
|
115
|
+
export type AnyLineCap = LineCap | "butt" | "round" | "square";
|
|
116
|
+
|
|
117
|
+
export type AnyLineJoin = LineJoin | "bevel" | "round" | "miter";
|
|
118
|
+
|
|
119
|
+
export type AnyExport =
|
|
120
|
+
| Export
|
|
121
|
+
| "canvas"
|
|
122
|
+
| "ctx"
|
|
123
|
+
| "buffer"
|
|
124
|
+
| "svg"
|
|
125
|
+
| "png"
|
|
126
|
+
| "apng"
|
|
127
|
+
| "jpg"
|
|
128
|
+
| "webp"
|
|
129
|
+
| "yaml"
|
|
130
|
+
| "json";
|
|
131
|
+
|
|
132
|
+
export type AnyCentring =
|
|
133
|
+
| Centring
|
|
134
|
+
| "start"
|
|
135
|
+
| "start-top"
|
|
136
|
+
| "start-bottom"
|
|
137
|
+
| "center"
|
|
138
|
+
| "center-top"
|
|
139
|
+
| "center-bottom"
|
|
140
|
+
| "end"
|
|
141
|
+
| "end-top"
|
|
142
|
+
| "end-bottom"
|
|
143
|
+
| "none";
|
|
144
|
+
|
|
145
|
+
export type AnyPatternType = PatternType | "repeat" | "repeat-x" | "repeat-y" | "no-repeat";
|
|
146
|
+
|
|
147
|
+
export type AnyLinkType = LinkType | "width" | "height" | "x" | "y";
|
|
148
|
+
|
|
149
|
+
export type AnyGlobalCompositeOperation =
|
|
150
|
+
| GlobalCompositeOperation
|
|
151
|
+
| "source-over"
|
|
152
|
+
| "source-in"
|
|
153
|
+
| "source-out"
|
|
154
|
+
| "source-atop"
|
|
155
|
+
| "destination-over"
|
|
156
|
+
| "destination-in"
|
|
157
|
+
| "destination-out"
|
|
158
|
+
| "destination-atop"
|
|
159
|
+
| "lighter"
|
|
160
|
+
| "copy"
|
|
161
|
+
| "xor"
|
|
162
|
+
| "multiply"
|
|
163
|
+
| "screen"
|
|
164
|
+
| "overlay"
|
|
165
|
+
| "darken"
|
|
166
|
+
| "lighten"
|
|
167
|
+
| "color-dodge"
|
|
168
|
+
| "color-burn"
|
|
169
|
+
| "hard-light"
|
|
170
|
+
| "soft-light"
|
|
171
|
+
| "difference"
|
|
172
|
+
| "exclusion"
|
|
173
|
+
| "hue"
|
|
174
|
+
| "saturation"
|
|
175
|
+
| "color"
|
|
176
|
+
| "luminosity";
|
|
177
|
+
|
|
178
|
+
export type AnyColorSpace = ColorSpace | "rgb565" | "rgba4444" | "rgba444";
|
|
179
|
+
|
|
180
|
+
export type AnyFilter =
|
|
181
|
+
| `sepia(${number}%)`
|
|
182
|
+
| `saturate(${number}%)`
|
|
183
|
+
| `opacity(${number}%)`
|
|
184
|
+
| `invert(${number}%)`
|
|
185
|
+
| `hue-rotate(${number}deg)`
|
|
186
|
+
| `grayscale(${number}%)`
|
|
187
|
+
| `drop-shadow(${number}px ${number}px ${number}px ${string})`
|
|
188
|
+
| `contrast(${number}%)`
|
|
189
|
+
| `brightness(${number}%)`
|
|
190
|
+
| `blur(${number}px)`;
|
|
191
|
+
|
|
192
|
+
export type Point = {
|
|
193
|
+
x: ScaleType;
|
|
194
|
+
y: ScaleType;
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
export type PointNumber = {
|
|
198
|
+
x: number;
|
|
199
|
+
y: number;
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
export type Extensions = "svg" | "png" | "jpeg" | "jpg" | "gif" | "webp" | "yaml" | "json";
|
|
203
|
+
|
|
204
|
+
export interface Transform {
|
|
205
|
+
rotate?: number;
|
|
206
|
+
scale?: {
|
|
207
|
+
x: number;
|
|
208
|
+
y: number;
|
|
209
|
+
};
|
|
210
|
+
translate?: {
|
|
211
|
+
x: number;
|
|
212
|
+
y: number;
|
|
213
|
+
};
|
|
214
|
+
matrix?: DOMMatrix2DInit;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
export type RadiusCorner = "leftTop" | "leftBottom" | "rightTop" | "rightBottom" | "all";
|
|
218
|
+
|
|
219
|
+
export type SubStringColor = {
|
|
220
|
+
color: StringColorType;
|
|
221
|
+
start: number;
|
|
222
|
+
end: number;
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
export type StrokeOptions = {
|
|
226
|
+
width: number;
|
|
227
|
+
cap?: CanvasLineCap;
|
|
228
|
+
join?: CanvasLineJoin;
|
|
229
|
+
dashOffset?: number;
|
|
230
|
+
dash?: number[];
|
|
231
|
+
miterLimit?: number;
|
|
232
|
+
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* APNG Encoder that works directly with Uint8ClampedArray (ImageData)
|
|
3
|
+
* Much faster than encoding each frame to PNG separately
|
|
4
|
+
*/
|
|
5
|
+
export declare class APNGEncoder {
|
|
6
|
+
private frames;
|
|
7
|
+
private width;
|
|
8
|
+
private height;
|
|
9
|
+
private fps;
|
|
10
|
+
constructor(width: number, height: number, fps?: number);
|
|
11
|
+
/**
|
|
12
|
+
* Add a frame from ImageData
|
|
13
|
+
*/
|
|
14
|
+
addFrame(imageData: Uint8ClampedArray): this;
|
|
15
|
+
addFrames(...imageDatas: Uint8ClampedArray[]): this;
|
|
16
|
+
/**
|
|
17
|
+
* Encode all frames to APNG buffer
|
|
18
|
+
*/
|
|
19
|
+
encode(): Buffer;
|
|
20
|
+
/**
|
|
21
|
+
* Create IHDR chunk (image header)
|
|
22
|
+
*/
|
|
23
|
+
private createIHDR;
|
|
24
|
+
/**
|
|
25
|
+
* Create acTL chunk (animation control)
|
|
26
|
+
*/
|
|
27
|
+
private createACTL;
|
|
28
|
+
/**
|
|
29
|
+
* Create frame chunks (fcTL + fdAT or IDAT)
|
|
30
|
+
* @param frameIndex - Index of the frame (0-based)
|
|
31
|
+
* @param sequenceNumber - Global sequence number for fcTL/fdAT chunks
|
|
32
|
+
*/
|
|
33
|
+
private createFrame;
|
|
34
|
+
/**
|
|
35
|
+
* Compress ImageData using PNG filter and zlib
|
|
36
|
+
*/
|
|
37
|
+
private compressImageData;
|
|
38
|
+
/**
|
|
39
|
+
* Create IEND chunk
|
|
40
|
+
*/
|
|
41
|
+
private createIEND;
|
|
42
|
+
/**
|
|
43
|
+
* Create a PNG chunk with length, type, data, and CRC
|
|
44
|
+
*/
|
|
45
|
+
private createChunk;
|
|
46
|
+
/**
|
|
47
|
+
* Calculate CRC32 checksum
|
|
48
|
+
*/
|
|
49
|
+
private crc32;
|
|
50
|
+
/**
|
|
51
|
+
* CRC32 lookup table
|
|
52
|
+
*/
|
|
53
|
+
private crcTable;
|
|
54
|
+
/**
|
|
55
|
+
* Get number of frames
|
|
56
|
+
*/
|
|
57
|
+
getFrameCount(): number;
|
|
58
|
+
/**
|
|
59
|
+
* Clear all frames
|
|
60
|
+
*/
|
|
61
|
+
clear(): void;
|
|
62
|
+
}
|
|
63
|
+
export default APNGEncoder;
|
|
64
|
+
/**
|
|
65
|
+
* Helper function to create APNG from ImageData array
|
|
66
|
+
*/
|
|
67
|
+
export declare function createAPNG(frames: Uint8ClampedArray[], width: number, height: number, fps?: number): Buffer;
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.APNGEncoder = void 0;
|
|
4
|
+
exports.createAPNG = createAPNG;
|
|
5
|
+
const node_zlib_1 = require("node:zlib");
|
|
6
|
+
/**
|
|
7
|
+
* APNG Encoder that works directly with Uint8ClampedArray (ImageData)
|
|
8
|
+
* Much faster than encoding each frame to PNG separately
|
|
9
|
+
*/
|
|
10
|
+
class APNGEncoder {
|
|
11
|
+
constructor(width, height, fps = 30) {
|
|
12
|
+
this.frames = [];
|
|
13
|
+
/**
|
|
14
|
+
* CRC32 lookup table
|
|
15
|
+
*/
|
|
16
|
+
this.crcTable = (() => {
|
|
17
|
+
const table = new Uint32Array(256);
|
|
18
|
+
for (let i = 0; i < 256; i++) {
|
|
19
|
+
let c = i;
|
|
20
|
+
for (let k = 0; k < 8; k++) {
|
|
21
|
+
c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;
|
|
22
|
+
}
|
|
23
|
+
table[i] = c;
|
|
24
|
+
}
|
|
25
|
+
return table;
|
|
26
|
+
})();
|
|
27
|
+
this.width = width;
|
|
28
|
+
this.height = height;
|
|
29
|
+
this.fps = fps;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Add a frame from ImageData
|
|
33
|
+
*/
|
|
34
|
+
addFrame(imageData) {
|
|
35
|
+
if (imageData.length !== this.width * this.height * 4) {
|
|
36
|
+
throw new Error(`Invalid ImageData size. Expected ${this.width * this.height * 4}, got ${imageData.length}`);
|
|
37
|
+
}
|
|
38
|
+
this.frames.push(imageData);
|
|
39
|
+
return this;
|
|
40
|
+
}
|
|
41
|
+
addFrames(...imageDatas) {
|
|
42
|
+
for (const imageData of imageDatas) {
|
|
43
|
+
this.addFrame(imageData);
|
|
44
|
+
}
|
|
45
|
+
return this;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Encode all frames to APNG buffer
|
|
49
|
+
*/
|
|
50
|
+
encode() {
|
|
51
|
+
if (this.frames.length === 0) {
|
|
52
|
+
throw new Error("No frames to encode");
|
|
53
|
+
}
|
|
54
|
+
const chunks = [];
|
|
55
|
+
// PNG signature
|
|
56
|
+
chunks.push(Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]));
|
|
57
|
+
// IHDR chunk
|
|
58
|
+
chunks.push(this.createIHDR());
|
|
59
|
+
// acTL chunk (animation control)
|
|
60
|
+
chunks.push(this.createACTL());
|
|
61
|
+
// Add all frames with proper sequence numbering
|
|
62
|
+
let sequenceNumber = 0;
|
|
63
|
+
for (let i = 0; i < this.frames.length; i++) {
|
|
64
|
+
chunks.push(...this.createFrame(i, sequenceNumber));
|
|
65
|
+
// First frame: fcTL (0) + IDAT = 1 chunk with sequence
|
|
66
|
+
// Other frames: fcTL (n) + fdAT (n+1) = 2 chunks with sequences
|
|
67
|
+
sequenceNumber += i === 0 ? 1 : 2;
|
|
68
|
+
}
|
|
69
|
+
// IEND chunk
|
|
70
|
+
chunks.push(this.createIEND());
|
|
71
|
+
return Buffer.concat(chunks);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Create IHDR chunk (image header)
|
|
75
|
+
*/
|
|
76
|
+
createIHDR() {
|
|
77
|
+
const data = Buffer.alloc(13);
|
|
78
|
+
data.writeUInt32BE(this.width, 0);
|
|
79
|
+
data.writeUInt32BE(this.height, 4);
|
|
80
|
+
data[8] = 8; // bit depth
|
|
81
|
+
data[9] = 6; // color type: RGBA
|
|
82
|
+
data[10] = 0; // compression method
|
|
83
|
+
data[11] = 0; // filter method
|
|
84
|
+
data[12] = 0; // interlace method
|
|
85
|
+
return this.createChunk("IHDR", data);
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Create acTL chunk (animation control)
|
|
89
|
+
*/
|
|
90
|
+
createACTL() {
|
|
91
|
+
const data = Buffer.alloc(8);
|
|
92
|
+
data.writeUInt32BE(this.frames.length, 0); // num_frames
|
|
93
|
+
data.writeUInt32BE(0, 4); // num_plays (0 = infinite)
|
|
94
|
+
return this.createChunk("acTL", data);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Create frame chunks (fcTL + fdAT or IDAT)
|
|
98
|
+
* @param frameIndex - Index of the frame (0-based)
|
|
99
|
+
* @param sequenceNumber - Global sequence number for fcTL/fdAT chunks
|
|
100
|
+
*/
|
|
101
|
+
createFrame(frameIndex, sequenceNumber) {
|
|
102
|
+
const chunks = [];
|
|
103
|
+
// fcTL chunk (frame control) - always comes first
|
|
104
|
+
const fctl = Buffer.alloc(26);
|
|
105
|
+
fctl.writeUInt32BE(sequenceNumber, 0); // sequence_number
|
|
106
|
+
fctl.writeUInt32BE(this.width, 4); // width
|
|
107
|
+
fctl.writeUInt32BE(this.height, 8); // height
|
|
108
|
+
fctl.writeUInt32BE(0, 12); // x_offset
|
|
109
|
+
fctl.writeUInt32BE(0, 16); // y_offset
|
|
110
|
+
// Frame delay (delay_num / delay_den seconds)
|
|
111
|
+
const delayNum = 1;
|
|
112
|
+
const delayDen = this.fps;
|
|
113
|
+
fctl.writeUInt16BE(delayNum, 20);
|
|
114
|
+
fctl.writeUInt16BE(delayDen, 22);
|
|
115
|
+
fctl[24] = 0; // dispose_op: APNG_DISPOSE_OP_NONE
|
|
116
|
+
fctl[25] = 0; // blend_op: APNG_BLEND_OP_SOURCE
|
|
117
|
+
chunks.push(this.createChunk("fcTL", fctl));
|
|
118
|
+
// Compress frame data
|
|
119
|
+
const imageData = this.frames[frameIndex];
|
|
120
|
+
const compressed = this.compressImageData(imageData);
|
|
121
|
+
// First frame uses IDAT (no sequence number), subsequent frames use fdAT
|
|
122
|
+
if (frameIndex === 0) {
|
|
123
|
+
chunks.push(this.createChunk("IDAT", compressed));
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
// fdAT includes sequence number (sequenceNumber + 1 for the data chunk)
|
|
127
|
+
const fdatData = Buffer.alloc(4 + compressed.length);
|
|
128
|
+
fdatData.writeUInt32BE(sequenceNumber + 1, 0);
|
|
129
|
+
compressed.copy(fdatData, 4);
|
|
130
|
+
chunks.push(this.createChunk("fdAT", fdatData));
|
|
131
|
+
}
|
|
132
|
+
return chunks;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Compress ImageData using PNG filter and zlib
|
|
136
|
+
*/
|
|
137
|
+
compressImageData(imageData) {
|
|
138
|
+
const bytesPerPixel = 4; // RGBA
|
|
139
|
+
const stride = this.width * bytesPerPixel;
|
|
140
|
+
const filtered = Buffer.alloc(imageData.length + this.height);
|
|
141
|
+
// Apply PNG filter type 0 (None) to each scanline
|
|
142
|
+
for (let y = 0; y < this.height; y++) {
|
|
143
|
+
const offset = y * stride;
|
|
144
|
+
const filteredOffset = y * (stride + 1);
|
|
145
|
+
filtered[filteredOffset] = 0; // Filter type: None
|
|
146
|
+
imageData.subarray(offset, offset + stride).forEach((byte, i) => {
|
|
147
|
+
filtered[filteredOffset + 1 + i] = byte;
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
// Compress with zlib
|
|
151
|
+
return (0, node_zlib_1.deflateSync)(filtered, { level: 6 });
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Create IEND chunk
|
|
155
|
+
*/
|
|
156
|
+
createIEND() {
|
|
157
|
+
return this.createChunk("IEND", Buffer.alloc(0));
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Create a PNG chunk with length, type, data, and CRC
|
|
161
|
+
*/
|
|
162
|
+
createChunk(type, data) {
|
|
163
|
+
const length = Buffer.alloc(4);
|
|
164
|
+
length.writeUInt32BE(data.length, 0);
|
|
165
|
+
const typeBuffer = Buffer.from(type, "ascii");
|
|
166
|
+
const crc = this.crc32(Buffer.concat([typeBuffer, data]));
|
|
167
|
+
const crcBuffer = Buffer.alloc(4);
|
|
168
|
+
crcBuffer.writeUInt32BE(crc, 0);
|
|
169
|
+
return Buffer.concat([length, typeBuffer, data, crcBuffer]);
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Calculate CRC32 checksum
|
|
173
|
+
*/
|
|
174
|
+
crc32(data) {
|
|
175
|
+
let crc = 0xffffffff;
|
|
176
|
+
for (let i = 0; i < data.length; i++) {
|
|
177
|
+
crc = this.crcTable[(crc ^ data[i]) & 0xff] ^ (crc >>> 8);
|
|
178
|
+
}
|
|
179
|
+
return (crc ^ 0xffffffff) >>> 0;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Get number of frames
|
|
183
|
+
*/
|
|
184
|
+
getFrameCount() {
|
|
185
|
+
return this.frames.length;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Clear all frames
|
|
189
|
+
*/
|
|
190
|
+
clear() {
|
|
191
|
+
this.frames = [];
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
exports.APNGEncoder = APNGEncoder;
|
|
195
|
+
exports.default = APNGEncoder;
|
|
196
|
+
/**
|
|
197
|
+
* Helper function to create APNG from ImageData array
|
|
198
|
+
*/
|
|
199
|
+
function createAPNG(frames, width, height, fps = 30) {
|
|
200
|
+
const encoder = new APNGEncoder(width, height, fps);
|
|
201
|
+
for (const frame of frames) {
|
|
202
|
+
encoder.addFrame(frame);
|
|
203
|
+
}
|
|
204
|
+
return encoder.encode();
|
|
205
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { SKRSContext2D } from "@napi-rs/canvas";
|
|
2
|
+
import { Signal } from "../core/Signal";
|
|
3
|
+
import { StrokeOptions } from "../types";
|
|
4
|
+
export declare class DrawUtils {
|
|
5
|
+
static drawShadow(ctx: SKRSContext2D, shadow: any): void;
|
|
6
|
+
static opacity(ctx: SKRSContext2D, opacity?: number | Signal<number>): void;
|
|
7
|
+
static filters(ctx: SKRSContext2D, filters: string | null | undefined): void;
|
|
8
|
+
static fillStyle(ctx: SKRSContext2D, color: string | CanvasGradient | CanvasPattern, fillStyle?: StrokeOptions): void;
|
|
9
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DrawUtils = void 0;
|
|
4
|
+
const Signal_1 = require("../core/Signal");
|
|
5
|
+
class DrawUtils {
|
|
6
|
+
static drawShadow(ctx, shadow) {
|
|
7
|
+
if (shadow) {
|
|
8
|
+
ctx.shadowColor = shadow.color;
|
|
9
|
+
ctx.shadowBlur = shadow.blur || 0;
|
|
10
|
+
ctx.shadowOffsetX = shadow.offsetX || 0;
|
|
11
|
+
ctx.shadowOffsetY = shadow.offsetY || 0;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
static opacity(ctx, opacity = 1) {
|
|
15
|
+
const opacityValue = (0, Signal_1.unwrap)(opacity);
|
|
16
|
+
if (opacityValue < 1) {
|
|
17
|
+
ctx.globalAlpha = opacityValue;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
static filters(ctx, filters) {
|
|
21
|
+
if (filters) {
|
|
22
|
+
ctx.filter = filters;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
static fillStyle(ctx, color, fillStyle) {
|
|
26
|
+
if (fillStyle) {
|
|
27
|
+
ctx.lineWidth = fillStyle.width;
|
|
28
|
+
ctx.lineCap = fillStyle.cap || "butt";
|
|
29
|
+
ctx.lineJoin = fillStyle.join || "miter";
|
|
30
|
+
ctx.miterLimit = fillStyle.miterLimit || 10;
|
|
31
|
+
if (fillStyle.dash) {
|
|
32
|
+
ctx.setLineDash(fillStyle.dash);
|
|
33
|
+
ctx.lineDashOffset = fillStyle.dashOffset || 0;
|
|
34
|
+
}
|
|
35
|
+
ctx.strokeStyle = color;
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
ctx.fillStyle = color;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
exports.DrawUtils = DrawUtils;
|
package/dist/utils/LazyUtil.js
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.defaultArg = exports.LazyLog = exports.LazyError = void 0;
|
|
4
4
|
class LazyError extends Error {
|
|
5
|
-
message;
|
|
6
5
|
constructor(message) {
|
|
7
6
|
super(message);
|
|
8
7
|
this.message = "[LazyCanvas] [ERROR] " + message;
|
|
@@ -31,5 +30,5 @@ exports.defaultArg = {
|
|
|
31
30
|
},
|
|
32
31
|
vl(vertical, layer) {
|
|
33
32
|
return { vertical: vertical || false, layer: layer || false };
|
|
34
|
-
}
|
|
33
|
+
},
|
|
35
34
|
};
|