Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

tsparticles-shape-image

Package Overview
Dependencies
Maintainers
2
Versions
53
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

tsparticles-shape-image - npm Package Compare versions

Comparing version 2.10.1 to 2.11.0

browser/GifUtils/ByteStream.js

91

browser/ImageDrawer.js

@@ -10,2 +10,3 @@ import { errorPrefix } from "tsparticles-engine";

await this._engine.loadImage({
gif: imageShape.gif,
name: imageShape.name,

@@ -24,13 +25,84 @@ replaceColor: imageShape.replaceColor ?? imageShape.replace_color ?? false,

}
draw(context, particle, radius, opacity) {
draw(context, particle, radius, opacity, delta) {
const image = particle.image, element = image?.element;
if (!element) {
if (!image) {
return;
}
const ratio = image?.ratio ?? 1, pos = {
x: -radius,
y: -radius,
};
context.globalAlpha = opacity;
context.drawImage(element, pos.x, pos.y, radius * 2, (radius * 2) / ratio);
if (image.gif && image.gifData) {
const offscreenCanvas = new OffscreenCanvas(image.gifData.width, image.gifData.height), offscreenContext = offscreenCanvas.getContext("2d");
if (!offscreenContext) {
throw new Error("could not create offscreen canvas context");
}
offscreenContext.imageSmoothingQuality = "low";
offscreenContext.imageSmoothingEnabled = false;
offscreenContext.clearRect(0, 0, offscreenCanvas.width, offscreenCanvas.height);
if (particle.gifLoopCount === undefined) {
particle.gifLoopCount = image.gifLoopCount ?? 0;
}
let frameIndex = particle.gifFrame ?? 0;
const pos = { x: -image.gifData.width * 0.5, y: -image.gifData.height * 0.5 }, frame = image.gifData.frames[frameIndex];
if (particle.gifTime === undefined) {
particle.gifTime = 0;
}
if (!frame.bitmap) {
return;
}
context.scale(radius / image.gifData.width, radius / image.gifData.height);
switch (frame.disposalMethod) {
case 4:
case 5:
case 6:
case 7:
case 0:
offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
context.drawImage(offscreenCanvas, pos.x, pos.y);
offscreenContext.clearRect(0, 0, offscreenCanvas.width, offscreenCanvas.height);
break;
case 1:
offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
context.drawImage(offscreenCanvas, pos.x, pos.y);
break;
case 2:
offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
context.drawImage(offscreenCanvas, pos.x, pos.y);
offscreenContext.clearRect(0, 0, offscreenCanvas.width, offscreenCanvas.height);
if (image.gifData.globalColorTable.length === 0) {
offscreenContext.putImageData(image.gifData.frames[0].image, pos.x + frame.left, pos.y + frame.top);
}
else {
offscreenContext.putImageData(image.gifData.backgroundImage, pos.x, pos.y);
}
break;
case 3:
{
const previousImageData = offscreenContext.getImageData(0, 0, offscreenCanvas.width, offscreenCanvas.height);
offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
context.drawImage(offscreenCanvas, pos.x, pos.y);
offscreenContext.clearRect(0, 0, offscreenCanvas.width, offscreenCanvas.height);
offscreenContext.putImageData(previousImageData, 0, 0);
}
break;
}
particle.gifTime += delta.value;
if (particle.gifTime > frame.delayTime) {
particle.gifTime -= frame.delayTime;
if (++frameIndex >= image.gifData.frames.length) {
if (--particle.gifLoopCount <= 0) {
return;
}
frameIndex = 0;
offscreenContext.clearRect(0, 0, offscreenCanvas.width, offscreenCanvas.height);
}
particle.gifFrame = frameIndex;
}
context.scale(image.gifData.width / radius, image.gifData.height / radius);
}
else if (element) {
const ratio = image.ratio, pos = {
x: -radius,
y: -radius,
};
context.drawImage(element, pos.x, pos.y, radius * 2, (radius * 2) / ratio);
}
context.globalAlpha = 1;

@@ -47,3 +119,3 @@ }

for (const imageData of options.preload) {
this._engine.loadImage(imageData);
await this._engine.loadImage(imageData);
}

@@ -93,2 +165,5 @@ }

element: image.element,
gif: image.gif,
gifData: image.gifData,
gifLoopCount: image.gifLoopCount,
loaded: true,

@@ -95,0 +170,0 @@ ratio: imageData.width && imageData.height ? imageData.width / imageData.height : image.ratio ?? 1,

71

browser/index.js

@@ -1,39 +0,44 @@

import { downloadSvgImage, loadImage } from "./Utils";
import { downloadSvgImage, loadGifImage, loadImage } from "./Utils";
import { ImageDrawer } from "./ImageDrawer";
import { ImagePreloaderPlugin } from "./ImagePreloader";
import { errorPrefix } from "tsparticles-engine";
export async function loadImageShape(engine) {
if (!engine.loadImage) {
engine.loadImage = async (data) => {
if (!data.name && !data.src) {
throw new Error(`${errorPrefix} no image source provided`);
}
if (!engine.images) {
engine.images = [];
}
if (engine.images.find((t) => t.name === data.name || t.source === data.src)) {
return;
}
try {
const image = {
name: data.name ?? data.src,
source: data.src,
type: data.src.substring(data.src.length - 3),
error: false,
loading: true,
replaceColor: data.replaceColor,
ratio: data.width && data.height ? data.width / data.height : undefined,
};
engine.images.push(image);
const imageFunc = data.replaceColor ? downloadSvgImage : loadImage;
await imageFunc(image);
}
catch {
throw new Error(`${errorPrefix} ${data.name ?? data.src} not found`);
}
};
function addLoadImageToEngine(engine) {
if (engine.loadImage) {
return;
}
engine.loadImage = async (data) => {
if (!data.name && !data.src) {
throw new Error(`${errorPrefix} no image source provided`);
}
if (!engine.images) {
engine.images = [];
}
if (engine.images.find((t) => t.name === data.name || t.source === data.src)) {
return;
}
try {
const image = {
gif: data.gif ?? false,
name: data.name ?? data.src,
source: data.src,
type: data.src.substring(data.src.length - 3),
error: false,
loading: true,
replaceColor: data.replaceColor,
ratio: data.width && data.height ? data.width / data.height : undefined,
};
engine.images.push(image);
const imageFunc = data.gif ? loadGifImage : data.replaceColor ? downloadSvgImage : loadImage;
await imageFunc(image);
}
catch {
throw new Error(`${errorPrefix} ${data.name ?? data.src} not found`);
}
};
}
export async function loadImageShape(engine, refresh = true) {
addLoadImageToEngine(engine);
const preloader = new ImagePreloaderPlugin(engine);
await engine.addPlugin(preloader);
await engine.addShape(["image", "images"], new ImageDrawer(engine));
await engine.addPlugin(preloader, refresh);
await engine.addShape(["image", "images"], new ImageDrawer(engine), refresh);
}
export class Preload {
constructor() {
this.src = "";
this.gif = false;
}

@@ -9,2 +10,5 @@ load(data) {

}
if (data.gif !== undefined) {
this.gif = data.gif;
}
if (data.height !== undefined) {

@@ -11,0 +15,0 @@ this.height = data.height;

@@ -1,2 +0,3 @@

import { errorPrefix, getStyleFromHsl } from "tsparticles-engine";
import { errorPrefix, getLogger, getStyleFromHsl } from "tsparticles-engine";
import { decodeGIF, getGIFLoopAmount } from "./GifUtils/Utils";
const currentColorRegex = /(#(?:[0-9a-f]{2}){2,4}|(#[0-9a-f]{3})|(rgb|hsl)a?\((-?\d+%?[,\s]+){2,3}\s*[\d.]+%?\))|currentcolor/gi;

@@ -28,3 +29,3 @@ function replaceColorSvg(imageShape, color, opacity) {

image.loading = false;
console.error(`${errorPrefix} loading image: ${image.source}`);
getLogger().error(`${errorPrefix} loading image: ${image.source}`);
resolve();

@@ -35,2 +36,20 @@ });

}
export async function loadGifImage(image) {
if (image.type !== "gif") {
await loadImage(image);
return;
}
image.loading = true;
try {
image.gifData = await decodeGIF(image.source);
image.gifLoopCount = getGIFLoopAmount(image.gifData) ?? 0;
if (image.gifLoopCount === 0) {
image.gifLoopCount = Infinity;
}
}
catch {
image.error = true;
}
image.loading = false;
}
export async function downloadSvgImage(image) {

@@ -44,6 +63,6 @@ if (image.type !== "svg") {

if (!response.ok) {
console.error(`${errorPrefix} Image not found`);
getLogger().error(`${errorPrefix} Image not found`);
image.error = true;
}
if (!image.error) {
else {
image.svgData = await response.text();

@@ -56,2 +75,3 @@ }

color,
gif: imageData.gif,
data: {

@@ -58,0 +78,0 @@ ...image,

@@ -13,2 +13,3 @@ "use strict";

await this._engine.loadImage({
gif: imageShape.gif,
name: imageShape.name,

@@ -27,13 +28,84 @@ replaceColor: imageShape.replaceColor ?? imageShape.replace_color ?? false,

}
draw(context, particle, radius, opacity) {
draw(context, particle, radius, opacity, delta) {
const image = particle.image, element = image?.element;
if (!element) {
if (!image) {
return;
}
const ratio = image?.ratio ?? 1, pos = {
x: -radius,
y: -radius,
};
context.globalAlpha = opacity;
context.drawImage(element, pos.x, pos.y, radius * 2, (radius * 2) / ratio);
if (image.gif && image.gifData) {
const offscreenCanvas = new OffscreenCanvas(image.gifData.width, image.gifData.height), offscreenContext = offscreenCanvas.getContext("2d");
if (!offscreenContext) {
throw new Error("could not create offscreen canvas context");
}
offscreenContext.imageSmoothingQuality = "low";
offscreenContext.imageSmoothingEnabled = false;
offscreenContext.clearRect(0, 0, offscreenCanvas.width, offscreenCanvas.height);
if (particle.gifLoopCount === undefined) {
particle.gifLoopCount = image.gifLoopCount ?? 0;
}
let frameIndex = particle.gifFrame ?? 0;
const pos = { x: -image.gifData.width * 0.5, y: -image.gifData.height * 0.5 }, frame = image.gifData.frames[frameIndex];
if (particle.gifTime === undefined) {
particle.gifTime = 0;
}
if (!frame.bitmap) {
return;
}
context.scale(radius / image.gifData.width, radius / image.gifData.height);
switch (frame.disposalMethod) {
case 4:
case 5:
case 6:
case 7:
case 0:
offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
context.drawImage(offscreenCanvas, pos.x, pos.y);
offscreenContext.clearRect(0, 0, offscreenCanvas.width, offscreenCanvas.height);
break;
case 1:
offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
context.drawImage(offscreenCanvas, pos.x, pos.y);
break;
case 2:
offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
context.drawImage(offscreenCanvas, pos.x, pos.y);
offscreenContext.clearRect(0, 0, offscreenCanvas.width, offscreenCanvas.height);
if (image.gifData.globalColorTable.length === 0) {
offscreenContext.putImageData(image.gifData.frames[0].image, pos.x + frame.left, pos.y + frame.top);
}
else {
offscreenContext.putImageData(image.gifData.backgroundImage, pos.x, pos.y);
}
break;
case 3:
{
const previousImageData = offscreenContext.getImageData(0, 0, offscreenCanvas.width, offscreenCanvas.height);
offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
context.drawImage(offscreenCanvas, pos.x, pos.y);
offscreenContext.clearRect(0, 0, offscreenCanvas.width, offscreenCanvas.height);
offscreenContext.putImageData(previousImageData, 0, 0);
}
break;
}
particle.gifTime += delta.value;
if (particle.gifTime > frame.delayTime) {
particle.gifTime -= frame.delayTime;
if (++frameIndex >= image.gifData.frames.length) {
if (--particle.gifLoopCount <= 0) {
return;
}
frameIndex = 0;
offscreenContext.clearRect(0, 0, offscreenCanvas.width, offscreenCanvas.height);
}
particle.gifFrame = frameIndex;
}
context.scale(image.gifData.width / radius, image.gifData.height / radius);
}
else if (element) {
const ratio = image.ratio, pos = {
x: -radius,
y: -radius,
};
context.drawImage(element, pos.x, pos.y, radius * 2, (radius * 2) / ratio);
}
context.globalAlpha = 1;

@@ -50,3 +122,3 @@ }

for (const imageData of options.preload) {
this._engine.loadImage(imageData);
await this._engine.loadImage(imageData);
}

@@ -96,2 +168,5 @@ }

element: image.element,
gif: image.gif,
gifData: image.gifData,
gifLoopCount: image.gifLoopCount,
loaded: true,

@@ -98,0 +173,0 @@ ratio: imageData.width && imageData.height ? imageData.width / imageData.height : image.ratio ?? 1,

@@ -8,37 +8,42 @@ "use strict";

const tsparticles_engine_1 = require("tsparticles-engine");
async function loadImageShape(engine) {
if (!engine.loadImage) {
engine.loadImage = async (data) => {
if (!data.name && !data.src) {
throw new Error(`${tsparticles_engine_1.errorPrefix} no image source provided`);
}
if (!engine.images) {
engine.images = [];
}
if (engine.images.find((t) => t.name === data.name || t.source === data.src)) {
return;
}
try {
const image = {
name: data.name ?? data.src,
source: data.src,
type: data.src.substring(data.src.length - 3),
error: false,
loading: true,
replaceColor: data.replaceColor,
ratio: data.width && data.height ? data.width / data.height : undefined,
};
engine.images.push(image);
const imageFunc = data.replaceColor ? Utils_1.downloadSvgImage : Utils_1.loadImage;
await imageFunc(image);
}
catch {
throw new Error(`${tsparticles_engine_1.errorPrefix} ${data.name ?? data.src} not found`);
}
};
function addLoadImageToEngine(engine) {
if (engine.loadImage) {
return;
}
engine.loadImage = async (data) => {
if (!data.name && !data.src) {
throw new Error(`${tsparticles_engine_1.errorPrefix} no image source provided`);
}
if (!engine.images) {
engine.images = [];
}
if (engine.images.find((t) => t.name === data.name || t.source === data.src)) {
return;
}
try {
const image = {
gif: data.gif ?? false,
name: data.name ?? data.src,
source: data.src,
type: data.src.substring(data.src.length - 3),
error: false,
loading: true,
replaceColor: data.replaceColor,
ratio: data.width && data.height ? data.width / data.height : undefined,
};
engine.images.push(image);
const imageFunc = data.gif ? Utils_1.loadGifImage : data.replaceColor ? Utils_1.downloadSvgImage : Utils_1.loadImage;
await imageFunc(image);
}
catch {
throw new Error(`${tsparticles_engine_1.errorPrefix} ${data.name ?? data.src} not found`);
}
};
}
async function loadImageShape(engine, refresh = true) {
addLoadImageToEngine(engine);
const preloader = new ImagePreloader_1.ImagePreloaderPlugin(engine);
await engine.addPlugin(preloader);
await engine.addShape(["image", "images"], new ImageDrawer_1.ImageDrawer(engine));
await engine.addPlugin(preloader, refresh);
await engine.addShape(["image", "images"], new ImageDrawer_1.ImageDrawer(engine), refresh);
}
exports.loadImageShape = loadImageShape;

@@ -7,2 +7,3 @@ "use strict";

this.src = "";
this.gif = false;
}

@@ -13,2 +14,5 @@ load(data) {

}
if (data.gif !== undefined) {
this.gif = data.gif;
}
if (data.height !== undefined) {

@@ -15,0 +19,0 @@ this.height = data.height;

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.replaceImageColor = exports.downloadSvgImage = exports.loadImage = void 0;
exports.replaceImageColor = exports.downloadSvgImage = exports.loadGifImage = exports.loadImage = void 0;
const tsparticles_engine_1 = require("tsparticles-engine");
const Utils_1 = require("./GifUtils/Utils");
const currentColorRegex = /(#(?:[0-9a-f]{2}){2,4}|(#[0-9a-f]{3})|(rgb|hsl)a?\((-?\d+%?[,\s]+){2,3}\s*[\d.]+%?\))|currentcolor/gi;

@@ -31,3 +32,3 @@ function replaceColorSvg(imageShape, color, opacity) {

image.loading = false;
console.error(`${tsparticles_engine_1.errorPrefix} loading image: ${image.source}`);
(0, tsparticles_engine_1.getLogger)().error(`${tsparticles_engine_1.errorPrefix} loading image: ${image.source}`);
resolve();

@@ -39,2 +40,21 @@ });

exports.loadImage = loadImage;
async function loadGifImage(image) {
if (image.type !== "gif") {
await loadImage(image);
return;
}
image.loading = true;
try {
image.gifData = await (0, Utils_1.decodeGIF)(image.source);
image.gifLoopCount = (0, Utils_1.getGIFLoopAmount)(image.gifData) ?? 0;
if (image.gifLoopCount === 0) {
image.gifLoopCount = Infinity;
}
}
catch {
image.error = true;
}
image.loading = false;
}
exports.loadGifImage = loadGifImage;
async function downloadSvgImage(image) {

@@ -48,6 +68,6 @@ if (image.type !== "svg") {

if (!response.ok) {
console.error(`${tsparticles_engine_1.errorPrefix} Image not found`);
(0, tsparticles_engine_1.getLogger)().error(`${tsparticles_engine_1.errorPrefix} Image not found`);
image.error = true;
}
if (!image.error) {
else {
image.svgData = await response.text();

@@ -61,2 +81,3 @@ }

color,
gif: imageData.gif,
data: {

@@ -63,0 +84,0 @@ ...image,

@@ -10,2 +10,3 @@ import { errorPrefix } from "tsparticles-engine";

await this._engine.loadImage({
gif: imageShape.gif,
name: imageShape.name,

@@ -24,13 +25,84 @@ replaceColor: imageShape.replaceColor ?? imageShape.replace_color ?? false,

}
draw(context, particle, radius, opacity) {
draw(context, particle, radius, opacity, delta) {
const image = particle.image, element = image?.element;
if (!element) {
if (!image) {
return;
}
const ratio = image?.ratio ?? 1, pos = {
x: -radius,
y: -radius,
};
context.globalAlpha = opacity;
context.drawImage(element, pos.x, pos.y, radius * 2, (radius * 2) / ratio);
if (image.gif && image.gifData) {
const offscreenCanvas = new OffscreenCanvas(image.gifData.width, image.gifData.height), offscreenContext = offscreenCanvas.getContext("2d");
if (!offscreenContext) {
throw new Error("could not create offscreen canvas context");
}
offscreenContext.imageSmoothingQuality = "low";
offscreenContext.imageSmoothingEnabled = false;
offscreenContext.clearRect(0, 0, offscreenCanvas.width, offscreenCanvas.height);
if (particle.gifLoopCount === undefined) {
particle.gifLoopCount = image.gifLoopCount ?? 0;
}
let frameIndex = particle.gifFrame ?? 0;
const pos = { x: -image.gifData.width * 0.5, y: -image.gifData.height * 0.5 }, frame = image.gifData.frames[frameIndex];
if (particle.gifTime === undefined) {
particle.gifTime = 0;
}
if (!frame.bitmap) {
return;
}
context.scale(radius / image.gifData.width, radius / image.gifData.height);
switch (frame.disposalMethod) {
case 4:
case 5:
case 6:
case 7:
case 0:
offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
context.drawImage(offscreenCanvas, pos.x, pos.y);
offscreenContext.clearRect(0, 0, offscreenCanvas.width, offscreenCanvas.height);
break;
case 1:
offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
context.drawImage(offscreenCanvas, pos.x, pos.y);
break;
case 2:
offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
context.drawImage(offscreenCanvas, pos.x, pos.y);
offscreenContext.clearRect(0, 0, offscreenCanvas.width, offscreenCanvas.height);
if (image.gifData.globalColorTable.length === 0) {
offscreenContext.putImageData(image.gifData.frames[0].image, pos.x + frame.left, pos.y + frame.top);
}
else {
offscreenContext.putImageData(image.gifData.backgroundImage, pos.x, pos.y);
}
break;
case 3:
{
const previousImageData = offscreenContext.getImageData(0, 0, offscreenCanvas.width, offscreenCanvas.height);
offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
context.drawImage(offscreenCanvas, pos.x, pos.y);
offscreenContext.clearRect(0, 0, offscreenCanvas.width, offscreenCanvas.height);
offscreenContext.putImageData(previousImageData, 0, 0);
}
break;
}
particle.gifTime += delta.value;
if (particle.gifTime > frame.delayTime) {
particle.gifTime -= frame.delayTime;
if (++frameIndex >= image.gifData.frames.length) {
if (--particle.gifLoopCount <= 0) {
return;
}
frameIndex = 0;
offscreenContext.clearRect(0, 0, offscreenCanvas.width, offscreenCanvas.height);
}
particle.gifFrame = frameIndex;
}
context.scale(image.gifData.width / radius, image.gifData.height / radius);
}
else if (element) {
const ratio = image.ratio, pos = {
x: -radius,
y: -radius,
};
context.drawImage(element, pos.x, pos.y, radius * 2, (radius * 2) / ratio);
}
context.globalAlpha = 1;

@@ -47,3 +119,3 @@ }

for (const imageData of options.preload) {
this._engine.loadImage(imageData);
await this._engine.loadImage(imageData);
}

@@ -93,2 +165,5 @@ }

element: image.element,
gif: image.gif,
gifData: image.gifData,
gifLoopCount: image.gifLoopCount,
loaded: true,

@@ -95,0 +170,0 @@ ratio: imageData.width && imageData.height ? imageData.width / imageData.height : image.ratio ?? 1,

@@ -1,39 +0,44 @@

import { downloadSvgImage, loadImage } from "./Utils";
import { downloadSvgImage, loadGifImage, loadImage } from "./Utils";
import { ImageDrawer } from "./ImageDrawer";
import { ImagePreloaderPlugin } from "./ImagePreloader";
import { errorPrefix } from "tsparticles-engine";
export async function loadImageShape(engine) {
if (!engine.loadImage) {
engine.loadImage = async (data) => {
if (!data.name && !data.src) {
throw new Error(`${errorPrefix} no image source provided`);
}
if (!engine.images) {
engine.images = [];
}
if (engine.images.find((t) => t.name === data.name || t.source === data.src)) {
return;
}
try {
const image = {
name: data.name ?? data.src,
source: data.src,
type: data.src.substring(data.src.length - 3),
error: false,
loading: true,
replaceColor: data.replaceColor,
ratio: data.width && data.height ? data.width / data.height : undefined,
};
engine.images.push(image);
const imageFunc = data.replaceColor ? downloadSvgImage : loadImage;
await imageFunc(image);
}
catch {
throw new Error(`${errorPrefix} ${data.name ?? data.src} not found`);
}
};
function addLoadImageToEngine(engine) {
if (engine.loadImage) {
return;
}
engine.loadImage = async (data) => {
if (!data.name && !data.src) {
throw new Error(`${errorPrefix} no image source provided`);
}
if (!engine.images) {
engine.images = [];
}
if (engine.images.find((t) => t.name === data.name || t.source === data.src)) {
return;
}
try {
const image = {
gif: data.gif ?? false,
name: data.name ?? data.src,
source: data.src,
type: data.src.substring(data.src.length - 3),
error: false,
loading: true,
replaceColor: data.replaceColor,
ratio: data.width && data.height ? data.width / data.height : undefined,
};
engine.images.push(image);
const imageFunc = data.gif ? loadGifImage : data.replaceColor ? downloadSvgImage : loadImage;
await imageFunc(image);
}
catch {
throw new Error(`${errorPrefix} ${data.name ?? data.src} not found`);
}
};
}
export async function loadImageShape(engine, refresh = true) {
addLoadImageToEngine(engine);
const preloader = new ImagePreloaderPlugin(engine);
await engine.addPlugin(preloader);
await engine.addShape(["image", "images"], new ImageDrawer(engine));
await engine.addPlugin(preloader, refresh);
await engine.addShape(["image", "images"], new ImageDrawer(engine), refresh);
}
export class Preload {
constructor() {
this.src = "";
this.gif = false;
}

@@ -9,2 +10,5 @@ load(data) {

}
if (data.gif !== undefined) {
this.gif = data.gif;
}
if (data.height !== undefined) {

@@ -11,0 +15,0 @@ this.height = data.height;

@@ -1,2 +0,3 @@

import { errorPrefix, getStyleFromHsl } from "tsparticles-engine";
import { errorPrefix, getLogger, getStyleFromHsl } from "tsparticles-engine";
import { decodeGIF, getGIFLoopAmount } from "./GifUtils/Utils";
const currentColorRegex = /(#(?:[0-9a-f]{2}){2,4}|(#[0-9a-f]{3})|(rgb|hsl)a?\((-?\d+%?[,\s]+){2,3}\s*[\d.]+%?\))|currentcolor/gi;

@@ -28,3 +29,3 @@ function replaceColorSvg(imageShape, color, opacity) {

image.loading = false;
console.error(`${errorPrefix} loading image: ${image.source}`);
getLogger().error(`${errorPrefix} loading image: ${image.source}`);
resolve();

@@ -35,2 +36,20 @@ });

}
export async function loadGifImage(image) {
if (image.type !== "gif") {
await loadImage(image);
return;
}
image.loading = true;
try {
image.gifData = await decodeGIF(image.source);
image.gifLoopCount = getGIFLoopAmount(image.gifData) ?? 0;
if (image.gifLoopCount === 0) {
image.gifLoopCount = Infinity;
}
}
catch {
image.error = true;
}
image.loading = false;
}
export async function downloadSvgImage(image) {

@@ -44,6 +63,6 @@ if (image.type !== "svg") {

if (!response.ok) {
console.error(`${errorPrefix} Image not found`);
getLogger().error(`${errorPrefix} Image not found`);
image.error = true;
}
if (!image.error) {
else {
image.svgData = await response.text();

@@ -56,2 +75,3 @@ }

color,
gif: imageData.gif,
data: {

@@ -58,0 +78,0 @@ ...image,

{
"name": "tsparticles-shape-image",
"version": "2.10.1",
"version": "2.11.0",
"description": "tsParticles image shape",

@@ -48,5 +48,6 @@ "homepage": "https://particles.js.org",

"types": "types/index.d.ts",
"sideEffects": false,
"dependencies": {
"tsparticles-engine": "^2.10.1"
"tsparticles-engine": "^2.11.0"
}
}

@@ -28,8 +28,13 @@ [![banner](https://particles.js.org/images/banner2.png)](https://particles.js.org)

```javascript
loadImageShape(tsParticles);
(async () => {
await loadImageShape(tsParticles);
tsParticles.load("tsparticles", {
/* options */
/* here you can use particles.shape.type: "image" */
});
await tsParticles.load({
id: "tsparticles",
options: {
/* options */
/* here you can use particles.shape.type: "image" */
},
});
})();
```

@@ -57,3 +62,5 @@

loadImageShape(tsParticles);
(async () => {
await loadImageShape(tsParticles);
})();
```

@@ -67,3 +74,5 @@

loadImageShape(tsParticles);
(async () => {
await loadImageShape(tsParticles);
})();
```

@@ -7,3 +7,3 @@ /*!

* How to use? : Check the GitHub README
* v2.10.1
* v2.11.0
*/

@@ -100,4 +100,421 @@ (function webpackUniversalModuleDefinition(root, factory) {

var external_commonjs_tsparticles_engine_commonjs2_tsparticles_engine_amd_tsparticles_engine_root_window_ = __webpack_require__(961);
;// CONCATENATED MODULE: ./dist/browser/GifUtils/Constants.js
const InterlaceOffsets = [0, 4, 2, 1];
const InterlaceSteps = [8, 8, 4, 2];
;// CONCATENATED MODULE: ./dist/browser/GifUtils/ByteStream.js
class ByteStream {
constructor(bytes) {
this.pos = 0;
this.data = new Uint8ClampedArray(bytes);
}
getString(count) {
const slice = this.data.slice(this.pos, this.pos + count);
this.pos += slice.length;
return slice.reduce((acc, curr) => acc + String.fromCharCode(curr), "");
}
nextByte() {
return this.data[this.pos++];
}
nextTwoBytes() {
this.pos += 2;
return this.data[this.pos - 2] + (this.data[this.pos - 1] << 8);
}
readSubBlocks() {
let blockString = "",
size = 0;
do {
size = this.data[this.pos++];
for (let count = size; --count >= 0; blockString += String.fromCharCode(this.data[this.pos++])) {}
} while (size !== 0);
return blockString;
}
readSubBlocksBin() {
let size = 0,
len = 0;
for (let offset = 0; (size = this.data[this.pos + offset]) !== 0; offset += size + 1) {
len += size;
}
const blockData = new Uint8Array(len);
for (let i = 0; (size = this.data[this.pos++]) !== 0;) {
for (let count = size; --count >= 0; blockData[i++] = this.data[this.pos++]) {}
}
return blockData;
}
skipSubBlocks() {
for (; this.data[this.pos] !== 0; this.pos += this.data[this.pos] + 1) {}
this.pos++;
}
}
;// CONCATENATED MODULE: ./dist/browser/GifUtils/Utils.js
function parseColorTable(byteStream, count) {
const colors = [];
for (let i = 0; i < count; i++) {
colors.push({
r: byteStream.data[byteStream.pos],
g: byteStream.data[byteStream.pos + 1],
b: byteStream.data[byteStream.pos + 2]
});
byteStream.pos += 3;
}
return colors;
}
async function parseExtensionBlock(byteStream, gif, getFrameIndex, getTransparencyIndex) {
switch (byteStream.nextByte()) {
case 249:
{
const frame = gif.frames[getFrameIndex(false)];
byteStream.pos++;
const packedByte = byteStream.nextByte();
frame.GCreserved = (packedByte & 0xe0) >>> 5;
frame.disposalMethod = (packedByte & 0x1c) >>> 2;
frame.userInputDelayFlag = (packedByte & 2) === 2;
const transparencyFlag = (packedByte & 1) === 1;
frame.delayTime = byteStream.nextTwoBytes() * 0xa;
const transparencyIndex = byteStream.nextByte();
if (transparencyFlag) {
getTransparencyIndex(transparencyIndex);
}
byteStream.pos++;
break;
}
case 255:
{
byteStream.pos++;
const applicationExtension = {
identifier: byteStream.getString(8),
authenticationCode: byteStream.getString(3),
data: byteStream.readSubBlocksBin()
};
gif.applicationExtensions.push(applicationExtension);
break;
}
case 254:
{
gif.comments.push([getFrameIndex(false), byteStream.readSubBlocks()]);
break;
}
case 1:
{
if (gif.globalColorTable.length === 0) {
throw new EvalError("plain text extension without global color table");
}
byteStream.pos++;
gif.frames[getFrameIndex(false)].plainTextData = {
left: byteStream.nextTwoBytes(),
top: byteStream.nextTwoBytes(),
width: byteStream.nextTwoBytes(),
height: byteStream.nextTwoBytes(),
charSize: {
width: byteStream.nextTwoBytes(),
height: byteStream.nextTwoBytes()
},
foregroundColor: byteStream.nextByte(),
backgroundColor: byteStream.nextByte(),
text: byteStream.readSubBlocks()
};
break;
}
default:
byteStream.skipSubBlocks();
break;
}
}
async function parseImageBlock(byteStream, gif, avgAlpha, getFrameIndex, getTransparencyIndex, progressCallback) {
const frame = gif.frames[getFrameIndex(true)];
frame.left = byteStream.nextTwoBytes();
frame.top = byteStream.nextTwoBytes();
frame.width = byteStream.nextTwoBytes();
frame.height = byteStream.nextTwoBytes();
const packedByte = byteStream.nextByte(),
localColorTableFlag = (packedByte & 0x80) === 0x80,
interlacedFlag = (packedByte & 0x40) === 0x40;
frame.sortFlag = (packedByte & 0x20) === 0x20;
frame.reserved = (packedByte & 0x18) >>> 3;
const localColorCount = 1 << (packedByte & 7) + 1;
if (localColorTableFlag) {
frame.localColorTable = parseColorTable(byteStream, localColorCount);
}
const getColor = index => {
const {
r,
g,
b
} = (localColorTableFlag ? frame.localColorTable : gif.globalColorTable)[index];
return {
r,
g,
b,
a: index === getTransparencyIndex(null) ? avgAlpha ? ~~((r + g + b) / 3) : 0 : 255
};
};
const image = (() => {
try {
return new ImageData(frame.width, frame.height, {
colorSpace: "srgb"
});
} catch (error) {
if (error instanceof DOMException && error.name === "IndexSizeError") {
return null;
}
throw error;
}
})();
if (image == null) {
throw new EvalError("GIF frame size is to large");
}
const minCodeSize = byteStream.nextByte(),
imageData = byteStream.readSubBlocksBin(),
clearCode = 1 << minCodeSize;
const readBits = (pos, len) => {
const bytePos = pos >>> 3,
bitPos = pos & 7;
return (imageData[bytePos] + (imageData[bytePos + 1] << 8) + (imageData[bytePos + 2] << 16) & (1 << len) - 1 << bitPos) >>> bitPos;
};
if (interlacedFlag) {
for (let code = 0, size = minCodeSize + 1, pos = 0, dic = [[0]], pass = 0; pass < 4; pass++) {
if (InterlaceOffsets[pass] < frame.height) {
for (let pixelPos = 0, lineIndex = 0;;) {
const last = code;
code = readBits(pos, size);
pos += size + 1;
if (code === clearCode) {
size = minCodeSize + 1;
dic.length = clearCode + 2;
for (let i = 0; i < dic.length; i++) {
dic[i] = i < clearCode ? [i] : [];
}
} else {
if (code >= dic.length) {
dic.push(dic[last].concat(dic[last][0]));
} else if (last !== clearCode) {
dic.push(dic[last].concat(dic[code][0]));
}
for (let i = 0; i < dic[code].length; i++) {
const {
r,
g,
b,
a
} = getColor(dic[code][i]);
image.data.set([r, g, b, a], InterlaceOffsets[pass] * frame.width + InterlaceSteps[pass] * lineIndex + pixelPos % (frame.width * 4));
pixelPos += 4;
}
if (dic.length === 1 << size && size < 0xc) {
size++;
}
}
if (pixelPos === frame.width * 4 * (lineIndex + 1)) {
lineIndex++;
if (InterlaceOffsets[pass] + InterlaceSteps[pass] * lineIndex >= frame.height) {
break;
}
}
}
}
progressCallback?.(byteStream.pos / (byteStream.data.length - 1), getFrameIndex(false) + 1, image, {
x: frame.left,
y: frame.top
}, {
width: gif.width,
height: gif.height
});
}
frame.image = image;
frame.bitmap = await createImageBitmap(image);
} else {
for (let code = 0, size = minCodeSize + 1, pos = 0, dic = [[0]], pixelPos = -4;;) {
const last = code;
code = readBits(pos, size);
pos += size;
if (code === clearCode) {
size = minCodeSize + 1;
dic.length = clearCode + 2;
for (let i = 0; i < dic.length; i++) {
dic[i] = i < clearCode ? [i] : [];
}
} else {
if (code === clearCode + 1) {
break;
}
if (code >= dic.length) {
dic.push(dic[last].concat(dic[last][0]));
} else if (last !== clearCode) {
dic.push(dic[last].concat(dic[code][0]));
}
for (let i = 0; i < dic[code].length; i++) {
const {
r,
g,
b,
a
} = getColor(dic[code][i]);
image.data.set([r, g, b, a], pixelPos += 4);
}
if (dic.length >= 1 << size && size < 0xc) {
size++;
}
}
}
frame.image = image;
frame.bitmap = await createImageBitmap(image);
progressCallback?.((byteStream.pos + 1) / byteStream.data.length, getFrameIndex(false) + 1, frame.image, {
x: frame.left,
y: frame.top
}, {
width: gif.width,
height: gif.height
});
}
}
async function parseBlock(byteStream, gif, avgAlpha, getFrameIndex, getTransparencyIndex, progressCallback) {
switch (byteStream.nextByte()) {
case 59:
return true;
case 44:
await parseImageBlock(byteStream, gif, avgAlpha, getFrameIndex, getTransparencyIndex, progressCallback);
break;
case 33:
await parseExtensionBlock(byteStream, gif, getFrameIndex, getTransparencyIndex);
break;
default:
throw new EvalError("undefined block found");
}
return false;
}
function getGIFLoopAmount(gif) {
for (const extension of gif.applicationExtensions) {
if (extension.identifier + extension.authenticationCode !== "NETSCAPE2.0") {
continue;
}
return extension.data[1] + (extension.data[2] << 8);
}
return NaN;
}
async function decodeGIF(gifURL, progressCallback, avgAlpha) {
if (!avgAlpha) avgAlpha = false;
const res = await fetch(gifURL);
if (!res.ok && res.status === 404) {
throw new EvalError("file not found");
}
const buffer = await res.arrayBuffer();
const gif = {
width: 0,
height: 0,
totalTime: 0,
colorRes: 0,
pixelAspectRatio: 0,
frames: [],
sortFlag: false,
globalColorTable: [],
backgroundImage: new ImageData(1, 1, {
colorSpace: "srgb"
}),
comments: [],
applicationExtensions: []
},
byteStream = new ByteStream(new Uint8ClampedArray(buffer));
if (byteStream.getString(6) !== "GIF89a") {
throw new Error("not a supported GIF file");
}
gif.width = byteStream.nextTwoBytes();
gif.height = byteStream.nextTwoBytes();
const packedByte = byteStream.nextByte(),
globalColorTableFlag = (packedByte & 0x80) === 0x80;
gif.colorRes = (packedByte & 0x70) >>> 4;
gif.sortFlag = (packedByte & 8) === 8;
const globalColorCount = 1 << (packedByte & 7) + 1,
backgroundColorIndex = byteStream.nextByte();
gif.pixelAspectRatio = byteStream.nextByte();
if (gif.pixelAspectRatio !== 0) {
gif.pixelAspectRatio = (gif.pixelAspectRatio + 0xf) / 0x40;
}
if (globalColorTableFlag) {
gif.globalColorTable = parseColorTable(byteStream, globalColorCount);
}
const backgroundImage = (() => {
try {
return new ImageData(gif.width, gif.height, {
colorSpace: "srgb"
});
} catch (error) {
if (error instanceof DOMException && error.name === "IndexSizeError") {
return null;
}
throw error;
}
})();
if (backgroundImage == null) {
throw new Error("GIF frame size is to large");
}
const {
r,
g,
b
} = gif.globalColorTable[backgroundColorIndex];
backgroundImage.data.set(globalColorTableFlag ? [r, g, b, 255] : [0, 0, 0, 0]);
for (let i = 4; i < backgroundImage.data.length; i *= 2) {
backgroundImage.data.copyWithin(i, 0, i);
}
gif.backgroundImage = backgroundImage;
let frameIndex = -1,
incrementFrameIndex = true,
transparencyIndex = -1;
const getframeIndex = increment => {
if (increment) {
incrementFrameIndex = true;
}
return frameIndex;
};
const getTransparencyIndex = newValue => {
if (newValue != null) {
transparencyIndex = newValue;
}
return transparencyIndex;
};
try {
do {
if (incrementFrameIndex) {
gif.frames.push({
left: 0,
top: 0,
width: 0,
height: 0,
disposalMethod: 0,
image: new ImageData(1, 1, {
colorSpace: "srgb"
}),
plainTextData: null,
userInputDelayFlag: false,
delayTime: 0,
sortFlag: false,
localColorTable: [],
reserved: 0,
GCreserved: 0
});
frameIndex++;
transparencyIndex = -1;
incrementFrameIndex = false;
}
} while (!(await parseBlock(byteStream, gif, avgAlpha, getframeIndex, getTransparencyIndex, progressCallback)));
gif.frames.length--;
for (const frame of gif.frames) {
if (frame.userInputDelayFlag && frame.delayTime === 0) {
gif.totalTime = Infinity;
break;
}
gif.totalTime += frame.delayTime;
}
return gif;
} catch (error) {
if (error instanceof EvalError) {
throw new Error(`error while parsing frame ${frameIndex} "${error.message}"`);
}
throw error;
}
}
;// CONCATENATED MODULE: ./dist/browser/Utils.js
const currentColorRegex = /(#(?:[0-9a-f]{2}){2,4}|(#[0-9a-f]{3})|(rgb|hsl)a?\((-?\d+%?[,\s]+){2,3}\s*[\d.]+%?\))|currentcolor/gi;

@@ -131,3 +548,3 @@ function replaceColorSvg(imageShape, color, opacity) {

image.loading = false;
console.error(`${external_commonjs_tsparticles_engine_commonjs2_tsparticles_engine_amd_tsparticles_engine_root_window_.errorPrefix} loading image: ${image.source}`);
(0,external_commonjs_tsparticles_engine_commonjs2_tsparticles_engine_amd_tsparticles_engine_root_window_.getLogger)().error(`${external_commonjs_tsparticles_engine_commonjs2_tsparticles_engine_amd_tsparticles_engine_root_window_.errorPrefix} loading image: ${image.source}`);
resolve();

@@ -138,2 +555,19 @@ });

}
async function loadGifImage(image) {
if (image.type !== "gif") {
await loadImage(image);
return;
}
image.loading = true;
try {
image.gifData = await decodeGIF(image.source);
image.gifLoopCount = getGIFLoopAmount(image.gifData) ?? 0;
if (image.gifLoopCount === 0) {
image.gifLoopCount = Infinity;
}
} catch {
image.error = true;
}
image.loading = false;
}
async function downloadSvgImage(image) {

@@ -147,6 +581,5 @@ if (image.type !== "svg") {

if (!response.ok) {
console.error(`${external_commonjs_tsparticles_engine_commonjs2_tsparticles_engine_amd_tsparticles_engine_root_window_.errorPrefix} Image not found`);
(0,external_commonjs_tsparticles_engine_commonjs2_tsparticles_engine_amd_tsparticles_engine_root_window_.getLogger)().error(`${external_commonjs_tsparticles_engine_commonjs2_tsparticles_engine_amd_tsparticles_engine_root_window_.errorPrefix} Image not found`);
image.error = true;
}
if (!image.error) {
} else {
image.svgData = await response.text();

@@ -160,2 +593,3 @@ }

color,
gif: imageData.gif,
data: {

@@ -208,2 +642,3 @@ ...image,

await this._engine.loadImage({
gif: imageShape.gif,
name: imageShape.name,

@@ -222,15 +657,89 @@ replaceColor: imageShape.replaceColor ?? imageShape.replace_color ?? false,

}
draw(context, particle, radius, opacity) {
draw(context, particle, radius, opacity, delta) {
const image = particle.image,
element = image?.element;
if (!element) {
if (!image) {
return;
}
const ratio = image?.ratio ?? 1,
pos = {
x: -radius,
y: -radius
};
context.globalAlpha = opacity;
context.drawImage(element, pos.x, pos.y, radius * 2, radius * 2 / ratio);
if (image.gif && image.gifData) {
const offscreenCanvas = new OffscreenCanvas(image.gifData.width, image.gifData.height),
offscreenContext = offscreenCanvas.getContext("2d");
if (!offscreenContext) {
throw new Error("could not create offscreen canvas context");
}
offscreenContext.imageSmoothingQuality = "low";
offscreenContext.imageSmoothingEnabled = false;
offscreenContext.clearRect(0, 0, offscreenCanvas.width, offscreenCanvas.height);
if (particle.gifLoopCount === undefined) {
particle.gifLoopCount = image.gifLoopCount ?? 0;
}
let frameIndex = particle.gifFrame ?? 0;
const pos = {
x: -image.gifData.width * 0.5,
y: -image.gifData.height * 0.5
},
frame = image.gifData.frames[frameIndex];
if (particle.gifTime === undefined) {
particle.gifTime = 0;
}
if (!frame.bitmap) {
return;
}
context.scale(radius / image.gifData.width, radius / image.gifData.height);
switch (frame.disposalMethod) {
case 4:
case 5:
case 6:
case 7:
case 0:
offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
context.drawImage(offscreenCanvas, pos.x, pos.y);
offscreenContext.clearRect(0, 0, offscreenCanvas.width, offscreenCanvas.height);
break;
case 1:
offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
context.drawImage(offscreenCanvas, pos.x, pos.y);
break;
case 2:
offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
context.drawImage(offscreenCanvas, pos.x, pos.y);
offscreenContext.clearRect(0, 0, offscreenCanvas.width, offscreenCanvas.height);
if (image.gifData.globalColorTable.length === 0) {
offscreenContext.putImageData(image.gifData.frames[0].image, pos.x + frame.left, pos.y + frame.top);
} else {
offscreenContext.putImageData(image.gifData.backgroundImage, pos.x, pos.y);
}
break;
case 3:
{
const previousImageData = offscreenContext.getImageData(0, 0, offscreenCanvas.width, offscreenCanvas.height);
offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
context.drawImage(offscreenCanvas, pos.x, pos.y);
offscreenContext.clearRect(0, 0, offscreenCanvas.width, offscreenCanvas.height);
offscreenContext.putImageData(previousImageData, 0, 0);
}
break;
}
particle.gifTime += delta.value;
if (particle.gifTime > frame.delayTime) {
particle.gifTime -= frame.delayTime;
if (++frameIndex >= image.gifData.frames.length) {
if (--particle.gifLoopCount <= 0) {
return;
}
frameIndex = 0;
offscreenContext.clearRect(0, 0, offscreenCanvas.width, offscreenCanvas.height);
}
particle.gifFrame = frameIndex;
}
context.scale(image.gifData.width / radius, image.gifData.height / radius);
} else if (element) {
const ratio = image.ratio,
pos = {
x: -radius,
y: -radius
};
context.drawImage(element, pos.x, pos.y, radius * 2, radius * 2 / ratio);
}
context.globalAlpha = 1;

@@ -247,3 +756,3 @@ }

for (const imageData of options.preload) {
this._engine.loadImage(imageData);
await this._engine.loadImage(imageData);
}

@@ -296,2 +805,5 @@ }

element: image.element,
gif: image.gif,
gifData: image.gifData,
gifLoopCount: image.gifLoopCount,
loaded: true,

@@ -323,2 +835,3 @@ ratio: imageData.width && imageData.height ? imageData.width / imageData.height : image.ratio ?? 1,

this.src = "";
this.gif = false;
}

@@ -329,2 +842,5 @@ load(data) {

}
if (data.gif !== undefined) {
this.gif = data.gif;
}
if (data.height !== undefined) {

@@ -385,35 +901,40 @@ this.height = data.height;

async function loadImageShape(engine) {
if (!engine.loadImage) {
engine.loadImage = async data => {
if (!data.name && !data.src) {
throw new Error(`${external_commonjs_tsparticles_engine_commonjs2_tsparticles_engine_amd_tsparticles_engine_root_window_.errorPrefix} no image source provided`);
}
if (!engine.images) {
engine.images = [];
}
if (engine.images.find(t => t.name === data.name || t.source === data.src)) {
return;
}
try {
const image = {
name: data.name ?? data.src,
source: data.src,
type: data.src.substring(data.src.length - 3),
error: false,
loading: true,
replaceColor: data.replaceColor,
ratio: data.width && data.height ? data.width / data.height : undefined
};
engine.images.push(image);
const imageFunc = data.replaceColor ? downloadSvgImage : loadImage;
await imageFunc(image);
} catch {
throw new Error(`${external_commonjs_tsparticles_engine_commonjs2_tsparticles_engine_amd_tsparticles_engine_root_window_.errorPrefix} ${data.name ?? data.src} not found`);
}
};
function addLoadImageToEngine(engine) {
if (engine.loadImage) {
return;
}
engine.loadImage = async data => {
if (!data.name && !data.src) {
throw new Error(`${external_commonjs_tsparticles_engine_commonjs2_tsparticles_engine_amd_tsparticles_engine_root_window_.errorPrefix} no image source provided`);
}
if (!engine.images) {
engine.images = [];
}
if (engine.images.find(t => t.name === data.name || t.source === data.src)) {
return;
}
try {
const image = {
gif: data.gif ?? false,
name: data.name ?? data.src,
source: data.src,
type: data.src.substring(data.src.length - 3),
error: false,
loading: true,
replaceColor: data.replaceColor,
ratio: data.width && data.height ? data.width / data.height : undefined
};
engine.images.push(image);
const imageFunc = data.gif ? loadGifImage : data.replaceColor ? downloadSvgImage : loadImage;
await imageFunc(image);
} catch {
throw new Error(`${external_commonjs_tsparticles_engine_commonjs2_tsparticles_engine_amd_tsparticles_engine_root_window_.errorPrefix} ${data.name ?? data.src} not found`);
}
};
}
async function loadImageShape(engine, refresh = true) {
addLoadImageToEngine(engine);
const preloader = new ImagePreloaderPlugin(engine);
await engine.addPlugin(preloader);
await engine.addShape(["image", "images"], new ImageDrawer(engine));
await engine.addPlugin(preloader, refresh);
await engine.addShape(["image", "images"], new ImageDrawer(engine), refresh);
}

@@ -420,0 +941,0 @@ })();

/*! For license information please see tsparticles.shape.image.min.js.LICENSE.txt */
!function(e,r){if("object"==typeof exports&&"object"==typeof module)module.exports=r(require("tsparticles-engine"));else if("function"==typeof define&&define.amd)define(["tsparticles-engine"],r);else{var o="object"==typeof exports?r(require("tsparticles-engine")):r(e.window);for(var t in o)("object"==typeof exports?exports:e)[t]=o[t]}}(this,(e=>(()=>{"use strict";var r={961:r=>{r.exports=e}},o={};function t(e){var a=o[e];if(void 0!==a)return a.exports;var i=o[e]={exports:{}};return r[e](i,i.exports,t),i.exports}t.d=(e,r)=>{for(var o in r)t.o(r,o)&&!t.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:r[o]})},t.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),t.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var a={};return(()=>{t.r(a),t.d(a,{loadImageShape:()=>d});var e=t(961);const r=/(#(?:[0-9a-f]{2}){2,4}|(#[0-9a-f]{3})|(rgb|hsl)a?\((-?\d+%?[,\s]+){2,3}\s*[\d.]+%?\))|currentcolor/gi;async function o(r){return new Promise((o=>{r.loading=!0;const t=new Image;r.element=t,t.addEventListener("load",(()=>{r.loading=!1,o()})),t.addEventListener("error",(()=>{r.element=void 0,r.error=!0,r.loading=!1,console.error(`${e.errorPrefix} loading image: ${r.source}`),o()})),t.src=r.source}))}async function i(r){if("svg"!==r.type)return void await o(r);r.loading=!0;const t=await fetch(r.source);t.ok||(console.error(`${e.errorPrefix} Image not found`),r.error=!0),r.error||(r.svgData=await t.text()),r.loading=!1}function n(t,a,i,n){const s=function(o,t,a){const{svgData:i}=o;if(!i)return"";const n=(0,e.getStyleFromHsl)(t,a);if(i.includes("fill"))return i.replace(r,(()=>n));const s=i.indexOf(">");return`${i.substring(0,s)} fill="${n}"${i.substring(s)}`}(t,i,n.opacity?.value??1),l={color:i,data:{...t,svgData:s},loaded:!1,ratio:a.width/a.height,replaceColor:a.replaceColor??a.replace_color,source:a.src};return new Promise((e=>{const r=new Blob([s],{type:"image/svg+xml"}),a=URL||window.URL||window.webkitURL||window,i=a.createObjectURL(r),n=new Image;n.addEventListener("load",(()=>{l.loaded=!0,l.element=n,e(l),a.revokeObjectURL(i)})),n.addEventListener("error",(async()=>{a.revokeObjectURL(i);const r={...t,error:!1,loading:!0};await o(r),l.loaded=!0,l.element=r.element,e(l)})),n.src=i}))}class s{constructor(r){this.loadImageShape=async r=>{if(!this._engine.loadImage)throw new Error(`${e.errorPrefix} image shape not initialized`);await this._engine.loadImage({name:r.name,replaceColor:r.replaceColor??r.replace_color??!1,src:r.src})},this._engine=r}addImage(e){this._engine.images||(this._engine.images=[]),this._engine.images.push(e)}draw(e,r,o,t){const a=r.image,i=a?.element;if(!i)return;const n=a?.ratio??1,s={x:-o,y:-o};e.globalAlpha=t,e.drawImage(i,s.x,s.y,2*o,2*o/n),e.globalAlpha=1}getSidesCount(){return 12}async init(e){const r=e.actualOptions;if(r.preload&&this._engine.loadImage)for(const e of r.preload)this._engine.loadImage(e)}loadShape(e){if("image"!==e.shape&&"images"!==e.shape)return;this._engine.images||(this._engine.images=[]);const r=e.shapeData;this._engine.images.find((e=>e.name===r.name||e.source===r.src))||this.loadImageShape(r).then((()=>{this.loadShape(e)}))}particleInit(e,r){if("image"!==r.shape&&"images"!==r.shape)return;this._engine.images||(this._engine.images=[]);const o=this._engine.images,t=r.shapeData,a=r.getFillColor(),i=o.find((e=>e.name===t.name||e.source===t.src));if(!i)return;const s=t.replaceColor??t.replace_color??i.replaceColor;i.loading?setTimeout((()=>{this.particleInit(e,r)})):(async()=>{let e;e=i.svgData&&a?await n(i,t,a,r):{color:a,data:i,element:i.element,loaded:!0,ratio:t.width&&t.height?t.width/t.height:i.ratio??1,replaceColor:s,source:t.src},e.ratio||(e.ratio=1);const o={image:e,fill:t.fill??r.fill,close:t.close??r.close};r.image=o.image,r.fill=o.fill,r.close=o.close})()}}class l{constructor(){this.src=""}load(e){e&&(void 0!==e.height&&(this.height=e.height),void 0!==e.name&&(this.name=e.name),void 0!==e.replaceColor&&(this.replaceColor=e.replaceColor),void 0!==e.src&&(this.src=e.src),void 0!==e.width&&(this.width=e.width))}}class c{constructor(e){this.id="imagePreloader",this._engine=e}getPlugin(){return{}}loadOptions(e,r){if(!r||!r.preload)return;e.preload||(e.preload=[]);const o=e.preload;for(const e of r.preload){const r=o.find((r=>r.name===e.name||r.src===e.src));if(r)r.load(e);else{const r=new l;r.load(e),o.push(r)}}}needsPlugin(){return!0}}async function d(r){r.loadImage||(r.loadImage=async t=>{if(!t.name&&!t.src)throw new Error(`${e.errorPrefix} no image source provided`);if(r.images||(r.images=[]),!r.images.find((e=>e.name===t.name||e.source===t.src)))try{const e={name:t.name??t.src,source:t.src,type:t.src.substring(t.src.length-3),error:!1,loading:!0,replaceColor:t.replaceColor,ratio:t.width&&t.height?t.width/t.height:void 0};r.images.push(e);const a=t.replaceColor?i:o;await a(e)}catch{throw new Error(`${e.errorPrefix} ${t.name??t.src} not found`)}});const t=new c(r);await r.addPlugin(t),await r.addShape(["image","images"],new s(r))}})(),a})()));
!function(e,t){if("object"==typeof exports&&"object"==typeof module)module.exports=t(require("tsparticles-engine"));else if("function"==typeof define&&define.amd)define(["tsparticles-engine"],t);else{var a="object"==typeof exports?t(require("tsparticles-engine")):t(e.window);for(var o in a)("object"==typeof exports?exports:e)[o]=a[o]}}(this,(e=>(()=>{"use strict";var t={961:t=>{t.exports=e}},a={};function o(e){var i=a[e];if(void 0!==i)return i.exports;var r=a[e]={exports:{}};return t[e](r,r.exports,o),r.exports}o.d=(e,t)=>{for(var a in t)o.o(t,a)&&!o.o(e,a)&&Object.defineProperty(e,a,{enumerable:!0,get:t[a]})},o.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),o.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var i={};return(()=>{o.r(i),o.d(i,{loadImageShape:()=>u});var e=o(961);const t=[0,4,2,1],a=[8,8,4,2];class r{constructor(e){this.pos=0,this.data=new Uint8ClampedArray(e)}getString(e){const t=this.data.slice(this.pos,this.pos+e);return this.pos+=t.length,t.reduce(((e,t)=>e+String.fromCharCode(t)),"")}nextByte(){return this.data[this.pos++]}nextTwoBytes(){return this.pos+=2,this.data[this.pos-2]+(this.data[this.pos-1]<<8)}readSubBlocks(){let e="",t=0;do{t=this.data[this.pos++];for(let a=t;--a>=0;e+=String.fromCharCode(this.data[this.pos++]));}while(0!==t);return e}readSubBlocksBin(){let e=0,t=0;for(let a=0;0!==(e=this.data[this.pos+a]);a+=e+1)t+=e;const a=new Uint8Array(t);for(let t=0;0!==(e=this.data[this.pos++]);)for(let o=e;--o>=0;a[t++]=this.data[this.pos++]);return a}skipSubBlocks(){for(;0!==this.data[this.pos];this.pos+=this.data[this.pos]+1);this.pos++}}function n(e,t){const a=[];for(let o=0;o<t;o++)a.push({r:e.data[e.pos],g:e.data[e.pos+1],b:e.data[e.pos+2]}),e.pos+=3;return a}async function s(e,o,i,r,s,l){switch(e.nextByte()){case 59:return!0;case 44:await async function(e,o,i,r,s,l){const c=o.frames[r(!0)];c.left=e.nextTwoBytes(),c.top=e.nextTwoBytes(),c.width=e.nextTwoBytes(),c.height=e.nextTwoBytes();const g=e.nextByte(),h=128==(128&g),d=64==(64&g);c.sortFlag=32==(32&g),c.reserved=(24&g)>>>3;const f=1<<1+(7&g);h&&(c.localColorTable=n(e,f));const p=e=>{const{r:t,g:a,b:r}=(h?c.localColorTable:o.globalColorTable)[e];return{r:t,g:a,b:r,a:e===s(null)?i?~~((t+a+r)/3):0:255}},m=(()=>{try{return new ImageData(c.width,c.height,{colorSpace:"srgb"})}catch(e){if(e instanceof DOMException&&"IndexSizeError"===e.name)return null;throw e}})();if(null==m)throw new EvalError("GIF frame size is to large");const u=e.nextByte(),w=e.readSubBlocksBin(),y=1<<u,b=(e,t)=>{const a=e>>>3,o=7&e;return(w[a]+(w[a+1]<<8)+(w[a+2]<<16)&(1<<t)-1<<o)>>>o};if(d){for(let i=0,n=u+1,s=0,g=[[0]],h=0;h<4;h++){if(t[h]<c.height)for(let e=0,o=0;;){const r=i;if(i=b(s,n),s+=n+1,i===y){n=u+1,g.length=y+2;for(let e=0;e<g.length;e++)g[e]=e<y?[e]:[]}else{i>=g.length?g.push(g[r].concat(g[r][0])):r!==y&&g.push(g[r].concat(g[i][0]));for(let r=0;r<g[i].length;r++){const{r:n,g:s,b:l,a:d}=p(g[i][r]);m.data.set([n,s,l,d],t[h]*c.width+a[h]*o+e%(4*c.width)),e+=4}g.length===1<<n&&n<12&&n++}if(e===4*c.width*(o+1)&&(o++,t[h]+a[h]*o>=c.height))break}l?.(e.pos/(e.data.length-1),r(!1)+1,m,{x:c.left,y:c.top},{width:o.width,height:o.height})}c.image=m,c.bitmap=await createImageBitmap(m)}else{for(let e=0,t=u+1,a=0,o=[[0]],i=-4;;){const r=e;if(e=b(a,t),a+=t,e===y){t=u+1,o.length=y+2;for(let e=0;e<o.length;e++)o[e]=e<y?[e]:[]}else{if(e===y+1)break;e>=o.length?o.push(o[r].concat(o[r][0])):r!==y&&o.push(o[r].concat(o[e][0]));for(let t=0;t<o[e].length;t++){const{r:a,g:r,b:n,a:s}=p(o[e][t]);m.data.set([a,r,n,s],i+=4)}o.length>=1<<t&&t<12&&t++}}c.image=m,c.bitmap=await createImageBitmap(m),l?.((e.pos+1)/e.data.length,r(!1)+1,c.image,{x:c.left,y:c.top},{width:o.width,height:o.height})}}(e,o,i,r,s,l);break;case 33:await async function(e,t,a,o){switch(e.nextByte()){case 249:{const i=t.frames[a(!1)];e.pos++;const r=e.nextByte();i.GCreserved=(224&r)>>>5,i.disposalMethod=(28&r)>>>2,i.userInputDelayFlag=2==(2&r);const n=1==(1&r);i.delayTime=10*e.nextTwoBytes();const s=e.nextByte();n&&o(s),e.pos++;break}case 255:{e.pos++;const a={identifier:e.getString(8),authenticationCode:e.getString(3),data:e.readSubBlocksBin()};t.applicationExtensions.push(a);break}case 254:t.comments.push([a(!1),e.readSubBlocks()]);break;case 1:if(0===t.globalColorTable.length)throw new EvalError("plain text extension without global color table");e.pos++,t.frames[a(!1)].plainTextData={left:e.nextTwoBytes(),top:e.nextTwoBytes(),width:e.nextTwoBytes(),height:e.nextTwoBytes(),charSize:{width:e.nextTwoBytes(),height:e.nextTwoBytes()},foregroundColor:e.nextByte(),backgroundColor:e.nextByte(),text:e.readSubBlocks()};break;default:e.skipSubBlocks()}}(e,o,r,s);break;default:throw new EvalError("undefined block found")}return!1}const l=/(#(?:[0-9a-f]{2}){2,4}|(#[0-9a-f]{3})|(rgb|hsl)a?\((-?\d+%?[,\s]+){2,3}\s*[\d.]+%?\))|currentcolor/gi;async function c(t){return new Promise((a=>{t.loading=!0;const o=new Image;t.element=o,o.addEventListener("load",(()=>{t.loading=!1,a()})),o.addEventListener("error",(()=>{t.element=void 0,t.error=!0,t.loading=!1,(0,e.getLogger)().error(`${e.errorPrefix} loading image: ${t.source}`),a()})),o.src=t.source}))}async function g(e){if("gif"===e.type){e.loading=!0;try{e.gifData=await async function(e,t,a){a||(a=!1);const o=await fetch(e);if(!o.ok&&404===o.status)throw new EvalError("file not found");const i=await o.arrayBuffer(),l={width:0,height:0,totalTime:0,colorRes:0,pixelAspectRatio:0,frames:[],sortFlag:!1,globalColorTable:[],backgroundImage:new ImageData(1,1,{colorSpace:"srgb"}),comments:[],applicationExtensions:[]},c=new r(new Uint8ClampedArray(i));if("GIF89a"!==c.getString(6))throw new Error("not a supported GIF file");l.width=c.nextTwoBytes(),l.height=c.nextTwoBytes();const g=c.nextByte(),h=128==(128&g);l.colorRes=(112&g)>>>4,l.sortFlag=8==(8&g);const d=1<<1+(7&g),f=c.nextByte();l.pixelAspectRatio=c.nextByte(),0!==l.pixelAspectRatio&&(l.pixelAspectRatio=(l.pixelAspectRatio+15)/64),h&&(l.globalColorTable=n(c,d));const p=(()=>{try{return new ImageData(l.width,l.height,{colorSpace:"srgb"})}catch(e){if(e instanceof DOMException&&"IndexSizeError"===e.name)return null;throw e}})();if(null==p)throw new Error("GIF frame size is to large");const{r:m,g:u,b:w}=l.globalColorTable[f];p.data.set(h?[m,u,w,255]:[0,0,0,0]);for(let e=4;e<p.data.length;e*=2)p.data.copyWithin(e,0,e);l.backgroundImage=p;let y=-1,b=!0,x=-1;const v=e=>(e&&(b=!0),y),C=e=>(null!=e&&(x=e),x);try{do{b&&(l.frames.push({left:0,top:0,width:0,height:0,disposalMethod:0,image:new ImageData(1,1,{colorSpace:"srgb"}),plainTextData:null,userInputDelayFlag:!1,delayTime:0,sortFlag:!1,localColorTable:[],reserved:0,GCreserved:0}),y++,x=-1,b=!1)}while(!await s(c,l,a,v,C,t));l.frames.length--;for(const e of l.frames){if(e.userInputDelayFlag&&0===e.delayTime){l.totalTime=1/0;break}l.totalTime+=e.delayTime}return l}catch(e){if(e instanceof EvalError)throw new Error(`error while parsing frame ${y} "${e.message}"`);throw e}}(e.source),e.gifLoopCount=function(e){for(const t of e.applicationExtensions)if(t.identifier+t.authenticationCode==="NETSCAPE2.0")return t.data[1]+(t.data[2]<<8);return NaN}(e.gifData)??0,0===e.gifLoopCount&&(e.gifLoopCount=1/0)}catch{e.error=!0}e.loading=!1}else await c(e)}async function h(t){if("svg"!==t.type)return void await c(t);t.loading=!0;const a=await fetch(t.source);a.ok?t.svgData=await a.text():((0,e.getLogger)().error(`${e.errorPrefix} Image not found`),t.error=!0),t.loading=!1}function d(t,a,o,i){const r=function(t,a,o){const{svgData:i}=t;if(!i)return"";const r=(0,e.getStyleFromHsl)(a,o);if(i.includes("fill"))return i.replace(l,(()=>r));const n=i.indexOf(">");return`${i.substring(0,n)} fill="${r}"${i.substring(n)}`}(t,o,i.opacity?.value??1),n={color:o,gif:a.gif,data:{...t,svgData:r},loaded:!1,ratio:a.width/a.height,replaceColor:a.replaceColor??a.replace_color,source:a.src};return new Promise((e=>{const a=new Blob([r],{type:"image/svg+xml"}),o=URL||window.URL||window.webkitURL||window,i=o.createObjectURL(a),s=new Image;s.addEventListener("load",(()=>{n.loaded=!0,n.element=s,e(n),o.revokeObjectURL(i)})),s.addEventListener("error",(async()=>{o.revokeObjectURL(i);const a={...t,error:!1,loading:!0};await c(a),n.loaded=!0,n.element=a.element,e(n)})),s.src=i}))}class f{constructor(t){this.loadImageShape=async t=>{if(!this._engine.loadImage)throw new Error(`${e.errorPrefix} image shape not initialized`);await this._engine.loadImage({gif:t.gif,name:t.name,replaceColor:t.replaceColor??t.replace_color??!1,src:t.src})},this._engine=t}addImage(e){this._engine.images||(this._engine.images=[]),this._engine.images.push(e)}draw(e,t,a,o,i){const r=t.image,n=r?.element;if(r){if(e.globalAlpha=o,r.gif&&r.gifData){const o=new OffscreenCanvas(r.gifData.width,r.gifData.height),n=o.getContext("2d");if(!n)throw new Error("could not create offscreen canvas context");n.imageSmoothingQuality="low",n.imageSmoothingEnabled=!1,n.clearRect(0,0,o.width,o.height),void 0===t.gifLoopCount&&(t.gifLoopCount=r.gifLoopCount??0);let s=t.gifFrame??0;const l={x:.5*-r.gifData.width,y:.5*-r.gifData.height},c=r.gifData.frames[s];if(void 0===t.gifTime&&(t.gifTime=0),!c.bitmap)return;switch(e.scale(a/r.gifData.width,a/r.gifData.height),c.disposalMethod){case 4:case 5:case 6:case 7:case 0:n.drawImage(c.bitmap,c.left,c.top),e.drawImage(o,l.x,l.y),n.clearRect(0,0,o.width,o.height);break;case 1:n.drawImage(c.bitmap,c.left,c.top),e.drawImage(o,l.x,l.y);break;case 2:n.drawImage(c.bitmap,c.left,c.top),e.drawImage(o,l.x,l.y),n.clearRect(0,0,o.width,o.height),0===r.gifData.globalColorTable.length?n.putImageData(r.gifData.frames[0].image,l.x+c.left,l.y+c.top):n.putImageData(r.gifData.backgroundImage,l.x,l.y);break;case 3:{const t=n.getImageData(0,0,o.width,o.height);n.drawImage(c.bitmap,c.left,c.top),e.drawImage(o,l.x,l.y),n.clearRect(0,0,o.width,o.height),n.putImageData(t,0,0)}}if(t.gifTime+=i.value,t.gifTime>c.delayTime){if(t.gifTime-=c.delayTime,++s>=r.gifData.frames.length){if(--t.gifLoopCount<=0)return;s=0,n.clearRect(0,0,o.width,o.height)}t.gifFrame=s}e.scale(r.gifData.width/a,r.gifData.height/a)}else if(n){const t=r.ratio,o={x:-a,y:-a};e.drawImage(n,o.x,o.y,2*a,2*a/t)}e.globalAlpha=1}}getSidesCount(){return 12}async init(e){const t=e.actualOptions;if(t.preload&&this._engine.loadImage)for(const e of t.preload)await this._engine.loadImage(e)}loadShape(e){if("image"!==e.shape&&"images"!==e.shape)return;this._engine.images||(this._engine.images=[]);const t=e.shapeData;this._engine.images.find((e=>e.name===t.name||e.source===t.src))||this.loadImageShape(t).then((()=>{this.loadShape(e)}))}particleInit(e,t){if("image"!==t.shape&&"images"!==t.shape)return;this._engine.images||(this._engine.images=[]);const a=this._engine.images,o=t.shapeData,i=t.getFillColor(),r=a.find((e=>e.name===o.name||e.source===o.src));if(!r)return;const n=o.replaceColor??o.replace_color??r.replaceColor;r.loading?setTimeout((()=>{this.particleInit(e,t)})):(async()=>{let e;e=r.svgData&&i?await d(r,o,i,t):{color:i,data:r,element:r.element,gif:r.gif,gifData:r.gifData,gifLoopCount:r.gifLoopCount,loaded:!0,ratio:o.width&&o.height?o.width/o.height:r.ratio??1,replaceColor:n,source:o.src},e.ratio||(e.ratio=1);const a={image:e,fill:o.fill??t.fill,close:o.close??t.close};t.image=a.image,t.fill=a.fill,t.close=a.close})()}}class p{constructor(){this.src="",this.gif=!1}load(e){e&&(void 0!==e.gif&&(this.gif=e.gif),void 0!==e.height&&(this.height=e.height),void 0!==e.name&&(this.name=e.name),void 0!==e.replaceColor&&(this.replaceColor=e.replaceColor),void 0!==e.src&&(this.src=e.src),void 0!==e.width&&(this.width=e.width))}}class m{constructor(e){this.id="imagePreloader",this._engine=e}getPlugin(){return{}}loadOptions(e,t){if(!t||!t.preload)return;e.preload||(e.preload=[]);const a=e.preload;for(const e of t.preload){const t=a.find((t=>t.name===e.name||t.src===e.src));if(t)t.load(e);else{const t=new p;t.load(e),a.push(t)}}}needsPlugin(){return!0}}async function u(t,a=!0){!function(t){t.loadImage||(t.loadImage=async a=>{if(!a.name&&!a.src)throw new Error(`${e.errorPrefix} no image source provided`);if(t.images||(t.images=[]),!t.images.find((e=>e.name===a.name||e.source===a.src)))try{const e={gif:a.gif??!1,name:a.name??a.src,source:a.src,type:a.src.substring(a.src.length-3),error:!1,loading:!0,replaceColor:a.replaceColor,ratio:a.width&&a.height?a.width/a.height:void 0};t.images.push(e);const o=a.gif?g:a.replaceColor?h:c;await o(e)}catch{throw new Error(`${e.errorPrefix} ${a.name??a.src} not found`)}})}(t);const o=new m(t);await t.addPlugin(o,a),await t.addShape(["image","images"],new f(t),a)}})(),i})()));

@@ -1,1 +0,1 @@

/*! tsParticles Image Shape v2.10.1 by Matteo Bruni */
/*! tsParticles Image Shape v2.11.0 by Matteo Bruni */
import type { IShapeValues } from "tsparticles-engine";
export interface IImageShape extends IShapeValues {
gif: boolean;
height: number;

@@ -4,0 +5,0 @@ name: string;

@@ -1,2 +0,2 @@

import { type Container, type IShapeDrawer } from "tsparticles-engine";
import { type Container, type IDelta, type IShapeDrawer } from "tsparticles-engine";
import type { IImage, ImageParticle } from "./Utils";

@@ -8,3 +8,3 @@ import type { ImageContainer, ImageEngine } from "./types";

addImage(image: IImage): void;
draw(context: CanvasRenderingContext2D, particle: ImageParticle, radius: number, opacity: number): void;
draw(context: CanvasRenderingContext2D, particle: ImageParticle, radius: number, opacity: number, delta: IDelta): void;
getSidesCount(): number;

@@ -11,0 +11,0 @@ init(container: ImageContainer): Promise<void>;

import type { ImageEngine } from "./types";
export declare function loadImageShape(engine: ImageEngine): Promise<void>;
export declare function loadImageShape(engine: ImageEngine, refresh?: boolean): Promise<void>;
import type { IOptionLoader, RecursivePartial } from "tsparticles-engine";
import type { IPreload } from "../Interfaces/IPreload";
export declare class Preload implements IPreload, IOptionLoader<IPreload> {
gif: boolean;
height?: number;

@@ -5,0 +6,0 @@ name?: string | undefined;

export interface IPreload {
gif: boolean;
height?: number;

@@ -3,0 +4,0 @@ name?: string;

import { type IHsl, type Particle } from "tsparticles-engine";
import type { GIF } from "./GifUtils/Types/GIF";
import type { IImageShape } from "./IImageShape";

@@ -7,2 +8,5 @@ export interface IImage {

error: boolean;
gif: boolean;
gifData?: GIF;
gifLoopCount?: number;
loading: boolean;

@@ -20,2 +24,5 @@ name: string;

element?: HTMLImageElement;
gif: boolean;
gifData?: GIF;
gifLoopCount?: number;
loaded?: boolean;

@@ -27,6 +34,10 @@ ratio: number;

export type ImageParticle = Particle & {
gifFrame?: number;
gifLoopCount?: number;
gifTime?: number;
image?: IParticleImage;
};
export declare function loadImage(image: IImage): Promise<void>;
export declare function loadGifImage(image: IImage): Promise<void>;
export declare function downloadSvgImage(image: IImage): Promise<void>;
export declare function replaceImageColor(image: IImage, imageData: IImageShape, color: IHsl, particle: Particle): Promise<IParticleImage>;

@@ -22,2 +22,3 @@ (function (factory) {

await this._engine.loadImage({
gif: imageShape.gif,
name: imageShape.name,

@@ -36,13 +37,84 @@ replaceColor: imageShape.replaceColor ?? imageShape.replace_color ?? false,

}
draw(context, particle, radius, opacity) {
draw(context, particle, radius, opacity, delta) {
const image = particle.image, element = image?.element;
if (!element) {
if (!image) {
return;
}
const ratio = image?.ratio ?? 1, pos = {
x: -radius,
y: -radius,
};
context.globalAlpha = opacity;
context.drawImage(element, pos.x, pos.y, radius * 2, (radius * 2) / ratio);
if (image.gif && image.gifData) {
const offscreenCanvas = new OffscreenCanvas(image.gifData.width, image.gifData.height), offscreenContext = offscreenCanvas.getContext("2d");
if (!offscreenContext) {
throw new Error("could not create offscreen canvas context");
}
offscreenContext.imageSmoothingQuality = "low";
offscreenContext.imageSmoothingEnabled = false;
offscreenContext.clearRect(0, 0, offscreenCanvas.width, offscreenCanvas.height);
if (particle.gifLoopCount === undefined) {
particle.gifLoopCount = image.gifLoopCount ?? 0;
}
let frameIndex = particle.gifFrame ?? 0;
const pos = { x: -image.gifData.width * 0.5, y: -image.gifData.height * 0.5 }, frame = image.gifData.frames[frameIndex];
if (particle.gifTime === undefined) {
particle.gifTime = 0;
}
if (!frame.bitmap) {
return;
}
context.scale(radius / image.gifData.width, radius / image.gifData.height);
switch (frame.disposalMethod) {
case 4:
case 5:
case 6:
case 7:
case 0:
offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
context.drawImage(offscreenCanvas, pos.x, pos.y);
offscreenContext.clearRect(0, 0, offscreenCanvas.width, offscreenCanvas.height);
break;
case 1:
offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
context.drawImage(offscreenCanvas, pos.x, pos.y);
break;
case 2:
offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
context.drawImage(offscreenCanvas, pos.x, pos.y);
offscreenContext.clearRect(0, 0, offscreenCanvas.width, offscreenCanvas.height);
if (image.gifData.globalColorTable.length === 0) {
offscreenContext.putImageData(image.gifData.frames[0].image, pos.x + frame.left, pos.y + frame.top);
}
else {
offscreenContext.putImageData(image.gifData.backgroundImage, pos.x, pos.y);
}
break;
case 3:
{
const previousImageData = offscreenContext.getImageData(0, 0, offscreenCanvas.width, offscreenCanvas.height);
offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
context.drawImage(offscreenCanvas, pos.x, pos.y);
offscreenContext.clearRect(0, 0, offscreenCanvas.width, offscreenCanvas.height);
offscreenContext.putImageData(previousImageData, 0, 0);
}
break;
}
particle.gifTime += delta.value;
if (particle.gifTime > frame.delayTime) {
particle.gifTime -= frame.delayTime;
if (++frameIndex >= image.gifData.frames.length) {
if (--particle.gifLoopCount <= 0) {
return;
}
frameIndex = 0;
offscreenContext.clearRect(0, 0, offscreenCanvas.width, offscreenCanvas.height);
}
particle.gifFrame = frameIndex;
}
context.scale(image.gifData.width / radius, image.gifData.height / radius);
}
else if (element) {
const ratio = image.ratio, pos = {
x: -radius,
y: -radius,
};
context.drawImage(element, pos.x, pos.y, radius * 2, (radius * 2) / ratio);
}
context.globalAlpha = 1;

@@ -59,3 +131,3 @@ }

for (const imageData of options.preload) {
this._engine.loadImage(imageData);
await this._engine.loadImage(imageData);
}

@@ -105,2 +177,5 @@ }

element: image.element,
gif: image.gif,
gifData: image.gifData,
gifLoopCount: image.gifLoopCount,
loaded: true,

@@ -107,0 +182,0 @@ ratio: imageData.width && imageData.height ? imageData.width / imageData.height : image.ratio ?? 1,

@@ -17,38 +17,43 @@ (function (factory) {

const tsparticles_engine_1 = require("tsparticles-engine");
async function loadImageShape(engine) {
if (!engine.loadImage) {
engine.loadImage = async (data) => {
if (!data.name && !data.src) {
throw new Error(`${tsparticles_engine_1.errorPrefix} no image source provided`);
}
if (!engine.images) {
engine.images = [];
}
if (engine.images.find((t) => t.name === data.name || t.source === data.src)) {
return;
}
try {
const image = {
name: data.name ?? data.src,
source: data.src,
type: data.src.substring(data.src.length - 3),
error: false,
loading: true,
replaceColor: data.replaceColor,
ratio: data.width && data.height ? data.width / data.height : undefined,
};
engine.images.push(image);
const imageFunc = data.replaceColor ? Utils_1.downloadSvgImage : Utils_1.loadImage;
await imageFunc(image);
}
catch {
throw new Error(`${tsparticles_engine_1.errorPrefix} ${data.name ?? data.src} not found`);
}
};
function addLoadImageToEngine(engine) {
if (engine.loadImage) {
return;
}
engine.loadImage = async (data) => {
if (!data.name && !data.src) {
throw new Error(`${tsparticles_engine_1.errorPrefix} no image source provided`);
}
if (!engine.images) {
engine.images = [];
}
if (engine.images.find((t) => t.name === data.name || t.source === data.src)) {
return;
}
try {
const image = {
gif: data.gif ?? false,
name: data.name ?? data.src,
source: data.src,
type: data.src.substring(data.src.length - 3),
error: false,
loading: true,
replaceColor: data.replaceColor,
ratio: data.width && data.height ? data.width / data.height : undefined,
};
engine.images.push(image);
const imageFunc = data.gif ? Utils_1.loadGifImage : data.replaceColor ? Utils_1.downloadSvgImage : Utils_1.loadImage;
await imageFunc(image);
}
catch {
throw new Error(`${tsparticles_engine_1.errorPrefix} ${data.name ?? data.src} not found`);
}
};
}
async function loadImageShape(engine, refresh = true) {
addLoadImageToEngine(engine);
const preloader = new ImagePreloader_1.ImagePreloaderPlugin(engine);
await engine.addPlugin(preloader);
await engine.addShape(["image", "images"], new ImageDrawer_1.ImageDrawer(engine));
await engine.addPlugin(preloader, refresh);
await engine.addShape(["image", "images"], new ImageDrawer_1.ImageDrawer(engine), refresh);
}
exports.loadImageShape = loadImageShape;
});

@@ -16,2 +16,3 @@ (function (factory) {

this.src = "";
this.gif = false;
}

@@ -22,2 +23,5 @@ load(data) {

}
if (data.gif !== undefined) {
this.gif = data.gif;
}
if (data.height !== undefined) {

@@ -24,0 +28,0 @@ this.height = data.height;

@@ -7,3 +7,3 @@ (function (factory) {

else if (typeof define === "function" && define.amd) {
define(["require", "exports", "tsparticles-engine"], factory);
define(["require", "exports", "tsparticles-engine", "./GifUtils/Utils"], factory);
}

@@ -13,4 +13,5 @@ })(function (require, exports) {

Object.defineProperty(exports, "__esModule", { value: true });
exports.replaceImageColor = exports.downloadSvgImage = exports.loadImage = void 0;
exports.replaceImageColor = exports.downloadSvgImage = exports.loadGifImage = exports.loadImage = void 0;
const tsparticles_engine_1 = require("tsparticles-engine");
const Utils_1 = require("./GifUtils/Utils");
const currentColorRegex = /(#(?:[0-9a-f]{2}){2,4}|(#[0-9a-f]{3})|(rgb|hsl)a?\((-?\d+%?[,\s]+){2,3}\s*[\d.]+%?\))|currentcolor/gi;

@@ -42,3 +43,3 @@ function replaceColorSvg(imageShape, color, opacity) {

image.loading = false;
console.error(`${tsparticles_engine_1.errorPrefix} loading image: ${image.source}`);
(0, tsparticles_engine_1.getLogger)().error(`${tsparticles_engine_1.errorPrefix} loading image: ${image.source}`);
resolve();

@@ -50,2 +51,21 @@ });

exports.loadImage = loadImage;
async function loadGifImage(image) {
if (image.type !== "gif") {
await loadImage(image);
return;
}
image.loading = true;
try {
image.gifData = await (0, Utils_1.decodeGIF)(image.source);
image.gifLoopCount = (0, Utils_1.getGIFLoopAmount)(image.gifData) ?? 0;
if (image.gifLoopCount === 0) {
image.gifLoopCount = Infinity;
}
}
catch {
image.error = true;
}
image.loading = false;
}
exports.loadGifImage = loadGifImage;
async function downloadSvgImage(image) {

@@ -59,6 +79,6 @@ if (image.type !== "svg") {

if (!response.ok) {
console.error(`${tsparticles_engine_1.errorPrefix} Image not found`);
(0, tsparticles_engine_1.getLogger)().error(`${tsparticles_engine_1.errorPrefix} Image not found`);
image.error = true;
}
if (!image.error) {
else {
image.svgData = await response.text();

@@ -72,2 +92,3 @@ }

color,
gif: imageData.gif,
data: {

@@ -74,0 +95,0 @@ ...image,

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc