@tsparticles/shape-image 4.0.0-alpha.5 → 4.0.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/375.min.js +1 -0
- package/550.min.js +1 -0
- package/682.min.js +1 -0
- package/814.min.js +1 -0
- package/browser/GifUtils/ByteStream.js +3 -1
- package/browser/GifUtils/Utils.js +36 -42
- package/browser/ImageDrawer.js +29 -35
- package/browser/ImagePreloader.js +7 -5
- package/browser/ImagePreloaderInstance.js +11 -0
- package/browser/Options/Classes/Preload.js +6 -0
- package/browser/Utils.js +7 -6
- package/browser/index.js +27 -13
- package/cjs/GifUtils/ByteStream.js +3 -1
- package/cjs/GifUtils/Utils.js +36 -42
- package/cjs/ImageDrawer.js +29 -35
- package/cjs/ImagePreloader.js +7 -5
- package/cjs/ImagePreloaderInstance.js +11 -0
- package/cjs/Options/Classes/Preload.js +6 -0
- package/cjs/Utils.js +7 -6
- package/cjs/index.js +27 -13
- package/dist_browser_GifUtils_Utils_js.js +6 -16
- package/dist_browser_ImageDrawer_js.js +2 -2
- package/dist_browser_ImagePreloaderInstance_js.js +30 -0
- package/dist_browser_ImagePreloader_js.js +3 -3
- package/esm/GifUtils/ByteStream.js +3 -1
- package/esm/GifUtils/Utils.js +36 -42
- package/esm/ImageDrawer.js +29 -35
- package/esm/ImagePreloader.js +7 -5
- package/esm/ImagePreloaderInstance.js +11 -0
- package/esm/Options/Classes/Preload.js +6 -0
- package/esm/Utils.js +7 -6
- package/esm/index.js +27 -13
- package/package.json +2 -2
- package/report.html +3 -3
- package/tsparticles.shape.image.js +40 -18
- package/tsparticles.shape.image.min.js +2 -2
- package/types/GifUtils/Utils.d.ts +4 -4
- package/types/ImageDrawer.d.ts +1 -3
- package/types/ImagePreloader.d.ts +5 -4
- package/types/ImagePreloaderInstance.d.ts +8 -0
- package/types/Utils.d.ts +1 -0
- package/types/types.d.ts +3 -2
- package/umd/GifUtils/ByteStream.js +3 -1
- package/umd/GifUtils/Utils.js +37 -43
- package/umd/ImageDrawer.js +28 -34
- package/umd/ImagePreloader.js +41 -5
- package/umd/ImagePreloaderInstance.js +25 -0
- package/umd/Options/Classes/Preload.js +6 -0
- package/umd/Utils.js +8 -6
- package/umd/index.js +28 -14
- package/324.min.js +0 -2
- package/324.min.js.LICENSE.txt +0 -1
- package/337.min.js +0 -2
- package/337.min.js.LICENSE.txt +0 -1
- package/413.min.js +0 -2
- package/413.min.js.LICENSE.txt +0 -1
- package/72.min.js +0 -2
- package/72.min.js.LICENSE.txt +0 -1
- package/dist_browser_Utils_js.js +0 -30
- package/tsparticles.shape.image.min.js.LICENSE.txt +0 -1
package/375.min.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";(this.webpackChunk_tsparticles_shape_image=this.webpackChunk_tsparticles_shape_image||[]).push([[375],{375(e,i,t){t.d(i,{ImagePreloaderPlugin:()=>a});var s=t(303);class r{gif;height;name;replaceColor;src;width;constructor(){this.src="",this.gif=!1}load(e){(0,s.isNull)(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 a{id="image-preloader";_engine;constructor(e){this._engine=e}async getPlugin(e){let{ImagePreloaderInstance:i}=await t.e(550).then(t.bind(t,550));return new i(this._engine,e)}loadOptions(e,i,t){if(!t?.preload)return;i.preload??=[];let s=i.preload;for(let e of t.preload){let i=s.find(i=>i.name===e.name||i.src===e.src);if(i)i.load(e);else{let i=new r;i.load(e),s.push(i)}}}needsPlugin(){return!0}}}}]);
|
package/550.min.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";(this.webpackChunk_tsparticles_shape_image=this.webpackChunk_tsparticles_shape_image||[]).push([[550],{550(e,s,t){t.d(s,{ImagePreloaderInstance:()=>i});class i{_container;_engine;constructor(e,s){this._engine=e,this._container=s}destroy(){this._engine.images?.delete(this._container)}}}}]);
|
package/682.min.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";(this.webpackChunk_tsparticles_shape_image=this.webpackChunk_tsparticles_shape_image||[]).push([[682,814],{814(e,t,a){a.d(t,{zS:()=>w,loadGifImage:()=>x});var i,o,n,r,l=a(183),s=a(303);let h=[0,4,2,1],g=[8,8,4,2];class d{data;pos;constructor(e){this.pos=0,this.data=new Uint8ClampedArray(e)}getString(e){let 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;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=this.data[this.pos],t=0;for(let a=0;0!==e;a+=e+1,e=this.data[this.pos+a])t+=e;let a=new Uint8Array(t);e=this.data[this.pos++];for(let t=0;0!==e;e=this.data[this.pos++])for(let i=e;--i>=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 f(e,t){let a=[];for(let i=0;i<t;i++)a.push({r:e.data[e.pos],g:e.data[e.pos+1],b:e.data[e.pos+2]}),e.pos+=3;return a}function c(e,t,a){let i=t>>>3,o=7&t;return(e[i]+(e[i+1]<<8)+(e[i+2]<<16)&(1<<a)-1<<o)>>>o}async function p(e,t,a,i,o,n,r){let l=t.frames[i(!0)];l.left=e.nextTwoBytes(),l.top=e.nextTwoBytes(),l.width=e.nextTwoBytes(),l.height=e.nextTwoBytes();let s=e.nextByte(),d=(128&s)==128;l.sortFlag=(32&s)==32,l.reserved=(24&s)>>>3,d&&(l.localColorTable=f(e,1<<(7&s)+1));let p=e=>{let{r:i,g:n,b:r}=(d?l.localColorTable:t.globalColorTable)[e];return e!==o(null)?{r:i,g:n,b:r,a:255}:{r:i,g:n,b:r,a:a?Math.trunc((i+n+r)/3):0}},m=(()=>{try{return new ImageData(l.width,l.height,n)}catch(e){if(e instanceof DOMException&&"IndexSizeError"===e.name)return null;throw e}})();if(null==m)throw EvalError("GIF frame size is to large");let u=e.nextByte(),w=e.readSubBlocksBin(),x=1<<u;if((64&s)==64){for(let a=0,o=u+1,n=0,s=[[0]],d=0;d<4;d++){if(h[d]<l.height){let e=0,t=0,i=!1;for(;!i;){let r=a;if(a=c(w,n,o),n+=o+1,a===x){o=u+1,s.length=x+2;for(let e=0;e<s.length;e++)s[e]=e<x?[e]:[]}else{for(let i of(a>=s.length?s.push(s[r].concat(s[r][0])):r!==x&&s.push(s[r].concat(s[a][0])),s[a])){let{r:a,g:o,b:n,a:r}=p(i);m.data.set([a,o,n,r],h[d]*l.width+g[d]*t+e%(4*l.width)),e+=4}s.length===1<<o&&o<12&&o++}e===4*l.width*(t+1)&&(t++,h[d]+g[d]*t>=l.height&&(i=!0))}}r?.(e.pos/(e.data.length-1),i(!1)+1,m,{x:l.left,y:l.top},{width:t.width,height:t.height})}l.image=m,l.bitmap=await createImageBitmap(m)}else{let a=0,o=u+1,n=0,s=-4,h=[[0]];for(;;){let e=a;if(a=c(w,n,o),n+=o,a===x){o=u+1,h.length=x+2;for(let e=0;e<h.length;e++)h[e]=e<x?[e]:[]}else{if(a===x+1)break;for(let t of(a>=h.length?h.push(h[e].concat(h[e][0])):e!==x&&h.push(h[e].concat(h[a][0])),h[a])){let{r:e,g:a,b:i,a:o}=p(t);s+=4,m.data.set([e,a,i,o],s)}h.length>=1<<o&&o<12&&o++}}l.image=m,l.bitmap=await createImageBitmap(m),r?.((e.pos+1)/e.data.length,i(!1)+1,l.image,{x:l.left,y:l.top},{width:t.width,height:t.height})}}async function m(e,t,a,i,o,n,l){switch(e.nextByte()){case r.EndOfFile:return!0;case r.Image:await p(e,t,a,i,o,n,l);break;case r.Extension:switch(e.nextByte()){case r.GraphicsControlExtension:{let a=t.frames[i(!1)];e.pos++;let n=e.nextByte();a.GCreserved=(224&n)>>>5,a.disposalMethod=(28&n)>>>2,a.userInputDelayFlag=(2&n)==2,a.delayTime=10*e.nextTwoBytes();let r=e.nextByte();(1&n)==1&&o(r),e.pos++;break}case r.ApplicationExtension:{e.pos++;let a={identifier:e.getString(8),authenticationCode:e.getString(3),data:e.readSubBlocksBin()};t.applicationExtensions.push(a);break}case r.CommentExtension:t.comments.push([i(!1),e.readSubBlocks()]);break;case r.PlainTextExtension:if(0===t.globalColorTable.length)throw EvalError("plain text extension without global color table");e.pos++,t.frames[i(!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()}break;default:throw EvalError("undefined block found")}return!1}async function u(e,t,a,i){i??=!1;let o=await fetch(e);if(!o.ok&&404===o.status)throw EvalError("file not found");let r=await o.arrayBuffer(),l={width:0,height:0,totalTime:0,colorRes:0,pixelAspectRatio:0,frames:[],sortFlag:!1,globalColorTable:[],backgroundImage:new ImageData(1,1,t),comments:[],applicationExtensions:[]},s=new d(new Uint8ClampedArray(r));if("GIF89a"!==s.getString(6))throw Error("not a supported GIF file");l.width=s.nextTwoBytes(),l.height=s.nextTwoBytes();let h=s.nextByte(),g=(128&h)==128;l.colorRes=(112&h)>>>4,l.sortFlag=(8&h)==8;let c=s.nextByte();l.pixelAspectRatio=s.nextByte(),0!==l.pixelAspectRatio&&(l.pixelAspectRatio=(l.pixelAspectRatio+15)/64),g&&(l.globalColorTable=f(s,1<<(7&h)+1));let p=(()=>{try{return new ImageData(l.width,l.height,t)}catch(e){if(e instanceof DOMException&&"IndexSizeError"===e.name)return null;throw e}})();if(null==p)throw Error("GIF frame size is to large");let{r:u,g:w,b:x}=l.globalColorTable[c];p.data.set(g?[u,w,x,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,C=-1,I=e=>(e&&(b=!0),y),B=e=>(null!=e&&(C=e),C);try{do b&&(l.frames.push({left:0,top:0,width:0,height:0,disposalMethod:n.Replace,image:new ImageData(1,1,t),plainTextData:null,userInputDelayFlag:!1,delayTime:0,sortFlag:!1,localColorTable:[],reserved:0,GCreserved:0}),y++,C=-1,b=!1);while(!await m(s,l,i,I,B,t,a))for(let e of(l.frames.length--,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 Error(`error while parsing frame ${y.toString()} "${e.message}"`,{cause:e});throw e}}function w(e,t){let{context:a,radius:i,particle:o,delta:r}=e,l=o.image;if(!l?.gifData||!l.gif)return;let h=new OffscreenCanvas(l.gifData.width,l.gifData.height),g=h.getContext("2d",t);if(!g)throw Error("could not create offscreen canvas context");g.imageSmoothingQuality="low",g.imageSmoothingEnabled=!1,g.clearRect(s.originPoint.x,s.originPoint.y,h.width,h.height),o.gifLoopCount??=l.gifLoopCount??0;let d=o.gifFrame??0,f={x:-l.gifData.width*s.half,y:-l.gifData.height*s.half},c=l.gifData.frames[d];if(o.gifTime??=0,c.bitmap){switch(a.scale(i/l.gifData.width,i/l.gifData.height),c.disposalMethod){case n.UndefinedA:case n.UndefinedB:case n.UndefinedC:case n.UndefinedD:case n.Replace:g.drawImage(c.bitmap,c.left,c.top),a.drawImage(h,f.x,f.y),g.clearRect(s.originPoint.x,s.originPoint.y,h.width,h.height);break;case n.Combine:g.drawImage(c.bitmap,c.left,c.top),a.drawImage(h,f.x,f.y);break;case n.RestoreBackground:g.drawImage(c.bitmap,c.left,c.top),a.drawImage(h,f.x,f.y),g.clearRect(s.originPoint.x,s.originPoint.y,h.width,h.height),l.gifData.globalColorTable.length?g.putImageData(l.gifData.backgroundImage,f.x,f.y):g.putImageData(l.gifData.frames[0].image,f.x+c.left,f.y+c.top);break;case n.RestorePrevious:{let e=g.getImageData(s.originPoint.x,s.originPoint.y,h.width,h.height);g.drawImage(c.bitmap,c.left,c.top),a.drawImage(h,f.x,f.y),g.clearRect(s.originPoint.x,s.originPoint.y,h.width,h.height),g.putImageData(e,s.originPoint.x,s.originPoint.y)}}if(o.gifTime+=r.value,o.gifTime>c.delayTime){if(o.gifTime-=c.delayTime,++d>=l.gifData.frames.length){if(--o.gifLoopCount<=0)return;d=0,g.clearRect(s.originPoint.x,s.originPoint.y,h.width,h.height)}o.gifFrame=d}a.scale(l.gifData.width/i,l.gifData.height/i)}}async function x(e,t){if("gif"!==e.type)return void await (0,l.loadImage)(e);e.loading=!0;try{e.gifData=await u(e.source,t),e.gifLoopCount=function(e){for(let t of e.applicationExtensions)if(t.identifier+t.authenticationCode==="NETSCAPE2.0")return t.data[1]+(t.data[2]<<8);return NaN}(e.gifData),e.gifLoopCount||(e.gifLoopCount=1/0)}catch{e.error=!0}e.loading=!1}(i=n||(n={}))[i.Replace=0]="Replace",i[i.Combine=1]="Combine",i[i.RestoreBackground=2]="RestoreBackground",i[i.RestorePrevious=3]="RestorePrevious",i[i.UndefinedA=4]="UndefinedA",i[i.UndefinedB=5]="UndefinedB",i[i.UndefinedC=6]="UndefinedC",i[i.UndefinedD=7]="UndefinedD",(o=r||(r={}))[o.Extension=33]="Extension",o[o.ApplicationExtension=255]="ApplicationExtension",o[o.GraphicsControlExtension=249]="GraphicsControlExtension",o[o.PlainTextExtension=1]="PlainTextExtension",o[o.CommentExtension=254]="CommentExtension",o[o.Image=44]="Image",o[o.EndOfFile=59]="EndOfFile"},682(e,t,a){a.d(t,{ImageDrawer:()=>r});var i=a(303),o=a(183),n=a(814);class r{_engine;constructor(e){this._engine=e}draw(e){let{context:t,radius:a,particle:o,opacity:r}=e,l=o.image,s=l?.element;if(l){if(t.globalAlpha=r,l.gif&&l.gifData)(0,n.zS)(e,o.container.canvas.settings);else if(s){let e=l.ratio,o={x:-a,y:-a},n=a*i.double;t.drawImage(s,o.x,o.y,n,n/e)}t.globalAlpha=i.defaultAlpha}}getSidesCount(){return 12}async init(e){let t=e.actualOptions;if(!t.preload||!this._engine.loadImage)return;let a=[];for(let i of t.preload)a.push(this._engine.loadImage(e,i));await Promise.all(a)}loadShape(e){let{container:t}=e;if(!e.shape||!o.z.includes(e.shape))return;let a=e.shapeData;if(!a)return;let i=this._engine.getImages?.(t);i?.find(e=>e.name===a.name||e.source===a.src)||this.loadImageShape(t,a).then(()=>{this.loadShape(e)})}particleInit(e,t){if("image"!==t.shape&&"images"!==t.shape)return;let a=this._engine.getImages?.(e),n=t.shapeData;if(!n)return;let r=t.getFillColor(),l=a?.find(e=>e.name===n.name||e.source===n.src);if(!l)return;let s=n.replaceColor;l.loading?setTimeout(()=>{this.particleInit(e,t)}):(async()=>{let a;(a=l.svgData&&r?await (0,o.d)(l,n,r,t,e.hdr):{color:r,data:l,element:l.element,gif:l.gif,gifData:l.gifData,gifLoopCount:l.gifLoopCount,loaded:!0,ratio:n.width&&n.height?n.width/n.height:l.ratio??i.defaultRatio,replaceColor:s,source:n.src}).ratio||(a.ratio=1);let h=n.close??t.shapeClose;t.image=a,t.shapeClose=h})()}loadImageShape=async(e,t)=>{if(!this._engine.loadImage)throw Error("Image shape not initialized");await this._engine.loadImage(e,{gif:t.gif,name:t.name,replaceColor:t.replaceColor,src:t.src})}}}}]);
|
package/814.min.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";(this.webpackChunk_tsparticles_shape_image=this.webpackChunk_tsparticles_shape_image||[]).push([[814],{814(t,e,a){a.d(e,{zS:()=>w,loadGifImage:()=>x});var i,o,n,r,l=a(183),s=a(303);let h=[0,4,2,1],g=[8,8,4,2];class d{data;pos;constructor(t){this.pos=0,this.data=new Uint8ClampedArray(t)}getString(t){let e=this.data.slice(this.pos,this.pos+t);return this.pos+=e.length,e.reduce((t,e)=>t+String.fromCharCode(e),"")}nextByte(){return this.data[this.pos++]}nextTwoBytes(){return this.pos+=2,this.data[this.pos-2]+(this.data[this.pos-1]<<8)}readSubBlocks(){let t="",e;do{e=this.data[this.pos++];for(let a=e;--a>=0;t+=String.fromCharCode(this.data[this.pos++]));}while(0!==e)return t}readSubBlocksBin(){let t=this.data[this.pos],e=0;for(let a=0;0!==t;a+=t+1,t=this.data[this.pos+a])e+=t;let a=new Uint8Array(e);t=this.data[this.pos++];for(let e=0;0!==t;t=this.data[this.pos++])for(let i=t;--i>=0;a[e++]=this.data[this.pos++]);return a}skipSubBlocks(){for(;0!==this.data[this.pos];this.pos+=this.data[this.pos]+1);this.pos++}}function f(t,e){let a=[];for(let i=0;i<e;i++)a.push({r:t.data[t.pos],g:t.data[t.pos+1],b:t.data[t.pos+2]}),t.pos+=3;return a}function c(t,e,a){let i=e>>>3,o=7&e;return(t[i]+(t[i+1]<<8)+(t[i+2]<<16)&(1<<a)-1<<o)>>>o}async function p(t,e,a,i,o,n,r){let l=e.frames[i(!0)];l.left=t.nextTwoBytes(),l.top=t.nextTwoBytes(),l.width=t.nextTwoBytes(),l.height=t.nextTwoBytes();let s=t.nextByte(),d=(128&s)==128;l.sortFlag=(32&s)==32,l.reserved=(24&s)>>>3,d&&(l.localColorTable=f(t,1<<(7&s)+1));let p=t=>{let{r:i,g:n,b:r}=(d?l.localColorTable:e.globalColorTable)[t];return t!==o(null)?{r:i,g:n,b:r,a:255}:{r:i,g:n,b:r,a:a?Math.trunc((i+n+r)/3):0}},u=(()=>{try{return new ImageData(l.width,l.height,n)}catch(t){if(t instanceof DOMException&&"IndexSizeError"===t.name)return null;throw t}})();if(null==u)throw EvalError("GIF frame size is to large");let m=t.nextByte(),w=t.readSubBlocksBin(),x=1<<m;if((64&s)==64){for(let a=0,o=m+1,n=0,s=[[0]],d=0;d<4;d++){if(h[d]<l.height){let t=0,e=0,i=!1;for(;!i;){let r=a;if(a=c(w,n,o),n+=o+1,a===x){o=m+1,s.length=x+2;for(let t=0;t<s.length;t++)s[t]=t<x?[t]:[]}else{for(let i of(a>=s.length?s.push(s[r].concat(s[r][0])):r!==x&&s.push(s[r].concat(s[a][0])),s[a])){let{r:a,g:o,b:n,a:r}=p(i);u.data.set([a,o,n,r],h[d]*l.width+g[d]*e+t%(4*l.width)),t+=4}s.length===1<<o&&o<12&&o++}t===4*l.width*(e+1)&&(e++,h[d]+g[d]*e>=l.height&&(i=!0))}}r?.(t.pos/(t.data.length-1),i(!1)+1,u,{x:l.left,y:l.top},{width:e.width,height:e.height})}l.image=u,l.bitmap=await createImageBitmap(u)}else{let a=0,o=m+1,n=0,s=-4,h=[[0]];for(;;){let t=a;if(a=c(w,n,o),n+=o,a===x){o=m+1,h.length=x+2;for(let t=0;t<h.length;t++)h[t]=t<x?[t]:[]}else{if(a===x+1)break;for(let e of(a>=h.length?h.push(h[t].concat(h[t][0])):t!==x&&h.push(h[t].concat(h[a][0])),h[a])){let{r:t,g:a,b:i,a:o}=p(e);s+=4,u.data.set([t,a,i,o],s)}h.length>=1<<o&&o<12&&o++}}l.image=u,l.bitmap=await createImageBitmap(u),r?.((t.pos+1)/t.data.length,i(!1)+1,l.image,{x:l.left,y:l.top},{width:e.width,height:e.height})}}async function u(t,e,a,i,o,n,l){switch(t.nextByte()){case r.EndOfFile:return!0;case r.Image:await p(t,e,a,i,o,n,l);break;case r.Extension:switch(t.nextByte()){case r.GraphicsControlExtension:{let a=e.frames[i(!1)];t.pos++;let n=t.nextByte();a.GCreserved=(224&n)>>>5,a.disposalMethod=(28&n)>>>2,a.userInputDelayFlag=(2&n)==2,a.delayTime=10*t.nextTwoBytes();let r=t.nextByte();(1&n)==1&&o(r),t.pos++;break}case r.ApplicationExtension:{t.pos++;let a={identifier:t.getString(8),authenticationCode:t.getString(3),data:t.readSubBlocksBin()};e.applicationExtensions.push(a);break}case r.CommentExtension:e.comments.push([i(!1),t.readSubBlocks()]);break;case r.PlainTextExtension:if(0===e.globalColorTable.length)throw EvalError("plain text extension without global color table");t.pos++,e.frames[i(!1)].plainTextData={left:t.nextTwoBytes(),top:t.nextTwoBytes(),width:t.nextTwoBytes(),height:t.nextTwoBytes(),charSize:{width:t.nextTwoBytes(),height:t.nextTwoBytes()},foregroundColor:t.nextByte(),backgroundColor:t.nextByte(),text:t.readSubBlocks()};break;default:t.skipSubBlocks()}break;default:throw EvalError("undefined block found")}return!1}async function m(t,e,a,i){i??=!1;let o=await fetch(t);if(!o.ok&&404===o.status)throw EvalError("file not found");let r=await o.arrayBuffer(),l={width:0,height:0,totalTime:0,colorRes:0,pixelAspectRatio:0,frames:[],sortFlag:!1,globalColorTable:[],backgroundImage:new ImageData(1,1,e),comments:[],applicationExtensions:[]},s=new d(new Uint8ClampedArray(r));if("GIF89a"!==s.getString(6))throw Error("not a supported GIF file");l.width=s.nextTwoBytes(),l.height=s.nextTwoBytes();let h=s.nextByte(),g=(128&h)==128;l.colorRes=(112&h)>>>4,l.sortFlag=(8&h)==8;let c=s.nextByte();l.pixelAspectRatio=s.nextByte(),0!==l.pixelAspectRatio&&(l.pixelAspectRatio=(l.pixelAspectRatio+15)/64),g&&(l.globalColorTable=f(s,1<<(7&h)+1));let p=(()=>{try{return new ImageData(l.width,l.height,e)}catch(t){if(t instanceof DOMException&&"IndexSizeError"===t.name)return null;throw t}})();if(null==p)throw Error("GIF frame size is to large");let{r:m,g:w,b:x}=l.globalColorTable[c];p.data.set(g?[m,w,x,255]:[0,0,0,0]);for(let t=4;t<p.data.length;t*=2)p.data.copyWithin(t,0,t);l.backgroundImage=p;let y=-1,b=!0,B=-1,C=t=>(t&&(b=!0),y),E=t=>(null!=t&&(B=t),B);try{do b&&(l.frames.push({left:0,top:0,width:0,height:0,disposalMethod:n.Replace,image:new ImageData(1,1,e),plainTextData:null,userInputDelayFlag:!1,delayTime:0,sortFlag:!1,localColorTable:[],reserved:0,GCreserved:0}),y++,B=-1,b=!1);while(!await u(s,l,i,C,E,e,a))for(let t of(l.frames.length--,l.frames)){if(t.userInputDelayFlag&&0===t.delayTime){l.totalTime=1/0;break}l.totalTime+=t.delayTime}return l}catch(t){if(t instanceof EvalError)throw Error(`error while parsing frame ${y.toString()} "${t.message}"`,{cause:t});throw t}}function w(t,e){let{context:a,radius:i,particle:o,delta:r}=t,l=o.image;if(!l?.gifData||!l.gif)return;let h=new OffscreenCanvas(l.gifData.width,l.gifData.height),g=h.getContext("2d",e);if(!g)throw Error("could not create offscreen canvas context");g.imageSmoothingQuality="low",g.imageSmoothingEnabled=!1,g.clearRect(s.originPoint.x,s.originPoint.y,h.width,h.height),o.gifLoopCount??=l.gifLoopCount??0;let d=o.gifFrame??0,f={x:-l.gifData.width*s.half,y:-l.gifData.height*s.half},c=l.gifData.frames[d];if(o.gifTime??=0,c.bitmap){switch(a.scale(i/l.gifData.width,i/l.gifData.height),c.disposalMethod){case n.UndefinedA:case n.UndefinedB:case n.UndefinedC:case n.UndefinedD:case n.Replace:g.drawImage(c.bitmap,c.left,c.top),a.drawImage(h,f.x,f.y),g.clearRect(s.originPoint.x,s.originPoint.y,h.width,h.height);break;case n.Combine:g.drawImage(c.bitmap,c.left,c.top),a.drawImage(h,f.x,f.y);break;case n.RestoreBackground:g.drawImage(c.bitmap,c.left,c.top),a.drawImage(h,f.x,f.y),g.clearRect(s.originPoint.x,s.originPoint.y,h.width,h.height),l.gifData.globalColorTable.length?g.putImageData(l.gifData.backgroundImage,f.x,f.y):g.putImageData(l.gifData.frames[0].image,f.x+c.left,f.y+c.top);break;case n.RestorePrevious:{let t=g.getImageData(s.originPoint.x,s.originPoint.y,h.width,h.height);g.drawImage(c.bitmap,c.left,c.top),a.drawImage(h,f.x,f.y),g.clearRect(s.originPoint.x,s.originPoint.y,h.width,h.height),g.putImageData(t,s.originPoint.x,s.originPoint.y)}}if(o.gifTime+=r.value,o.gifTime>c.delayTime){if(o.gifTime-=c.delayTime,++d>=l.gifData.frames.length){if(--o.gifLoopCount<=0)return;d=0,g.clearRect(s.originPoint.x,s.originPoint.y,h.width,h.height)}o.gifFrame=d}a.scale(l.gifData.width/i,l.gifData.height/i)}}async function x(t,e){if("gif"!==t.type)return void await (0,l.loadImage)(t);t.loading=!0;try{t.gifData=await m(t.source,e),t.gifLoopCount=function(t){for(let e of t.applicationExtensions)if(e.identifier+e.authenticationCode==="NETSCAPE2.0")return e.data[1]+(e.data[2]<<8);return NaN}(t.gifData),t.gifLoopCount||(t.gifLoopCount=1/0)}catch{t.error=!0}t.loading=!1}(i=n||(n={}))[i.Replace=0]="Replace",i[i.Combine=1]="Combine",i[i.RestoreBackground=2]="RestoreBackground",i[i.RestorePrevious=3]="RestorePrevious",i[i.UndefinedA=4]="UndefinedA",i[i.UndefinedB=5]="UndefinedB",i[i.UndefinedC=6]="UndefinedC",i[i.UndefinedD=7]="UndefinedD",(o=r||(r={}))[o.Extension=33]="Extension",o[o.ApplicationExtension=255]="ApplicationExtension",o[o.GraphicsControlExtension=249]="GraphicsControlExtension",o[o.PlainTextExtension=1]="PlainTextExtension",o[o.CommentExtension=254]="CommentExtension",o[o.Image=44]="Image",o[o.EndOfFile=59]="EndOfFile"}}]);
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export class ByteStream {
|
|
2
|
+
data;
|
|
3
|
+
pos;
|
|
2
4
|
constructor(bytes) {
|
|
3
5
|
this.pos = 0;
|
|
4
6
|
this.data = new Uint8ClampedArray(bytes);
|
|
@@ -17,7 +19,7 @@ export class ByteStream {
|
|
|
17
19
|
return this.data[this.pos - increment] + (this.data[this.pos - previous] << shift);
|
|
18
20
|
}
|
|
19
21
|
readSubBlocks() {
|
|
20
|
-
let blockString = "", size
|
|
22
|
+
let blockString = "", size;
|
|
21
23
|
const minCount = 0, emptySize = 0;
|
|
22
24
|
do {
|
|
23
25
|
size = this.data[this.pos++];
|
|
@@ -1,13 +1,10 @@
|
|
|
1
|
-
import { half } from "@tsparticles/engine";
|
|
2
1
|
import { loadImage } from "../Utils.js";
|
|
2
|
+
import { half, originPoint } from "@tsparticles/engine";
|
|
3
3
|
import { InterlaceOffsets, InterlaceSteps } from "./Constants.js";
|
|
4
4
|
import { ByteStream } from "./ByteStream.js";
|
|
5
5
|
import { DisposalMethod } from "./Enums/DisposalMethod.js";
|
|
6
6
|
import { GIFDataHeaders } from "./Types/GIFDataHeaders.js";
|
|
7
|
-
const
|
|
8
|
-
x: 0,
|
|
9
|
-
y: 0,
|
|
10
|
-
}, defaultFrame = 0, initialTime = 0, firstIndex = 0, defaultLoopCount = 0;
|
|
7
|
+
const defaultFrame = 0, initialTime = 0, firstIndex = 0, defaultLoopCount = 0;
|
|
11
8
|
function parseColorTable(byteStream, count) {
|
|
12
9
|
const colors = [];
|
|
13
10
|
for (let i = 0; i < count; i++) {
|
|
@@ -77,7 +74,13 @@ function parseExtensionBlock(byteStream, gif, getFrameIndex, getTransparencyInde
|
|
|
77
74
|
break;
|
|
78
75
|
}
|
|
79
76
|
}
|
|
80
|
-
|
|
77
|
+
function readBits(imageData, pos, len) {
|
|
78
|
+
const bytePos = pos >>> 3, bitPos = pos & 7;
|
|
79
|
+
return (((imageData[bytePos] + (imageData[bytePos + 1] << 8) + (imageData[bytePos + 2] << 16)) &
|
|
80
|
+
(((1 << len) - 1) << bitPos)) >>>
|
|
81
|
+
bitPos);
|
|
82
|
+
}
|
|
83
|
+
async function parseImageBlock(byteStream, gif, avgAlpha, getFrameIndex, getTransparencyIndex, canvasSettings, progressCallback) {
|
|
81
84
|
const frame = gif.frames[getFrameIndex(true)];
|
|
82
85
|
frame.left = byteStream.nextTwoBytes();
|
|
83
86
|
frame.top = byteStream.nextTwoBytes();
|
|
@@ -96,10 +99,9 @@ async function parseImageBlock(byteStream, gif, avgAlpha, getFrameIndex, getTran
|
|
|
96
99
|
return { r, g, b, a: 255 };
|
|
97
100
|
}
|
|
98
101
|
return { r, g, b, a: avgAlpha ? Math.trunc((r + g + b) / 3) : 0 };
|
|
99
|
-
}
|
|
100
|
-
const image = (() => {
|
|
102
|
+
}, image = (() => {
|
|
101
103
|
try {
|
|
102
|
-
return new ImageData(frame.width, frame.height,
|
|
104
|
+
return new ImageData(frame.width, frame.height, canvasSettings);
|
|
103
105
|
}
|
|
104
106
|
catch (error) {
|
|
105
107
|
if (error instanceof DOMException && error.name === "IndexSizeError") {
|
|
@@ -112,19 +114,13 @@ async function parseImageBlock(byteStream, gif, avgAlpha, getFrameIndex, getTran
|
|
|
112
114
|
throw new EvalError("GIF frame size is to large");
|
|
113
115
|
}
|
|
114
116
|
const minCodeSize = byteStream.nextByte(), imageData = byteStream.readSubBlocksBin(), clearCode = 1 << minCodeSize;
|
|
115
|
-
const readBits = (pos, len) => {
|
|
116
|
-
const bytePos = pos >>> 3, bitPos = pos & 7;
|
|
117
|
-
return (((imageData[bytePos] + (imageData[bytePos + 1] << 8) + (imageData[bytePos + 2] << 16)) &
|
|
118
|
-
(((1 << len) - 1) << bitPos)) >>>
|
|
119
|
-
bitPos);
|
|
120
|
-
};
|
|
121
117
|
if (interlacedFlag) {
|
|
122
118
|
for (let code = 0, size = minCodeSize + 1, pos = 0, dic = [[0]], pass = 0; pass < 4; pass++) {
|
|
123
119
|
if (InterlaceOffsets[pass] < frame.height) {
|
|
124
120
|
let pixelPos = 0, lineIndex = 0, exit = false;
|
|
125
121
|
while (!exit) {
|
|
126
122
|
const last = code;
|
|
127
|
-
code = readBits(pos, size);
|
|
123
|
+
code = readBits(imageData, pos, size);
|
|
128
124
|
pos += size + 1;
|
|
129
125
|
if (code === clearCode) {
|
|
130
126
|
size = minCodeSize + 1;
|
|
@@ -169,7 +165,7 @@ async function parseImageBlock(byteStream, gif, avgAlpha, getFrameIndex, getTran
|
|
|
169
165
|
const dic = [[0]];
|
|
170
166
|
for (;;) {
|
|
171
167
|
const last = code;
|
|
172
|
-
code = readBits(pos, size);
|
|
168
|
+
code = readBits(imageData, pos, size);
|
|
173
169
|
pos += size;
|
|
174
170
|
if (code === clearCode) {
|
|
175
171
|
size = minCodeSize + 1;
|
|
@@ -190,8 +186,8 @@ async function parseImageBlock(byteStream, gif, avgAlpha, getFrameIndex, getTran
|
|
|
190
186
|
}
|
|
191
187
|
for (const item of dic[code]) {
|
|
192
188
|
const { r, g, b, a } = getColor(item);
|
|
193
|
-
image.data.set([r, g, b, a], pixelPos);
|
|
194
189
|
pixelPos += 4;
|
|
190
|
+
image.data.set([r, g, b, a], pixelPos);
|
|
195
191
|
}
|
|
196
192
|
if (dic.length >= 1 << size && size < 0xc) {
|
|
197
193
|
size++;
|
|
@@ -203,12 +199,12 @@ async function parseImageBlock(byteStream, gif, avgAlpha, getFrameIndex, getTran
|
|
|
203
199
|
progressCallback?.((byteStream.pos + 1) / byteStream.data.length, getFrameIndex(false) + 1, frame.image, { x: frame.left, y: frame.top }, { width: gif.width, height: gif.height });
|
|
204
200
|
}
|
|
205
201
|
}
|
|
206
|
-
async function parseBlock(byteStream, gif, avgAlpha, getFrameIndex, getTransparencyIndex, progressCallback) {
|
|
202
|
+
async function parseBlock(byteStream, gif, avgAlpha, getFrameIndex, getTransparencyIndex, canvasSettings, progressCallback) {
|
|
207
203
|
switch (byteStream.nextByte()) {
|
|
208
204
|
case GIFDataHeaders.EndOfFile:
|
|
209
205
|
return true;
|
|
210
206
|
case GIFDataHeaders.Image:
|
|
211
|
-
await parseImageBlock(byteStream, gif, avgAlpha, getFrameIndex, getTransparencyIndex, progressCallback);
|
|
207
|
+
await parseImageBlock(byteStream, gif, avgAlpha, getFrameIndex, getTransparencyIndex, canvasSettings, progressCallback);
|
|
212
208
|
break;
|
|
213
209
|
case GIFDataHeaders.Extension:
|
|
214
210
|
parseExtensionBlock(byteStream, gif, getFrameIndex, getTransparencyIndex);
|
|
@@ -225,16 +221,15 @@ export function getGIFLoopAmount(gif) {
|
|
|
225
221
|
}
|
|
226
222
|
return extension.data[1] + (extension.data[2] << 8);
|
|
227
223
|
}
|
|
228
|
-
return NaN;
|
|
224
|
+
return Number.NaN;
|
|
229
225
|
}
|
|
230
|
-
export async function decodeGIF(gifURL, progressCallback, avgAlpha) {
|
|
226
|
+
export async function decodeGIF(gifURL, canvasSettings, progressCallback, avgAlpha) {
|
|
231
227
|
avgAlpha ??= false;
|
|
232
228
|
const res = await fetch(gifURL);
|
|
233
229
|
if (!res.ok && res.status === 404) {
|
|
234
230
|
throw new EvalError("file not found");
|
|
235
231
|
}
|
|
236
|
-
const buffer = await res.arrayBuffer()
|
|
237
|
-
const gif = {
|
|
232
|
+
const buffer = await res.arrayBuffer(), gif = {
|
|
238
233
|
width: 0,
|
|
239
234
|
height: 0,
|
|
240
235
|
totalTime: 0,
|
|
@@ -243,7 +238,7 @@ export async function decodeGIF(gifURL, progressCallback, avgAlpha) {
|
|
|
243
238
|
frames: [],
|
|
244
239
|
sortFlag: false,
|
|
245
240
|
globalColorTable: [],
|
|
246
|
-
backgroundImage: new ImageData(1, 1,
|
|
241
|
+
backgroundImage: new ImageData(1, 1, canvasSettings),
|
|
247
242
|
comments: [],
|
|
248
243
|
applicationExtensions: [],
|
|
249
244
|
}, byteStream = new ByteStream(new Uint8ClampedArray(buffer));
|
|
@@ -265,7 +260,7 @@ export async function decodeGIF(gifURL, progressCallback, avgAlpha) {
|
|
|
265
260
|
}
|
|
266
261
|
const backgroundImage = (() => {
|
|
267
262
|
try {
|
|
268
|
-
return new ImageData(gif.width, gif.height,
|
|
263
|
+
return new ImageData(gif.width, gif.height, canvasSettings);
|
|
269
264
|
}
|
|
270
265
|
catch (error) {
|
|
271
266
|
if (error instanceof DOMException && error.name === "IndexSizeError") {
|
|
@@ -289,8 +284,7 @@ export async function decodeGIF(gifURL, progressCallback, avgAlpha) {
|
|
|
289
284
|
incrementFrameIndex = true;
|
|
290
285
|
}
|
|
291
286
|
return frameIndex;
|
|
292
|
-
}
|
|
293
|
-
const getTransparencyIndex = (newValue) => {
|
|
287
|
+
}, getTransparencyIndex = (newValue) => {
|
|
294
288
|
if (newValue != null) {
|
|
295
289
|
transparencyIndex = newValue;
|
|
296
290
|
}
|
|
@@ -305,7 +299,7 @@ export async function decodeGIF(gifURL, progressCallback, avgAlpha) {
|
|
|
305
299
|
width: 0,
|
|
306
300
|
height: 0,
|
|
307
301
|
disposalMethod: DisposalMethod.Replace,
|
|
308
|
-
image: new ImageData(1, 1,
|
|
302
|
+
image: new ImageData(1, 1, canvasSettings),
|
|
309
303
|
plainTextData: null,
|
|
310
304
|
userInputDelayFlag: false,
|
|
311
305
|
delayTime: 0,
|
|
@@ -318,7 +312,7 @@ export async function decodeGIF(gifURL, progressCallback, avgAlpha) {
|
|
|
318
312
|
transparencyIndex = -1;
|
|
319
313
|
incrementFrameIndex = false;
|
|
320
314
|
}
|
|
321
|
-
} while (!(await parseBlock(byteStream, gif, avgAlpha, getframeIndex, getTransparencyIndex, progressCallback)));
|
|
315
|
+
} while (!(await parseBlock(byteStream, gif, avgAlpha, getframeIndex, getTransparencyIndex, canvasSettings, progressCallback)));
|
|
322
316
|
gif.frames.length--;
|
|
323
317
|
for (const frame of gif.frames) {
|
|
324
318
|
if (frame.userInputDelayFlag && frame.delayTime === 0) {
|
|
@@ -331,23 +325,23 @@ export async function decodeGIF(gifURL, progressCallback, avgAlpha) {
|
|
|
331
325
|
}
|
|
332
326
|
catch (error) {
|
|
333
327
|
if (error instanceof EvalError) {
|
|
334
|
-
throw new Error(`error while parsing frame ${frameIndex.toString()} "${error.message}"
|
|
328
|
+
throw new Error(`error while parsing frame ${frameIndex.toString()} "${error.message}"`, { cause: error });
|
|
335
329
|
}
|
|
336
330
|
throw error;
|
|
337
331
|
}
|
|
338
332
|
}
|
|
339
|
-
export function drawGif(data) {
|
|
333
|
+
export function drawGif(data, canvasSettings) {
|
|
340
334
|
const { context, radius, particle, delta } = data, image = particle.image;
|
|
341
335
|
if (!image?.gifData || !image.gif) {
|
|
342
336
|
return;
|
|
343
337
|
}
|
|
344
|
-
const offscreenCanvas = new OffscreenCanvas(image.gifData.width, image.gifData.height), offscreenContext = offscreenCanvas.getContext("2d");
|
|
338
|
+
const offscreenCanvas = new OffscreenCanvas(image.gifData.width, image.gifData.height), offscreenContext = offscreenCanvas.getContext("2d", canvasSettings);
|
|
345
339
|
if (!offscreenContext) {
|
|
346
340
|
throw new Error("could not create offscreen canvas context");
|
|
347
341
|
}
|
|
348
342
|
offscreenContext.imageSmoothingQuality = "low";
|
|
349
343
|
offscreenContext.imageSmoothingEnabled = false;
|
|
350
|
-
offscreenContext.clearRect(
|
|
344
|
+
offscreenContext.clearRect(originPoint.x, originPoint.y, offscreenCanvas.width, offscreenCanvas.height);
|
|
351
345
|
particle.gifLoopCount ??= image.gifLoopCount ?? defaultLoopCount;
|
|
352
346
|
let frameIndex = particle.gifFrame ?? defaultFrame;
|
|
353
347
|
const pos = { x: -image.gifData.width * half, y: -image.gifData.height * half }, frame = image.gifData.frames[frameIndex];
|
|
@@ -364,7 +358,7 @@ export function drawGif(data) {
|
|
|
364
358
|
case DisposalMethod.Replace:
|
|
365
359
|
offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
|
|
366
360
|
context.drawImage(offscreenCanvas, pos.x, pos.y);
|
|
367
|
-
offscreenContext.clearRect(
|
|
361
|
+
offscreenContext.clearRect(originPoint.x, originPoint.y, offscreenCanvas.width, offscreenCanvas.height);
|
|
368
362
|
break;
|
|
369
363
|
case DisposalMethod.Combine:
|
|
370
364
|
offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
|
|
@@ -373,7 +367,7 @@ export function drawGif(data) {
|
|
|
373
367
|
case DisposalMethod.RestoreBackground:
|
|
374
368
|
offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
|
|
375
369
|
context.drawImage(offscreenCanvas, pos.x, pos.y);
|
|
376
|
-
offscreenContext.clearRect(
|
|
370
|
+
offscreenContext.clearRect(originPoint.x, originPoint.y, offscreenCanvas.width, offscreenCanvas.height);
|
|
377
371
|
if (!image.gifData.globalColorTable.length) {
|
|
378
372
|
offscreenContext.putImageData(image.gifData.frames[firstIndex].image, pos.x + frame.left, pos.y + frame.top);
|
|
379
373
|
}
|
|
@@ -383,11 +377,11 @@ export function drawGif(data) {
|
|
|
383
377
|
break;
|
|
384
378
|
case DisposalMethod.RestorePrevious:
|
|
385
379
|
{
|
|
386
|
-
const previousImageData = offscreenContext.getImageData(
|
|
380
|
+
const previousImageData = offscreenContext.getImageData(originPoint.x, originPoint.y, offscreenCanvas.width, offscreenCanvas.height);
|
|
387
381
|
offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
|
|
388
382
|
context.drawImage(offscreenCanvas, pos.x, pos.y);
|
|
389
|
-
offscreenContext.clearRect(
|
|
390
|
-
offscreenContext.putImageData(previousImageData,
|
|
383
|
+
offscreenContext.clearRect(originPoint.x, originPoint.y, offscreenCanvas.width, offscreenCanvas.height);
|
|
384
|
+
offscreenContext.putImageData(previousImageData, originPoint.x, originPoint.y);
|
|
391
385
|
}
|
|
392
386
|
break;
|
|
393
387
|
}
|
|
@@ -399,20 +393,20 @@ export function drawGif(data) {
|
|
|
399
393
|
return;
|
|
400
394
|
}
|
|
401
395
|
frameIndex = firstIndex;
|
|
402
|
-
offscreenContext.clearRect(
|
|
396
|
+
offscreenContext.clearRect(originPoint.x, originPoint.y, offscreenCanvas.width, offscreenCanvas.height);
|
|
403
397
|
}
|
|
404
398
|
particle.gifFrame = frameIndex;
|
|
405
399
|
}
|
|
406
400
|
context.scale(image.gifData.width / radius, image.gifData.height / radius);
|
|
407
401
|
}
|
|
408
|
-
export async function loadGifImage(image) {
|
|
402
|
+
export async function loadGifImage(image, canvasSettings) {
|
|
409
403
|
if (image.type !== "gif") {
|
|
410
404
|
await loadImage(image);
|
|
411
405
|
return;
|
|
412
406
|
}
|
|
413
407
|
image.loading = true;
|
|
414
408
|
try {
|
|
415
|
-
image.gifData = await decodeGIF(image.source);
|
|
409
|
+
image.gifData = await decodeGIF(image.source, canvasSettings);
|
|
416
410
|
image.gifLoopCount = getGIFLoopAmount(image.gifData);
|
|
417
411
|
if (!image.gifLoopCount) {
|
|
418
412
|
image.gifLoopCount = Infinity;
|
package/browser/ImageDrawer.js
CHANGED
|
@@ -1,27 +1,12 @@
|
|
|
1
1
|
import { defaultAlpha, defaultRatio, double, } from "@tsparticles/engine";
|
|
2
|
-
import { replaceImageColor } from "./Utils.js";
|
|
2
|
+
import { replaceImageColor, shapeTypes } from "./Utils.js";
|
|
3
3
|
import { drawGif } from "./GifUtils/Utils.js";
|
|
4
4
|
const sides = 12;
|
|
5
5
|
export class ImageDrawer {
|
|
6
|
+
_engine;
|
|
6
7
|
constructor(engine) {
|
|
7
|
-
this.validTypes = ["image", "images"];
|
|
8
|
-
this.loadImageShape = async (imageShape) => {
|
|
9
|
-
if (!this._engine.loadImage) {
|
|
10
|
-
throw new Error(`Image shape not initialized`);
|
|
11
|
-
}
|
|
12
|
-
await this._engine.loadImage({
|
|
13
|
-
gif: imageShape.gif,
|
|
14
|
-
name: imageShape.name,
|
|
15
|
-
replaceColor: imageShape.replaceColor,
|
|
16
|
-
src: imageShape.src,
|
|
17
|
-
});
|
|
18
|
-
};
|
|
19
8
|
this._engine = engine;
|
|
20
9
|
}
|
|
21
|
-
addImage(image) {
|
|
22
|
-
this._engine.images ??= [];
|
|
23
|
-
this._engine.images.push(image);
|
|
24
|
-
}
|
|
25
10
|
draw(data) {
|
|
26
11
|
const { context, radius, particle, opacity } = data, image = particle.image, element = image?.element;
|
|
27
12
|
if (!image) {
|
|
@@ -29,7 +14,7 @@ export class ImageDrawer {
|
|
|
29
14
|
}
|
|
30
15
|
context.globalAlpha = opacity;
|
|
31
16
|
if (image.gif && image.gifData) {
|
|
32
|
-
drawGif(data);
|
|
17
|
+
drawGif(data, particle.container.canvas.settings);
|
|
33
18
|
}
|
|
34
19
|
else if (element) {
|
|
35
20
|
const ratio = image.ratio, pos = {
|
|
@@ -48,36 +33,38 @@ export class ImageDrawer {
|
|
|
48
33
|
if (!options.preload || !this._engine.loadImage) {
|
|
49
34
|
return;
|
|
50
35
|
}
|
|
36
|
+
const promises = [];
|
|
51
37
|
for (const imageData of options.preload) {
|
|
52
|
-
|
|
38
|
+
promises.push(this._engine.loadImage(container, imageData));
|
|
53
39
|
}
|
|
40
|
+
await Promise.all(promises);
|
|
54
41
|
}
|
|
55
42
|
loadShape(particle) {
|
|
56
|
-
|
|
43
|
+
const { container } = particle;
|
|
44
|
+
if (!particle.shape || !shapeTypes.includes(particle.shape)) {
|
|
57
45
|
return;
|
|
58
46
|
}
|
|
59
|
-
this._engine.images ??= [];
|
|
60
47
|
const imageData = particle.shapeData;
|
|
61
48
|
if (!imageData) {
|
|
62
49
|
return;
|
|
63
50
|
}
|
|
64
|
-
const
|
|
65
|
-
if (
|
|
66
|
-
|
|
67
|
-
this.loadShape(particle);
|
|
68
|
-
});
|
|
51
|
+
const images = this._engine.getImages?.(container), image = images?.find((t) => t.name === imageData.name || t.source === imageData.src);
|
|
52
|
+
if (image) {
|
|
53
|
+
return;
|
|
69
54
|
}
|
|
55
|
+
void this.loadImageShape(container, imageData).then(() => {
|
|
56
|
+
this.loadShape(particle);
|
|
57
|
+
});
|
|
70
58
|
}
|
|
71
59
|
particleInit(container, particle) {
|
|
72
60
|
if (particle.shape !== "image" && particle.shape !== "images") {
|
|
73
61
|
return;
|
|
74
62
|
}
|
|
75
|
-
this._engine.
|
|
76
|
-
const images = this._engine.images, imageData = particle.shapeData;
|
|
63
|
+
const images = this._engine.getImages?.(container), imageData = particle.shapeData;
|
|
77
64
|
if (!imageData) {
|
|
78
65
|
return;
|
|
79
66
|
}
|
|
80
|
-
const color = particle.getFillColor(), image = images
|
|
67
|
+
const color = particle.getFillColor(), image = images?.find((t) => t.name === imageData.name || t.source === imageData.src);
|
|
81
68
|
if (!image) {
|
|
82
69
|
return;
|
|
83
70
|
}
|
|
@@ -102,9 +89,7 @@ export class ImageDrawer {
|
|
|
102
89
|
gifData: image.gifData,
|
|
103
90
|
gifLoopCount: image.gifLoopCount,
|
|
104
91
|
loaded: true,
|
|
105
|
-
ratio: imageData.width && imageData.height
|
|
106
|
-
? imageData.width / imageData.height
|
|
107
|
-
: (image.ratio ?? defaultRatio),
|
|
92
|
+
ratio: imageData.width && imageData.height ? imageData.width / imageData.height : (image.ratio ?? defaultRatio),
|
|
108
93
|
replaceColor: replaceColor,
|
|
109
94
|
source: imageData.src,
|
|
110
95
|
};
|
|
@@ -112,14 +97,23 @@ export class ImageDrawer {
|
|
|
112
97
|
if (!imageRes.ratio) {
|
|
113
98
|
imageRes.ratio = 1;
|
|
114
99
|
}
|
|
115
|
-
const
|
|
100
|
+
const close = imageData.close ?? particle.shapeClose, imageShape = {
|
|
116
101
|
image: imageRes,
|
|
117
|
-
fill,
|
|
118
102
|
close,
|
|
119
103
|
};
|
|
120
104
|
particle.image = imageShape.image;
|
|
121
|
-
particle.shapeFill = imageShape.fill;
|
|
122
105
|
particle.shapeClose = imageShape.close;
|
|
123
106
|
})();
|
|
124
107
|
}
|
|
108
|
+
loadImageShape = async (container, imageShape) => {
|
|
109
|
+
if (!this._engine.loadImage) {
|
|
110
|
+
throw new Error(`Image shape not initialized`);
|
|
111
|
+
}
|
|
112
|
+
await this._engine.loadImage(container, {
|
|
113
|
+
gif: imageShape.gif,
|
|
114
|
+
name: imageShape.name,
|
|
115
|
+
replaceColor: imageShape.replaceColor,
|
|
116
|
+
src: imageShape.src,
|
|
117
|
+
});
|
|
118
|
+
};
|
|
125
119
|
}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { Preload } from "./Options/Classes/Preload.js";
|
|
2
2
|
export class ImagePreloaderPlugin {
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
id = "image-preloader";
|
|
4
|
+
_engine;
|
|
5
|
+
constructor(engine) {
|
|
6
|
+
this._engine = engine;
|
|
5
7
|
}
|
|
6
|
-
async getPlugin() {
|
|
7
|
-
await
|
|
8
|
-
return
|
|
8
|
+
async getPlugin(container) {
|
|
9
|
+
const { ImagePreloaderInstance } = await import("./ImagePreloaderInstance.js");
|
|
10
|
+
return new ImagePreloaderInstance(this._engine, container);
|
|
9
11
|
}
|
|
10
12
|
loadOptions(_container, options, source) {
|
|
11
13
|
if (!source?.preload) {
|
package/browser/Utils.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getLogger, getStyleFromHsl } from "@tsparticles/engine";
|
|
2
|
+
export const shapeTypes = ["image", "images"];
|
|
2
3
|
const stringStart = 0, defaultOpacity = 1;
|
|
3
4
|
const currentColorRegex = /(#(?:[0-9a-f]{2}){2,4}|(#[0-9a-f]{3})|(rgb|hsl)a?\((-?\d+%?[,\s]+){2,3}\s*[\d.]+%?\))|currentcolor/gi;
|
|
4
5
|
function replaceColorSvg(imageShape, color, opacity, hdr = false) {
|
|
@@ -8,13 +9,13 @@ function replaceColorSvg(imageShape, color, opacity, hdr = false) {
|
|
|
8
9
|
}
|
|
9
10
|
const colorStyle = getStyleFromHsl(color, hdr, opacity);
|
|
10
11
|
if (svgData.includes("fill")) {
|
|
11
|
-
return svgData.
|
|
12
|
+
return svgData.replaceAll(currentColorRegex, () => colorStyle);
|
|
12
13
|
}
|
|
13
14
|
const preFillIndex = svgData.indexOf(">");
|
|
14
15
|
return `${svgData.substring(stringStart, preFillIndex)} fill="${colorStyle}"${svgData.substring(preFillIndex)}`;
|
|
15
16
|
}
|
|
16
17
|
export async function loadImage(image) {
|
|
17
|
-
return new Promise(
|
|
18
|
+
return new Promise(resolve => {
|
|
18
19
|
image.loading = true;
|
|
19
20
|
const img = new Image();
|
|
20
21
|
image.element = img;
|
|
@@ -39,12 +40,12 @@ export async function downloadSvgImage(image) {
|
|
|
39
40
|
}
|
|
40
41
|
image.loading = true;
|
|
41
42
|
const response = await fetch(image.source);
|
|
42
|
-
if (
|
|
43
|
-
|
|
44
|
-
image.error = true;
|
|
43
|
+
if (response.ok) {
|
|
44
|
+
image.svgData = await response.text();
|
|
45
45
|
}
|
|
46
46
|
else {
|
|
47
|
-
|
|
47
|
+
getLogger().error("Image not found");
|
|
48
|
+
image.error = true;
|
|
48
49
|
}
|
|
49
50
|
image.loading = false;
|
|
50
51
|
}
|
package/browser/index.js
CHANGED
|
@@ -1,14 +1,25 @@
|
|
|
1
|
+
import { shapeTypes } from "./Utils.js";
|
|
1
2
|
const extLength = 3;
|
|
2
3
|
function addLoadImageToEngine(engine) {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
engine.getImages ??= (container) => {
|
|
5
|
+
engine.images ??= new Map();
|
|
6
|
+
let images = engine.images.get(container);
|
|
7
|
+
if (!images) {
|
|
8
|
+
images = [];
|
|
9
|
+
engine.images.set(container, images);
|
|
10
|
+
}
|
|
11
|
+
return images;
|
|
12
|
+
};
|
|
13
|
+
engine.loadImage ??= async (container, data) => {
|
|
14
|
+
if (!engine.getImages) {
|
|
15
|
+
throw new Error("No images collection found");
|
|
16
|
+
}
|
|
7
17
|
if (!data.name && !data.src) {
|
|
8
18
|
throw new Error("No image source provided");
|
|
9
19
|
}
|
|
10
|
-
engine.images ??=
|
|
11
|
-
|
|
20
|
+
engine.images ??= new Map();
|
|
21
|
+
const containerImages = engine.getImages(container);
|
|
22
|
+
if (containerImages.some((t) => t.name === data.name || t.source === data.src)) {
|
|
12
23
|
return;
|
|
13
24
|
}
|
|
14
25
|
try {
|
|
@@ -22,11 +33,12 @@ function addLoadImageToEngine(engine) {
|
|
|
22
33
|
replaceColor: data.replaceColor,
|
|
23
34
|
ratio: data.width && data.height ? data.width / data.height : undefined,
|
|
24
35
|
};
|
|
25
|
-
|
|
36
|
+
containerImages.push(image);
|
|
37
|
+
engine.images.set(container, containerImages);
|
|
26
38
|
let imageFunc;
|
|
27
39
|
if (data.gif) {
|
|
28
40
|
const { loadGifImage } = await import("./GifUtils/Utils.js");
|
|
29
|
-
imageFunc = loadGifImage;
|
|
41
|
+
imageFunc = (img) => loadGifImage(img, { colorSpace: "srgb" });
|
|
30
42
|
}
|
|
31
43
|
else if (data.replaceColor) {
|
|
32
44
|
const { downloadSvgImage } = await import("./Utils.js");
|
|
@@ -44,12 +56,14 @@ function addLoadImageToEngine(engine) {
|
|
|
44
56
|
};
|
|
45
57
|
}
|
|
46
58
|
export async function loadImageShape(engine) {
|
|
47
|
-
engine.checkVersion("4.0.0-
|
|
59
|
+
engine.checkVersion("4.0.0-beta.0");
|
|
48
60
|
await engine.register(async (e) => {
|
|
49
|
-
const {
|
|
61
|
+
const { ImagePreloaderPlugin } = await import("./ImagePreloader.js");
|
|
50
62
|
addLoadImageToEngine(e);
|
|
51
|
-
|
|
52
|
-
e.
|
|
53
|
-
|
|
63
|
+
e.addPlugin(new ImagePreloaderPlugin(e));
|
|
64
|
+
e.addShape(shapeTypes, async () => {
|
|
65
|
+
const { ImageDrawer } = await import("./ImageDrawer.js");
|
|
66
|
+
return new ImageDrawer(e);
|
|
67
|
+
});
|
|
54
68
|
});
|
|
55
69
|
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export class ByteStream {
|
|
2
|
+
data;
|
|
3
|
+
pos;
|
|
2
4
|
constructor(bytes) {
|
|
3
5
|
this.pos = 0;
|
|
4
6
|
this.data = new Uint8ClampedArray(bytes);
|
|
@@ -17,7 +19,7 @@ export class ByteStream {
|
|
|
17
19
|
return this.data[this.pos - increment] + (this.data[this.pos - previous] << shift);
|
|
18
20
|
}
|
|
19
21
|
readSubBlocks() {
|
|
20
|
-
let blockString = "", size
|
|
22
|
+
let blockString = "", size;
|
|
21
23
|
const minCount = 0, emptySize = 0;
|
|
22
24
|
do {
|
|
23
25
|
size = this.data[this.pos++];
|