@tsparticles/shape-image 3.0.3 → 3.2.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.
Files changed (42) hide show
  1. package/21.min.js +2 -0
  2. package/21.min.js.LICENSE.txt +1 -0
  3. package/618.min.js +2 -0
  4. package/618.min.js.LICENSE.txt +1 -0
  5. package/623.min.js +2 -0
  6. package/623.min.js.LICENSE.txt +1 -0
  7. package/browser/GifUtils/ByteStream.js +13 -9
  8. package/browser/GifUtils/Utils.js +113 -10
  9. package/browser/ImageDrawer.js +44 -109
  10. package/browser/ImagePreloader.js +3 -2
  11. package/browser/Utils.js +6 -23
  12. package/browser/index.js +12 -5
  13. package/cjs/GifUtils/ByteStream.js +13 -9
  14. package/cjs/GifUtils/Utils.js +139 -11
  15. package/cjs/ImageDrawer.js +67 -109
  16. package/cjs/ImagePreloader.js +3 -2
  17. package/cjs/Utils.js +7 -25
  18. package/cjs/index.js +36 -6
  19. package/dist_browser_GifUtils_Utils_js.js +50 -0
  20. package/dist_browser_ImageDrawer_js.js +30 -0
  21. package/dist_browser_ImagePreloader_js.js +40 -0
  22. package/esm/GifUtils/ByteStream.js +13 -9
  23. package/esm/GifUtils/Utils.js +113 -10
  24. package/esm/ImageDrawer.js +44 -109
  25. package/esm/ImagePreloader.js +3 -2
  26. package/esm/Utils.js +6 -23
  27. package/esm/index.js +12 -5
  28. package/package.json +2 -2
  29. package/report.html +3 -3
  30. package/tsparticles.shape.image.js +251 -862
  31. package/tsparticles.shape.image.min.js +1 -1
  32. package/tsparticles.shape.image.min.js.LICENSE.txt +1 -1
  33. package/types/GifUtils/Utils.d.ts +4 -0
  34. package/types/ImageDrawer.d.ts +3 -3
  35. package/types/ImagePreloader.d.ts +1 -1
  36. package/types/Utils.d.ts +0 -1
  37. package/umd/GifUtils/ByteStream.js +13 -9
  38. package/umd/GifUtils/Utils.js +140 -11
  39. package/umd/ImageDrawer.js +69 -110
  40. package/umd/ImagePreloader.js +3 -2
  41. package/umd/Utils.js +8 -26
  42. package/umd/index.js +38 -7
@@ -0,0 +1,50 @@
1
+ /*!
2
+ * Author : Matteo Bruni
3
+ * MIT license: https://opensource.org/licenses/MIT
4
+ * Demo / Generator : https://particles.js.org/
5
+ * GitHub : https://www.github.com/matteobruni/tsparticles
6
+ * How to use? : Check the GitHub README
7
+ * v3.2.0
8
+ */
9
+ "use strict";
10
+ /*
11
+ * ATTENTION: The "eval" devtool has been used (maybe by default in mode: "development").
12
+ * This devtool is neither made for production nor for readable output files.
13
+ * It uses "eval()" calls to create a separate source file in the browser devtools.
14
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
15
+ * or disable the default devtool with "devtool: false".
16
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
17
+ */
18
+ (this["webpackChunk_tsparticles_shape_image"] = this["webpackChunk_tsparticles_shape_image"] || []).push([["dist_browser_GifUtils_Utils_js"],{
19
+
20
+ /***/ "./dist/browser/GifUtils/ByteStream.js":
21
+ /*!*********************************************!*\
22
+ !*** ./dist/browser/GifUtils/ByteStream.js ***!
23
+ \*********************************************/
24
+ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
25
+
26
+ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ ByteStream: () => (/* binding */ ByteStream)\n/* harmony export */ });\nclass ByteStream {\n constructor(bytes) {\n this.pos = 0;\n this.data = new Uint8ClampedArray(bytes);\n }\n getString(count) {\n const slice = this.data.slice(this.pos, this.pos + count);\n this.pos += slice.length;\n return slice.reduce((acc, curr) => acc + String.fromCharCode(curr), \"\");\n }\n nextByte() {\n return this.data[this.pos++];\n }\n nextTwoBytes() {\n const increment = 2,\n previous = 1,\n shift = 8;\n this.pos += increment;\n return this.data[this.pos - increment] + (this.data[this.pos - previous] << shift);\n }\n readSubBlocks() {\n let blockString = \"\",\n size = 0;\n const minCount = 0,\n emptySize = 0;\n do {\n size = this.data[this.pos++];\n for (let count = size; --count >= minCount; blockString += String.fromCharCode(this.data[this.pos++])) {}\n } while (size !== emptySize);\n return blockString;\n }\n readSubBlocksBin() {\n let size = this.data[this.pos],\n len = 0;\n const emptySize = 0,\n increment = 1;\n for (let offset = 0; size !== emptySize; offset += size + increment, size = this.data[this.pos + offset]) {\n len += size;\n }\n const blockData = new Uint8Array(len);\n size = this.data[this.pos++];\n for (let i = 0; size !== emptySize; size = this.data[this.pos++]) {\n for (let count = size; --count >= emptySize; blockData[i++] = this.data[this.pos++]) {}\n }\n return blockData;\n }\n skipSubBlocks() {\n for (const increment = 1, noData = 0; this.data[this.pos] !== noData; this.pos += this.data[this.pos] + increment) {}\n this.pos++;\n }\n}\n\n//# sourceURL=webpack://@tsparticles/shape-image/./dist/browser/GifUtils/ByteStream.js?");
27
+
28
+ /***/ }),
29
+
30
+ /***/ "./dist/browser/GifUtils/Constants.js":
31
+ /*!********************************************!*\
32
+ !*** ./dist/browser/GifUtils/Constants.js ***!
33
+ \********************************************/
34
+ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
35
+
36
+ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ InterlaceOffsets: () => (/* binding */ InterlaceOffsets),\n/* harmony export */ InterlaceSteps: () => (/* binding */ InterlaceSteps)\n/* harmony export */ });\nconst InterlaceOffsets = [0, 4, 2, 1];\nconst InterlaceSteps = [8, 8, 4, 2];\n\n//# sourceURL=webpack://@tsparticles/shape-image/./dist/browser/GifUtils/Constants.js?");
37
+
38
+ /***/ }),
39
+
40
+ /***/ "./dist/browser/GifUtils/Utils.js":
41
+ /*!****************************************!*\
42
+ !*** ./dist/browser/GifUtils/Utils.js ***!
43
+ \****************************************/
44
+ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
45
+
46
+ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ decodeGIF: () => (/* binding */ decodeGIF),\n/* harmony export */ drawGif: () => (/* binding */ drawGif),\n/* harmony export */ getGIFLoopAmount: () => (/* binding */ getGIFLoopAmount),\n/* harmony export */ loadGifImage: () => (/* binding */ loadGifImage)\n/* harmony export */ });\n/* harmony import */ var _Constants_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Constants.js */ \"./dist/browser/GifUtils/Constants.js\");\n/* harmony import */ var _ByteStream_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./ByteStream.js */ \"./dist/browser/GifUtils/ByteStream.js\");\n\n\nconst origin = {\n x: 0,\n y: 0\n },\n defaultFrame = 0,\n half = 0.5,\n initialTime = 0,\n firstIndex = 0,\n defaultLoopCount = 0;\nfunction parseColorTable(byteStream, count) {\n const colors = [];\n for (let i = 0; i < count; i++) {\n colors.push({\n r: byteStream.data[byteStream.pos],\n g: byteStream.data[byteStream.pos + 1],\n b: byteStream.data[byteStream.pos + 2]\n });\n byteStream.pos += 3;\n }\n return colors;\n}\nfunction parseExtensionBlock(byteStream, gif, getFrameIndex, getTransparencyIndex) {\n switch (byteStream.nextByte()) {\n case 249:\n {\n const frame = gif.frames[getFrameIndex(false)];\n byteStream.pos++;\n const packedByte = byteStream.nextByte();\n frame.GCreserved = (packedByte & 0xe0) >>> 5;\n frame.disposalMethod = (packedByte & 0x1c) >>> 2;\n frame.userInputDelayFlag = (packedByte & 2) === 2;\n const transparencyFlag = (packedByte & 1) === 1;\n frame.delayTime = byteStream.nextTwoBytes() * 0xa;\n const transparencyIndex = byteStream.nextByte();\n if (transparencyFlag) {\n getTransparencyIndex(transparencyIndex);\n }\n byteStream.pos++;\n break;\n }\n case 255:\n {\n byteStream.pos++;\n const applicationExtension = {\n identifier: byteStream.getString(8),\n authenticationCode: byteStream.getString(3),\n data: byteStream.readSubBlocksBin()\n };\n gif.applicationExtensions.push(applicationExtension);\n break;\n }\n case 254:\n {\n gif.comments.push([getFrameIndex(false), byteStream.readSubBlocks()]);\n break;\n }\n case 1:\n {\n if (gif.globalColorTable.length === 0) {\n throw new EvalError(\"plain text extension without global color table\");\n }\n byteStream.pos++;\n gif.frames[getFrameIndex(false)].plainTextData = {\n left: byteStream.nextTwoBytes(),\n top: byteStream.nextTwoBytes(),\n width: byteStream.nextTwoBytes(),\n height: byteStream.nextTwoBytes(),\n charSize: {\n width: byteStream.nextTwoBytes(),\n height: byteStream.nextTwoBytes()\n },\n foregroundColor: byteStream.nextByte(),\n backgroundColor: byteStream.nextByte(),\n text: byteStream.readSubBlocks()\n };\n break;\n }\n default:\n byteStream.skipSubBlocks();\n break;\n }\n}\nasync function parseImageBlock(byteStream, gif, avgAlpha, getFrameIndex, getTransparencyIndex, progressCallback) {\n const frame = gif.frames[getFrameIndex(true)];\n frame.left = byteStream.nextTwoBytes();\n frame.top = byteStream.nextTwoBytes();\n frame.width = byteStream.nextTwoBytes();\n frame.height = byteStream.nextTwoBytes();\n const packedByte = byteStream.nextByte(),\n localColorTableFlag = (packedByte & 0x80) === 0x80,\n interlacedFlag = (packedByte & 0x40) === 0x40;\n frame.sortFlag = (packedByte & 0x20) === 0x20;\n frame.reserved = (packedByte & 0x18) >>> 3;\n const localColorCount = 1 << (packedByte & 7) + 1;\n if (localColorTableFlag) {\n frame.localColorTable = parseColorTable(byteStream, localColorCount);\n }\n const getColor = index => {\n const {\n r,\n g,\n b\n } = (localColorTableFlag ? frame.localColorTable : gif.globalColorTable)[index];\n if (index !== getTransparencyIndex(null)) {\n return {\n r,\n g,\n b,\n a: 255\n };\n }\n return {\n r,\n g,\n b,\n a: avgAlpha ? ~~((r + g + b) / 3) : 0\n };\n };\n const image = (() => {\n try {\n return new ImageData(frame.width, frame.height, {\n colorSpace: \"srgb\"\n });\n } catch (error) {\n if (error instanceof DOMException && error.name === \"IndexSizeError\") {\n return null;\n }\n throw error;\n }\n })();\n if (image == null) {\n throw new EvalError(\"GIF frame size is to large\");\n }\n const minCodeSize = byteStream.nextByte(),\n imageData = byteStream.readSubBlocksBin(),\n clearCode = 1 << minCodeSize;\n const readBits = (pos, len) => {\n const bytePos = pos >>> 3,\n bitPos = pos & 7;\n return (imageData[bytePos] + (imageData[bytePos + 1] << 8) + (imageData[bytePos + 2] << 16) & (1 << len) - 1 << bitPos) >>> bitPos;\n };\n if (interlacedFlag) {\n for (let code = 0, size = minCodeSize + 1, pos = 0, dic = [[0]], pass = 0; pass < 4; pass++) {\n if (_Constants_js__WEBPACK_IMPORTED_MODULE_0__.InterlaceOffsets[pass] < frame.height) {\n let pixelPos = 0,\n lineIndex = 0,\n exit = false;\n while (!exit) {\n const last = code;\n code = readBits(pos, size);\n pos += size + 1;\n if (code === clearCode) {\n size = minCodeSize + 1;\n dic.length = clearCode + 2;\n for (let i = 0; i < dic.length; i++) {\n dic[i] = i < clearCode ? [i] : [];\n }\n } else {\n if (code >= dic.length) {\n dic.push(dic[last].concat(dic[last][0]));\n } else if (last !== clearCode) {\n dic.push(dic[last].concat(dic[code][0]));\n }\n for (const item of dic[code]) {\n const {\n r,\n g,\n b,\n a\n } = getColor(item);\n image.data.set([r, g, b, a], _Constants_js__WEBPACK_IMPORTED_MODULE_0__.InterlaceOffsets[pass] * frame.width + _Constants_js__WEBPACK_IMPORTED_MODULE_0__.InterlaceSteps[pass] * lineIndex + pixelPos % (frame.width * 4));\n pixelPos += 4;\n }\n if (dic.length === 1 << size && size < 0xc) {\n size++;\n }\n }\n if (pixelPos === frame.width * 4 * (lineIndex + 1)) {\n lineIndex++;\n if (_Constants_js__WEBPACK_IMPORTED_MODULE_0__.InterlaceOffsets[pass] + _Constants_js__WEBPACK_IMPORTED_MODULE_0__.InterlaceSteps[pass] * lineIndex >= frame.height) {\n exit = true;\n }\n }\n }\n }\n progressCallback?.(byteStream.pos / (byteStream.data.length - 1), getFrameIndex(false) + 1, image, {\n x: frame.left,\n y: frame.top\n }, {\n width: gif.width,\n height: gif.height\n });\n }\n frame.image = image;\n frame.bitmap = await createImageBitmap(image);\n } else {\n let code = 0,\n size = minCodeSize + 1,\n pos = 0,\n pixelPos = -4,\n exit = false;\n const dic = [[0]];\n while (!exit) {\n const last = code;\n code = readBits(pos, size);\n pos += size;\n if (code === clearCode) {\n size = minCodeSize + 1;\n dic.length = clearCode + 2;\n for (let i = 0; i < dic.length; i++) {\n dic[i] = i < clearCode ? [i] : [];\n }\n } else {\n if (code === clearCode + 1) {\n exit = true;\n break;\n }\n if (code >= dic.length) {\n dic.push(dic[last].concat(dic[last][0]));\n } else if (last !== clearCode) {\n dic.push(dic[last].concat(dic[code][0]));\n }\n for (const item of dic[code]) {\n const {\n r,\n g,\n b,\n a\n } = getColor(item);\n image.data.set([r, g, b, a], pixelPos += 4);\n }\n if (dic.length >= 1 << size && size < 0xc) {\n size++;\n }\n }\n }\n frame.image = image;\n frame.bitmap = await createImageBitmap(image);\n progressCallback?.((byteStream.pos + 1) / byteStream.data.length, getFrameIndex(false) + 1, frame.image, {\n x: frame.left,\n y: frame.top\n }, {\n width: gif.width,\n height: gif.height\n });\n }\n}\nasync function parseBlock(byteStream, gif, avgAlpha, getFrameIndex, getTransparencyIndex, progressCallback) {\n switch (byteStream.nextByte()) {\n case 59:\n return true;\n case 44:\n await parseImageBlock(byteStream, gif, avgAlpha, getFrameIndex, getTransparencyIndex, progressCallback);\n break;\n case 33:\n parseExtensionBlock(byteStream, gif, getFrameIndex, getTransparencyIndex);\n break;\n default:\n throw new EvalError(\"undefined block found\");\n }\n return false;\n}\nfunction getGIFLoopAmount(gif) {\n for (const extension of gif.applicationExtensions) {\n if (extension.identifier + extension.authenticationCode !== \"NETSCAPE2.0\") {\n continue;\n }\n return extension.data[1] + (extension.data[2] << 8);\n }\n return NaN;\n}\nasync function decodeGIF(gifURL, progressCallback, avgAlpha) {\n if (!avgAlpha) avgAlpha = false;\n const res = await fetch(gifURL);\n if (!res.ok && res.status === 404) {\n throw new EvalError(\"file not found\");\n }\n const buffer = await res.arrayBuffer();\n const gif = {\n width: 0,\n height: 0,\n totalTime: 0,\n colorRes: 0,\n pixelAspectRatio: 0,\n frames: [],\n sortFlag: false,\n globalColorTable: [],\n backgroundImage: new ImageData(1, 1, {\n colorSpace: \"srgb\"\n }),\n comments: [],\n applicationExtensions: []\n },\n byteStream = new _ByteStream_js__WEBPACK_IMPORTED_MODULE_1__.ByteStream(new Uint8ClampedArray(buffer));\n if (byteStream.getString(6) !== \"GIF89a\") {\n throw new Error(\"not a supported GIF file\");\n }\n gif.width = byteStream.nextTwoBytes();\n gif.height = byteStream.nextTwoBytes();\n const packedByte = byteStream.nextByte(),\n globalColorTableFlag = (packedByte & 0x80) === 0x80;\n gif.colorRes = (packedByte & 0x70) >>> 4;\n gif.sortFlag = (packedByte & 8) === 8;\n const globalColorCount = 1 << (packedByte & 7) + 1,\n backgroundColorIndex = byteStream.nextByte();\n gif.pixelAspectRatio = byteStream.nextByte();\n if (gif.pixelAspectRatio !== 0) {\n gif.pixelAspectRatio = (gif.pixelAspectRatio + 0xf) / 0x40;\n }\n if (globalColorTableFlag) {\n gif.globalColorTable = parseColorTable(byteStream, globalColorCount);\n }\n const backgroundImage = (() => {\n try {\n return new ImageData(gif.width, gif.height, {\n colorSpace: \"srgb\"\n });\n } catch (error) {\n if (error instanceof DOMException && error.name === \"IndexSizeError\") {\n return null;\n }\n throw error;\n }\n })();\n if (backgroundImage == null) {\n throw new Error(\"GIF frame size is to large\");\n }\n const {\n r,\n g,\n b\n } = gif.globalColorTable[backgroundColorIndex];\n backgroundImage.data.set(globalColorTableFlag ? [r, g, b, 255] : [0, 0, 0, 0]);\n for (let i = 4; i < backgroundImage.data.length; i *= 2) {\n backgroundImage.data.copyWithin(i, 0, i);\n }\n gif.backgroundImage = backgroundImage;\n let frameIndex = -1,\n incrementFrameIndex = true,\n transparencyIndex = -1;\n const getframeIndex = increment => {\n if (increment) {\n incrementFrameIndex = true;\n }\n return frameIndex;\n };\n const getTransparencyIndex = newValue => {\n if (newValue != null) {\n transparencyIndex = newValue;\n }\n return transparencyIndex;\n };\n try {\n do {\n if (incrementFrameIndex) {\n gif.frames.push({\n left: 0,\n top: 0,\n width: 0,\n height: 0,\n disposalMethod: 0,\n image: new ImageData(1, 1, {\n colorSpace: \"srgb\"\n }),\n plainTextData: null,\n userInputDelayFlag: false,\n delayTime: 0,\n sortFlag: false,\n localColorTable: [],\n reserved: 0,\n GCreserved: 0\n });\n frameIndex++;\n transparencyIndex = -1;\n incrementFrameIndex = false;\n }\n } while (!(await parseBlock(byteStream, gif, avgAlpha, getframeIndex, getTransparencyIndex, progressCallback)));\n gif.frames.length--;\n for (const frame of gif.frames) {\n if (frame.userInputDelayFlag && frame.delayTime === 0) {\n gif.totalTime = Infinity;\n break;\n }\n gif.totalTime += frame.delayTime;\n }\n return gif;\n } catch (error) {\n if (error instanceof EvalError) {\n throw new Error(`error while parsing frame ${frameIndex} \"${error.message}\"`);\n }\n throw error;\n }\n}\nfunction drawGif(data) {\n const {\n context,\n radius,\n particle,\n delta\n } = data,\n image = particle.image;\n if (!image?.gifData || !image.gif) {\n return;\n }\n const offscreenCanvas = new OffscreenCanvas(image.gifData.width, image.gifData.height),\n offscreenContext = offscreenCanvas.getContext(\"2d\");\n if (!offscreenContext) {\n throw new Error(\"could not create offscreen canvas context\");\n }\n offscreenContext.imageSmoothingQuality = \"low\";\n offscreenContext.imageSmoothingEnabled = false;\n offscreenContext.clearRect(origin.x, origin.y, offscreenCanvas.width, offscreenCanvas.height);\n if (particle.gifLoopCount === undefined) {\n particle.gifLoopCount = image.gifLoopCount ?? defaultLoopCount;\n }\n let frameIndex = particle.gifFrame ?? defaultFrame;\n const pos = {\n x: -image.gifData.width * half,\n y: -image.gifData.height * half\n },\n frame = image.gifData.frames[frameIndex];\n if (particle.gifTime === undefined) {\n particle.gifTime = initialTime;\n }\n if (!frame.bitmap) {\n return;\n }\n context.scale(radius / image.gifData.width, radius / image.gifData.height);\n switch (frame.disposalMethod) {\n case 4:\n case 5:\n case 6:\n case 7:\n case 0:\n offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);\n context.drawImage(offscreenCanvas, pos.x, pos.y);\n offscreenContext.clearRect(origin.x, origin.y, offscreenCanvas.width, offscreenCanvas.height);\n break;\n case 1:\n offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);\n context.drawImage(offscreenCanvas, pos.x, pos.y);\n break;\n case 2:\n offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);\n context.drawImage(offscreenCanvas, pos.x, pos.y);\n offscreenContext.clearRect(origin.x, origin.y, offscreenCanvas.width, offscreenCanvas.height);\n if (!image.gifData.globalColorTable.length) {\n offscreenContext.putImageData(image.gifData.frames[firstIndex].image, pos.x + frame.left, pos.y + frame.top);\n } else {\n offscreenContext.putImageData(image.gifData.backgroundImage, pos.x, pos.y);\n }\n break;\n case 3:\n {\n const previousImageData = offscreenContext.getImageData(origin.x, origin.y, offscreenCanvas.width, offscreenCanvas.height);\n offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);\n context.drawImage(offscreenCanvas, pos.x, pos.y);\n offscreenContext.clearRect(origin.x, origin.y, offscreenCanvas.width, offscreenCanvas.height);\n offscreenContext.putImageData(previousImageData, origin.x, origin.y);\n }\n break;\n }\n particle.gifTime += delta.value;\n if (particle.gifTime > frame.delayTime) {\n particle.gifTime -= frame.delayTime;\n if (++frameIndex >= image.gifData.frames.length) {\n if (--particle.gifLoopCount <= defaultLoopCount) {\n return;\n }\n frameIndex = firstIndex;\n offscreenContext.clearRect(origin.x, origin.y, offscreenCanvas.width, offscreenCanvas.height);\n }\n particle.gifFrame = frameIndex;\n }\n context.scale(image.gifData.width / radius, image.gifData.height / radius);\n}\nasync function loadGifImage(image) {\n if (image.type !== \"gif\") {\n const {\n loadImage\n } = await Promise.resolve(/*! import() */).then(__webpack_require__.bind(__webpack_require__, /*! ../Utils.js */ \"./dist/browser/Utils.js\"));\n await loadImage(image);\n return;\n }\n image.loading = true;\n try {\n image.gifData = await decodeGIF(image.source);\n image.gifLoopCount = getGIFLoopAmount(image.gifData) ?? defaultLoopCount;\n if (!image.gifLoopCount) {\n image.gifLoopCount = Infinity;\n }\n } catch {\n image.error = true;\n }\n image.loading = false;\n}\n\n//# sourceURL=webpack://@tsparticles/shape-image/./dist/browser/GifUtils/Utils.js?");
47
+
48
+ /***/ })
49
+
50
+ }]);
@@ -0,0 +1,30 @@
1
+ /*!
2
+ * Author : Matteo Bruni
3
+ * MIT license: https://opensource.org/licenses/MIT
4
+ * Demo / Generator : https://particles.js.org/
5
+ * GitHub : https://www.github.com/matteobruni/tsparticles
6
+ * How to use? : Check the GitHub README
7
+ * v3.2.0
8
+ */
9
+ "use strict";
10
+ /*
11
+ * ATTENTION: The "eval" devtool has been used (maybe by default in mode: "development").
12
+ * This devtool is neither made for production nor for readable output files.
13
+ * It uses "eval()" calls to create a separate source file in the browser devtools.
14
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
15
+ * or disable the default devtool with "devtool: false".
16
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
17
+ */
18
+ (this["webpackChunk_tsparticles_shape_image"] = this["webpackChunk_tsparticles_shape_image"] || []).push([["dist_browser_ImageDrawer_js"],{
19
+
20
+ /***/ "./dist/browser/ImageDrawer.js":
21
+ /*!*************************************!*\
22
+ !*** ./dist/browser/ImageDrawer.js ***!
23
+ \*************************************/
24
+ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
25
+
26
+ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ ImageDrawer: () => (/* binding */ ImageDrawer)\n/* harmony export */ });\n/* harmony import */ var _tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @tsparticles/engine */ \"@tsparticles/engine\");\n/* harmony import */ var _tsparticles_engine__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__);\n\nconst double = 2,\n defaultAlpha = 1,\n sides = 12,\n defaultRatio = 1;\nclass ImageDrawer {\n constructor(engine) {\n this.loadImageShape = async imageShape => {\n if (!this._engine.loadImage) {\n throw new Error(`${_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.errorPrefix} image shape not initialized`);\n }\n await this._engine.loadImage({\n gif: imageShape.gif,\n name: imageShape.name,\n replaceColor: imageShape.replaceColor ?? false,\n src: imageShape.src\n });\n };\n this._engine = engine;\n }\n addImage(image) {\n if (!this._engine.images) {\n this._engine.images = [];\n }\n this._engine.images.push(image);\n }\n async draw(data) {\n const {\n context,\n radius,\n particle,\n opacity\n } = data,\n image = particle.image,\n element = image?.element;\n if (!image) {\n return;\n }\n context.globalAlpha = opacity;\n if (image.gif && image.gifData) {\n const {\n drawGif\n } = await __webpack_require__.e(/*! import() */ \"dist_browser_GifUtils_Utils_js\").then(__webpack_require__.bind(__webpack_require__, /*! ./GifUtils/Utils.js */ \"./dist/browser/GifUtils/Utils.js\"));\n drawGif(data);\n } else if (element) {\n const ratio = image.ratio,\n pos = {\n x: -radius,\n y: -radius\n },\n diameter = radius * double;\n context.drawImage(element, pos.x, pos.y, diameter, diameter / ratio);\n }\n context.globalAlpha = defaultAlpha;\n }\n getSidesCount() {\n return sides;\n }\n async init(container) {\n const options = container.actualOptions;\n if (!options.preload || !this._engine.loadImage) {\n return;\n }\n for (const imageData of options.preload) {\n await this._engine.loadImage(imageData);\n }\n }\n async loadShape(particle) {\n if (particle.shape !== \"image\" && particle.shape !== \"images\") {\n return;\n }\n if (!this._engine.images) {\n this._engine.images = [];\n }\n const imageData = particle.shapeData;\n if (!imageData) {\n return;\n }\n const image = this._engine.images.find(t => t.name === imageData.name || t.source === imageData.src);\n if (!image) {\n await this.loadImageShape(imageData);\n await this.loadShape(particle);\n }\n }\n async particleInit(container, particle) {\n if (particle.shape !== \"image\" && particle.shape !== \"images\") {\n return;\n }\n if (!this._engine.images) {\n this._engine.images = [];\n }\n const images = this._engine.images,\n imageData = particle.shapeData;\n if (!imageData) {\n return;\n }\n const color = particle.getFillColor(),\n image = images.find(t => t.name === imageData.name || t.source === imageData.src);\n if (!image) {\n return;\n }\n const replaceColor = imageData.replaceColor ?? image.replaceColor;\n if (image.loading) {\n setTimeout(() => {\n void this.particleInit(container, particle);\n });\n return;\n }\n let imageRes;\n if (image.svgData && color) {\n const {\n replaceImageColor\n } = await Promise.resolve(/*! import() */).then(__webpack_require__.bind(__webpack_require__, /*! ./Utils.js */ \"./dist/browser/Utils.js\"));\n imageRes = await replaceImageColor(image, imageData, color, particle);\n } else {\n imageRes = {\n color,\n data: image,\n element: image.element,\n gif: image.gif,\n gifData: image.gifData,\n gifLoopCount: image.gifLoopCount,\n loaded: true,\n ratio: imageData.width && imageData.height ? imageData.width / imageData.height : image.ratio ?? defaultRatio,\n replaceColor: replaceColor,\n source: imageData.src\n };\n }\n if (!imageRes.ratio) {\n imageRes.ratio = 1;\n }\n const fill = imageData.fill ?? particle.shapeFill,\n close = imageData.close ?? particle.shapeClose,\n imageShape = {\n image: imageRes,\n fill,\n close\n };\n particle.image = imageShape.image;\n particle.shapeFill = imageShape.fill;\n particle.shapeClose = imageShape.close;\n }\n}\n\n//# sourceURL=webpack://@tsparticles/shape-image/./dist/browser/ImageDrawer.js?");
27
+
28
+ /***/ })
29
+
30
+ }]);
@@ -0,0 +1,40 @@
1
+ /*!
2
+ * Author : Matteo Bruni
3
+ * MIT license: https://opensource.org/licenses/MIT
4
+ * Demo / Generator : https://particles.js.org/
5
+ * GitHub : https://www.github.com/matteobruni/tsparticles
6
+ * How to use? : Check the GitHub README
7
+ * v3.2.0
8
+ */
9
+ "use strict";
10
+ /*
11
+ * ATTENTION: The "eval" devtool has been used (maybe by default in mode: "development").
12
+ * This devtool is neither made for production nor for readable output files.
13
+ * It uses "eval()" calls to create a separate source file in the browser devtools.
14
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
15
+ * or disable the default devtool with "devtool: false".
16
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
17
+ */
18
+ (this["webpackChunk_tsparticles_shape_image"] = this["webpackChunk_tsparticles_shape_image"] || []).push([["dist_browser_ImagePreloader_js"],{
19
+
20
+ /***/ "./dist/browser/ImagePreloader.js":
21
+ /*!****************************************!*\
22
+ !*** ./dist/browser/ImagePreloader.js ***!
23
+ \****************************************/
24
+ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
25
+
26
+ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ ImagePreloaderPlugin: () => (/* binding */ ImagePreloaderPlugin)\n/* harmony export */ });\n/* harmony import */ var _Options_Classes_Preload_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Options/Classes/Preload.js */ \"./dist/browser/Options/Classes/Preload.js\");\n\nclass ImagePreloaderPlugin {\n constructor(engine) {\n this.id = \"imagePreloader\";\n this._engine = engine;\n }\n async getPlugin() {\n await Promise.resolve();\n return {};\n }\n loadOptions(options, source) {\n if (!source?.preload) {\n return;\n }\n if (!options.preload) {\n options.preload = [];\n }\n const preloadOptions = options.preload;\n for (const item of source.preload) {\n const existing = preloadOptions.find(t => t.name === item.name || t.src === item.src);\n if (existing) {\n existing.load(item);\n } else {\n const preload = new _Options_Classes_Preload_js__WEBPACK_IMPORTED_MODULE_0__.Preload();\n preload.load(item);\n preloadOptions.push(preload);\n }\n }\n }\n needsPlugin() {\n return true;\n }\n}\n\n//# sourceURL=webpack://@tsparticles/shape-image/./dist/browser/ImagePreloader.js?");
27
+
28
+ /***/ }),
29
+
30
+ /***/ "./dist/browser/Options/Classes/Preload.js":
31
+ /*!*************************************************!*\
32
+ !*** ./dist/browser/Options/Classes/Preload.js ***!
33
+ \*************************************************/
34
+ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
35
+
36
+ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ Preload: () => (/* binding */ Preload)\n/* harmony export */ });\nclass Preload {\n constructor() {\n this.src = \"\";\n this.gif = false;\n }\n load(data) {\n if (!data) {\n return;\n }\n if (data.gif !== undefined) {\n this.gif = data.gif;\n }\n if (data.height !== undefined) {\n this.height = data.height;\n }\n if (data.name !== undefined) {\n this.name = data.name;\n }\n if (data.replaceColor !== undefined) {\n this.replaceColor = data.replaceColor;\n }\n if (data.src !== undefined) {\n this.src = data.src;\n }\n if (data.width !== undefined) {\n this.width = data.width;\n }\n }\n}\n\n//# sourceURL=webpack://@tsparticles/shape-image/./dist/browser/Options/Classes/Preload.js?");
37
+
38
+ /***/ })
39
+
40
+ }]);
@@ -12,32 +12,36 @@ export class ByteStream {
12
12
  return this.data[this.pos++];
13
13
  }
14
14
  nextTwoBytes() {
15
- this.pos += 2;
16
- return this.data[this.pos - 2] + (this.data[this.pos - 1] << 8);
15
+ const increment = 2, previous = 1, shift = 8;
16
+ this.pos += increment;
17
+ return this.data[this.pos - increment] + (this.data[this.pos - previous] << shift);
17
18
  }
18
19
  readSubBlocks() {
19
20
  let blockString = "", size = 0;
21
+ const minCount = 0, emptySize = 0;
20
22
  do {
21
23
  size = this.data[this.pos++];
22
- for (let count = size; --count >= 0; blockString += String.fromCharCode(this.data[this.pos++])) {
24
+ for (let count = size; --count >= minCount; blockString += String.fromCharCode(this.data[this.pos++])) {
23
25
  }
24
- } while (size !== 0);
26
+ } while (size !== emptySize);
25
27
  return blockString;
26
28
  }
27
29
  readSubBlocksBin() {
28
- let size = 0, len = 0;
29
- for (let offset = 0; (size = this.data[this.pos + offset]) !== 0; offset += size + 1) {
30
+ let size = this.data[this.pos], len = 0;
31
+ const emptySize = 0, increment = 1;
32
+ for (let offset = 0; size !== emptySize; offset += size + increment, size = this.data[this.pos + offset]) {
30
33
  len += size;
31
34
  }
32
35
  const blockData = new Uint8Array(len);
33
- for (let i = 0; (size = this.data[this.pos++]) !== 0;) {
34
- for (let count = size; --count >= 0; blockData[i++] = this.data[this.pos++]) {
36
+ size = this.data[this.pos++];
37
+ for (let i = 0; size !== emptySize; size = this.data[this.pos++]) {
38
+ for (let count = size; --count >= emptySize; blockData[i++] = this.data[this.pos++]) {
35
39
  }
36
40
  }
37
41
  return blockData;
38
42
  }
39
43
  skipSubBlocks() {
40
- for (; this.data[this.pos] !== 0; this.pos += this.data[this.pos] + 1) {
44
+ for (const increment = 1, noData = 0; this.data[this.pos] !== noData; this.pos += this.data[this.pos] + increment) {
41
45
  }
42
46
  this.pos++;
43
47
  }
@@ -1,5 +1,9 @@
1
1
  import { InterlaceOffsets, InterlaceSteps } from "./Constants.js";
2
2
  import { ByteStream } from "./ByteStream.js";
3
+ const origin = {
4
+ x: 0,
5
+ y: 0,
6
+ }, defaultFrame = 0, half = 0.5, initialTime = 0, firstIndex = 0, defaultLoopCount = 0;
3
7
  function parseColorTable(byteStream, count) {
4
8
  const colors = [];
5
9
  for (let i = 0; i < count; i++) {
@@ -12,7 +16,7 @@ function parseColorTable(byteStream, count) {
12
16
  }
13
17
  return colors;
14
18
  }
15
- async function parseExtensionBlock(byteStream, gif, getFrameIndex, getTransparencyIndex) {
19
+ function parseExtensionBlock(byteStream, gif, getFrameIndex, getTransparencyIndex) {
16
20
  switch (byteStream.nextByte()) {
17
21
  case 249: {
18
22
  const frame = gif.frames[getFrameIndex(false)];
@@ -84,7 +88,10 @@ async function parseImageBlock(byteStream, gif, avgAlpha, getFrameIndex, getTran
84
88
  }
85
89
  const getColor = (index) => {
86
90
  const { r, g, b } = (localColorTableFlag ? frame.localColorTable : gif.globalColorTable)[index];
87
- return { r, g, b, a: index === getTransparencyIndex(null) ? (avgAlpha ? ~~((r + g + b) / 3) : 0) : 255 };
91
+ if (index !== getTransparencyIndex(null)) {
92
+ return { r, g, b, a: 255 };
93
+ }
94
+ return { r, g, b, a: avgAlpha ? ~~((r + g + b) / 3) : 0 };
88
95
  };
89
96
  const image = (() => {
90
97
  try {
@@ -110,7 +117,8 @@ async function parseImageBlock(byteStream, gif, avgAlpha, getFrameIndex, getTran
110
117
  if (interlacedFlag) {
111
118
  for (let code = 0, size = minCodeSize + 1, pos = 0, dic = [[0]], pass = 0; pass < 4; pass++) {
112
119
  if (InterlaceOffsets[pass] < frame.height) {
113
- for (let pixelPos = 0, lineIndex = 0;;) {
120
+ let pixelPos = 0, lineIndex = 0, exit = false;
121
+ while (!exit) {
114
122
  const last = code;
115
123
  code = readBits(pos, size);
116
124
  pos += size + 1;
@@ -128,8 +136,8 @@ async function parseImageBlock(byteStream, gif, avgAlpha, getFrameIndex, getTran
128
136
  else if (last !== clearCode) {
129
137
  dic.push(dic[last].concat(dic[code][0]));
130
138
  }
131
- for (let i = 0; i < dic[code].length; i++) {
132
- const { r, g, b, a } = getColor(dic[code][i]);
139
+ for (const item of dic[code]) {
140
+ const { r, g, b, a } = getColor(item);
133
141
  image.data.set([r, g, b, a], InterlaceOffsets[pass] * frame.width +
134
142
  InterlaceSteps[pass] * lineIndex +
135
143
  (pixelPos % (frame.width * 4)));
@@ -142,7 +150,7 @@ async function parseImageBlock(byteStream, gif, avgAlpha, getFrameIndex, getTran
142
150
  if (pixelPos === frame.width * 4 * (lineIndex + 1)) {
143
151
  lineIndex++;
144
152
  if (InterlaceOffsets[pass] + InterlaceSteps[pass] * lineIndex >= frame.height) {
145
- break;
153
+ exit = true;
146
154
  }
147
155
  }
148
156
  }
@@ -153,7 +161,9 @@ async function parseImageBlock(byteStream, gif, avgAlpha, getFrameIndex, getTran
153
161
  frame.bitmap = await createImageBitmap(image);
154
162
  }
155
163
  else {
156
- for (let code = 0, size = minCodeSize + 1, pos = 0, dic = [[0]], pixelPos = -4;;) {
164
+ let code = 0, size = minCodeSize + 1, pos = 0, pixelPos = -4, exit = false;
165
+ const dic = [[0]];
166
+ while (!exit) {
157
167
  const last = code;
158
168
  code = readBits(pos, size);
159
169
  pos += size;
@@ -166,6 +176,7 @@ async function parseImageBlock(byteStream, gif, avgAlpha, getFrameIndex, getTran
166
176
  }
167
177
  else {
168
178
  if (code === clearCode + 1) {
179
+ exit = true;
169
180
  break;
170
181
  }
171
182
  if (code >= dic.length) {
@@ -174,8 +185,8 @@ async function parseImageBlock(byteStream, gif, avgAlpha, getFrameIndex, getTran
174
185
  else if (last !== clearCode) {
175
186
  dic.push(dic[last].concat(dic[code][0]));
176
187
  }
177
- for (let i = 0; i < dic[code].length; i++) {
178
- const { r, g, b, a } = getColor(dic[code][i]);
188
+ for (const item of dic[code]) {
189
+ const { r, g, b, a } = getColor(item);
179
190
  image.data.set([r, g, b, a], (pixelPos += 4));
180
191
  }
181
192
  if (dic.length >= 1 << size && size < 0xc) {
@@ -196,7 +207,7 @@ async function parseBlock(byteStream, gif, avgAlpha, getFrameIndex, getTranspare
196
207
  await parseImageBlock(byteStream, gif, avgAlpha, getFrameIndex, getTransparencyIndex, progressCallback);
197
208
  break;
198
209
  case 33:
199
- await parseExtensionBlock(byteStream, gif, getFrameIndex, getTransparencyIndex);
210
+ parseExtensionBlock(byteStream, gif, getFrameIndex, getTransparencyIndex);
200
211
  break;
201
212
  default:
202
213
  throw new EvalError("undefined block found");
@@ -322,3 +333,95 @@ export async function decodeGIF(gifURL, progressCallback, avgAlpha) {
322
333
  throw error;
323
334
  }
324
335
  }
336
+ export function drawGif(data) {
337
+ const { context, radius, particle, delta } = data, image = particle.image;
338
+ if (!image?.gifData || !image.gif) {
339
+ return;
340
+ }
341
+ const offscreenCanvas = new OffscreenCanvas(image.gifData.width, image.gifData.height), offscreenContext = offscreenCanvas.getContext("2d");
342
+ if (!offscreenContext) {
343
+ throw new Error("could not create offscreen canvas context");
344
+ }
345
+ offscreenContext.imageSmoothingQuality = "low";
346
+ offscreenContext.imageSmoothingEnabled = false;
347
+ offscreenContext.clearRect(origin.x, origin.y, offscreenCanvas.width, offscreenCanvas.height);
348
+ if (particle.gifLoopCount === undefined) {
349
+ particle.gifLoopCount = image.gifLoopCount ?? defaultLoopCount;
350
+ }
351
+ let frameIndex = particle.gifFrame ?? defaultFrame;
352
+ const pos = { x: -image.gifData.width * half, y: -image.gifData.height * half }, frame = image.gifData.frames[frameIndex];
353
+ if (particle.gifTime === undefined) {
354
+ particle.gifTime = initialTime;
355
+ }
356
+ if (!frame.bitmap) {
357
+ return;
358
+ }
359
+ context.scale(radius / image.gifData.width, radius / image.gifData.height);
360
+ switch (frame.disposalMethod) {
361
+ case 4:
362
+ case 5:
363
+ case 6:
364
+ case 7:
365
+ case 0:
366
+ offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
367
+ context.drawImage(offscreenCanvas, pos.x, pos.y);
368
+ offscreenContext.clearRect(origin.x, origin.y, offscreenCanvas.width, offscreenCanvas.height);
369
+ break;
370
+ case 1:
371
+ offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
372
+ context.drawImage(offscreenCanvas, pos.x, pos.y);
373
+ break;
374
+ case 2:
375
+ offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
376
+ context.drawImage(offscreenCanvas, pos.x, pos.y);
377
+ offscreenContext.clearRect(origin.x, origin.y, offscreenCanvas.width, offscreenCanvas.height);
378
+ if (!image.gifData.globalColorTable.length) {
379
+ offscreenContext.putImageData(image.gifData.frames[firstIndex].image, pos.x + frame.left, pos.y + frame.top);
380
+ }
381
+ else {
382
+ offscreenContext.putImageData(image.gifData.backgroundImage, pos.x, pos.y);
383
+ }
384
+ break;
385
+ case 3:
386
+ {
387
+ const previousImageData = offscreenContext.getImageData(origin.x, origin.y, offscreenCanvas.width, offscreenCanvas.height);
388
+ offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
389
+ context.drawImage(offscreenCanvas, pos.x, pos.y);
390
+ offscreenContext.clearRect(origin.x, origin.y, offscreenCanvas.width, offscreenCanvas.height);
391
+ offscreenContext.putImageData(previousImageData, origin.x, origin.y);
392
+ }
393
+ break;
394
+ }
395
+ particle.gifTime += delta.value;
396
+ if (particle.gifTime > frame.delayTime) {
397
+ particle.gifTime -= frame.delayTime;
398
+ if (++frameIndex >= image.gifData.frames.length) {
399
+ if (--particle.gifLoopCount <= defaultLoopCount) {
400
+ return;
401
+ }
402
+ frameIndex = firstIndex;
403
+ offscreenContext.clearRect(origin.x, origin.y, offscreenCanvas.width, offscreenCanvas.height);
404
+ }
405
+ particle.gifFrame = frameIndex;
406
+ }
407
+ context.scale(image.gifData.width / radius, image.gifData.height / radius);
408
+ }
409
+ export async function loadGifImage(image) {
410
+ if (image.type !== "gif") {
411
+ const { loadImage } = await import("../Utils.js");
412
+ await loadImage(image);
413
+ return;
414
+ }
415
+ image.loading = true;
416
+ try {
417
+ image.gifData = await decodeGIF(image.source);
418
+ image.gifLoopCount = getGIFLoopAmount(image.gifData) ?? defaultLoopCount;
419
+ if (!image.gifLoopCount) {
420
+ image.gifLoopCount = Infinity;
421
+ }
422
+ }
423
+ catch {
424
+ image.error = true;
425
+ }
426
+ image.loading = false;
427
+ }
@@ -1,5 +1,5 @@
1
1
  import { errorPrefix } from "@tsparticles/engine";
2
- import { replaceImageColor } from "./Utils.js";
2
+ const double = 2, defaultAlpha = 1, sides = 12, defaultRatio = 1;
3
3
  export class ImageDrawer {
4
4
  constructor(engine) {
5
5
  this.loadImageShape = async (imageShape) => {
@@ -21,92 +21,27 @@ export class ImageDrawer {
21
21
  }
22
22
  this._engine.images.push(image);
23
23
  }
24
- draw(data) {
25
- const { context, radius, particle, opacity, delta } = data, image = particle.image, element = image?.element;
24
+ async draw(data) {
25
+ const { context, radius, particle, opacity } = data, image = particle.image, element = image?.element;
26
26
  if (!image) {
27
27
  return;
28
28
  }
29
29
  context.globalAlpha = opacity;
30
30
  if (image.gif && image.gifData) {
31
- const offscreenCanvas = new OffscreenCanvas(image.gifData.width, image.gifData.height), offscreenContext = offscreenCanvas.getContext("2d");
32
- if (!offscreenContext) {
33
- throw new Error("could not create offscreen canvas context");
34
- }
35
- offscreenContext.imageSmoothingQuality = "low";
36
- offscreenContext.imageSmoothingEnabled = false;
37
- offscreenContext.clearRect(0, 0, offscreenCanvas.width, offscreenCanvas.height);
38
- if (particle.gifLoopCount === undefined) {
39
- particle.gifLoopCount = image.gifLoopCount ?? 0;
40
- }
41
- let frameIndex = particle.gifFrame ?? 0;
42
- const pos = { x: -image.gifData.width * 0.5, y: -image.gifData.height * 0.5 }, frame = image.gifData.frames[frameIndex];
43
- if (particle.gifTime === undefined) {
44
- particle.gifTime = 0;
45
- }
46
- if (!frame.bitmap) {
47
- return;
48
- }
49
- context.scale(radius / image.gifData.width, radius / image.gifData.height);
50
- switch (frame.disposalMethod) {
51
- case 4:
52
- case 5:
53
- case 6:
54
- case 7:
55
- case 0:
56
- offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
57
- context.drawImage(offscreenCanvas, pos.x, pos.y);
58
- offscreenContext.clearRect(0, 0, offscreenCanvas.width, offscreenCanvas.height);
59
- break;
60
- case 1:
61
- offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
62
- context.drawImage(offscreenCanvas, pos.x, pos.y);
63
- break;
64
- case 2:
65
- offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
66
- context.drawImage(offscreenCanvas, pos.x, pos.y);
67
- offscreenContext.clearRect(0, 0, offscreenCanvas.width, offscreenCanvas.height);
68
- if (image.gifData.globalColorTable.length === 0) {
69
- offscreenContext.putImageData(image.gifData.frames[0].image, pos.x + frame.left, pos.y + frame.top);
70
- }
71
- else {
72
- offscreenContext.putImageData(image.gifData.backgroundImage, pos.x, pos.y);
73
- }
74
- break;
75
- case 3:
76
- {
77
- const previousImageData = offscreenContext.getImageData(0, 0, offscreenCanvas.width, offscreenCanvas.height);
78
- offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
79
- context.drawImage(offscreenCanvas, pos.x, pos.y);
80
- offscreenContext.clearRect(0, 0, offscreenCanvas.width, offscreenCanvas.height);
81
- offscreenContext.putImageData(previousImageData, 0, 0);
82
- }
83
- break;
84
- }
85
- particle.gifTime += delta.value;
86
- if (particle.gifTime > frame.delayTime) {
87
- particle.gifTime -= frame.delayTime;
88
- if (++frameIndex >= image.gifData.frames.length) {
89
- if (--particle.gifLoopCount <= 0) {
90
- return;
91
- }
92
- frameIndex = 0;
93
- offscreenContext.clearRect(0, 0, offscreenCanvas.width, offscreenCanvas.height);
94
- }
95
- particle.gifFrame = frameIndex;
96
- }
97
- context.scale(image.gifData.width / radius, image.gifData.height / radius);
31
+ const { drawGif } = await import("./GifUtils/Utils.js");
32
+ drawGif(data);
98
33
  }
99
34
  else if (element) {
100
35
  const ratio = image.ratio, pos = {
101
36
  x: -radius,
102
37
  y: -radius,
103
- }, diameter = radius * 2;
38
+ }, diameter = radius * double;
104
39
  context.drawImage(element, pos.x, pos.y, diameter, diameter / ratio);
105
40
  }
106
- context.globalAlpha = 1;
41
+ context.globalAlpha = defaultAlpha;
107
42
  }
108
43
  getSidesCount() {
109
- return 12;
44
+ return sides;
110
45
  }
111
46
  async init(container) {
112
47
  const options = container.actualOptions;
@@ -117,7 +52,7 @@ export class ImageDrawer {
117
52
  await this._engine.loadImage(imageData);
118
53
  }
119
54
  }
120
- loadShape(particle) {
55
+ async loadShape(particle) {
121
56
  if (particle.shape !== "image" && particle.shape !== "images") {
122
57
  return;
123
58
  }
@@ -130,12 +65,11 @@ export class ImageDrawer {
130
65
  }
131
66
  const image = this._engine.images.find((t) => t.name === imageData.name || t.source === imageData.src);
132
67
  if (!image) {
133
- this.loadImageShape(imageData).then(() => {
134
- this.loadShape(particle);
135
- });
68
+ await this.loadImageShape(imageData);
69
+ await this.loadShape(particle);
136
70
  }
137
71
  }
138
- particleInit(container, particle) {
72
+ async particleInit(container, particle) {
139
73
  if (particle.shape !== "image" && particle.shape !== "images") {
140
74
  return;
141
75
  }
@@ -153,40 +87,41 @@ export class ImageDrawer {
153
87
  const replaceColor = imageData.replaceColor ?? image.replaceColor;
154
88
  if (image.loading) {
155
89
  setTimeout(() => {
156
- this.particleInit(container, particle);
90
+ void this.particleInit(container, particle);
157
91
  });
158
92
  return;
159
93
  }
160
- (async () => {
161
- let imageRes;
162
- if (image.svgData && color) {
163
- imageRes = await replaceImageColor(image, imageData, color, particle);
164
- }
165
- else {
166
- imageRes = {
167
- color,
168
- data: image,
169
- element: image.element,
170
- gif: image.gif,
171
- gifData: image.gifData,
172
- gifLoopCount: image.gifLoopCount,
173
- loaded: true,
174
- ratio: imageData.width && imageData.height ? imageData.width / imageData.height : image.ratio ?? 1,
175
- replaceColor: replaceColor,
176
- source: imageData.src,
177
- };
178
- }
179
- if (!imageRes.ratio) {
180
- imageRes.ratio = 1;
181
- }
182
- const fill = imageData.fill ?? particle.shapeFill, close = imageData.close ?? particle.shapeClose, imageShape = {
183
- image: imageRes,
184
- fill,
185
- close,
94
+ let imageRes;
95
+ if (image.svgData && color) {
96
+ const { replaceImageColor } = await import("./Utils.js");
97
+ imageRes = await replaceImageColor(image, imageData, color, particle);
98
+ }
99
+ else {
100
+ imageRes = {
101
+ color,
102
+ data: image,
103
+ element: image.element,
104
+ gif: image.gif,
105
+ gifData: image.gifData,
106
+ gifLoopCount: image.gifLoopCount,
107
+ loaded: true,
108
+ ratio: imageData.width && imageData.height
109
+ ? imageData.width / imageData.height
110
+ : image.ratio ?? defaultRatio,
111
+ replaceColor: replaceColor,
112
+ source: imageData.src,
186
113
  };
187
- particle.image = imageShape.image;
188
- particle.shapeFill = imageShape.fill;
189
- particle.shapeClose = imageShape.close;
190
- })();
114
+ }
115
+ if (!imageRes.ratio) {
116
+ imageRes.ratio = 1;
117
+ }
118
+ const fill = imageData.fill ?? particle.shapeFill, close = imageData.close ?? particle.shapeClose, imageShape = {
119
+ image: imageRes,
120
+ fill,
121
+ close,
122
+ };
123
+ particle.image = imageShape.image;
124
+ particle.shapeFill = imageShape.fill;
125
+ particle.shapeClose = imageShape.close;
191
126
  }
192
127
  }
@@ -4,11 +4,12 @@ export class ImagePreloaderPlugin {
4
4
  this.id = "imagePreloader";
5
5
  this._engine = engine;
6
6
  }
7
- getPlugin() {
7
+ async getPlugin() {
8
+ await Promise.resolve();
8
9
  return {};
9
10
  }
10
11
  loadOptions(options, source) {
11
- if (!source || !source.preload) {
12
+ if (!source?.preload) {
12
13
  return;
13
14
  }
14
15
  if (!options.preload) {