@tsparticles/shape-image 3.3.0 → 3.4.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/Enums/DisposalMethod.js +11 -1
- package/browser/GifUtils/Types/GIFDataHeaders.js +10 -1
- package/browser/GifUtils/Utils.js +19 -17
- package/browser/ImageDrawer.js +1 -0
- package/browser/ImagePreloader.js +1 -1
- package/browser/Utils.js +1 -1
- package/browser/index.js +4 -3
- package/cjs/GifUtils/Enums/DisposalMethod.js +12 -0
- package/cjs/GifUtils/Types/GIFDataHeaders.js +11 -0
- package/cjs/GifUtils/Utils.js +20 -18
- package/cjs/ImageDrawer.js +1 -0
- package/cjs/ImagePreloader.js +1 -1
- package/cjs/Utils.js +1 -1
- package/cjs/index.js +6 -5
- package/esm/GifUtils/Enums/DisposalMethod.js +11 -1
- package/esm/GifUtils/Types/GIFDataHeaders.js +10 -1
- package/esm/GifUtils/Utils.js +19 -17
- package/esm/ImageDrawer.js +1 -0
- package/esm/ImagePreloader.js +1 -1
- package/esm/Utils.js +1 -1
- package/esm/index.js +4 -3
- package/package.json +2 -2
- package/report.html +1 -1
- package/tsparticles.shape.image.js +82 -200
- package/tsparticles.shape.image.min.js +1 -1
- package/tsparticles.shape.image.min.js.LICENSE.txt +1 -1
- package/types/GifUtils/Enums/DisposalMethod.d.ts +1 -1
- package/types/GifUtils/Types/GIFDataHeaders.d.ts +1 -1
- package/types/GifUtils/Utils.d.ts +1 -1
- package/types/ImageDrawer.d.ts +1 -0
- package/umd/GifUtils/Enums/DisposalMethod.js +12 -0
- package/umd/GifUtils/Types/GIFDataHeaders.js +11 -0
- package/umd/GifUtils/Utils.js +21 -43
- package/umd/ImageDrawer.js +1 -0
- package/umd/ImagePreloader.js +1 -1
- package/umd/Utils.js +1 -1
- package/umd/index.js +7 -30
- package/329.min.js +0 -2
- package/329.min.js.LICENSE.txt +0 -1
- package/33.min.js +0 -2
- package/33.min.js.LICENSE.txt +0 -1
- package/715.min.js +0 -2
- package/715.min.js.LICENSE.txt +0 -1
- package/dist_browser_GifUtils_Utils_js.js +0 -50
- package/dist_browser_ImageDrawer_js.js +0 -30
- package/dist_browser_ImagePreloader_js.js +0 -40
|
@@ -1 +1,11 @@
|
|
|
1
|
-
export
|
|
1
|
+
export var DisposalMethod;
|
|
2
|
+
(function (DisposalMethod) {
|
|
3
|
+
DisposalMethod[DisposalMethod["Replace"] = 0] = "Replace";
|
|
4
|
+
DisposalMethod[DisposalMethod["Combine"] = 1] = "Combine";
|
|
5
|
+
DisposalMethod[DisposalMethod["RestoreBackground"] = 2] = "RestoreBackground";
|
|
6
|
+
DisposalMethod[DisposalMethod["RestorePrevious"] = 3] = "RestorePrevious";
|
|
7
|
+
DisposalMethod[DisposalMethod["UndefinedA"] = 4] = "UndefinedA";
|
|
8
|
+
DisposalMethod[DisposalMethod["UndefinedB"] = 5] = "UndefinedB";
|
|
9
|
+
DisposalMethod[DisposalMethod["UndefinedC"] = 6] = "UndefinedC";
|
|
10
|
+
DisposalMethod[DisposalMethod["UndefinedD"] = 7] = "UndefinedD";
|
|
11
|
+
})(DisposalMethod || (DisposalMethod = {}));
|
|
@@ -1 +1,10 @@
|
|
|
1
|
-
export
|
|
1
|
+
export var GIFDataHeaders;
|
|
2
|
+
(function (GIFDataHeaders) {
|
|
3
|
+
GIFDataHeaders[GIFDataHeaders["Extension"] = 33] = "Extension";
|
|
4
|
+
GIFDataHeaders[GIFDataHeaders["ApplicationExtension"] = 255] = "ApplicationExtension";
|
|
5
|
+
GIFDataHeaders[GIFDataHeaders["GraphicsControlExtension"] = 249] = "GraphicsControlExtension";
|
|
6
|
+
GIFDataHeaders[GIFDataHeaders["PlainTextExtension"] = 1] = "PlainTextExtension";
|
|
7
|
+
GIFDataHeaders[GIFDataHeaders["CommentExtension"] = 254] = "CommentExtension";
|
|
8
|
+
GIFDataHeaders[GIFDataHeaders["Image"] = 44] = "Image";
|
|
9
|
+
GIFDataHeaders[GIFDataHeaders["EndOfFile"] = 59] = "EndOfFile";
|
|
10
|
+
})(GIFDataHeaders || (GIFDataHeaders = {}));
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
import { loadImage } from "../Utils.js";
|
|
1
2
|
import { InterlaceOffsets, InterlaceSteps } from "./Constants.js";
|
|
2
3
|
import { ByteStream } from "./ByteStream.js";
|
|
4
|
+
import { DisposalMethod } from "./Enums/DisposalMethod.js";
|
|
5
|
+
import { GIFDataHeaders } from "./Types/GIFDataHeaders.js";
|
|
3
6
|
const origin = {
|
|
4
7
|
x: 0,
|
|
5
8
|
y: 0,
|
|
@@ -18,7 +21,7 @@ function parseColorTable(byteStream, count) {
|
|
|
18
21
|
}
|
|
19
22
|
function parseExtensionBlock(byteStream, gif, getFrameIndex, getTransparencyIndex) {
|
|
20
23
|
switch (byteStream.nextByte()) {
|
|
21
|
-
case
|
|
24
|
+
case GIFDataHeaders.GraphicsControlExtension: {
|
|
22
25
|
const frame = gif.frames[getFrameIndex(false)];
|
|
23
26
|
byteStream.pos++;
|
|
24
27
|
const packedByte = byteStream.nextByte();
|
|
@@ -34,7 +37,7 @@ function parseExtensionBlock(byteStream, gif, getFrameIndex, getTransparencyInde
|
|
|
34
37
|
byteStream.pos++;
|
|
35
38
|
break;
|
|
36
39
|
}
|
|
37
|
-
case
|
|
40
|
+
case GIFDataHeaders.ApplicationExtension: {
|
|
38
41
|
byteStream.pos++;
|
|
39
42
|
const applicationExtension = {
|
|
40
43
|
identifier: byteStream.getString(8),
|
|
@@ -44,11 +47,11 @@ function parseExtensionBlock(byteStream, gif, getFrameIndex, getTransparencyInde
|
|
|
44
47
|
gif.applicationExtensions.push(applicationExtension);
|
|
45
48
|
break;
|
|
46
49
|
}
|
|
47
|
-
case
|
|
50
|
+
case GIFDataHeaders.CommentExtension: {
|
|
48
51
|
gif.comments.push([getFrameIndex(false), byteStream.readSubBlocks()]);
|
|
49
52
|
break;
|
|
50
53
|
}
|
|
51
|
-
case
|
|
54
|
+
case GIFDataHeaders.PlainTextExtension: {
|
|
52
55
|
if (gif.globalColorTable.length === 0) {
|
|
53
56
|
throw new EvalError("plain text extension without global color table");
|
|
54
57
|
}
|
|
@@ -201,12 +204,12 @@ async function parseImageBlock(byteStream, gif, avgAlpha, getFrameIndex, getTran
|
|
|
201
204
|
}
|
|
202
205
|
async function parseBlock(byteStream, gif, avgAlpha, getFrameIndex, getTransparencyIndex, progressCallback) {
|
|
203
206
|
switch (byteStream.nextByte()) {
|
|
204
|
-
case
|
|
207
|
+
case GIFDataHeaders.EndOfFile:
|
|
205
208
|
return true;
|
|
206
|
-
case
|
|
209
|
+
case GIFDataHeaders.Image:
|
|
207
210
|
await parseImageBlock(byteStream, gif, avgAlpha, getFrameIndex, getTransparencyIndex, progressCallback);
|
|
208
211
|
break;
|
|
209
|
-
case
|
|
212
|
+
case GIFDataHeaders.Extension:
|
|
210
213
|
parseExtensionBlock(byteStream, gif, getFrameIndex, getTransparencyIndex);
|
|
211
214
|
break;
|
|
212
215
|
default:
|
|
@@ -301,7 +304,7 @@ export async function decodeGIF(gifURL, progressCallback, avgAlpha) {
|
|
|
301
304
|
top: 0,
|
|
302
305
|
width: 0,
|
|
303
306
|
height: 0,
|
|
304
|
-
disposalMethod:
|
|
307
|
+
disposalMethod: DisposalMethod.Replace,
|
|
305
308
|
image: new ImageData(1, 1, { colorSpace: "srgb" }),
|
|
306
309
|
plainTextData: null,
|
|
307
310
|
userInputDelayFlag: false,
|
|
@@ -358,20 +361,20 @@ export function drawGif(data) {
|
|
|
358
361
|
}
|
|
359
362
|
context.scale(radius / image.gifData.width, radius / image.gifData.height);
|
|
360
363
|
switch (frame.disposalMethod) {
|
|
361
|
-
case
|
|
362
|
-
case
|
|
363
|
-
case
|
|
364
|
-
case
|
|
365
|
-
case
|
|
364
|
+
case DisposalMethod.UndefinedA:
|
|
365
|
+
case DisposalMethod.UndefinedB:
|
|
366
|
+
case DisposalMethod.UndefinedC:
|
|
367
|
+
case DisposalMethod.UndefinedD:
|
|
368
|
+
case DisposalMethod.Replace:
|
|
366
369
|
offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
|
|
367
370
|
context.drawImage(offscreenCanvas, pos.x, pos.y);
|
|
368
371
|
offscreenContext.clearRect(origin.x, origin.y, offscreenCanvas.width, offscreenCanvas.height);
|
|
369
372
|
break;
|
|
370
|
-
case
|
|
373
|
+
case DisposalMethod.Combine:
|
|
371
374
|
offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
|
|
372
375
|
context.drawImage(offscreenCanvas, pos.x, pos.y);
|
|
373
376
|
break;
|
|
374
|
-
case
|
|
377
|
+
case DisposalMethod.RestoreBackground:
|
|
375
378
|
offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
|
|
376
379
|
context.drawImage(offscreenCanvas, pos.x, pos.y);
|
|
377
380
|
offscreenContext.clearRect(origin.x, origin.y, offscreenCanvas.width, offscreenCanvas.height);
|
|
@@ -382,7 +385,7 @@ export function drawGif(data) {
|
|
|
382
385
|
offscreenContext.putImageData(image.gifData.backgroundImage, pos.x, pos.y);
|
|
383
386
|
}
|
|
384
387
|
break;
|
|
385
|
-
case
|
|
388
|
+
case DisposalMethod.RestorePrevious:
|
|
386
389
|
{
|
|
387
390
|
const previousImageData = offscreenContext.getImageData(origin.x, origin.y, offscreenCanvas.width, offscreenCanvas.height);
|
|
388
391
|
offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
|
|
@@ -408,7 +411,6 @@ export function drawGif(data) {
|
|
|
408
411
|
}
|
|
409
412
|
export async function loadGifImage(image) {
|
|
410
413
|
if (image.type !== "gif") {
|
|
411
|
-
const { loadImage } = await import("../Utils.js");
|
|
412
414
|
await loadImage(image);
|
|
413
415
|
return;
|
|
414
416
|
}
|
package/browser/ImageDrawer.js
CHANGED
|
@@ -4,6 +4,7 @@ import { drawGif } from "./GifUtils/Utils.js";
|
|
|
4
4
|
const double = 2, defaultAlpha = 1, sides = 12, defaultRatio = 1;
|
|
5
5
|
export class ImageDrawer {
|
|
6
6
|
constructor(engine) {
|
|
7
|
+
this.validTypes = ["image", "images"];
|
|
7
8
|
this.loadImageShape = async (imageShape) => {
|
|
8
9
|
if (!this._engine.loadImage) {
|
|
9
10
|
throw new Error(`${errorPrefix} image shape not initialized`);
|
|
@@ -17,7 +17,7 @@ export class ImagePreloaderPlugin {
|
|
|
17
17
|
}
|
|
18
18
|
const preloadOptions = options.preload;
|
|
19
19
|
for (const item of source.preload) {
|
|
20
|
-
const existing = preloadOptions.find(
|
|
20
|
+
const existing = preloadOptions.find(t => t.name === item.name || t.src === item.src);
|
|
21
21
|
if (existing) {
|
|
22
22
|
existing.load(item);
|
|
23
23
|
}
|
package/browser/Utils.js
CHANGED
|
@@ -61,7 +61,7 @@ export function replaceImageColor(image, imageData, color, particle) {
|
|
|
61
61
|
replaceColor: imageData.replaceColor,
|
|
62
62
|
source: imageData.src,
|
|
63
63
|
};
|
|
64
|
-
return new Promise(
|
|
64
|
+
return new Promise(resolve => {
|
|
65
65
|
const svg = new Blob([svgColoredData], { type: "image/svg+xml" }), domUrl = URL || window.URL || window.webkitURL || window, url = domUrl.createObjectURL(svg), img = new Image();
|
|
66
66
|
img.addEventListener("load", () => {
|
|
67
67
|
imageRes.loaded = true;
|
package/browser/index.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { downloadSvgImage, loadImage } from "./Utils.js";
|
|
2
|
+
import { ImageDrawer } from "./ImageDrawer.js";
|
|
3
|
+
import { ImagePreloaderPlugin } from "./ImagePreloader.js";
|
|
2
4
|
import { errorPrefix } from "@tsparticles/engine";
|
|
5
|
+
import { loadGifImage } from "./GifUtils/Utils.js";
|
|
3
6
|
const extLength = 3;
|
|
4
7
|
function addLoadImageToEngine(engine) {
|
|
5
8
|
if (engine.loadImage) {
|
|
@@ -29,7 +32,6 @@ function addLoadImageToEngine(engine) {
|
|
|
29
32
|
engine.images.push(image);
|
|
30
33
|
let imageFunc;
|
|
31
34
|
if (data.gif) {
|
|
32
|
-
const { loadGifImage } = await import("./GifUtils/Utils.js");
|
|
33
35
|
imageFunc = loadGifImage;
|
|
34
36
|
}
|
|
35
37
|
else {
|
|
@@ -44,8 +46,7 @@ function addLoadImageToEngine(engine) {
|
|
|
44
46
|
}
|
|
45
47
|
export async function loadImageShape(engine, refresh = true) {
|
|
46
48
|
addLoadImageToEngine(engine);
|
|
47
|
-
const { ImagePreloaderPlugin } = await import("./ImagePreloader.js"), { ImageDrawer } = await import("./ImageDrawer.js");
|
|
48
49
|
const preloader = new ImagePreloaderPlugin(engine);
|
|
49
50
|
await engine.addPlugin(preloader, refresh);
|
|
50
|
-
await engine.addShape(
|
|
51
|
+
await engine.addShape(new ImageDrawer(engine), refresh);
|
|
51
52
|
}
|
|
@@ -1,2 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DisposalMethod = void 0;
|
|
4
|
+
var DisposalMethod;
|
|
5
|
+
(function (DisposalMethod) {
|
|
6
|
+
DisposalMethod[DisposalMethod["Replace"] = 0] = "Replace";
|
|
7
|
+
DisposalMethod[DisposalMethod["Combine"] = 1] = "Combine";
|
|
8
|
+
DisposalMethod[DisposalMethod["RestoreBackground"] = 2] = "RestoreBackground";
|
|
9
|
+
DisposalMethod[DisposalMethod["RestorePrevious"] = 3] = "RestorePrevious";
|
|
10
|
+
DisposalMethod[DisposalMethod["UndefinedA"] = 4] = "UndefinedA";
|
|
11
|
+
DisposalMethod[DisposalMethod["UndefinedB"] = 5] = "UndefinedB";
|
|
12
|
+
DisposalMethod[DisposalMethod["UndefinedC"] = 6] = "UndefinedC";
|
|
13
|
+
DisposalMethod[DisposalMethod["UndefinedD"] = 7] = "UndefinedD";
|
|
14
|
+
})(DisposalMethod || (exports.DisposalMethod = DisposalMethod = {}));
|
|
@@ -1,2 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GIFDataHeaders = void 0;
|
|
4
|
+
var GIFDataHeaders;
|
|
5
|
+
(function (GIFDataHeaders) {
|
|
6
|
+
GIFDataHeaders[GIFDataHeaders["Extension"] = 33] = "Extension";
|
|
7
|
+
GIFDataHeaders[GIFDataHeaders["ApplicationExtension"] = 255] = "ApplicationExtension";
|
|
8
|
+
GIFDataHeaders[GIFDataHeaders["GraphicsControlExtension"] = 249] = "GraphicsControlExtension";
|
|
9
|
+
GIFDataHeaders[GIFDataHeaders["PlainTextExtension"] = 1] = "PlainTextExtension";
|
|
10
|
+
GIFDataHeaders[GIFDataHeaders["CommentExtension"] = 254] = "CommentExtension";
|
|
11
|
+
GIFDataHeaders[GIFDataHeaders["Image"] = 44] = "Image";
|
|
12
|
+
GIFDataHeaders[GIFDataHeaders["EndOfFile"] = 59] = "EndOfFile";
|
|
13
|
+
})(GIFDataHeaders || (exports.GIFDataHeaders = GIFDataHeaders = {}));
|
package/cjs/GifUtils/Utils.js
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.loadGifImage = exports.drawGif = exports.decodeGIF = exports.getGIFLoopAmount = void 0;
|
|
4
|
+
const Utils_js_1 = require("../Utils.js");
|
|
4
5
|
const Constants_js_1 = require("./Constants.js");
|
|
5
6
|
const ByteStream_js_1 = require("./ByteStream.js");
|
|
7
|
+
const DisposalMethod_js_1 = require("./Enums/DisposalMethod.js");
|
|
8
|
+
const GIFDataHeaders_js_1 = require("./Types/GIFDataHeaders.js");
|
|
6
9
|
const origin = {
|
|
7
10
|
x: 0,
|
|
8
11
|
y: 0,
|
|
@@ -21,7 +24,7 @@ function parseColorTable(byteStream, count) {
|
|
|
21
24
|
}
|
|
22
25
|
function parseExtensionBlock(byteStream, gif, getFrameIndex, getTransparencyIndex) {
|
|
23
26
|
switch (byteStream.nextByte()) {
|
|
24
|
-
case
|
|
27
|
+
case GIFDataHeaders_js_1.GIFDataHeaders.GraphicsControlExtension: {
|
|
25
28
|
const frame = gif.frames[getFrameIndex(false)];
|
|
26
29
|
byteStream.pos++;
|
|
27
30
|
const packedByte = byteStream.nextByte();
|
|
@@ -37,7 +40,7 @@ function parseExtensionBlock(byteStream, gif, getFrameIndex, getTransparencyInde
|
|
|
37
40
|
byteStream.pos++;
|
|
38
41
|
break;
|
|
39
42
|
}
|
|
40
|
-
case
|
|
43
|
+
case GIFDataHeaders_js_1.GIFDataHeaders.ApplicationExtension: {
|
|
41
44
|
byteStream.pos++;
|
|
42
45
|
const applicationExtension = {
|
|
43
46
|
identifier: byteStream.getString(8),
|
|
@@ -47,11 +50,11 @@ function parseExtensionBlock(byteStream, gif, getFrameIndex, getTransparencyInde
|
|
|
47
50
|
gif.applicationExtensions.push(applicationExtension);
|
|
48
51
|
break;
|
|
49
52
|
}
|
|
50
|
-
case
|
|
53
|
+
case GIFDataHeaders_js_1.GIFDataHeaders.CommentExtension: {
|
|
51
54
|
gif.comments.push([getFrameIndex(false), byteStream.readSubBlocks()]);
|
|
52
55
|
break;
|
|
53
56
|
}
|
|
54
|
-
case
|
|
57
|
+
case GIFDataHeaders_js_1.GIFDataHeaders.PlainTextExtension: {
|
|
55
58
|
if (gif.globalColorTable.length === 0) {
|
|
56
59
|
throw new EvalError("plain text extension without global color table");
|
|
57
60
|
}
|
|
@@ -204,12 +207,12 @@ async function parseImageBlock(byteStream, gif, avgAlpha, getFrameIndex, getTran
|
|
|
204
207
|
}
|
|
205
208
|
async function parseBlock(byteStream, gif, avgAlpha, getFrameIndex, getTransparencyIndex, progressCallback) {
|
|
206
209
|
switch (byteStream.nextByte()) {
|
|
207
|
-
case
|
|
210
|
+
case GIFDataHeaders_js_1.GIFDataHeaders.EndOfFile:
|
|
208
211
|
return true;
|
|
209
|
-
case
|
|
212
|
+
case GIFDataHeaders_js_1.GIFDataHeaders.Image:
|
|
210
213
|
await parseImageBlock(byteStream, gif, avgAlpha, getFrameIndex, getTransparencyIndex, progressCallback);
|
|
211
214
|
break;
|
|
212
|
-
case
|
|
215
|
+
case GIFDataHeaders_js_1.GIFDataHeaders.Extension:
|
|
213
216
|
parseExtensionBlock(byteStream, gif, getFrameIndex, getTransparencyIndex);
|
|
214
217
|
break;
|
|
215
218
|
default:
|
|
@@ -305,7 +308,7 @@ async function decodeGIF(gifURL, progressCallback, avgAlpha) {
|
|
|
305
308
|
top: 0,
|
|
306
309
|
width: 0,
|
|
307
310
|
height: 0,
|
|
308
|
-
disposalMethod:
|
|
311
|
+
disposalMethod: DisposalMethod_js_1.DisposalMethod.Replace,
|
|
309
312
|
image: new ImageData(1, 1, { colorSpace: "srgb" }),
|
|
310
313
|
plainTextData: null,
|
|
311
314
|
userInputDelayFlag: false,
|
|
@@ -363,20 +366,20 @@ function drawGif(data) {
|
|
|
363
366
|
}
|
|
364
367
|
context.scale(radius / image.gifData.width, radius / image.gifData.height);
|
|
365
368
|
switch (frame.disposalMethod) {
|
|
366
|
-
case
|
|
367
|
-
case
|
|
368
|
-
case
|
|
369
|
-
case
|
|
370
|
-
case
|
|
369
|
+
case DisposalMethod_js_1.DisposalMethod.UndefinedA:
|
|
370
|
+
case DisposalMethod_js_1.DisposalMethod.UndefinedB:
|
|
371
|
+
case DisposalMethod_js_1.DisposalMethod.UndefinedC:
|
|
372
|
+
case DisposalMethod_js_1.DisposalMethod.UndefinedD:
|
|
373
|
+
case DisposalMethod_js_1.DisposalMethod.Replace:
|
|
371
374
|
offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
|
|
372
375
|
context.drawImage(offscreenCanvas, pos.x, pos.y);
|
|
373
376
|
offscreenContext.clearRect(origin.x, origin.y, offscreenCanvas.width, offscreenCanvas.height);
|
|
374
377
|
break;
|
|
375
|
-
case
|
|
378
|
+
case DisposalMethod_js_1.DisposalMethod.Combine:
|
|
376
379
|
offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
|
|
377
380
|
context.drawImage(offscreenCanvas, pos.x, pos.y);
|
|
378
381
|
break;
|
|
379
|
-
case
|
|
382
|
+
case DisposalMethod_js_1.DisposalMethod.RestoreBackground:
|
|
380
383
|
offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
|
|
381
384
|
context.drawImage(offscreenCanvas, pos.x, pos.y);
|
|
382
385
|
offscreenContext.clearRect(origin.x, origin.y, offscreenCanvas.width, offscreenCanvas.height);
|
|
@@ -387,7 +390,7 @@ function drawGif(data) {
|
|
|
387
390
|
offscreenContext.putImageData(image.gifData.backgroundImage, pos.x, pos.y);
|
|
388
391
|
}
|
|
389
392
|
break;
|
|
390
|
-
case
|
|
393
|
+
case DisposalMethod_js_1.DisposalMethod.RestorePrevious:
|
|
391
394
|
{
|
|
392
395
|
const previousImageData = offscreenContext.getImageData(origin.x, origin.y, offscreenCanvas.width, offscreenCanvas.height);
|
|
393
396
|
offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
|
|
@@ -414,8 +417,7 @@ function drawGif(data) {
|
|
|
414
417
|
exports.drawGif = drawGif;
|
|
415
418
|
async function loadGifImage(image) {
|
|
416
419
|
if (image.type !== "gif") {
|
|
417
|
-
|
|
418
|
-
await loadImage(image);
|
|
420
|
+
await (0, Utils_js_1.loadImage)(image);
|
|
419
421
|
return;
|
|
420
422
|
}
|
|
421
423
|
image.loading = true;
|
package/cjs/ImageDrawer.js
CHANGED
|
@@ -7,6 +7,7 @@ const Utils_js_2 = require("./GifUtils/Utils.js");
|
|
|
7
7
|
const double = 2, defaultAlpha = 1, sides = 12, defaultRatio = 1;
|
|
8
8
|
class ImageDrawer {
|
|
9
9
|
constructor(engine) {
|
|
10
|
+
this.validTypes = ["image", "images"];
|
|
10
11
|
this.loadImageShape = async (imageShape) => {
|
|
11
12
|
if (!this._engine.loadImage) {
|
|
12
13
|
throw new Error(`${engine_1.errorPrefix} image shape not initialized`);
|
package/cjs/ImagePreloader.js
CHANGED
|
@@ -20,7 +20,7 @@ class ImagePreloaderPlugin {
|
|
|
20
20
|
}
|
|
21
21
|
const preloadOptions = options.preload;
|
|
22
22
|
for (const item of source.preload) {
|
|
23
|
-
const existing = preloadOptions.find(
|
|
23
|
+
const existing = preloadOptions.find(t => t.name === item.name || t.src === item.src);
|
|
24
24
|
if (existing) {
|
|
25
25
|
existing.load(item);
|
|
26
26
|
}
|
package/cjs/Utils.js
CHANGED
|
@@ -66,7 +66,7 @@ function replaceImageColor(image, imageData, color, particle) {
|
|
|
66
66
|
replaceColor: imageData.replaceColor,
|
|
67
67
|
source: imageData.src,
|
|
68
68
|
};
|
|
69
|
-
return new Promise(
|
|
69
|
+
return new Promise(resolve => {
|
|
70
70
|
const svg = new Blob([svgColoredData], { type: "image/svg+xml" }), domUrl = URL || window.URL || window.webkitURL || window, url = domUrl.createObjectURL(svg), img = new Image();
|
|
71
71
|
img.addEventListener("load", () => {
|
|
72
72
|
imageRes.loaded = true;
|
package/cjs/index.js
CHANGED
|
@@ -2,7 +2,10 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.loadImageShape = void 0;
|
|
4
4
|
const Utils_js_1 = require("./Utils.js");
|
|
5
|
+
const ImageDrawer_js_1 = require("./ImageDrawer.js");
|
|
6
|
+
const ImagePreloader_js_1 = require("./ImagePreloader.js");
|
|
5
7
|
const engine_1 = require("@tsparticles/engine");
|
|
8
|
+
const Utils_js_2 = require("./GifUtils/Utils.js");
|
|
6
9
|
const extLength = 3;
|
|
7
10
|
function addLoadImageToEngine(engine) {
|
|
8
11
|
if (engine.loadImage) {
|
|
@@ -32,8 +35,7 @@ function addLoadImageToEngine(engine) {
|
|
|
32
35
|
engine.images.push(image);
|
|
33
36
|
let imageFunc;
|
|
34
37
|
if (data.gif) {
|
|
35
|
-
|
|
36
|
-
imageFunc = loadGifImage;
|
|
38
|
+
imageFunc = Utils_js_2.loadGifImage;
|
|
37
39
|
}
|
|
38
40
|
else {
|
|
39
41
|
imageFunc = data.replaceColor ? Utils_js_1.downloadSvgImage : Utils_js_1.loadImage;
|
|
@@ -47,9 +49,8 @@ function addLoadImageToEngine(engine) {
|
|
|
47
49
|
}
|
|
48
50
|
async function loadImageShape(engine, refresh = true) {
|
|
49
51
|
addLoadImageToEngine(engine);
|
|
50
|
-
const
|
|
51
|
-
const preloader = new ImagePreloaderPlugin(engine);
|
|
52
|
+
const preloader = new ImagePreloader_js_1.ImagePreloaderPlugin(engine);
|
|
52
53
|
await engine.addPlugin(preloader, refresh);
|
|
53
|
-
await engine.addShape(
|
|
54
|
+
await engine.addShape(new ImageDrawer_js_1.ImageDrawer(engine), refresh);
|
|
54
55
|
}
|
|
55
56
|
exports.loadImageShape = loadImageShape;
|
|
@@ -1 +1,11 @@
|
|
|
1
|
-
export
|
|
1
|
+
export var DisposalMethod;
|
|
2
|
+
(function (DisposalMethod) {
|
|
3
|
+
DisposalMethod[DisposalMethod["Replace"] = 0] = "Replace";
|
|
4
|
+
DisposalMethod[DisposalMethod["Combine"] = 1] = "Combine";
|
|
5
|
+
DisposalMethod[DisposalMethod["RestoreBackground"] = 2] = "RestoreBackground";
|
|
6
|
+
DisposalMethod[DisposalMethod["RestorePrevious"] = 3] = "RestorePrevious";
|
|
7
|
+
DisposalMethod[DisposalMethod["UndefinedA"] = 4] = "UndefinedA";
|
|
8
|
+
DisposalMethod[DisposalMethod["UndefinedB"] = 5] = "UndefinedB";
|
|
9
|
+
DisposalMethod[DisposalMethod["UndefinedC"] = 6] = "UndefinedC";
|
|
10
|
+
DisposalMethod[DisposalMethod["UndefinedD"] = 7] = "UndefinedD";
|
|
11
|
+
})(DisposalMethod || (DisposalMethod = {}));
|
|
@@ -1 +1,10 @@
|
|
|
1
|
-
export
|
|
1
|
+
export var GIFDataHeaders;
|
|
2
|
+
(function (GIFDataHeaders) {
|
|
3
|
+
GIFDataHeaders[GIFDataHeaders["Extension"] = 33] = "Extension";
|
|
4
|
+
GIFDataHeaders[GIFDataHeaders["ApplicationExtension"] = 255] = "ApplicationExtension";
|
|
5
|
+
GIFDataHeaders[GIFDataHeaders["GraphicsControlExtension"] = 249] = "GraphicsControlExtension";
|
|
6
|
+
GIFDataHeaders[GIFDataHeaders["PlainTextExtension"] = 1] = "PlainTextExtension";
|
|
7
|
+
GIFDataHeaders[GIFDataHeaders["CommentExtension"] = 254] = "CommentExtension";
|
|
8
|
+
GIFDataHeaders[GIFDataHeaders["Image"] = 44] = "Image";
|
|
9
|
+
GIFDataHeaders[GIFDataHeaders["EndOfFile"] = 59] = "EndOfFile";
|
|
10
|
+
})(GIFDataHeaders || (GIFDataHeaders = {}));
|
package/esm/GifUtils/Utils.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
import { loadImage } from "../Utils.js";
|
|
1
2
|
import { InterlaceOffsets, InterlaceSteps } from "./Constants.js";
|
|
2
3
|
import { ByteStream } from "./ByteStream.js";
|
|
4
|
+
import { DisposalMethod } from "./Enums/DisposalMethod.js";
|
|
5
|
+
import { GIFDataHeaders } from "./Types/GIFDataHeaders.js";
|
|
3
6
|
const origin = {
|
|
4
7
|
x: 0,
|
|
5
8
|
y: 0,
|
|
@@ -18,7 +21,7 @@ function parseColorTable(byteStream, count) {
|
|
|
18
21
|
}
|
|
19
22
|
function parseExtensionBlock(byteStream, gif, getFrameIndex, getTransparencyIndex) {
|
|
20
23
|
switch (byteStream.nextByte()) {
|
|
21
|
-
case
|
|
24
|
+
case GIFDataHeaders.GraphicsControlExtension: {
|
|
22
25
|
const frame = gif.frames[getFrameIndex(false)];
|
|
23
26
|
byteStream.pos++;
|
|
24
27
|
const packedByte = byteStream.nextByte();
|
|
@@ -34,7 +37,7 @@ function parseExtensionBlock(byteStream, gif, getFrameIndex, getTransparencyInde
|
|
|
34
37
|
byteStream.pos++;
|
|
35
38
|
break;
|
|
36
39
|
}
|
|
37
|
-
case
|
|
40
|
+
case GIFDataHeaders.ApplicationExtension: {
|
|
38
41
|
byteStream.pos++;
|
|
39
42
|
const applicationExtension = {
|
|
40
43
|
identifier: byteStream.getString(8),
|
|
@@ -44,11 +47,11 @@ function parseExtensionBlock(byteStream, gif, getFrameIndex, getTransparencyInde
|
|
|
44
47
|
gif.applicationExtensions.push(applicationExtension);
|
|
45
48
|
break;
|
|
46
49
|
}
|
|
47
|
-
case
|
|
50
|
+
case GIFDataHeaders.CommentExtension: {
|
|
48
51
|
gif.comments.push([getFrameIndex(false), byteStream.readSubBlocks()]);
|
|
49
52
|
break;
|
|
50
53
|
}
|
|
51
|
-
case
|
|
54
|
+
case GIFDataHeaders.PlainTextExtension: {
|
|
52
55
|
if (gif.globalColorTable.length === 0) {
|
|
53
56
|
throw new EvalError("plain text extension without global color table");
|
|
54
57
|
}
|
|
@@ -201,12 +204,12 @@ async function parseImageBlock(byteStream, gif, avgAlpha, getFrameIndex, getTran
|
|
|
201
204
|
}
|
|
202
205
|
async function parseBlock(byteStream, gif, avgAlpha, getFrameIndex, getTransparencyIndex, progressCallback) {
|
|
203
206
|
switch (byteStream.nextByte()) {
|
|
204
|
-
case
|
|
207
|
+
case GIFDataHeaders.EndOfFile:
|
|
205
208
|
return true;
|
|
206
|
-
case
|
|
209
|
+
case GIFDataHeaders.Image:
|
|
207
210
|
await parseImageBlock(byteStream, gif, avgAlpha, getFrameIndex, getTransparencyIndex, progressCallback);
|
|
208
211
|
break;
|
|
209
|
-
case
|
|
212
|
+
case GIFDataHeaders.Extension:
|
|
210
213
|
parseExtensionBlock(byteStream, gif, getFrameIndex, getTransparencyIndex);
|
|
211
214
|
break;
|
|
212
215
|
default:
|
|
@@ -301,7 +304,7 @@ export async function decodeGIF(gifURL, progressCallback, avgAlpha) {
|
|
|
301
304
|
top: 0,
|
|
302
305
|
width: 0,
|
|
303
306
|
height: 0,
|
|
304
|
-
disposalMethod:
|
|
307
|
+
disposalMethod: DisposalMethod.Replace,
|
|
305
308
|
image: new ImageData(1, 1, { colorSpace: "srgb" }),
|
|
306
309
|
plainTextData: null,
|
|
307
310
|
userInputDelayFlag: false,
|
|
@@ -358,20 +361,20 @@ export function drawGif(data) {
|
|
|
358
361
|
}
|
|
359
362
|
context.scale(radius / image.gifData.width, radius / image.gifData.height);
|
|
360
363
|
switch (frame.disposalMethod) {
|
|
361
|
-
case
|
|
362
|
-
case
|
|
363
|
-
case
|
|
364
|
-
case
|
|
365
|
-
case
|
|
364
|
+
case DisposalMethod.UndefinedA:
|
|
365
|
+
case DisposalMethod.UndefinedB:
|
|
366
|
+
case DisposalMethod.UndefinedC:
|
|
367
|
+
case DisposalMethod.UndefinedD:
|
|
368
|
+
case DisposalMethod.Replace:
|
|
366
369
|
offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
|
|
367
370
|
context.drawImage(offscreenCanvas, pos.x, pos.y);
|
|
368
371
|
offscreenContext.clearRect(origin.x, origin.y, offscreenCanvas.width, offscreenCanvas.height);
|
|
369
372
|
break;
|
|
370
|
-
case
|
|
373
|
+
case DisposalMethod.Combine:
|
|
371
374
|
offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
|
|
372
375
|
context.drawImage(offscreenCanvas, pos.x, pos.y);
|
|
373
376
|
break;
|
|
374
|
-
case
|
|
377
|
+
case DisposalMethod.RestoreBackground:
|
|
375
378
|
offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
|
|
376
379
|
context.drawImage(offscreenCanvas, pos.x, pos.y);
|
|
377
380
|
offscreenContext.clearRect(origin.x, origin.y, offscreenCanvas.width, offscreenCanvas.height);
|
|
@@ -382,7 +385,7 @@ export function drawGif(data) {
|
|
|
382
385
|
offscreenContext.putImageData(image.gifData.backgroundImage, pos.x, pos.y);
|
|
383
386
|
}
|
|
384
387
|
break;
|
|
385
|
-
case
|
|
388
|
+
case DisposalMethod.RestorePrevious:
|
|
386
389
|
{
|
|
387
390
|
const previousImageData = offscreenContext.getImageData(origin.x, origin.y, offscreenCanvas.width, offscreenCanvas.height);
|
|
388
391
|
offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
|
|
@@ -408,7 +411,6 @@ export function drawGif(data) {
|
|
|
408
411
|
}
|
|
409
412
|
export async function loadGifImage(image) {
|
|
410
413
|
if (image.type !== "gif") {
|
|
411
|
-
const { loadImage } = await import("../Utils.js");
|
|
412
414
|
await loadImage(image);
|
|
413
415
|
return;
|
|
414
416
|
}
|
package/esm/ImageDrawer.js
CHANGED
|
@@ -4,6 +4,7 @@ import { drawGif } from "./GifUtils/Utils.js";
|
|
|
4
4
|
const double = 2, defaultAlpha = 1, sides = 12, defaultRatio = 1;
|
|
5
5
|
export class ImageDrawer {
|
|
6
6
|
constructor(engine) {
|
|
7
|
+
this.validTypes = ["image", "images"];
|
|
7
8
|
this.loadImageShape = async (imageShape) => {
|
|
8
9
|
if (!this._engine.loadImage) {
|
|
9
10
|
throw new Error(`${errorPrefix} image shape not initialized`);
|
package/esm/ImagePreloader.js
CHANGED
|
@@ -17,7 +17,7 @@ export class ImagePreloaderPlugin {
|
|
|
17
17
|
}
|
|
18
18
|
const preloadOptions = options.preload;
|
|
19
19
|
for (const item of source.preload) {
|
|
20
|
-
const existing = preloadOptions.find(
|
|
20
|
+
const existing = preloadOptions.find(t => t.name === item.name || t.src === item.src);
|
|
21
21
|
if (existing) {
|
|
22
22
|
existing.load(item);
|
|
23
23
|
}
|
package/esm/Utils.js
CHANGED
|
@@ -61,7 +61,7 @@ export function replaceImageColor(image, imageData, color, particle) {
|
|
|
61
61
|
replaceColor: imageData.replaceColor,
|
|
62
62
|
source: imageData.src,
|
|
63
63
|
};
|
|
64
|
-
return new Promise(
|
|
64
|
+
return new Promise(resolve => {
|
|
65
65
|
const svg = new Blob([svgColoredData], { type: "image/svg+xml" }), domUrl = URL || window.URL || window.webkitURL || window, url = domUrl.createObjectURL(svg), img = new Image();
|
|
66
66
|
img.addEventListener("load", () => {
|
|
67
67
|
imageRes.loaded = true;
|
package/esm/index.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { downloadSvgImage, loadImage } from "./Utils.js";
|
|
2
|
+
import { ImageDrawer } from "./ImageDrawer.js";
|
|
3
|
+
import { ImagePreloaderPlugin } from "./ImagePreloader.js";
|
|
2
4
|
import { errorPrefix } from "@tsparticles/engine";
|
|
5
|
+
import { loadGifImage } from "./GifUtils/Utils.js";
|
|
3
6
|
const extLength = 3;
|
|
4
7
|
function addLoadImageToEngine(engine) {
|
|
5
8
|
if (engine.loadImage) {
|
|
@@ -29,7 +32,6 @@ function addLoadImageToEngine(engine) {
|
|
|
29
32
|
engine.images.push(image);
|
|
30
33
|
let imageFunc;
|
|
31
34
|
if (data.gif) {
|
|
32
|
-
const { loadGifImage } = await import("./GifUtils/Utils.js");
|
|
33
35
|
imageFunc = loadGifImage;
|
|
34
36
|
}
|
|
35
37
|
else {
|
|
@@ -44,8 +46,7 @@ function addLoadImageToEngine(engine) {
|
|
|
44
46
|
}
|
|
45
47
|
export async function loadImageShape(engine, refresh = true) {
|
|
46
48
|
addLoadImageToEngine(engine);
|
|
47
|
-
const { ImagePreloaderPlugin } = await import("./ImagePreloader.js"), { ImageDrawer } = await import("./ImageDrawer.js");
|
|
48
49
|
const preloader = new ImagePreloaderPlugin(engine);
|
|
49
50
|
await engine.addPlugin(preloader, refresh);
|
|
50
|
-
await engine.addShape(
|
|
51
|
+
await engine.addShape(new ImageDrawer(engine), refresh);
|
|
51
52
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tsparticles/shape-image",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.4.0",
|
|
4
4
|
"description": "tsParticles image shape",
|
|
5
5
|
"homepage": "https://particles.js.org",
|
|
6
6
|
"repository": {
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
"./package.json": "./package.json"
|
|
60
60
|
},
|
|
61
61
|
"dependencies": {
|
|
62
|
-
"@tsparticles/engine": "^3.
|
|
62
|
+
"@tsparticles/engine": "^3.4.0"
|
|
63
63
|
},
|
|
64
64
|
"publishConfig": {
|
|
65
65
|
"access": "public"
|
package/report.html
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="UTF-8"/>
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
|
6
|
-
<title>@tsparticles/shape-image [
|
|
6
|
+
<title>@tsparticles/shape-image [13 May 2024 at 00:12]</title>
|
|
7
7
|
<link rel="shortcut icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAABrVBMVEUAAAD///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////+O1foceMD///+J0/qK1Pr7/v8Xdr/9///W8P4UdL7L7P0Scr2r4Pyj3vwad8D5/f/2/f+55f3E6f34+/2H0/ojfMKpzOd0rNgQcb3F3O/j9f7c8v6g3Pz0/P/w+v/q+P7n9v6T1/uQ1vuE0vqLut/y+v+Z2fvt+f+15Pzv9fuc2/vR7v2V2Pvd6/bg9P7I6/285/2y4/yp3/zp8vk8i8kqgMT7/P31+fyv4vxGkcz6/P6/6P3j7vfS5PNnpNUxhcbO7f7F6v3O4vHK3/DA2u631Ouy0eqXweKJud5wqthfoNMMbLvY8f73+v2dxeR8sNtTmdDx9/zX6PSjyeaCtd1YnNGX2PuQveCGt95Nls42h8dLlM3F4vBtAAAAM3RSTlMAAyOx0/sKBvik8opWGBMOAe3l1snDm2E9LSb06eHcu5JpHbarfHZCN9CBb08zzkdNS0kYaptYAAAFV0lEQVRYw92X51/aYBDHHS2O2qqttVbrqNq9m+TJIAYIShBkWwqIiCgoWvfeq7Z2/s29hyQNyUcR7LveGwVyXy6XH8/9rqxglLfUPLxVduUor3h0rfp2TYvpivk37929TkG037hffoX0+peVtZQc1589rigVUdXS/ABSAyEmGIO/1XfvldSK8vs3OqB6u3m0nxmIrvgB0dj7rr7Y9IbuF68hnfFaiHA/sxqm0wciIG43P60qKv9WXWc1RXGh/mFESFABTSBi0sNAKzqet17eCtOb3kZIDwxEEU0oAIJGYxNBDhBND29e0rtXXbcpuPmED9IhEAAQ/AXEaF8EPmnrrKsv0LvWR3fg5sWDNAFZOgAgaKvZDogHNU9MFwnnYROkc56RD5CjAbQX9Ow4g7upCsvYu55aSI/Nj0H1akgKQEUM94dwK65hYRmFU9MIcH/fqJYOZYcnuJSU/waKDgTOEVaVKhwrTRP5XzgSpAITYzom7UvkhFX5VutmxeNnWDjjswTKTyfgluNDGbUpWissXhF3s7mlSml+czWkg3D0l1nNjGNjz3myOQOa1KM/jOS6ebdbAVTCi4gljHSFrviza7tOgRWcS0MOUX9zdNgag5w7rRqA44Lzw0hr1WqES36dFliSJFlh2rXIae3FFcDDgKdxrUIDePr8jGcSClV1u7A9xeN0ModY/pHMxmR1EzRh8TJiwqsHmKW0l4FCEZI+jHio+JdPPE9qwQtTRxku2D8sIeRL2LnxWSllANCQGOIiqVHAz2ye2JR0DcH+HoxDkaADLjgxjKQ+AwCX/g0+DNgdG0ukYCONAe+dbc2IAc6fwt1ARoDSezNHxV2Cmzwv3O6lDMV55edBGwGK9n1+x2F8EDfAGCxug8MhpsMEcTEAWf3rx2vZhe/LAmtIn/6apE6PN0ULKgywD9mmdxbmFl3OvD5AS5fW5zLbv/YHmcsBTjf/afDz3MaZTVCfAP9z6/Bw6ycv8EUBWJIn9zYcoAWWlW9+OzO3vkTy8H+RANLmdrpOuYWdZYEXpo+TlCJrW5EARb7fF+bWdqf3hhyZI1nWJQHgznErZhbjoEsWqi8dQNoE294aldzFurwSABL2XXMf9+H1VQGke9exw5P/AnA5Pv5ngMul7LOvO922iwACu8WkCwLCafvM4CeWPxfA8lNHcWZSoi8EwMAIciKX2Z4SWCMAa3snCZ/G4EA8D6CMLNFsGQhkkz/gQNEBbPCbWsxGUpYVu3z8IyNAknwJkfPMEhLyrdi5RTyUVACkw4GSFRNWJNEW+fgPGwHD8/JxnRuLabN4CGNRkAE23na2+VmEAUmrYymSGjMAYqH84YUIyzgzs3XC7gNgH36Vcc4zKY9o9fgPBXUAiHHwVboBHGLiX6Zcjp1f2wu4tvzZKo0ecPnDtQYDQvJXaBeNzce45Fp28ZQLrEZVuFqgBwOalArKXnW1UzlnSusQKJqKYNuz4tOnI6sZG4zanpemv+7ySU2jbA9h6uhcgpfy6G2PahirDZ6zvq6zDduMVFTKvzw8wgyEdelwY9in3XkEPs3osJuwRQ4qTkfzifndg9Gfc4pdsu82+tTnHZTBa2EAMrqr2t43pguc8tNm7JQVQ2S0ukj2d22dhXYP0/veWtwKrCkNoNimAN5+Xr/oLrxswKbVJjteWrX7eR63o4j9q0GxnaBdWgGA5VStpanIjQmEhV0/nVt5VOFUvix6awJhPcAaTEShgrG+iGyvb5a0Ndb1YGHFPEwoqAinoaykaID1o1pdPNu7XsnCKQ3R+hwWIIhGvORcJUBYXe3Xa3vq/mF/N9V13ugufMkfXn+KHsRD0B8AAAAASUVORK5CYII=" type="image/x-icon" />
|
|
8
8
|
|
|
9
9
|
<script>
|