UNPKG

@xdadda/mini-gl

Version:

webgl image editing library with filters and effects

618 lines (531 loc) 39.6 kB
(function(B,$){typeof exports=="object"&&typeof module<"u"?$(exports):typeof define=="function"&&define.amd?define(["exports"],$):(B=typeof globalThis<"u"?globalThis:B||self,$(B["mini-gl"]={}))})(this,(function(B){"use strict";function $(e,o){const{gl:t,img:r}=e;o=o||{translateX:0,translateY:0,angle:0,scale:0,flipv:0,fliph:0};let{translateX:n,translateY:a,angle:l,scale:c,flipv:u,fliph:h}=o;c+=1;let s=[c,c];const f=[Math.round(t.canvas.width*n*100)/100,Math.round(t.canvas.height*a*100)/100],v=`#version 300 es in vec2 vertex; uniform mat3 matrix; out vec2 texCoord; void main() { texCoord = vertex; gl_Position = vec4((matrix * vec3(vertex, 1)).xy, 0, 1); } `,i=`#version 300 es precision highp float; in vec2 texCoord; uniform sampler2D _texture; out vec4 outColor; void main() { outColor = texture(_texture, vec2(texCoord.x, texCoord.y)); } `;if(t.canvas.width===e.height){const C=r.width/r.height;s[0]*=C,s[1]/=C}const g=T.projection(t.canvas.width,t.canvas.height),x=T.translation(f[0],f[1]),d=T.rotation(-l*Math.PI/180),m=T.scaling(s[0]*(-h||1),s[1]*(-u||1));let p=[1,0,0,0,1,0,0,0,1];p=T.multiply(p,g),p=T.multiply(p,x),p=T.multiply(p,T.translation(t.canvas.width/2,t.canvas.height/2)),p=T.multiply(p,d),p=T.multiply(p,m),p=T.multiply(p,T.translation(-t.canvas.width/2,-t.canvas.height/2)),p=T.multiply(p,T.scaling(t.canvas.width,t.canvas.height)),e._.$matrix=e._.$matrix||new b(t,v,i),e.runFilter(e._.$matrix,{matrix:p})}var T={projection:function(o,t){return[2/o,0,0,0,2/t,0,-1,-1,1]},translation:function(o,t){return[1,0,0,0,1,0,o,t,1]},rotation:function(o){var t=Math.cos(o),r=Math.sin(o);return[t,-r,0,r,t,0,0,0,1]},scaling:function(o,t){return[o,0,0,0,t,0,0,0,1]},multiply:function(o,t){var r=o[0],n=o[1],a=o[2],l=o[3],c=o[4],u=o[5],h=o[6],s=o[7],f=o[8],v=t[0],i=t[1],g=t[2],x=t[3],d=t[4],m=t[5],p=t[6],C=t[7],y=t[8];return[v*r+i*l+g*h,v*n+i*c+g*s,v*a+i*u+g*f,x*r+d*l+m*h,x*n+d*c+m*s,x*a+d*u+m*f,p*r+C*l+y*h,p*n+C*c+y*s,p*a+C*u+y*f]}};function Y(e,o,t){const{gl:r}=e;t+=1;const n=` vec3 fromLinear(vec3 linearRGB) { bvec3 cutoff = lessThan(linearRGB.rgb, vec3(0.0031308)); vec3 higher = vec3(1.055)*pow(linearRGB.rgb, vec3(1.0/2.4)) - vec3(0.055); vec3 lower = linearRGB.rgb * vec3(12.92); return vec3(mix(higher, lower, cutoff)); } vec3 toLinear(vec3 sRGB) { bvec3 cutoff = lessThan(sRGB.rgb, vec3(0.04045)); vec3 higher = pow((sRGB.rgb + vec3(0.055))/vec3(1.055), vec3(2.4)); vec3 lower = sRGB.rgb/vec3(12.92); return vec3(mix(higher, lower, cutoff)); }`;if(o.type==="1"){const a=`#version 300 es precision highp float; in vec2 texCoord; uniform sampler2D _texture; out vec4 outColor; uniform sampler2D map; uniform float filterStrength; ${n} vec4 lut(vec4 color) { vec3 texel = color.rgb; texel = fromLinear(texel); float size = 33.0; float sliceSize = 1.0 / size; float slicePixelSize = sliceSize / size; float sliceInnerSize = slicePixelSize * (size - 1.0); float xOffset = 0.5 * sliceSize + texel.x * (1.0 - sliceSize); float yOffset = 0.5 * slicePixelSize + texel.y * sliceInnerSize; float zOffset = texel.z * (size - 1.0); float zSlice0 = floor(zOffset); float zSlice1 = zSlice0 + 1.0; float s0 = yOffset + (zSlice0 * sliceSize); float s1 = yOffset + (zSlice1 * sliceSize); vec4 slice0Color = texture(map, vec2(xOffset, s0)); vec4 slice1Color = texture(map, vec2(xOffset, s1)); texel = mix(slice0Color, slice1Color, zOffset - zSlice0).rgb; texel = toLinear(texel); return vec4(texel, color.a); } void main() { vec4 color = texture(_texture, texCoord); outColor = color * (1.0 - filterStrength) + lut(color) * filterStrength; } `;e._.$insta1=e._.$insta1||new b(r,null,a),e._.$instatxt1=e._.$instatxt1||new R(r),e._.$instatxt1.loadImage(o.map1,r.RGBA),e._.$instatxt1.use(1),e.runFilter(e._.$insta1,{filterStrength:t??1,map:{unit:1}})}else if(o.type==="2"){const a=`#version 300 es precision highp float; precision highp int; in vec2 texCoord; uniform sampler2D _texture; out vec4 outColor; uniform sampler2D map; uniform sampler2D map2; uniform float filterStrength; ${n} vec4 lut(vec4 color) { vec3 texel = color.rgb; texel = fromLinear(texel); texel.r = texture(map, vec2(texel.r, 0.5)).r; texel.g = texture(map, vec2(texel.g, 0.5)).g; texel.b = texture(map, vec2(texel.b, 0.5)).b; float luma = dot(vec3(0.2126, 0.7152, 0.0722), texel); float shadowCoeff = 0.35 * max(0.0, 1.0 - luma); texel = mix(texel, max(vec3(0.0), 2.0 * texel - 1.0), shadowCoeff); texel = mix(texel, vec3(luma), -0.3); texel.r = texture(map2, vec2(texel.r, 0.5)).r; texel.g = texture(map2, vec2(texel.g, 0.5)).g; texel.b = texture(map2, vec2(texel.b, 0.5)).b; texel = toLinear(texel); return vec4(texel, color.a); } void main() { vec4 color = texture(_texture, texCoord); color = color * (1.0 - filterStrength) + lut(color) * filterStrength; outColor = color; } `;e._.$insta2=e._.$insta2||new b(r,null,a),e._.$instatxt1=e._.$instatxt1||new R(r),e._.$instatxt2=e._.$instatxt2||new R(r),e._.$instatxt1.loadImage(o.map1,r.RGBA),e._.$instatxt2.loadImage(o.map2,r.RGBA),e._.$instatxt1.use(1),e._.$instatxt2.use(2),e.runFilter(e._.$insta2,{filterStrength:t??1,map:{unit:1},map2:{unit:2}})}else if(o.type==="3"){const a=`#version 300 es precision highp float; precision highp int; in vec2 texCoord; uniform sampler2D _texture; out vec4 outColor; uniform sampler2D map; uniform sampler2D mapLgg; uniform float filterStrength; ${n} vec4 lut(vec4 color) { vec3 texel = color.rgb; texel = fromLinear(texel); texel = min(texel * 1.1343, vec3(1.0)); texel.r = texture(map, vec2(texel.r, 0.5)).r; texel.g = texture(map, vec2(texel.g, 0.5)).g; texel.b = texture(map, vec2(texel.b, 0.5)).b; vec3 shadowColor = vec3(0.956862, 0.0, 0.83529); float luma = dot(vec3(0.309, 0.609, 0.082), texel); vec3 shadowBlend = 2.0 * shadowColor * texel; float shadowAmount = 0.6 * max(0.0, (1.0 - 4.0 * luma)); texel = mix(texel, shadowBlend, shadowAmount); vec3 lgg; lgg.r = texture(mapLgg, vec2(texel.r, 0.5)).r; lgg.g = texture(mapLgg, vec2(texel.g, 0.5)).g; lgg.b = texture(mapLgg, vec2(texel.b, 0.5)).b; texel = mix(texel, lgg, min(1.0, 0.8 + luma)); texel = toLinear(texel); return vec4(texel, color.a); } void main() { vec4 color = texture(_texture, texCoord); outColor = color * (1.0 - filterStrength) + lut(color) * filterStrength; } `;e._.$insta3=e._.$insta3||new b(r,null,a),e._.$instatxt1=e._.$instatxt1||new R(r,0,0,r.RGBA,r.UNSIGNED_BYTE),e._.$instatxt1.loadImage(o.map1,r.RGBA),e._.$instatxt2=e._.$instatxt2||new R(r,0,0,r.RGBA,r.UNSIGNED_BYTE),e._.$instatxt2.loadImage(o.map2,r.RGBA),e._.$instatxt1.use(1),e._.$instatxt2.use(2),e.runFilter(e._.$insta3,{filterStrength:t??1,map:{unit:1},mapLgg:{unit:2}})}else if(o.type==="4"){const a=`#version 300 es precision highp float; precision highp int; in vec2 texCoord; uniform sampler2D _texture; out vec4 outColor; uniform sampler2D map; uniform sampler2D map2; uniform float filterStrength; ${n} vec4 lut(vec4 color) { vec3 texel = color.rgb; texel = fromLinear(texel); texel.r = texture(map, vec2(texel.r, 0.5)).r; texel.g = texture(map, vec2(texel.g, 0.5)).g; texel.b = texture(map, vec2(texel.b, 0.5)).b; vec3 desat = vec3(dot(vec3(0.7, 0.2, 0.1), texel)); texel = mix(texel, desat, 0.79); texel = vec3(min(1.0, 1.2 * dot(vec3(0.2, 0.7, 0.1), texel))); texel.r = texture(map2, vec2(texel.r, 0.5)).r; texel.g = texture(map2, vec2(texel.g, 0.5)).g; texel.b = texture(map2, vec2(texel.b, 0.5)).b; texel = toLinear(texel); return vec4(texel, color.a); } void main() { vec4 color = texture(_texture, texCoord); outColor = color * (1.0 - filterStrength) + lut(color) * filterStrength; } `;e._.$insta4=e._.$insta4||new b(r,null,a),e._.$instatxt1=e._.$instatxt1||new R(r,0,0,r.RGBA,r.UNSIGNED_BYTE),e._.$instatxt1.loadImage(o.map1,r.RGBA),e._.$instatxt2=e._.$instatxt2||new R(r,0,0,r.RGBA,r.UNSIGNED_BYTE),e._.$instatxt2.loadImage(o.map2,r.RGBA),e._.$instatxt1.use(1),e._.$instatxt2.use(2),e.runFilter(e._.$insta4,{filterStrength:t??1,map:{unit:1},map2:{unit:2}})}else if(o.type==="MTX"){const a=`#version 300 es precision highp float; precision highp int; in vec2 texCoord; uniform sampler2D _texture; out vec4 outColor; uniform float filterStrength; uniform mat4 uColorMatrix; uniform vec4 uColorOffset; vec4 applyColorMatrix(vec4 c, mat4 m, vec4 o) { vec4 res = (c * m) + (o * c.a); res = clamp(res, 0.0, 1.0); return res; } void main() { vec4 color = texture(_texture, texCoord); color = applyColorMatrix(color, uColorMatrix, uColorOffset); outColor = color; } `;let l={identity:[[1,0,0,0,0],[0,1,0,0,0],[0,0,1,0,0],[0,0,0,1,0]],polaroid:[[1+.438*t,-.062*t,-.062*t,0,0],[-.122*t,1+.378*t,-.122*t,0,0],[-.016*t,-.016*t,1+.483*t,0,0],[0,0,0,1,0]],kodachrome:[[(1+.1285582396593525*t)*((t/2+1)/2+.5),-.3967382283601348*t,-.03992559172921793*t,0,.06372958762196503*t],[-.16404339962244616*t,(1+.0835251566291304*t)*((t/2+1)/2+.5),-.05498805115633132*t,0,.024732407896706204*t],[-.16786010706155763*t,-.5603416277695248*t,(1+.6014850761964943*t)*((t/2+1)/2+.5),0,.03562982807460946*t],[0,0,0,1,0]],browni:[[(1-.4002976502*t)*((t/1.5+1)/2+.5),.34553243048391263*t,-.2708298674538042*t,0,.09486385711201746*t],[-.037703249837783157*t,(1-.1390422412*t)*((t/1.5+1)/2+.5),.15059552388459913*t,0,-.07393682996638255*t],[.24113635128153335*t,-.07441037908422492*t,(1-.5502781794*t)*((t/1.5+1)/2+.5),0,-.015124150555182566*t],[0,0,0,1,0]],vintage:[[(1-.3720654364*t)*((t/1.5+1)/2+.5),.3202183420819367*t,-.03965408211312453*t,0,.009651285835294123*t],[.02578397704808868*t,(1-.3558811356*t)*((t/1.5+1)/2+.5),.03259127616149294*t,0,.007462829176470591*t],[.0466055556782719*t,-.0851232987247891*t,(1-.4758351981*t)*((t/1.5+1)/2+.5),0,.005159190588235296*t],[0,0,0,1,0]]},c=l.identity,u=[0,0,0,0];t&&(c=H(c,l[o.mtx],4)),t&&(u=[0,1,2,3].map(f=>u[f]+l[o.mtx][f][4])),e._.$insta5=e._.$insta5||new b(r,null,a);const h=c.flat(),s=u;e.runFilter(e._.$insta5,{uColorMatrix:h,uColorOffset:s})}}function H(e,o,t=3){let r=[];for(var n=0;n<t;n++){r.push([]);for(var a=0;a<t;a++){r[n].push(0);for(var l=0;l<t;l++)e[n]&&o[l]&&(r[n][a]+=e[n][l]*o[l][a])}}return r}function I(e){var o=e.length;this.xa=[],this.ya=[],this.u=[],this.y2=[],e.sort(function(c,u){return c[0]-u[0]});for(var t=0;t<o;t++)this.xa.push(e[t][0]),this.ya.push(e[t][1]);this.u[0]=0,this.y2[0]=0;for(var t=1;t<o-1;++t){var r=this.xa[t+1]-this.xa[t-1],n=(this.xa[t]-this.xa[t-1])/r,a=n*this.y2[t-1]+2;this.y2[t]=(n-1)/a;var l=(this.ya[t+1]-this.ya[t])/(this.xa[t+1]-this.xa[t])-(this.ya[t]-this.ya[t-1])/(this.xa[t]-this.xa[t-1]);this.u[t]=(6*l/r-n*this.u[t-1])/a}this.y2[o-1]=0;for(var t=o-2;t>=0;--t)this.y2[t]=this.y2[t]*this.y2[t+1]+this.u[t]}I.prototype.at=function(e){for(var o=this.ya.length,t=0,r=o-1;r-t>1;){var n=r+t>>1;this.xa[n]>e?r=n:t=n}var a=this.xa[r]-this.xa[t],l=(this.xa[r]-e)/a,c=(e-this.xa[t])/a;return l*this.ya[t]+c*this.ya[r]+((l*l*l-l)*this.y2[t]+(c*c*c-c)*this.y2[r])*(a*a)/6};function M(e){for(var o=new I(e),t=[],r=0;r<256;r++)t.push(K(0,Math.floor(o.at(r/255)*256),255));return t}function K(e,o,t){return Math.max(e,Math.min(o,t))}function W(e,a){if(a.every(h=>h===null))return;a[0]||(a[0]=[[0,0],[1,1]]);let t=a[1]||a[0],r=a[2]||a[0],n=a[3]||a[0];if(t=M(t),r=M(r),n=M(n),t.length!==256||r.length!==256||n.length!==256)return console.error("curves: input unknown");for(var a=[],l=0;l<256;l++)a.splice(a.length,0,t[l],r[l],n[l],255);const c=`#version 300 es precision highp float; in vec2 texCoord; uniform sampler2D _texture; out vec4 outColor; uniform sampler2D curvemap; void main() { vec4 color = texture(_texture, texCoord); color.r = texture(curvemap, vec2(color.r)).r; color.g = texture(curvemap, vec2(color.g)).g; color.b = texture(curvemap, vec2(color.b)).b; outColor = color; } `,{gl:u}=e;e._.$curvestexture=e._.$curvestexture||new R(u),e._.$curvestexture.initFromBytes(256,1,a,u.RGBA),e._.$curvestexture.use(2),e._.$curves=e._.$curves||new b(u,null,c),e.runFilter(e._.$curves,{curvemap:{unit:2}})}function Z(e,o,t,r){const n=`#version 300 es precision highp float; in vec2 texCoord; uniform sampler2D _texture; uniform vec2 uResolution; uniform mat3 matrix; uniform bool useTextureSpace; out vec4 outColor; void main() { vec2 coord = texCoord * uResolution; if (useTextureSpace) coord = coord / uResolution * 2.0 - 1.0; vec3 warp = matrix * vec3(coord, 1.0); coord = warp.xy / warp.z; if (useTextureSpace) coord = (coord * 0.5 + 0.5) * uResolution; vec4 color = texture(_texture, coord / uResolution); vec2 clampedCoord = clamp(coord, vec2(0.0), uResolution); if (coord != clampedCoord) { //color.a *= max(0.0, 1.0 - length(coord - clampedCoord)); color.a = 0.; } outColor = color; } `,{gl:a,img:l}=e;if(e._.$warp=e._.$warp||new b(a,null,n),o=Array.prototype.concat.apply([],o),o.length==4)o=[o[0],o[1],0,o[2],o[3],0,0,0,1];else if(o.length!=9)throw"can only warp with 2x2 or 3x3 matrix";const c=[a.canvas.width,a.canvas.height];e.runFilter(e._.$warp,{matrix:t?j(o):o,uResolution:c,useTextureSpace:r|0})}function q(e,o,t,r,n){o=o.flat(),t=t.flat();var a=N.apply(null,t),l=N.apply(null,o),c=Q(j(a),l);return Z(e,c,r,n)}function N(e,o,t,r,n,a,l,c){var u=t-n,h=r-a,s=l-n,f=c-a,v=e-t+n-l,i=o-r+a-c,g=u*f-s*h,x=(v*f-s*i)/g,d=(u*i-v*h)/g;return[t-e+x*t,r-o+x*r,x,l-e+d*l,c-o+d*c,d,e,o,1]}function j(e){var o=e[0],t=e[1],r=e[2],n=e[3],a=e[4],l=e[5],c=e[6],u=e[7],h=e[8],s=o*a*h-o*l*u-t*n*h+t*l*c+r*n*u-r*a*c;return[(a*h-l*u)/s,(r*u-t*h)/s,(t*l-r*a)/s,(l*c-n*h)/s,(o*h-r*c)/s,(r*n-o*l)/s,(n*u-a*c)/s,(t*c-o*u)/s,(o*a-t*n)/s]}function Q(e,o){return[e[0]*o[0]+e[1]*o[3]+e[2]*o[6],e[0]*o[1]+e[1]*o[4]+e[2]*o[7],e[0]*o[2]+e[1]*o[5]+e[2]*o[8],e[3]*o[0]+e[4]*o[3]+e[5]*o[6],e[3]*o[1]+e[4]*o[4]+e[5]*o[7],e[3]*o[2]+e[4]*o[5]+e[5]*o[8],e[6]*o[0]+e[7]*o[3]+e[8]*o[6],e[6]*o[1]+e[7]*o[4]+e[8]*o[7],e[6]*o[2]+e[7]*o[5]+e[8]*o[8]]}function J(e,o,t){const{gl:r}=e,n=`#version 300 es precision highp float; in vec2 texCoord; uniform sampler2D _texture; out vec4 outColor; uniform sampler2D map; uniform float filterStrength; vec4 fromLinear(vec4 linearRGB) { bvec3 cutoff = lessThan(linearRGB.rgb, vec3(0.0031308)); vec3 higher = vec3(1.055)*pow(linearRGB.rgb, vec3(1.0/2.4)) - vec3(0.055); vec3 lower = linearRGB.rgb * vec3(12.92); return vec4(mix(higher, lower, cutoff), linearRGB.a); } vec4 toLinear(vec4 sRGB) { bvec3 cutoff = lessThan(sRGB.rgb, vec3(0.04045)); vec3 higher = pow((sRGB.rgb + vec3(0.055))/vec3(1.055), vec3(2.4)); vec3 lower = sRGB.rgb/vec3(12.92); return vec4(mix(higher, lower, cutoff), sRGB.a); } void main(){ vec4 color = texture(_texture, texCoord); vec4 texc = texture(map, texCoord); color = toLinear(color); texc = toLinear(texc); color = mix(color, texc, filterStrength); color = fromLinear(color); outColor = color; }`;e._.$blend=e._.$blend||new b(r,null,n),e._.$blendtxt=e._.$blendtxt||new R(r),e._.$blendtxt.loadImage(o),e._.$blendtxt.use(1),e.runFilter(e._.$blend,{filterStrength:t??1,map:{unit:1}})}function ee(e,o){const t=`#version 300 es //Bokeh disc. by David Hoskins. //https://www.shadertoy.com/view/4d2Xzw precision highp float; in vec2 texCoord; uniform sampler2D _texture; out vec4 outColor; uniform float bokehstrength; uniform float bokehlensin; uniform float bokehlensout; uniform float centerX; uniform float centerY; #define GOLDEN_ANGLE 2.39996323 #define ITERATIONS 512 const mat2 rot = mat2(cos(GOLDEN_ANGLE), sin(GOLDEN_ANGLE), -sin(GOLDEN_ANGLE), cos(GOLDEN_ANGLE)); vec3 Bokeh(sampler2D tex, vec2 uv, float radius) { vec3 acc = vec3(0), div = acc; float r = 1.; vec2 vangle = vec2(0.0,radius*.01 / sqrt(float(ITERATIONS))); for (int j = 0; j < ITERATIONS; j++) { // the approx increase in the scale of sqrt(0, 1, 2, 3...) r += 1. / r; vangle = rot * vangle; vec3 col = texture(tex, uv + (r-1.) * vangle).xyz; /// ... Sample the image //col = col * col *1.8; // ... Contrast it for better highlights - leave this out elsewhere. vec3 bokeh = pow(col, vec3(4)); acc += col * bokeh; div += bokeh; } return acc / div; } void main() { vec4 color = texture(_texture, texCoord); vec4 bcolor = vec4(Bokeh(_texture, texCoord, bokehstrength), 1.); //vignette used to control alpha //to blur inside circle smoothstep(lensin, lensout, dist) //to blur outside circle smoothstep(lensout, lensin, dist) float dist = distance(texCoord.xy, vec2(centerX,centerY)); float vigfin = pow(1.-smoothstep(max(0.001,bokehlensout), bokehlensin, dist),2.); outColor = mix( color, bcolor, vigfin); } `,{gl:r}=e;let{bokehstrength:n=.5,bokehlensin:a=0,bokehlensout:l=.5,centerX:c=0,centerY:u=0}=o||{};e._.$lensblur=e._.$lensblur||new b(r,null,t),e.runFilter(e._.$lensblur,{bokehstrength:n,bokehlensin:a,bokehlensout:l,centerX:c,centerY:u})}function te(e,o){const t=`#version 300 es //https://www.shadertoy.com/view/XdfGDH precision highp float; in vec2 texCoord; uniform sampler2D _texture; out vec4 outColor; uniform vec2 uResolution; uniform float gaussianstrength; uniform float gaussianlensin; uniform float gaussianlensout; uniform float centerX; uniform float centerY; float normpdf(in float x, in float sigma) { return 0.39894*exp(-0.5*x*x/(sigma*sigma))/sigma; } void main() { vec4 color = texture(_texture, texCoord); //declare stuff const int mSize = 11; const int kSize = (mSize-1)/2; float kernel[mSize]; vec3 final_colour = vec3(0.0); //create the 1-D kernel float sigma = 7.0*gaussianstrength; float Z = 0.0; for (int j = 0; j <= kSize; ++j) { kernel[kSize+j] = kernel[kSize-j] = normpdf(float(j), sigma); } //get the normalization factor (as the gaussian has been clamped) for (int j = 0; j < mSize; ++j) { Z += kernel[j]; } //read out the texels for (int i=-kSize; i <= kSize; ++i) { for (int j=-kSize; j <= kSize; ++j) { final_colour += kernel[kSize+j]*kernel[kSize+i]*texture(_texture, (texCoord.xy+vec2(float(i),float(j))/uResolution)).rgb; } } //vignette used to control alpha //to blur inside circle smoothstep(lensin, lensout, dist) //to blur outside circle smoothstep(lensout, lensin, dist) float dist = distance(texCoord.xy, vec2(centerX,centerY)); float vigfin = pow(1.-smoothstep(max(0.001,gaussianlensout), gaussianlensin, dist),2.); outColor = mix( color, vec4(final_colour/(Z*Z), 1.0), vigfin); } `,{gl:r}=e;let{gaussianstrength:n=.5,gaussianlensin:a=0,gaussianlensout:l=.5,centerX:c=0,centerY:u=0}=o||{};const h=[r.canvas.width,r.canvas.height];e._.$gaussianblur=e._.$gaussianblur||new b(r,null,t),e.runFilter(e._.$gaussianblur,{gaussianstrength:n,gaussianlensin:a,gaussianlensout:l,centerX:c,centerY:u,uResolution:h})}function re(e,o){const t=`#version 300 es precision highp float; in vec2 texCoord; uniform sampler2D _texture; out vec4 outColor; uniform vec2 uTextureSize; uniform mat4 uColorMatrix; uniform vec4 uColorOffset; uniform float uClarityKernel[9]; uniform float uClarityKernelWeight; uniform float uColorGamma; uniform float uVibrance; uniform float uColorVignette; uniform vec2 uVignettePos; uniform float vibrance; vec4 applyGamma(vec4 c, float g) { c.r = pow(c.r, g); c.g = pow(c.g, g); c.b = pow(c.b, g); return c; } vec4 applyVibrance(vec4 c, float v){ float max = max(c.r, max(c.g, c.b)); float avg = (c.r + c.g + c.b) / 3.0; float amt = (abs(max - avg) * 2.0) * -v; c.r += max != c.r ? (max - c.r) * amt : 0.00; c.g += max != c.g ? (max - c.g) * amt : 0.00; c.b += max != c.b ? (max - c.b) * amt : 0.00; return c; } vec4 applyColorMatrix(vec4 c, mat4 m, vec4 o) { vec4 res = (c * m) + (o * c.a); res = clamp(res, 0.0, 1.0); return res; } vec4 applyConvolutionMatrix(vec4 c, float k0, float k1, float k2, float k3, float k4, float k5, float k6, float k7, float k8, float w) { vec2 pixel = vec2(1) / uTextureSize; vec4 colorSum = texture(_texture, texCoord - pixel) * k0 + texture(_texture, texCoord + pixel * vec2(0.0, -1.0)) * k1 + texture(_texture, texCoord + pixel * vec2(1.0, -1.0)) * k2 + texture(_texture, texCoord + pixel * vec2(-1.0, 0.0)) * k3 + texture(_texture, texCoord) * k4 + texture(_texture, texCoord + pixel * vec2(1.0, 0.0)) * k5 + texture(_texture, texCoord + pixel * vec2(-1.0, 1.0)) * k6 + texture(_texture, texCoord + pixel * vec2(0.0, 1.0)) * k7 + texture(_texture, texCoord + pixel) * k8; vec4 color = vec4(clamp((colorSum / w), 0.0, 1.0).rgb, c.a); return color; } vec4 applyVignette2(vec4 c, vec2 pos, float v, vec2 upos){ #define inner .20 #define outer 1.1 #define curvature .65 vec2 curve = pow(abs(pos),vec2(1./curvature)); float edge = pow(length(curve),curvature); float scale = 1.-abs(upos.x); float vignette = 1.-v*smoothstep(inner*scale,outer*scale,edge); vec4 color = vec4(c.rgb *= vignette , c.a); return color; } vec4 vignette3(vec4 c, vec2 pos, float radius) { float ambientlight = 0.14; float circle = length(pos) - radius; float v = 1.0 - smoothstep(0.0, 0.4f, circle) + ambientlight; return vec4(c.rgb*v,c.a); } void main() { vec4 color = texture(_texture, texCoord); if (uClarityKernelWeight != -1.0) { color = applyConvolutionMatrix(color, uClarityKernel[0], uClarityKernel[1], uClarityKernel[2], uClarityKernel[3], uClarityKernel[4], uClarityKernel[5], uClarityKernel[6], uClarityKernel[7], uClarityKernel[8], uClarityKernelWeight); } color = applyGamma(color, uColorGamma); color = applyVibrance(color, uVibrance); color = applyColorMatrix(color, uColorMatrix, uColorOffset); if (uColorVignette != 0.0) { vec2 pos = texCoord.xy*2.-1. - uVignettePos; //color = vignette3(color, pos, uColorVignette); color = applyVignette2(color, pos, uColorVignette, uVignettePos); } outColor = color; } `,{gl:r}=e;let n=[0,0],{brightness:a=0,contrast:l=0,saturation:c=0,exposure:u=0,temperature:h=0,gamma:s=0,clarity:f=0,vibrance:v=0,vignette:i=0,tint:g=0,sepia:x=0}=o;a=a/4,l=(l+1)/2+.5,c=c+1,u=((u>0?u*3:u*1.5)+1)/2+.5,s+=1,h*=2,g*=2;let d={brightness:[[1,0,0,0,a],[0,1,0,0,a],[0,0,1,0,a],[0,0,0,1,0]],contrast:[[l,0,0,0,.5*(1-l)],[0,l,0,0,.5*(1-l)],[0,0,l,0,.5*(1-l)],[0,0,0,1,0]],saturation:[[.213+.787*c,.715-.715*c,.072-.072*c,0,0],[.213-.213*c,.715+.285*c,.072-.072*c,0,0],[.213-.213*c,.715-.715*c,.072+.928*c,0,0],[0,0,0,1,0]],exposure:[[u,0,0,0,0],[0,u,0,0,0],[0,0,u,0,0],[0,0,0,1,0]],temperature:h>0?[[1+.1*h,0,0,0,0],[0,1,0,0,0],[0,0,1+.1*-h,0,0],[0,0,0,1,0]]:[[1+.15*h,0,0,0,0],[0,1+.05*h,0,0,0],[0,0,1+.15*-h,0,0],[0,0,0,1,0]],tint:[[1,0,0,0,0],[0,1+.1*g,0,0,0],[0,0,1,0,0],[0,0,0,1,0]],sepia:[[1-.607*x,.769*x,.189*x,0,0],[.349*x,1-.314*x,.168*x,0,0],[.272*x,.534*x,1-.869*x,0,0],[0,0,0,1,0]],identity:[[1,0,0,0,0],[0,1,0,0,0],[0,0,1,0,0],[0,0,0,1,0]]},m=d.identity,p=[0,0,0,0];m=A(m,d.brightness,4),p=[0,1,2,3].map(S=>p[S]+d.brightness[S][4]),m=A(m,d.contrast,4),p=[0,1,2,3].map(S=>p[S]+d.contrast[S][4]),m=A(m,d.saturation,4),m=A(m,d.exposure,4),m=A(m,d.temperature,4),m=A(m,d.tint,4),m=A(m,d.sepia,4);let C=f>=0?[0,-1*f,0,-1*f,1+4*f,-1*f,0,-1*f,0]:[-1*f,-2*f,-1*f,-2*f,1+-3*f,-2*f,-1*f,-2*f,-1*f],y=C.reduce(((S,G)=>S+G),0);y=y<=0?1:y,C=[C];const F=m.flat(),L=p,U=[r.canvas.width,r.canvas.height],P=v,O=i,_=C,w=y,E=n;e._.$adj=e._.$adj||new b(r,null,t),e.runFilter(e._.$adj,{uColorMatrix:F,uColorOffset:L,uColorGamma:1/s,uClarityKernel:_,uClarityKernelWeight:w,uTextureSize:U,uVibrance:P,uColorVignette:O,uVignettePos:E})}function oe(e,o,t){const r=`#version 300 es precision highp float; in vec2 texCoord; uniform sampler2D _texture; out vec4 outColor; uniform float shadows; uniform float highlights; const mediump vec3 luminanceWeighting = vec3(0.2125, 0.7154, 0.0721); void main() { vec4 color = texture(_texture, texCoord); float luminance = dot(color.rgb, luminanceWeighting); float shadow = clamp((pow(luminance, 1.0/shadows) + (-0.76)*pow(luminance, 2.0/shadows)) - luminance, 0.0, 1.0); float highlight = clamp((1.0 - (pow(1.0-luminance, 1.0/(2.0-highlights)) + (-0.8)*pow(1.0-luminance, 2.0/(2.0-highlights)))) - luminance, -1.0, 0.0); vec3 result = vec3(0.0, 0.0, 0.0) + (luminance + shadow + highlight) * ((color.rgb - vec3(0.0, 0.0, 0.0))/luminance ); // blend toward white if highlights is more than 1 float contrastedLuminance = ((luminance - 0.5) * 1.5) + 0.5; float whiteInterp = contrastedLuminance*contrastedLuminance*contrastedLuminance; float whiteTarget = clamp(highlights, 0.0, 2.0) - 1.0; result = mix(result, vec3(1.0), whiteInterp*whiteTarget); // blend toward black if shadows is less than 1 float invContrastedLuminance = 1.0 - contrastedLuminance; float blackInterp = invContrastedLuminance*invContrastedLuminance*invContrastedLuminance; float blackTarget = 1.0 - clamp(shadows, 0.0, 1.0); result = mix(result, vec3(0.0), blackInterp*blackTarget); outColor = vec4(result, color.a); } `,{gl:n}=e;e._.$sg=e._.$sg||new b(n,null,r),e.runFilter(e._.$sg,{highlights:o+1,shadows:t/2+1})}function ae(e,o){const t=`#version 300 es precision highp float; in vec2 texCoord; uniform sampler2D _texture; out vec4 outColor; uniform vec2 uResolution; uniform float filterStrength; vec4 BlurColor (in vec2 Coord, in sampler2D Tex, in float MipBias) { vec2 TexelSize = MipBias/uResolution.xy; vec4 Color = texture(Tex, Coord, MipBias); Color += texture(Tex, Coord + vec2(TexelSize.x,0.0), MipBias); Color += texture(Tex, Coord + vec2(-TexelSize.x,0.0), MipBias); Color += texture(Tex, Coord + vec2(0.0,TexelSize.y), MipBias); Color += texture(Tex, Coord + vec2(0.0,-TexelSize.y), MipBias); Color += texture(Tex, Coord + vec2(TexelSize.x,TexelSize.y), MipBias); Color += texture(Tex, Coord + vec2(-TexelSize.x,TexelSize.y), MipBias); Color += texture(Tex, Coord + vec2(TexelSize.x,-TexelSize.y), MipBias); Color += texture(Tex, Coord + vec2(-TexelSize.x,-TexelSize.y), MipBias); return Color/9.0; } void main() { float Threshold = 0.4; float Intensity = filterStrength*1.0; float BlurSize = 3.0 * Intensity; vec4 color = texture(_texture, texCoord); vec4 Highlight = clamp(BlurColor(texCoord.xy, _texture, BlurSize)-Threshold,0.0,1.0)*1.0/(1.0-Threshold); outColor = 1.0-(1.0-color)*(1.0-Highlight*Intensity); //Screen Blend Mode } `,{gl:r}=e,n=[r.canvas.width,r.canvas.height];e._.$bloom=e._.$bloom||new b(r,null,t),e.runFilter(e._.$bloom,{filterStrength:o,uResolution:n})}function ne(e,o){const t=`#version 300 es precision highp float; in vec2 texCoord; uniform sampler2D _texture; out vec4 outColor; uniform vec2 uResolution; uniform float filterStrength; #define SIGMA 10.0 #define BSIGMA 0.1 #define MSIZE 15 float normpdf(in float x, in float sigma) { return 0.39894*exp(-0.5*x*x/(sigma*sigma))/sigma; } float normpdf3(in vec3 v, in float sigma) { return 0.39894*exp(-0.5*dot(v,v)/(sigma*sigma))/sigma; } vec4 applyFilter(vec4 c, sampler2D _texture, vec2 texCoord) { const int kSize = (MSIZE-1)/2; float kernel[MSIZE] = float[MSIZE](0.031225216, 0.033322271, 0.035206333, 0.036826804, 0.038138565, 0.039104044, 0.039695028, 0.039894000, 0.039695028, 0.039104044, 0.038138565, 0.036826804, 0.035206333, 0.033322271, 0.031225216); vec3 final_colour = vec3(0.0); vec3 cc; float factor; float Z = 0.0; float bZ = 1.0/normpdf(0.0, BSIGMA); for (int i=-kSize; i <= kSize; ++i) { for (int j=-kSize; j <= kSize; ++j) { cc = texture(_texture, (texCoord.xy+vec2(float(i),float(j))/uResolution)).rgb; factor = normpdf3(cc-c.rgb, BSIGMA)*bZ*kernel[kSize+j]*kernel[kSize+i]; Z += factor; final_colour += factor*cc; } } return vec4(final_colour/Z, 1.0); } void main() { vec4 color = texture(_texture, texCoord); color = color * (1.0 - filterStrength) + applyFilter(color, _texture, texCoord) * filterStrength; outColor = color; } `,{gl:r}=e,n=[r.canvas.width,r.canvas.height];e._.$noise=e._.$noise||new b(r,null,t),e.runFilter(e._.$noise,{filterStrength:o,uResolution:n})}function A(e,o,t=3){let r=[];for(var n=0;n<t;n++){r.push([]);for(var a=0;a<t;a++){r[n].push(0);for(var l=0;l<t;l++)e[n]&&o[l]&&(r[n][a]+=e[n][l]*o[l][a])}}return r}const X=Object.freeze(Object.defineProperty({__proto__:null,filterAdjustments:re,filterBlend:J,filterBloom:ae,filterBlurBokeh:ee,filterBlurGaussian:te,filterCurves:W,filterHighlightsShadows:oe,filterInsta:Y,filterMatrix:$,filterNoise:ne,filterPerspective:q},Symbol.toStringTag,{value:"Module"}));function le(e,o,t){let r=e.getContext("webgl2",{antialias:!1,premultipliedAlpha:!0});if(!r)return console.error("webgl2 not supported!");t==="display-p3"?(r.drawingBufferColorSpace="display-p3",r.unpackColorSpace="display-p3"):(r.drawingBufferColorSpace="srgb",r.unpackColorSpace="srgb");const n={width:0,height:0,gl:r,img:o,destroy:f,loadImage:g,paintCanvas:x,crop:F,resetCrop:L,resize:m,resetResize:p,captureImage:U,readPixels:P,runFilter:i,setupFiltersTextures:s,_:{}};r.canvas.width=n.width=o.naturalWidth,r.canvas.height=n.height=o.naturalHeight;const a=new R(r);a.loadImage(o);const l=new b(r),c=new b(r,null,ce);let u,h=0;function s(){u?.length&&u.forEach(w=>w.destroy()),u=[];for(var _=0;_<2;++_){const w=new R(r,r.canvas.width,r.canvas.height);u.push(w)}}s();function f(){u?.length&&u.forEach(_=>_.destroy()),C&&C.destroy(),a.destroy(),delete n.img_cropped}let v;function i(_,w){w&&_.uniforms(w),v&&v.use(),u[h%2].drawTo(),_.drawRect(),v=u[h%2],h++}function g(){C?v=C:v=a,i(l,null)}function x(){v&&v.use(),r.bindFramebuffer(r.FRAMEBUFFER,null),c.drawRect()}let d={width:0,height:0};function m(_,w){r.canvas.width=n.width=d.width=_,r.canvas.height=n.height=d.height=w,s()}function p(){d.width&&(d.width=d.height=0,r.canvas.width=n.width=y.width||o.naturalWidth,r.canvas.height=n.height=y.height||o.naturalHeight,s())}let C,y={width:0,height:0};function F({left:_,top:w,width:E,height:S}){const G=E*S*4,k=new Uint8Array(G);i(l,{}),r.readPixels(_,w,E,S,r.RGBA,r.UNSIGNED_BYTE,k);const z=r.unpackColorSpace,D=new ImageData(new Uint8ClampedArray(k.buffer),E,S,{colorSpace:z});C=new R(r),C.loadImage(D),r.canvas.width=n.width=y.width=E,r.canvas.height=n.height=y.height=S,s(),n.img_cropped=V(D,z)}function L(){C&&(C.destroy(),C=null,y.width=y.height=0,r.canvas.width=n.width=d.width||o.naturalWidth,r.canvas.height=n.height=d.height||o.naturalHeight,delete n.img_cropped,s())}function U(_,w){i(l,{});const{width:E,height:S}=r.canvas,G=E*S*4,k=new Uint8Array(G);r.readPixels(0,0,E,S,r.RGBA,r.UNSIGNED_BYTE,k);const z=r.unpackColorSpace,D=new ImageData(new Uint8ClampedArray(k.buffer),E,S,{colorSpace:z});return V(D,z,_,w)}function P(){i(l,{});const{width:_,height:w}=r.canvas,E=_*w*4,S=new Uint8Array(E);return r.readPixels(0,0,_,w,r.RGBA,r.UNSIGNED_BYTE,S),S}function O(_){return function(...w){_(n,...w)}}return Object.keys(X).forEach(_=>n[_]=O(X[_])),n}const ce=`#version 300 es precision highp float; in vec2 texCoord; uniform sampler2D _texture; out vec4 outColor; vec4 fromLinear(vec4 linearRGB) { bvec3 cutoff = lessThan(linearRGB.rgb, vec3(0.0031308)); vec3 higher = vec3(1.055)*pow(linearRGB.rgb, vec3(1.0/2.4)) - vec3(0.055); vec3 lower = linearRGB.rgb * vec3(12.92); return vec4(mix(higher, lower, cutoff), linearRGB.a); } void main() { vec4 color = texture(_texture, vec2(texCoord.x, 1.0 - texCoord.y)); //outColor = color; outColor = fromLinear(color); }`;function b(e,o,t){const r=`#version 300 es in vec2 vertex; out vec2 texCoord; void main() { texCoord = vertex; gl_Position = vec4(vertex * 2.0 - 1.0, 0.0, 1.0); } `,n=`#version 300 es precision highp float; in vec2 texCoord; uniform sampler2D _texture; out vec4 outColor; void main() { outColor = texture(_texture, texCoord); } `,a=e.createProgram();let l;e.attachShader(a,h(e,e.VERTEX_SHADER,o||r)),e.attachShader(a,h(e,e.FRAGMENT_SHADER,t||n)),e.linkProgram(a);function c(s=!0,f,v,i,g){const x=e.getParameter(e.VIEWPORT);f=f!==void 0?(f-x[0])/x[2]:0,v=v!==void 0?(v-x[1])/x[3]:0,i=i!==void 0?(i-x[0])/x[2]:1,g=g!==void 0?(g-x[1])/x[3]:1,e.useProgram(a),e.vertexBuffer=e.vertexBuffer||e.createBuffer(),e.bindBuffer(e.ARRAY_BUFFER,e.vertexBuffer),e.bufferData(e.ARRAY_BUFFER,new Float32Array([f,v,f,g,i,v,i,g]),e.STATIC_DRAW),l||(l=e.getAttribLocation(a,"vertex"),e.enableVertexAttribArray(l)),e.vertexAttribPointer(l,2,e.FLOAT,!1,0,0),s&&(e.clearColor(0,0,0,0),e.clear(e.COLOR_BUFFER_BIT|e.GL_DEPTH_BUFFER_BIT)),e.drawArrays(e.TRIANGLE_STRIP,0,4)}function u(s={}){e.useProgram(a);for(let f in s){const v=e.getUniformLocation(a,f);if(v===null)continue;let i=s[f];if(Array.isArray(i))switch(i.length){case 1:{Array.isArray(i[0])&&(i=i[0]),e.uniform1fv(v,new Float32Array(i));break}case 2:e.uniform2fv(v,new Float32Array(i));break;case 3:e.uniform3fv(v,new Float32Array(i));break;case 4:e.uniform4fv(v,new Float32Array(i));break;case 9:e.uniformMatrix3fv(v,!1,new Float32Array(i));break;case 16:e.uniformMatrix4fv(v,!1,new Float32Array(i));break;default:throw`dont't know how to load uniform "`+f+'" of length '+i.length}else if(i?.unit)e.uniform1i(v,i.unit);else if(typeof i=="number")e.uniform1f(v,i);else throw'attempted to set uniform "'+f+'" to invalid value '+(i||"undefined").toString()}}function h(s,f,v){var i=s.createShader(f);if(s.shaderSource(i,v),s.compileShader(i),!s.getShaderParameter(i,s.COMPILE_STATUS))throw"compile error: "+s.getShaderInfoLog(i);return i}return{drawRect:c,uniforms:u}}function R(e,o,t){let r=o,n=t,a=e.createTexture();e.bindTexture(e.TEXTURE_2D,a),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.LINEAR),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.LINEAR),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,e.CLAMP_TO_EDGE);const l=e.SRGB8_ALPHA8;o&&t&&e.texImage2D(e.TEXTURE_2D,0,l,o,t,0,e.RGBA,e.UNSIGNED_BYTE,null);function c(v=0){if(!a)return console.error("texture has been destroyed");e.activeTexture(e.TEXTURE0+v),e.bindTexture(e.TEXTURE_2D,a)}function u(){e.deleteTexture(a),a=null}function h(){if(!a)return console.error("texture has been destroyed");if(e.framebuffer=e.framebuffer||e.createFramebuffer(),e.bindFramebuffer(e.FRAMEBUFFER,e.framebuffer),e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,a,0),e.checkFramebufferStatus(e.FRAMEBUFFER)!==e.FRAMEBUFFER_COMPLETE)throw new Error("incomplete framebuffer");e.viewport(0,0,r,n)}function s(v,i){if(!a)return console.error("texture has been destroyed");r=v.naturalWidth,n=v.naturalHeight,e.bindTexture(e.TEXTURE_2D,a);let g=i||e.SRGB8_ALPHA8;e.texImage2D(e.TEXTURE_2D,0,g,e.RGBA,e.UNSIGNED_BYTE,v)}function f(v,i,g,x){r=v,n=i,e.bindTexture(e.TEXTURE_2D,a);let d=x||e.SRGB8_ALPHA8;e.texImage2D(e.TEXTURE_2D,0,d,v,i,0,e.RGBA,e.UNSIGNED_BYTE,new Uint8Array(g))}return{use:c,destroy:u,drawTo:h,loadImage:s,initFromBytes:f}}function V(e,o,t,r){const n=document.createElement("canvas");var a=n.getContext("2d",{colorSpace:o});n.width=e.width,n.height=e.height,a.putImageData(e,0,0);var l=new Image;return l.src=n.toDataURL(t,r),l}B.Shader=b,B.Spline=I,B.Texture=R,B.minigl=le,Object.defineProperty(B,Symbol.toStringTag,{value:"Module"})}));