@tsparticles/shape-image 3.0.0-alpha.1 → 3.0.0-beta.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/README.md +16 -12
- package/browser/GifUtils/ByteStream.js +44 -0
- package/browser/GifUtils/Constants.js +2 -0
- package/browser/GifUtils/Enums/DisposalMethod.js +1 -0
- package/browser/GifUtils/Types/ApplicationExtension.js +1 -0
- package/browser/GifUtils/Types/Frame.js +1 -0
- package/browser/GifUtils/Types/GIF.js +1 -0
- package/browser/GifUtils/Types/GIFDataHeaders.js +1 -0
- package/browser/GifUtils/Types/GIFProgressCallbackFunction.js +1 -0
- package/browser/GifUtils/Types/PlainTextData.js +1 -0
- package/browser/GifUtils/Utils.js +324 -0
- package/browser/ImageDrawer.js +122 -58
- package/browser/ImagePreloader.js +33 -0
- package/browser/Options/Classes/Preload.js +29 -0
- package/browser/Options/Interfaces/IPreload.js +1 -0
- package/browser/Utils.js +35 -9
- package/browser/index.js +43 -3
- package/browser/package.json +1 -0
- package/browser/types.js +1 -0
- package/cjs/GifUtils/ByteStream.js +48 -0
- package/cjs/GifUtils/Constants.js +5 -0
- package/cjs/GifUtils/Enums/DisposalMethod.js +2 -0
- package/cjs/GifUtils/Types/ApplicationExtension.js +2 -0
- package/cjs/GifUtils/Types/Frame.js +2 -0
- package/cjs/GifUtils/Types/GIF.js +2 -0
- package/cjs/GifUtils/Types/GIFDataHeaders.js +2 -0
- package/cjs/GifUtils/Types/GIFProgressCallbackFunction.js +2 -0
- package/cjs/GifUtils/Types/PlainTextData.js +2 -0
- package/cjs/GifUtils/Utils.js +329 -0
- package/cjs/ImageDrawer.js +125 -72
- package/cjs/ImagePreloader.js +37 -0
- package/cjs/Options/Classes/Preload.js +33 -0
- package/cjs/Options/Interfaces/IPreload.js +2 -0
- package/cjs/Utils.js +66 -52
- package/cjs/index.js +43 -14
- package/cjs/package.json +1 -0
- package/cjs/types.js +2 -0
- package/esm/GifUtils/ByteStream.js +44 -0
- package/esm/GifUtils/Constants.js +2 -0
- package/esm/GifUtils/Enums/DisposalMethod.js +1 -0
- package/esm/GifUtils/Types/ApplicationExtension.js +1 -0
- package/esm/GifUtils/Types/Frame.js +1 -0
- package/esm/GifUtils/Types/GIF.js +1 -0
- package/esm/GifUtils/Types/GIFDataHeaders.js +1 -0
- package/esm/GifUtils/Types/GIFProgressCallbackFunction.js +1 -0
- package/esm/GifUtils/Types/PlainTextData.js +1 -0
- package/esm/GifUtils/Utils.js +324 -0
- package/esm/ImageDrawer.js +122 -58
- package/esm/ImagePreloader.js +33 -0
- package/esm/Options/Classes/Preload.js +29 -0
- package/esm/Options/Interfaces/IPreload.js +1 -0
- package/esm/Utils.js +35 -9
- package/esm/index.js +43 -3
- package/esm/package.json +1 -0
- package/esm/types.js +1 -0
- package/package.json +19 -6
- package/report.html +4 -4
- package/tsparticles.shape.image.js +676 -73
- package/tsparticles.shape.image.min.js +1 -1
- package/tsparticles.shape.image.min.js.LICENSE.txt +1 -8
- package/types/GifUtils/ByteStream.d.ts +11 -0
- package/types/GifUtils/Constants.d.ts +2 -0
- package/types/GifUtils/Enums/DisposalMethod.d.ts +10 -0
- package/types/GifUtils/Types/ApplicationExtension.d.ts +5 -0
- package/types/GifUtils/Types/Frame.d.ts +19 -0
- package/types/GifUtils/Types/GIF.d.ts +16 -0
- package/types/GifUtils/Types/GIFDataHeaders.d.ts +9 -0
- package/types/GifUtils/Types/GIFProgressCallbackFunction.d.ts +2 -0
- package/types/GifUtils/Types/PlainTextData.d.ts +11 -0
- package/types/GifUtils/Utils.d.ts +4 -0
- package/types/IImageShape.d.ts +2 -1
- package/types/ImageDrawer.d.ts +9 -9
- package/types/ImagePreloader.d.ts +10 -0
- package/types/Options/Classes/Preload.d.ts +12 -0
- package/types/Options/Interfaces/IPreload.d.ts +8 -0
- package/types/Utils.d.ts +16 -6
- package/types/index.d.ts +2 -2
- package/types/types.d.ts +17 -0
- package/umd/GifUtils/ByteStream.js +58 -0
- package/umd/GifUtils/Constants.js +15 -0
- package/umd/GifUtils/Enums/DisposalMethod.js +12 -0
- package/umd/GifUtils/Types/ApplicationExtension.js +12 -0
- package/umd/GifUtils/Types/Frame.js +12 -0
- package/umd/GifUtils/Types/GIF.js +12 -0
- package/umd/GifUtils/Types/GIFDataHeaders.js +12 -0
- package/umd/GifUtils/Types/GIFProgressCallbackFunction.js +12 -0
- package/umd/GifUtils/Types/PlainTextData.js +12 -0
- package/umd/GifUtils/Utils.js +339 -0
- package/umd/ImageDrawer.js +124 -60
- package/umd/ImagePreloader.js +47 -0
- package/umd/Options/Classes/Preload.js +43 -0
- package/umd/Options/Interfaces/IPreload.js +12 -0
- package/umd/Utils.js +37 -10
- package/umd/index.js +44 -4
- package/umd/types.js +12 -0
package/browser/ImageDrawer.js
CHANGED
|
@@ -1,65 +1,148 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { errorPrefix } from "@tsparticles/engine";
|
|
2
|
+
import { replaceImageColor } from "./Utils.js";
|
|
2
3
|
export class ImageDrawer {
|
|
3
|
-
constructor() {
|
|
4
|
-
this.
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
constructor(engine) {
|
|
5
|
+
this.loadImageShape = async (imageShape) => {
|
|
6
|
+
if (!this._engine.loadImage) {
|
|
7
|
+
throw new Error(`${errorPrefix} image shape not initialized`);
|
|
8
|
+
}
|
|
9
|
+
await this._engine.loadImage({
|
|
10
|
+
gif: imageShape.gif,
|
|
11
|
+
name: imageShape.name,
|
|
12
|
+
replaceColor: imageShape.replaceColor ?? false,
|
|
13
|
+
src: imageShape.src,
|
|
14
|
+
});
|
|
15
|
+
};
|
|
16
|
+
this._engine = engine;
|
|
9
17
|
}
|
|
10
|
-
|
|
11
|
-
this.
|
|
18
|
+
addImage(image) {
|
|
19
|
+
if (!this._engine.images) {
|
|
20
|
+
this._engine.images = [];
|
|
21
|
+
}
|
|
22
|
+
this._engine.images.push(image);
|
|
12
23
|
}
|
|
13
|
-
draw(context, particle, radius, opacity) {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
if (!element) {
|
|
24
|
+
draw(context, particle, radius, opacity, delta) {
|
|
25
|
+
const image = particle.image, element = image?.element;
|
|
26
|
+
if (!image) {
|
|
17
27
|
return;
|
|
18
28
|
}
|
|
19
|
-
const ratio = (_a = image === null || image === void 0 ? void 0 : image.ratio) !== null && _a !== void 0 ? _a : 1, pos = {
|
|
20
|
-
x: -radius,
|
|
21
|
-
y: -radius,
|
|
22
|
-
};
|
|
23
29
|
context.globalAlpha = opacity;
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
30
|
+
if (image.gif && image.gifData) {
|
|
31
|
+
const offscreenCanvas = new OffscreenCanvas(image.gifData.width, image.gifData.height), offscreenContext = offscreenCanvas.getContext("2d");
|
|
32
|
+
if (!offscreenContext) {
|
|
33
|
+
throw new Error("could not create offscreen canvas context");
|
|
34
|
+
}
|
|
35
|
+
offscreenContext.imageSmoothingQuality = "low";
|
|
36
|
+
offscreenContext.imageSmoothingEnabled = false;
|
|
37
|
+
offscreenContext.clearRect(0, 0, offscreenCanvas.width, offscreenCanvas.height);
|
|
38
|
+
if (particle.gifLoopCount === undefined) {
|
|
39
|
+
particle.gifLoopCount = image.gifLoopCount ?? 0;
|
|
40
|
+
}
|
|
41
|
+
let frameIndex = particle.gifFrame ?? 0;
|
|
42
|
+
const pos = { x: -image.gifData.width * 0.5, y: -image.gifData.height * 0.5 }, frame = image.gifData.frames[frameIndex];
|
|
43
|
+
if (particle.gifTime === undefined) {
|
|
44
|
+
particle.gifTime = 0;
|
|
45
|
+
}
|
|
46
|
+
if (!frame.bitmap) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
context.scale(radius / image.gifData.width, radius / image.gifData.height);
|
|
50
|
+
switch (frame.disposalMethod) {
|
|
51
|
+
case 4:
|
|
52
|
+
case 5:
|
|
53
|
+
case 6:
|
|
54
|
+
case 7:
|
|
55
|
+
case 0:
|
|
56
|
+
offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
|
|
57
|
+
context.drawImage(offscreenCanvas, pos.x, pos.y);
|
|
58
|
+
offscreenContext.clearRect(0, 0, offscreenCanvas.width, offscreenCanvas.height);
|
|
59
|
+
break;
|
|
60
|
+
case 1:
|
|
61
|
+
offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
|
|
62
|
+
context.drawImage(offscreenCanvas, pos.x, pos.y);
|
|
63
|
+
break;
|
|
64
|
+
case 2:
|
|
65
|
+
offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
|
|
66
|
+
context.drawImage(offscreenCanvas, pos.x, pos.y);
|
|
67
|
+
offscreenContext.clearRect(0, 0, offscreenCanvas.width, offscreenCanvas.height);
|
|
68
|
+
if (image.gifData.globalColorTable.length === 0) {
|
|
69
|
+
offscreenContext.putImageData(image.gifData.frames[0].image, pos.x + frame.left, pos.y + frame.top);
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
offscreenContext.putImageData(image.gifData.backgroundImage, pos.x, pos.y);
|
|
73
|
+
}
|
|
74
|
+
break;
|
|
75
|
+
case 3:
|
|
76
|
+
{
|
|
77
|
+
const previousImageData = offscreenContext.getImageData(0, 0, offscreenCanvas.width, offscreenCanvas.height);
|
|
78
|
+
offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
|
|
79
|
+
context.drawImage(offscreenCanvas, pos.x, pos.y);
|
|
80
|
+
offscreenContext.clearRect(0, 0, offscreenCanvas.width, offscreenCanvas.height);
|
|
81
|
+
offscreenContext.putImageData(previousImageData, 0, 0);
|
|
82
|
+
}
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
particle.gifTime += delta.value;
|
|
86
|
+
if (particle.gifTime > frame.delayTime) {
|
|
87
|
+
particle.gifTime -= frame.delayTime;
|
|
88
|
+
if (++frameIndex >= image.gifData.frames.length) {
|
|
89
|
+
if (--particle.gifLoopCount <= 0) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
frameIndex = 0;
|
|
93
|
+
offscreenContext.clearRect(0, 0, offscreenCanvas.width, offscreenCanvas.height);
|
|
94
|
+
}
|
|
95
|
+
particle.gifFrame = frameIndex;
|
|
96
|
+
}
|
|
97
|
+
context.scale(image.gifData.width / radius, image.gifData.height / radius);
|
|
35
98
|
}
|
|
36
|
-
else {
|
|
37
|
-
|
|
99
|
+
else if (element) {
|
|
100
|
+
const ratio = image.ratio, pos = {
|
|
101
|
+
x: -radius,
|
|
102
|
+
y: -radius,
|
|
103
|
+
};
|
|
104
|
+
context.drawImage(element, pos.x, pos.y, radius * 2, (radius * 2) / ratio);
|
|
38
105
|
}
|
|
106
|
+
context.globalAlpha = 1;
|
|
39
107
|
}
|
|
40
108
|
getSidesCount() {
|
|
41
109
|
return 12;
|
|
42
110
|
}
|
|
111
|
+
async init(container) {
|
|
112
|
+
const options = container.actualOptions;
|
|
113
|
+
if (!options.preload || !this._engine.loadImage) {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
for (const imageData of options.preload) {
|
|
117
|
+
await this._engine.loadImage(imageData);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
43
120
|
loadShape(particle) {
|
|
44
121
|
if (particle.shape !== "image" && particle.shape !== "images") {
|
|
45
122
|
return;
|
|
46
123
|
}
|
|
47
|
-
|
|
124
|
+
if (!this._engine.images) {
|
|
125
|
+
this._engine.images = [];
|
|
126
|
+
}
|
|
127
|
+
const imageData = particle.shapeData, image = this._engine.images.find((t) => t.name === imageData.name || t.source === imageData.src);
|
|
48
128
|
if (!image) {
|
|
49
|
-
this.loadImageShape(
|
|
129
|
+
this.loadImageShape(imageData).then(() => {
|
|
50
130
|
this.loadShape(particle);
|
|
51
131
|
});
|
|
52
132
|
}
|
|
53
133
|
}
|
|
54
134
|
particleInit(container, particle) {
|
|
55
|
-
var _a;
|
|
56
135
|
if (particle.shape !== "image" && particle.shape !== "images") {
|
|
57
136
|
return;
|
|
58
137
|
}
|
|
59
|
-
|
|
138
|
+
if (!this._engine.images) {
|
|
139
|
+
this._engine.images = [];
|
|
140
|
+
}
|
|
141
|
+
const images = this._engine.images, imageData = particle.shapeData, color = particle.getFillColor(), image = images.find((t) => t.name === imageData.name || t.source === imageData.src);
|
|
60
142
|
if (!image) {
|
|
61
143
|
return;
|
|
62
144
|
}
|
|
145
|
+
const replaceColor = imageData.replaceColor ?? image.replaceColor;
|
|
63
146
|
if (image.loading) {
|
|
64
147
|
setTimeout(() => {
|
|
65
148
|
this.particleInit(container, particle);
|
|
@@ -67,7 +150,6 @@ export class ImageDrawer {
|
|
|
67
150
|
return;
|
|
68
151
|
}
|
|
69
152
|
(async () => {
|
|
70
|
-
var _a, _b;
|
|
71
153
|
let imageRes;
|
|
72
154
|
if (image.svgData && color) {
|
|
73
155
|
imageRes = await replaceImageColor(image, imageData, color, particle);
|
|
@@ -77,8 +159,11 @@ export class ImageDrawer {
|
|
|
77
159
|
color,
|
|
78
160
|
data: image,
|
|
79
161
|
element: image.element,
|
|
162
|
+
gif: image.gif,
|
|
163
|
+
gifData: image.gifData,
|
|
164
|
+
gifLoopCount: image.gifLoopCount,
|
|
80
165
|
loaded: true,
|
|
81
|
-
ratio: imageData.width / imageData.height,
|
|
166
|
+
ratio: imageData.width && imageData.height ? imageData.width / imageData.height : image.ratio ?? 1,
|
|
82
167
|
replaceColor: replaceColor,
|
|
83
168
|
source: imageData.src,
|
|
84
169
|
};
|
|
@@ -86,7 +171,7 @@ export class ImageDrawer {
|
|
|
86
171
|
if (!imageRes.ratio) {
|
|
87
172
|
imageRes.ratio = 1;
|
|
88
173
|
}
|
|
89
|
-
const fill =
|
|
174
|
+
const fill = imageData.fill ?? particle.fill, close = imageData.close ?? particle.close, imageShape = {
|
|
90
175
|
image: imageRes,
|
|
91
176
|
fill,
|
|
92
177
|
close,
|
|
@@ -96,25 +181,4 @@ export class ImageDrawer {
|
|
|
96
181
|
particle.close = imageShape.close;
|
|
97
182
|
})();
|
|
98
183
|
}
|
|
99
|
-
async loadImageShape(container, imageShape) {
|
|
100
|
-
var _a;
|
|
101
|
-
const source = imageShape.src;
|
|
102
|
-
if (!source) {
|
|
103
|
-
throw new Error("Error tsParticles - No image.src");
|
|
104
|
-
}
|
|
105
|
-
try {
|
|
106
|
-
const image = {
|
|
107
|
-
source: source,
|
|
108
|
-
type: source.substring(source.length - 3),
|
|
109
|
-
error: false,
|
|
110
|
-
loading: true,
|
|
111
|
-
};
|
|
112
|
-
this.addImage(container, image);
|
|
113
|
-
const imageFunc = ((_a = imageShape.replaceColor) !== null && _a !== void 0 ? _a : imageShape.replace_color) ? downloadSvgImage : loadImage;
|
|
114
|
-
await imageFunc(image);
|
|
115
|
-
}
|
|
116
|
-
catch (_b) {
|
|
117
|
-
throw new Error(`tsParticles error - ${imageShape.src} not found`);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
184
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Preload } from "./Options/Classes/Preload.js";
|
|
2
|
+
export class ImagePreloaderPlugin {
|
|
3
|
+
constructor(engine) {
|
|
4
|
+
this.id = "imagePreloader";
|
|
5
|
+
this._engine = engine;
|
|
6
|
+
}
|
|
7
|
+
getPlugin() {
|
|
8
|
+
return {};
|
|
9
|
+
}
|
|
10
|
+
loadOptions(options, source) {
|
|
11
|
+
if (!source || !source.preload) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
if (!options.preload) {
|
|
15
|
+
options.preload = [];
|
|
16
|
+
}
|
|
17
|
+
const preloadOptions = options.preload;
|
|
18
|
+
for (const item of source.preload) {
|
|
19
|
+
const existing = preloadOptions.find((t) => t.name === item.name || t.src === item.src);
|
|
20
|
+
if (existing) {
|
|
21
|
+
existing.load(item);
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
const preload = new Preload();
|
|
25
|
+
preload.load(item);
|
|
26
|
+
preloadOptions.push(preload);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
needsPlugin() {
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export class Preload {
|
|
2
|
+
constructor() {
|
|
3
|
+
this.src = "";
|
|
4
|
+
this.gif = false;
|
|
5
|
+
}
|
|
6
|
+
load(data) {
|
|
7
|
+
if (!data) {
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
if (data.gif !== undefined) {
|
|
11
|
+
this.gif = data.gif;
|
|
12
|
+
}
|
|
13
|
+
if (data.height !== undefined) {
|
|
14
|
+
this.height = data.height;
|
|
15
|
+
}
|
|
16
|
+
if (data.name !== undefined) {
|
|
17
|
+
this.name = data.name;
|
|
18
|
+
}
|
|
19
|
+
if (data.replaceColor !== undefined) {
|
|
20
|
+
this.replaceColor = data.replaceColor;
|
|
21
|
+
}
|
|
22
|
+
if (data.src !== undefined) {
|
|
23
|
+
this.src = data.src;
|
|
24
|
+
}
|
|
25
|
+
if (data.width !== undefined) {
|
|
26
|
+
this.width = data.width;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/browser/Utils.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { getStyleFromHsl } from "@tsparticles/engine";
|
|
1
|
+
import { errorPrefix, getLogger, getStyleFromHsl } from "@tsparticles/engine";
|
|
2
|
+
import { decodeGIF, getGIFLoopAmount } from "./GifUtils/Utils.js";
|
|
2
3
|
const currentColorRegex = /(#(?:[0-9a-f]{2}){2,4}|(#[0-9a-f]{3})|(rgb|hsl)a?\((-?\d+%?[,\s]+){2,3}\s*[\d.]+%?\))|currentcolor/gi;
|
|
3
4
|
function replaceColorSvg(imageShape, color, opacity) {
|
|
4
5
|
const { svgData } = imageShape;
|
|
@@ -25,12 +26,30 @@ export async function loadImage(image) {
|
|
|
25
26
|
image.element = undefined;
|
|
26
27
|
image.error = true;
|
|
27
28
|
image.loading = false;
|
|
28
|
-
|
|
29
|
+
getLogger().error(`${errorPrefix} loading image: ${image.source}`);
|
|
29
30
|
resolve();
|
|
30
31
|
});
|
|
31
32
|
img.src = image.source;
|
|
32
33
|
});
|
|
33
34
|
}
|
|
35
|
+
export async function loadGifImage(image) {
|
|
36
|
+
if (image.type !== "gif") {
|
|
37
|
+
await loadImage(image);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
image.loading = true;
|
|
41
|
+
try {
|
|
42
|
+
image.gifData = await decodeGIF(image.source);
|
|
43
|
+
image.gifLoopCount = getGIFLoopAmount(image.gifData) ?? 0;
|
|
44
|
+
if (image.gifLoopCount === 0) {
|
|
45
|
+
image.gifLoopCount = Infinity;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
image.error = true;
|
|
50
|
+
}
|
|
51
|
+
image.loading = false;
|
|
52
|
+
}
|
|
34
53
|
export async function downloadSvgImage(image) {
|
|
35
54
|
if (image.type !== "svg") {
|
|
36
55
|
await loadImage(image);
|
|
@@ -39,22 +58,25 @@ export async function downloadSvgImage(image) {
|
|
|
39
58
|
image.loading = true;
|
|
40
59
|
const response = await fetch(image.source);
|
|
41
60
|
if (!response.ok) {
|
|
42
|
-
|
|
61
|
+
getLogger().error(`${errorPrefix} Image not found`);
|
|
43
62
|
image.error = true;
|
|
44
63
|
}
|
|
45
|
-
|
|
64
|
+
else {
|
|
46
65
|
image.svgData = await response.text();
|
|
47
66
|
}
|
|
48
67
|
image.loading = false;
|
|
49
68
|
}
|
|
50
69
|
export function replaceImageColor(image, imageData, color, particle) {
|
|
51
|
-
|
|
52
|
-
const svgColoredData = replaceColorSvg(image, color, (_b = (_a = particle.opacity) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : 1), imageRes = {
|
|
70
|
+
const svgColoredData = replaceColorSvg(image, color, particle.opacity?.value ?? 1), imageRes = {
|
|
53
71
|
color,
|
|
54
|
-
|
|
72
|
+
gif: imageData.gif,
|
|
73
|
+
data: {
|
|
74
|
+
...image,
|
|
75
|
+
svgData: svgColoredData,
|
|
76
|
+
},
|
|
55
77
|
loaded: false,
|
|
56
78
|
ratio: imageData.width / imageData.height,
|
|
57
|
-
replaceColor:
|
|
79
|
+
replaceColor: imageData.replaceColor,
|
|
58
80
|
source: imageData.src,
|
|
59
81
|
};
|
|
60
82
|
return new Promise((resolve) => {
|
|
@@ -67,7 +89,11 @@ export function replaceImageColor(image, imageData, color, particle) {
|
|
|
67
89
|
});
|
|
68
90
|
img.addEventListener("error", async () => {
|
|
69
91
|
domUrl.revokeObjectURL(url);
|
|
70
|
-
const img2 =
|
|
92
|
+
const img2 = {
|
|
93
|
+
...image,
|
|
94
|
+
error: false,
|
|
95
|
+
loading: true,
|
|
96
|
+
};
|
|
71
97
|
await loadImage(img2);
|
|
72
98
|
imageRes.loaded = true;
|
|
73
99
|
imageRes.element = img2.element;
|
package/browser/index.js
CHANGED
|
@@ -1,4 +1,44 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { downloadSvgImage, loadGifImage, loadImage } from "./Utils.js";
|
|
2
|
+
import { ImageDrawer } from "./ImageDrawer.js";
|
|
3
|
+
import { ImagePreloaderPlugin } from "./ImagePreloader.js";
|
|
4
|
+
import { errorPrefix } from "@tsparticles/engine";
|
|
5
|
+
function addLoadImageToEngine(engine) {
|
|
6
|
+
if (engine.loadImage) {
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
engine.loadImage = async (data) => {
|
|
10
|
+
if (!data.name && !data.src) {
|
|
11
|
+
throw new Error(`${errorPrefix} no image source provided`);
|
|
12
|
+
}
|
|
13
|
+
if (!engine.images) {
|
|
14
|
+
engine.images = [];
|
|
15
|
+
}
|
|
16
|
+
if (engine.images.find((t) => t.name === data.name || t.source === data.src)) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
try {
|
|
20
|
+
const image = {
|
|
21
|
+
gif: data.gif ?? false,
|
|
22
|
+
name: data.name ?? data.src,
|
|
23
|
+
source: data.src,
|
|
24
|
+
type: data.src.substring(data.src.length - 3),
|
|
25
|
+
error: false,
|
|
26
|
+
loading: true,
|
|
27
|
+
replaceColor: data.replaceColor,
|
|
28
|
+
ratio: data.width && data.height ? data.width / data.height : undefined,
|
|
29
|
+
};
|
|
30
|
+
engine.images.push(image);
|
|
31
|
+
const imageFunc = data.gif ? loadGifImage : data.replaceColor ? downloadSvgImage : loadImage;
|
|
32
|
+
await imageFunc(image);
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
throw new Error(`${errorPrefix} ${data.name ?? data.src} not found`);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export async function loadImageShape(engine, refresh = true) {
|
|
40
|
+
addLoadImageToEngine(engine);
|
|
41
|
+
const preloader = new ImagePreloaderPlugin(engine);
|
|
42
|
+
await engine.addPlugin(preloader, refresh);
|
|
43
|
+
await engine.addShape(["image", "images"], new ImageDrawer(engine), refresh);
|
|
4
44
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "type": "module" }
|
package/browser/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ByteStream = void 0;
|
|
4
|
+
class ByteStream {
|
|
5
|
+
constructor(bytes) {
|
|
6
|
+
this.pos = 0;
|
|
7
|
+
this.data = new Uint8ClampedArray(bytes);
|
|
8
|
+
}
|
|
9
|
+
getString(count) {
|
|
10
|
+
const slice = this.data.slice(this.pos, this.pos + count);
|
|
11
|
+
this.pos += slice.length;
|
|
12
|
+
return slice.reduce((acc, curr) => acc + String.fromCharCode(curr), "");
|
|
13
|
+
}
|
|
14
|
+
nextByte() {
|
|
15
|
+
return this.data[this.pos++];
|
|
16
|
+
}
|
|
17
|
+
nextTwoBytes() {
|
|
18
|
+
this.pos += 2;
|
|
19
|
+
return this.data[this.pos - 2] + (this.data[this.pos - 1] << 8);
|
|
20
|
+
}
|
|
21
|
+
readSubBlocks() {
|
|
22
|
+
let blockString = "", size = 0;
|
|
23
|
+
do {
|
|
24
|
+
size = this.data[this.pos++];
|
|
25
|
+
for (let count = size; --count >= 0; blockString += String.fromCharCode(this.data[this.pos++])) {
|
|
26
|
+
}
|
|
27
|
+
} while (size !== 0);
|
|
28
|
+
return blockString;
|
|
29
|
+
}
|
|
30
|
+
readSubBlocksBin() {
|
|
31
|
+
let size = 0, len = 0;
|
|
32
|
+
for (let offset = 0; (size = this.data[this.pos + offset]) !== 0; offset += size + 1) {
|
|
33
|
+
len += size;
|
|
34
|
+
}
|
|
35
|
+
const blockData = new Uint8Array(len);
|
|
36
|
+
for (let i = 0; (size = this.data[this.pos++]) !== 0;) {
|
|
37
|
+
for (let count = size; --count >= 0; blockData[i++] = this.data[this.pos++]) {
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return blockData;
|
|
41
|
+
}
|
|
42
|
+
skipSubBlocks() {
|
|
43
|
+
for (; this.data[this.pos] !== 0; this.pos += this.data[this.pos] + 1) {
|
|
44
|
+
}
|
|
45
|
+
this.pos++;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
exports.ByteStream = ByteStream;
|