@tsparticles/shape-image 3.0.3 → 3.1.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.
- package/browser/GifUtils/ByteStream.js +11 -8
- package/browser/GifUtils/Utils.js +17 -10
- package/browser/ImageDrawer.js +28 -22
- package/browser/ImagePreloader.js +1 -1
- package/browser/Utils.js +8 -6
- package/browser/index.js +9 -2
- package/cjs/GifUtils/ByteStream.js +11 -8
- package/cjs/GifUtils/Utils.js +17 -10
- package/cjs/ImageDrawer.js +27 -21
- package/cjs/ImagePreloader.js +1 -1
- package/cjs/Utils.js +8 -6
- package/cjs/index.js +9 -2
- package/esm/GifUtils/ByteStream.js +11 -8
- package/esm/GifUtils/Utils.js +17 -10
- package/esm/ImageDrawer.js +28 -22
- package/esm/ImagePreloader.js +1 -1
- package/esm/Utils.js +8 -6
- package/esm/index.js +9 -2
- package/package.json +2 -2
- package/report.html +2 -2
- package/tsparticles.shape.image.js +98 -50
- package/tsparticles.shape.image.min.js +1 -1
- package/tsparticles.shape.image.min.js.LICENSE.txt +1 -1
- package/types/ImageDrawer.d.ts +1 -1
- package/umd/GifUtils/ByteStream.js +11 -8
- package/umd/GifUtils/Utils.js +17 -10
- package/umd/ImageDrawer.js +27 -21
- package/umd/ImagePreloader.js +1 -1
- package/umd/Utils.js +8 -6
- package/umd/index.js +9 -2
|
@@ -12,32 +12,35 @@ export class ByteStream {
|
|
|
12
12
|
return this.data[this.pos++];
|
|
13
13
|
}
|
|
14
14
|
nextTwoBytes() {
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
const increment = 2, previous = 1, shift = 8;
|
|
16
|
+
this.pos += increment;
|
|
17
|
+
return this.data[this.pos - increment] + (this.data[this.pos - previous] << shift);
|
|
17
18
|
}
|
|
18
19
|
readSubBlocks() {
|
|
19
20
|
let blockString = "", size = 0;
|
|
21
|
+
const minCount = 0, emptySize = 0;
|
|
20
22
|
do {
|
|
21
23
|
size = this.data[this.pos++];
|
|
22
|
-
for (let count = size; --count >=
|
|
24
|
+
for (let count = size; --count >= minCount; blockString += String.fromCharCode(this.data[this.pos++])) {
|
|
23
25
|
}
|
|
24
|
-
} while (size !==
|
|
26
|
+
} while (size !== emptySize);
|
|
25
27
|
return blockString;
|
|
26
28
|
}
|
|
27
29
|
readSubBlocksBin() {
|
|
28
30
|
let size = 0, len = 0;
|
|
29
|
-
|
|
31
|
+
const emptySize = 0, increment = 1;
|
|
32
|
+
for (let offset = 0; size !== emptySize; offset += size + increment, size = this.data[this.pos + offset]) {
|
|
30
33
|
len += size;
|
|
31
34
|
}
|
|
32
35
|
const blockData = new Uint8Array(len);
|
|
33
|
-
for (let i = 0;
|
|
34
|
-
for (let count = size; --count >=
|
|
36
|
+
for (let i = 0; size !== emptySize; size = this.data[this.pos++]) {
|
|
37
|
+
for (let count = size; --count >= emptySize; blockData[i++] = this.data[this.pos++]) {
|
|
35
38
|
}
|
|
36
39
|
}
|
|
37
40
|
return blockData;
|
|
38
41
|
}
|
|
39
42
|
skipSubBlocks() {
|
|
40
|
-
for (; this.data[this.pos] !==
|
|
43
|
+
for (const increment = 1, noData = 0; this.data[this.pos] !== noData; this.pos += this.data[this.pos] + increment) {
|
|
41
44
|
}
|
|
42
45
|
this.pos++;
|
|
43
46
|
}
|
|
@@ -12,7 +12,7 @@ function parseColorTable(byteStream, count) {
|
|
|
12
12
|
}
|
|
13
13
|
return colors;
|
|
14
14
|
}
|
|
15
|
-
|
|
15
|
+
function parseExtensionBlock(byteStream, gif, getFrameIndex, getTransparencyIndex) {
|
|
16
16
|
switch (byteStream.nextByte()) {
|
|
17
17
|
case 249: {
|
|
18
18
|
const frame = gif.frames[getFrameIndex(false)];
|
|
@@ -84,7 +84,10 @@ async function parseImageBlock(byteStream, gif, avgAlpha, getFrameIndex, getTran
|
|
|
84
84
|
}
|
|
85
85
|
const getColor = (index) => {
|
|
86
86
|
const { r, g, b } = (localColorTableFlag ? frame.localColorTable : gif.globalColorTable)[index];
|
|
87
|
-
|
|
87
|
+
if (index !== getTransparencyIndex(null)) {
|
|
88
|
+
return { r, g, b, a: 255 };
|
|
89
|
+
}
|
|
90
|
+
return { r, g, b, a: avgAlpha ? ~~((r + g + b) / 3) : 0 };
|
|
88
91
|
};
|
|
89
92
|
const image = (() => {
|
|
90
93
|
try {
|
|
@@ -110,7 +113,8 @@ async function parseImageBlock(byteStream, gif, avgAlpha, getFrameIndex, getTran
|
|
|
110
113
|
if (interlacedFlag) {
|
|
111
114
|
for (let code = 0, size = minCodeSize + 1, pos = 0, dic = [[0]], pass = 0; pass < 4; pass++) {
|
|
112
115
|
if (InterlaceOffsets[pass] < frame.height) {
|
|
113
|
-
|
|
116
|
+
let pixelPos = 0, lineIndex = 0, exit = false;
|
|
117
|
+
while (!exit) {
|
|
114
118
|
const last = code;
|
|
115
119
|
code = readBits(pos, size);
|
|
116
120
|
pos += size + 1;
|
|
@@ -128,8 +132,8 @@ async function parseImageBlock(byteStream, gif, avgAlpha, getFrameIndex, getTran
|
|
|
128
132
|
else if (last !== clearCode) {
|
|
129
133
|
dic.push(dic[last].concat(dic[code][0]));
|
|
130
134
|
}
|
|
131
|
-
for (
|
|
132
|
-
const { r, g, b, a } = getColor(
|
|
135
|
+
for (const item of dic[code]) {
|
|
136
|
+
const { r, g, b, a } = getColor(item);
|
|
133
137
|
image.data.set([r, g, b, a], InterlaceOffsets[pass] * frame.width +
|
|
134
138
|
InterlaceSteps[pass] * lineIndex +
|
|
135
139
|
(pixelPos % (frame.width * 4)));
|
|
@@ -142,7 +146,7 @@ async function parseImageBlock(byteStream, gif, avgAlpha, getFrameIndex, getTran
|
|
|
142
146
|
if (pixelPos === frame.width * 4 * (lineIndex + 1)) {
|
|
143
147
|
lineIndex++;
|
|
144
148
|
if (InterlaceOffsets[pass] + InterlaceSteps[pass] * lineIndex >= frame.height) {
|
|
145
|
-
|
|
149
|
+
exit = true;
|
|
146
150
|
}
|
|
147
151
|
}
|
|
148
152
|
}
|
|
@@ -153,7 +157,9 @@ async function parseImageBlock(byteStream, gif, avgAlpha, getFrameIndex, getTran
|
|
|
153
157
|
frame.bitmap = await createImageBitmap(image);
|
|
154
158
|
}
|
|
155
159
|
else {
|
|
156
|
-
|
|
160
|
+
let code = 0, size = minCodeSize + 1, pos = 0, pixelPos = -4, exit = false;
|
|
161
|
+
const dic = [[0]];
|
|
162
|
+
while (!exit) {
|
|
157
163
|
const last = code;
|
|
158
164
|
code = readBits(pos, size);
|
|
159
165
|
pos += size;
|
|
@@ -166,6 +172,7 @@ async function parseImageBlock(byteStream, gif, avgAlpha, getFrameIndex, getTran
|
|
|
166
172
|
}
|
|
167
173
|
else {
|
|
168
174
|
if (code === clearCode + 1) {
|
|
175
|
+
exit = true;
|
|
169
176
|
break;
|
|
170
177
|
}
|
|
171
178
|
if (code >= dic.length) {
|
|
@@ -174,8 +181,8 @@ async function parseImageBlock(byteStream, gif, avgAlpha, getFrameIndex, getTran
|
|
|
174
181
|
else if (last !== clearCode) {
|
|
175
182
|
dic.push(dic[last].concat(dic[code][0]));
|
|
176
183
|
}
|
|
177
|
-
for (
|
|
178
|
-
const { r, g, b, a } = getColor(
|
|
184
|
+
for (const item of dic[code]) {
|
|
185
|
+
const { r, g, b, a } = getColor(item);
|
|
179
186
|
image.data.set([r, g, b, a], (pixelPos += 4));
|
|
180
187
|
}
|
|
181
188
|
if (dic.length >= 1 << size && size < 0xc) {
|
|
@@ -196,7 +203,7 @@ async function parseBlock(byteStream, gif, avgAlpha, getFrameIndex, getTranspare
|
|
|
196
203
|
await parseImageBlock(byteStream, gif, avgAlpha, getFrameIndex, getTransparencyIndex, progressCallback);
|
|
197
204
|
break;
|
|
198
205
|
case 33:
|
|
199
|
-
|
|
206
|
+
parseExtensionBlock(byteStream, gif, getFrameIndex, getTransparencyIndex);
|
|
200
207
|
break;
|
|
201
208
|
default:
|
|
202
209
|
throw new EvalError("undefined block found");
|
package/browser/ImageDrawer.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
import { errorPrefix } from "@tsparticles/engine";
|
|
1
|
+
import { errorPrefix, } from "@tsparticles/engine";
|
|
2
2
|
import { replaceImageColor } from "./Utils.js";
|
|
3
|
+
const origin = {
|
|
4
|
+
x: 0,
|
|
5
|
+
y: 0,
|
|
6
|
+
}, defaultLoopCount = 0, defaultFrame = 0, half = 0.5, initialTime = 0, firstIndex = 0, double = 2, defaultAlpha = 1, sides = 12, defaultRatio = 1;
|
|
3
7
|
export class ImageDrawer {
|
|
4
8
|
constructor(engine) {
|
|
5
9
|
this.loadImageShape = async (imageShape) => {
|
|
@@ -34,14 +38,14 @@ export class ImageDrawer {
|
|
|
34
38
|
}
|
|
35
39
|
offscreenContext.imageSmoothingQuality = "low";
|
|
36
40
|
offscreenContext.imageSmoothingEnabled = false;
|
|
37
|
-
offscreenContext.clearRect(
|
|
41
|
+
offscreenContext.clearRect(origin.x, origin.y, offscreenCanvas.width, offscreenCanvas.height);
|
|
38
42
|
if (particle.gifLoopCount === undefined) {
|
|
39
|
-
particle.gifLoopCount = image.gifLoopCount ??
|
|
43
|
+
particle.gifLoopCount = image.gifLoopCount ?? defaultLoopCount;
|
|
40
44
|
}
|
|
41
|
-
let frameIndex = particle.gifFrame ??
|
|
42
|
-
const pos = { x: -image.gifData.width *
|
|
45
|
+
let frameIndex = particle.gifFrame ?? defaultFrame;
|
|
46
|
+
const pos = { x: -image.gifData.width * half, y: -image.gifData.height * half }, frame = image.gifData.frames[frameIndex];
|
|
43
47
|
if (particle.gifTime === undefined) {
|
|
44
|
-
particle.gifTime =
|
|
48
|
+
particle.gifTime = initialTime;
|
|
45
49
|
}
|
|
46
50
|
if (!frame.bitmap) {
|
|
47
51
|
return;
|
|
@@ -55,7 +59,7 @@ export class ImageDrawer {
|
|
|
55
59
|
case 0:
|
|
56
60
|
offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
|
|
57
61
|
context.drawImage(offscreenCanvas, pos.x, pos.y);
|
|
58
|
-
offscreenContext.clearRect(
|
|
62
|
+
offscreenContext.clearRect(origin.x, origin.y, offscreenCanvas.width, offscreenCanvas.height);
|
|
59
63
|
break;
|
|
60
64
|
case 1:
|
|
61
65
|
offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
|
|
@@ -64,9 +68,9 @@ export class ImageDrawer {
|
|
|
64
68
|
case 2:
|
|
65
69
|
offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
|
|
66
70
|
context.drawImage(offscreenCanvas, pos.x, pos.y);
|
|
67
|
-
offscreenContext.clearRect(
|
|
68
|
-
if (image.gifData.globalColorTable.length
|
|
69
|
-
offscreenContext.putImageData(image.gifData.frames[
|
|
71
|
+
offscreenContext.clearRect(origin.x, origin.y, offscreenCanvas.width, offscreenCanvas.height);
|
|
72
|
+
if (!image.gifData.globalColorTable.length) {
|
|
73
|
+
offscreenContext.putImageData(image.gifData.frames[firstIndex].image, pos.x + frame.left, pos.y + frame.top);
|
|
70
74
|
}
|
|
71
75
|
else {
|
|
72
76
|
offscreenContext.putImageData(image.gifData.backgroundImage, pos.x, pos.y);
|
|
@@ -74,11 +78,11 @@ export class ImageDrawer {
|
|
|
74
78
|
break;
|
|
75
79
|
case 3:
|
|
76
80
|
{
|
|
77
|
-
const previousImageData = offscreenContext.getImageData(
|
|
81
|
+
const previousImageData = offscreenContext.getImageData(origin.x, origin.y, offscreenCanvas.width, offscreenCanvas.height);
|
|
78
82
|
offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
|
|
79
83
|
context.drawImage(offscreenCanvas, pos.x, pos.y);
|
|
80
|
-
offscreenContext.clearRect(
|
|
81
|
-
offscreenContext.putImageData(previousImageData,
|
|
84
|
+
offscreenContext.clearRect(origin.x, origin.y, offscreenCanvas.width, offscreenCanvas.height);
|
|
85
|
+
offscreenContext.putImageData(previousImageData, origin.x, origin.y);
|
|
82
86
|
}
|
|
83
87
|
break;
|
|
84
88
|
}
|
|
@@ -86,11 +90,11 @@ export class ImageDrawer {
|
|
|
86
90
|
if (particle.gifTime > frame.delayTime) {
|
|
87
91
|
particle.gifTime -= frame.delayTime;
|
|
88
92
|
if (++frameIndex >= image.gifData.frames.length) {
|
|
89
|
-
if (--particle.gifLoopCount <=
|
|
93
|
+
if (--particle.gifLoopCount <= defaultLoopCount) {
|
|
90
94
|
return;
|
|
91
95
|
}
|
|
92
|
-
frameIndex =
|
|
93
|
-
offscreenContext.clearRect(
|
|
96
|
+
frameIndex = firstIndex;
|
|
97
|
+
offscreenContext.clearRect(origin.x, origin.y, offscreenCanvas.width, offscreenCanvas.height);
|
|
94
98
|
}
|
|
95
99
|
particle.gifFrame = frameIndex;
|
|
96
100
|
}
|
|
@@ -100,13 +104,13 @@ export class ImageDrawer {
|
|
|
100
104
|
const ratio = image.ratio, pos = {
|
|
101
105
|
x: -radius,
|
|
102
106
|
y: -radius,
|
|
103
|
-
}, diameter = radius *
|
|
107
|
+
}, diameter = radius * double;
|
|
104
108
|
context.drawImage(element, pos.x, pos.y, diameter, diameter / ratio);
|
|
105
109
|
}
|
|
106
|
-
context.globalAlpha =
|
|
110
|
+
context.globalAlpha = defaultAlpha;
|
|
107
111
|
}
|
|
108
112
|
getSidesCount() {
|
|
109
|
-
return
|
|
113
|
+
return sides;
|
|
110
114
|
}
|
|
111
115
|
async init(container) {
|
|
112
116
|
const options = container.actualOptions;
|
|
@@ -130,7 +134,7 @@ export class ImageDrawer {
|
|
|
130
134
|
}
|
|
131
135
|
const image = this._engine.images.find((t) => t.name === imageData.name || t.source === imageData.src);
|
|
132
136
|
if (!image) {
|
|
133
|
-
this.loadImageShape(imageData).then(() => {
|
|
137
|
+
void this.loadImageShape(imageData).then(() => {
|
|
134
138
|
this.loadShape(particle);
|
|
135
139
|
});
|
|
136
140
|
}
|
|
@@ -157,7 +161,7 @@ export class ImageDrawer {
|
|
|
157
161
|
});
|
|
158
162
|
return;
|
|
159
163
|
}
|
|
160
|
-
(async () => {
|
|
164
|
+
void (async () => {
|
|
161
165
|
let imageRes;
|
|
162
166
|
if (image.svgData && color) {
|
|
163
167
|
imageRes = await replaceImageColor(image, imageData, color, particle);
|
|
@@ -171,7 +175,9 @@ export class ImageDrawer {
|
|
|
171
175
|
gifData: image.gifData,
|
|
172
176
|
gifLoopCount: image.gifLoopCount,
|
|
173
177
|
loaded: true,
|
|
174
|
-
ratio: imageData.width && imageData.height
|
|
178
|
+
ratio: imageData.width && imageData.height
|
|
179
|
+
? imageData.width / imageData.height
|
|
180
|
+
: image.ratio ?? defaultRatio,
|
|
175
181
|
replaceColor: replaceColor,
|
|
176
182
|
source: imageData.src,
|
|
177
183
|
};
|
package/browser/Utils.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { errorPrefix, getLogger, getStyleFromHsl } from "@tsparticles/engine";
|
|
2
2
|
import { decodeGIF, getGIFLoopAmount } from "./GifUtils/Utils.js";
|
|
3
|
+
const stringStart = 0, defaultLoopCount = 0, defaultOpacity = 1;
|
|
3
4
|
const currentColorRegex = /(#(?:[0-9a-f]{2}){2,4}|(#[0-9a-f]{3})|(rgb|hsl)a?\((-?\d+%?[,\s]+){2,3}\s*[\d.]+%?\))|currentcolor/gi;
|
|
4
5
|
function replaceColorSvg(imageShape, color, opacity) {
|
|
5
6
|
const { svgData } = imageShape;
|
|
@@ -11,7 +12,7 @@ function replaceColorSvg(imageShape, color, opacity) {
|
|
|
11
12
|
return svgData.replace(currentColorRegex, () => colorStyle);
|
|
12
13
|
}
|
|
13
14
|
const preFillIndex = svgData.indexOf(">");
|
|
14
|
-
return `${svgData.substring(
|
|
15
|
+
return `${svgData.substring(stringStart, preFillIndex)} fill="${colorStyle}"${svgData.substring(preFillIndex)}`;
|
|
15
16
|
}
|
|
16
17
|
export async function loadImage(image) {
|
|
17
18
|
return new Promise((resolve) => {
|
|
@@ -40,8 +41,8 @@ export async function loadGifImage(image) {
|
|
|
40
41
|
image.loading = true;
|
|
41
42
|
try {
|
|
42
43
|
image.gifData = await decodeGIF(image.source);
|
|
43
|
-
image.gifLoopCount = getGIFLoopAmount(image.gifData) ??
|
|
44
|
-
if (image.gifLoopCount
|
|
44
|
+
image.gifLoopCount = getGIFLoopAmount(image.gifData) ?? defaultLoopCount;
|
|
45
|
+
if (!image.gifLoopCount) {
|
|
45
46
|
image.gifLoopCount = Infinity;
|
|
46
47
|
}
|
|
47
48
|
}
|
|
@@ -67,7 +68,7 @@ export async function downloadSvgImage(image) {
|
|
|
67
68
|
image.loading = false;
|
|
68
69
|
}
|
|
69
70
|
export function replaceImageColor(image, imageData, color, particle) {
|
|
70
|
-
const svgColoredData = replaceColorSvg(image, color, particle.opacity?.value ??
|
|
71
|
+
const svgColoredData = replaceColorSvg(image, color, particle.opacity?.value ?? defaultOpacity), imageRes = {
|
|
71
72
|
color,
|
|
72
73
|
gif: imageData.gif,
|
|
73
74
|
data: {
|
|
@@ -87,7 +88,7 @@ export function replaceImageColor(image, imageData, color, particle) {
|
|
|
87
88
|
resolve(imageRes);
|
|
88
89
|
domUrl.revokeObjectURL(url);
|
|
89
90
|
});
|
|
90
|
-
|
|
91
|
+
const errorHandler = async () => {
|
|
91
92
|
domUrl.revokeObjectURL(url);
|
|
92
93
|
const img2 = {
|
|
93
94
|
...image,
|
|
@@ -98,7 +99,8 @@ export function replaceImageColor(image, imageData, color, particle) {
|
|
|
98
99
|
imageRes.loaded = true;
|
|
99
100
|
imageRes.element = img2.element;
|
|
100
101
|
resolve(imageRes);
|
|
101
|
-
}
|
|
102
|
+
};
|
|
103
|
+
img.addEventListener("error", () => void errorHandler());
|
|
102
104
|
img.src = url;
|
|
103
105
|
});
|
|
104
106
|
}
|
package/browser/index.js
CHANGED
|
@@ -2,6 +2,7 @@ import { downloadSvgImage, loadGifImage, loadImage } from "./Utils.js";
|
|
|
2
2
|
import { ImageDrawer } from "./ImageDrawer.js";
|
|
3
3
|
import { ImagePreloaderPlugin } from "./ImagePreloader.js";
|
|
4
4
|
import { errorPrefix } from "@tsparticles/engine";
|
|
5
|
+
const extLength = 3;
|
|
5
6
|
function addLoadImageToEngine(engine) {
|
|
6
7
|
if (engine.loadImage) {
|
|
7
8
|
return;
|
|
@@ -21,14 +22,20 @@ function addLoadImageToEngine(engine) {
|
|
|
21
22
|
gif: data.gif ?? false,
|
|
22
23
|
name: data.name ?? data.src,
|
|
23
24
|
source: data.src,
|
|
24
|
-
type: data.src.substring(data.src.length -
|
|
25
|
+
type: data.src.substring(data.src.length - extLength),
|
|
25
26
|
error: false,
|
|
26
27
|
loading: true,
|
|
27
28
|
replaceColor: data.replaceColor,
|
|
28
29
|
ratio: data.width && data.height ? data.width / data.height : undefined,
|
|
29
30
|
};
|
|
30
31
|
engine.images.push(image);
|
|
31
|
-
|
|
32
|
+
let imageFunc;
|
|
33
|
+
if (data.gif) {
|
|
34
|
+
imageFunc = loadGifImage;
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
imageFunc = data.replaceColor ? downloadSvgImage : loadImage;
|
|
38
|
+
}
|
|
32
39
|
await imageFunc(image);
|
|
33
40
|
}
|
|
34
41
|
catch {
|
|
@@ -15,32 +15,35 @@ class ByteStream {
|
|
|
15
15
|
return this.data[this.pos++];
|
|
16
16
|
}
|
|
17
17
|
nextTwoBytes() {
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
const increment = 2, previous = 1, shift = 8;
|
|
19
|
+
this.pos += increment;
|
|
20
|
+
return this.data[this.pos - increment] + (this.data[this.pos - previous] << shift);
|
|
20
21
|
}
|
|
21
22
|
readSubBlocks() {
|
|
22
23
|
let blockString = "", size = 0;
|
|
24
|
+
const minCount = 0, emptySize = 0;
|
|
23
25
|
do {
|
|
24
26
|
size = this.data[this.pos++];
|
|
25
|
-
for (let count = size; --count >=
|
|
27
|
+
for (let count = size; --count >= minCount; blockString += String.fromCharCode(this.data[this.pos++])) {
|
|
26
28
|
}
|
|
27
|
-
} while (size !==
|
|
29
|
+
} while (size !== emptySize);
|
|
28
30
|
return blockString;
|
|
29
31
|
}
|
|
30
32
|
readSubBlocksBin() {
|
|
31
33
|
let size = 0, len = 0;
|
|
32
|
-
|
|
34
|
+
const emptySize = 0, increment = 1;
|
|
35
|
+
for (let offset = 0; size !== emptySize; offset += size + increment, size = this.data[this.pos + offset]) {
|
|
33
36
|
len += size;
|
|
34
37
|
}
|
|
35
38
|
const blockData = new Uint8Array(len);
|
|
36
|
-
for (let i = 0;
|
|
37
|
-
for (let count = size; --count >=
|
|
39
|
+
for (let i = 0; size !== emptySize; size = this.data[this.pos++]) {
|
|
40
|
+
for (let count = size; --count >= emptySize; blockData[i++] = this.data[this.pos++]) {
|
|
38
41
|
}
|
|
39
42
|
}
|
|
40
43
|
return blockData;
|
|
41
44
|
}
|
|
42
45
|
skipSubBlocks() {
|
|
43
|
-
for (; this.data[this.pos] !==
|
|
46
|
+
for (const increment = 1, noData = 0; this.data[this.pos] !== noData; this.pos += this.data[this.pos] + increment) {
|
|
44
47
|
}
|
|
45
48
|
this.pos++;
|
|
46
49
|
}
|
package/cjs/GifUtils/Utils.js
CHANGED
|
@@ -15,7 +15,7 @@ function parseColorTable(byteStream, count) {
|
|
|
15
15
|
}
|
|
16
16
|
return colors;
|
|
17
17
|
}
|
|
18
|
-
|
|
18
|
+
function parseExtensionBlock(byteStream, gif, getFrameIndex, getTransparencyIndex) {
|
|
19
19
|
switch (byteStream.nextByte()) {
|
|
20
20
|
case 249: {
|
|
21
21
|
const frame = gif.frames[getFrameIndex(false)];
|
|
@@ -87,7 +87,10 @@ async function parseImageBlock(byteStream, gif, avgAlpha, getFrameIndex, getTran
|
|
|
87
87
|
}
|
|
88
88
|
const getColor = (index) => {
|
|
89
89
|
const { r, g, b } = (localColorTableFlag ? frame.localColorTable : gif.globalColorTable)[index];
|
|
90
|
-
|
|
90
|
+
if (index !== getTransparencyIndex(null)) {
|
|
91
|
+
return { r, g, b, a: 255 };
|
|
92
|
+
}
|
|
93
|
+
return { r, g, b, a: avgAlpha ? ~~((r + g + b) / 3) : 0 };
|
|
91
94
|
};
|
|
92
95
|
const image = (() => {
|
|
93
96
|
try {
|
|
@@ -113,7 +116,8 @@ async function parseImageBlock(byteStream, gif, avgAlpha, getFrameIndex, getTran
|
|
|
113
116
|
if (interlacedFlag) {
|
|
114
117
|
for (let code = 0, size = minCodeSize + 1, pos = 0, dic = [[0]], pass = 0; pass < 4; pass++) {
|
|
115
118
|
if (Constants_js_1.InterlaceOffsets[pass] < frame.height) {
|
|
116
|
-
|
|
119
|
+
let pixelPos = 0, lineIndex = 0, exit = false;
|
|
120
|
+
while (!exit) {
|
|
117
121
|
const last = code;
|
|
118
122
|
code = readBits(pos, size);
|
|
119
123
|
pos += size + 1;
|
|
@@ -131,8 +135,8 @@ async function parseImageBlock(byteStream, gif, avgAlpha, getFrameIndex, getTran
|
|
|
131
135
|
else if (last !== clearCode) {
|
|
132
136
|
dic.push(dic[last].concat(dic[code][0]));
|
|
133
137
|
}
|
|
134
|
-
for (
|
|
135
|
-
const { r, g, b, a } = getColor(
|
|
138
|
+
for (const item of dic[code]) {
|
|
139
|
+
const { r, g, b, a } = getColor(item);
|
|
136
140
|
image.data.set([r, g, b, a], Constants_js_1.InterlaceOffsets[pass] * frame.width +
|
|
137
141
|
Constants_js_1.InterlaceSteps[pass] * lineIndex +
|
|
138
142
|
(pixelPos % (frame.width * 4)));
|
|
@@ -145,7 +149,7 @@ async function parseImageBlock(byteStream, gif, avgAlpha, getFrameIndex, getTran
|
|
|
145
149
|
if (pixelPos === frame.width * 4 * (lineIndex + 1)) {
|
|
146
150
|
lineIndex++;
|
|
147
151
|
if (Constants_js_1.InterlaceOffsets[pass] + Constants_js_1.InterlaceSteps[pass] * lineIndex >= frame.height) {
|
|
148
|
-
|
|
152
|
+
exit = true;
|
|
149
153
|
}
|
|
150
154
|
}
|
|
151
155
|
}
|
|
@@ -156,7 +160,9 @@ async function parseImageBlock(byteStream, gif, avgAlpha, getFrameIndex, getTran
|
|
|
156
160
|
frame.bitmap = await createImageBitmap(image);
|
|
157
161
|
}
|
|
158
162
|
else {
|
|
159
|
-
|
|
163
|
+
let code = 0, size = minCodeSize + 1, pos = 0, pixelPos = -4, exit = false;
|
|
164
|
+
const dic = [[0]];
|
|
165
|
+
while (!exit) {
|
|
160
166
|
const last = code;
|
|
161
167
|
code = readBits(pos, size);
|
|
162
168
|
pos += size;
|
|
@@ -169,6 +175,7 @@ async function parseImageBlock(byteStream, gif, avgAlpha, getFrameIndex, getTran
|
|
|
169
175
|
}
|
|
170
176
|
else {
|
|
171
177
|
if (code === clearCode + 1) {
|
|
178
|
+
exit = true;
|
|
172
179
|
break;
|
|
173
180
|
}
|
|
174
181
|
if (code >= dic.length) {
|
|
@@ -177,8 +184,8 @@ async function parseImageBlock(byteStream, gif, avgAlpha, getFrameIndex, getTran
|
|
|
177
184
|
else if (last !== clearCode) {
|
|
178
185
|
dic.push(dic[last].concat(dic[code][0]));
|
|
179
186
|
}
|
|
180
|
-
for (
|
|
181
|
-
const { r, g, b, a } = getColor(
|
|
187
|
+
for (const item of dic[code]) {
|
|
188
|
+
const { r, g, b, a } = getColor(item);
|
|
182
189
|
image.data.set([r, g, b, a], (pixelPos += 4));
|
|
183
190
|
}
|
|
184
191
|
if (dic.length >= 1 << size && size < 0xc) {
|
|
@@ -199,7 +206,7 @@ async function parseBlock(byteStream, gif, avgAlpha, getFrameIndex, getTranspare
|
|
|
199
206
|
await parseImageBlock(byteStream, gif, avgAlpha, getFrameIndex, getTransparencyIndex, progressCallback);
|
|
200
207
|
break;
|
|
201
208
|
case 33:
|
|
202
|
-
|
|
209
|
+
parseExtensionBlock(byteStream, gif, getFrameIndex, getTransparencyIndex);
|
|
203
210
|
break;
|
|
204
211
|
default:
|
|
205
212
|
throw new EvalError("undefined block found");
|
package/cjs/ImageDrawer.js
CHANGED
|
@@ -3,6 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.ImageDrawer = void 0;
|
|
4
4
|
const engine_1 = require("@tsparticles/engine");
|
|
5
5
|
const Utils_js_1 = require("./Utils.js");
|
|
6
|
+
const origin = {
|
|
7
|
+
x: 0,
|
|
8
|
+
y: 0,
|
|
9
|
+
}, defaultLoopCount = 0, defaultFrame = 0, half = 0.5, initialTime = 0, firstIndex = 0, double = 2, defaultAlpha = 1, sides = 12, defaultRatio = 1;
|
|
6
10
|
class ImageDrawer {
|
|
7
11
|
constructor(engine) {
|
|
8
12
|
this.loadImageShape = async (imageShape) => {
|
|
@@ -37,14 +41,14 @@ class ImageDrawer {
|
|
|
37
41
|
}
|
|
38
42
|
offscreenContext.imageSmoothingQuality = "low";
|
|
39
43
|
offscreenContext.imageSmoothingEnabled = false;
|
|
40
|
-
offscreenContext.clearRect(
|
|
44
|
+
offscreenContext.clearRect(origin.x, origin.y, offscreenCanvas.width, offscreenCanvas.height);
|
|
41
45
|
if (particle.gifLoopCount === undefined) {
|
|
42
|
-
particle.gifLoopCount = image.gifLoopCount ??
|
|
46
|
+
particle.gifLoopCount = image.gifLoopCount ?? defaultLoopCount;
|
|
43
47
|
}
|
|
44
|
-
let frameIndex = particle.gifFrame ??
|
|
45
|
-
const pos = { x: -image.gifData.width *
|
|
48
|
+
let frameIndex = particle.gifFrame ?? defaultFrame;
|
|
49
|
+
const pos = { x: -image.gifData.width * half, y: -image.gifData.height * half }, frame = image.gifData.frames[frameIndex];
|
|
46
50
|
if (particle.gifTime === undefined) {
|
|
47
|
-
particle.gifTime =
|
|
51
|
+
particle.gifTime = initialTime;
|
|
48
52
|
}
|
|
49
53
|
if (!frame.bitmap) {
|
|
50
54
|
return;
|
|
@@ -58,7 +62,7 @@ class ImageDrawer {
|
|
|
58
62
|
case 0:
|
|
59
63
|
offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
|
|
60
64
|
context.drawImage(offscreenCanvas, pos.x, pos.y);
|
|
61
|
-
offscreenContext.clearRect(
|
|
65
|
+
offscreenContext.clearRect(origin.x, origin.y, offscreenCanvas.width, offscreenCanvas.height);
|
|
62
66
|
break;
|
|
63
67
|
case 1:
|
|
64
68
|
offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
|
|
@@ -67,9 +71,9 @@ class ImageDrawer {
|
|
|
67
71
|
case 2:
|
|
68
72
|
offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
|
|
69
73
|
context.drawImage(offscreenCanvas, pos.x, pos.y);
|
|
70
|
-
offscreenContext.clearRect(
|
|
71
|
-
if (image.gifData.globalColorTable.length
|
|
72
|
-
offscreenContext.putImageData(image.gifData.frames[
|
|
74
|
+
offscreenContext.clearRect(origin.x, origin.y, offscreenCanvas.width, offscreenCanvas.height);
|
|
75
|
+
if (!image.gifData.globalColorTable.length) {
|
|
76
|
+
offscreenContext.putImageData(image.gifData.frames[firstIndex].image, pos.x + frame.left, pos.y + frame.top);
|
|
73
77
|
}
|
|
74
78
|
else {
|
|
75
79
|
offscreenContext.putImageData(image.gifData.backgroundImage, pos.x, pos.y);
|
|
@@ -77,11 +81,11 @@ class ImageDrawer {
|
|
|
77
81
|
break;
|
|
78
82
|
case 3:
|
|
79
83
|
{
|
|
80
|
-
const previousImageData = offscreenContext.getImageData(
|
|
84
|
+
const previousImageData = offscreenContext.getImageData(origin.x, origin.y, offscreenCanvas.width, offscreenCanvas.height);
|
|
81
85
|
offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
|
|
82
86
|
context.drawImage(offscreenCanvas, pos.x, pos.y);
|
|
83
|
-
offscreenContext.clearRect(
|
|
84
|
-
offscreenContext.putImageData(previousImageData,
|
|
87
|
+
offscreenContext.clearRect(origin.x, origin.y, offscreenCanvas.width, offscreenCanvas.height);
|
|
88
|
+
offscreenContext.putImageData(previousImageData, origin.x, origin.y);
|
|
85
89
|
}
|
|
86
90
|
break;
|
|
87
91
|
}
|
|
@@ -89,11 +93,11 @@ class ImageDrawer {
|
|
|
89
93
|
if (particle.gifTime > frame.delayTime) {
|
|
90
94
|
particle.gifTime -= frame.delayTime;
|
|
91
95
|
if (++frameIndex >= image.gifData.frames.length) {
|
|
92
|
-
if (--particle.gifLoopCount <=
|
|
96
|
+
if (--particle.gifLoopCount <= defaultLoopCount) {
|
|
93
97
|
return;
|
|
94
98
|
}
|
|
95
|
-
frameIndex =
|
|
96
|
-
offscreenContext.clearRect(
|
|
99
|
+
frameIndex = firstIndex;
|
|
100
|
+
offscreenContext.clearRect(origin.x, origin.y, offscreenCanvas.width, offscreenCanvas.height);
|
|
97
101
|
}
|
|
98
102
|
particle.gifFrame = frameIndex;
|
|
99
103
|
}
|
|
@@ -103,13 +107,13 @@ class ImageDrawer {
|
|
|
103
107
|
const ratio = image.ratio, pos = {
|
|
104
108
|
x: -radius,
|
|
105
109
|
y: -radius,
|
|
106
|
-
}, diameter = radius *
|
|
110
|
+
}, diameter = radius * double;
|
|
107
111
|
context.drawImage(element, pos.x, pos.y, diameter, diameter / ratio);
|
|
108
112
|
}
|
|
109
|
-
context.globalAlpha =
|
|
113
|
+
context.globalAlpha = defaultAlpha;
|
|
110
114
|
}
|
|
111
115
|
getSidesCount() {
|
|
112
|
-
return
|
|
116
|
+
return sides;
|
|
113
117
|
}
|
|
114
118
|
async init(container) {
|
|
115
119
|
const options = container.actualOptions;
|
|
@@ -133,7 +137,7 @@ class ImageDrawer {
|
|
|
133
137
|
}
|
|
134
138
|
const image = this._engine.images.find((t) => t.name === imageData.name || t.source === imageData.src);
|
|
135
139
|
if (!image) {
|
|
136
|
-
this.loadImageShape(imageData).then(() => {
|
|
140
|
+
void this.loadImageShape(imageData).then(() => {
|
|
137
141
|
this.loadShape(particle);
|
|
138
142
|
});
|
|
139
143
|
}
|
|
@@ -160,7 +164,7 @@ class ImageDrawer {
|
|
|
160
164
|
});
|
|
161
165
|
return;
|
|
162
166
|
}
|
|
163
|
-
(async () => {
|
|
167
|
+
void (async () => {
|
|
164
168
|
let imageRes;
|
|
165
169
|
if (image.svgData && color) {
|
|
166
170
|
imageRes = await (0, Utils_js_1.replaceImageColor)(image, imageData, color, particle);
|
|
@@ -174,7 +178,9 @@ class ImageDrawer {
|
|
|
174
178
|
gifData: image.gifData,
|
|
175
179
|
gifLoopCount: image.gifLoopCount,
|
|
176
180
|
loaded: true,
|
|
177
|
-
ratio: imageData.width && imageData.height
|
|
181
|
+
ratio: imageData.width && imageData.height
|
|
182
|
+
? imageData.width / imageData.height
|
|
183
|
+
: image.ratio ?? defaultRatio,
|
|
178
184
|
replaceColor: replaceColor,
|
|
179
185
|
source: imageData.src,
|
|
180
186
|
};
|