@xdadda/mini-gl
Version:
webgl image editing library with filters and effects
618 lines (531 loc) • 39.6 kB
JavaScript
(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"})}));