image-color-grading 1.0.3 → 1.0.4
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/README.md +25 -5
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +179 -8
- package/dist/index.d.ts +179 -8
- package/dist/index.js +1 -1
- package/package.json +6 -2
package/README.md
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
# image-color-grading
|
|
2
2
|
|
|
3
|
-
基于 WebGL 的高性能图像调色库,支持 22+ 种专业级调色参数,可用于图像编辑、滤镜应用等场景。
|
|
3
|
+
基于 WebGL/WebGPU 的高性能图像调色库,支持 22+ 种专业级调色参数,可用于图像编辑、滤镜应用等场景。
|
|
4
4
|
|
|
5
5
|
## 特性
|
|
6
6
|
|
|
7
|
-
- 🚀 **高性能** - 基于 WebGL 的 GPU 加速渲染
|
|
7
|
+
- 🚀 **高性能** - 基于 WebGL/WebGPU 的 GPU 加速渲染
|
|
8
|
+
- 🔄 **双后端支持** - 支持 WebGPU(更高性能)和 WebGL(更广兼容性),自动降级
|
|
8
9
|
- 🎨 **丰富的调色参数** - 支持 22+ 种专业调色参数
|
|
9
10
|
- 📦 **零依赖** - 无任何第三方依赖
|
|
10
11
|
- 🔧 **易于使用** - 简洁的 API 设计
|
|
@@ -30,9 +31,13 @@ pnpm add image-color-grading
|
|
|
30
31
|
```typescript
|
|
31
32
|
import { ImageColorGrading } from 'image-color-grading';
|
|
32
33
|
|
|
33
|
-
//
|
|
34
|
+
// 创建处理器实例(自动选择最佳后端,优先 WebGPU)
|
|
34
35
|
const processor = new ImageColorGrading();
|
|
35
36
|
|
|
37
|
+
// 或指定后端
|
|
38
|
+
const gpuProcessor = new ImageColorGrading({ backend: 'webgpu' });
|
|
39
|
+
const glProcessor = new ImageColorGrading({ backend: 'webgl' });
|
|
40
|
+
|
|
36
41
|
// 加载图像
|
|
37
42
|
await processor.loadImage('path/to/image.jpg');
|
|
38
43
|
|
|
@@ -44,6 +49,9 @@ processor.setSettings({
|
|
|
44
49
|
vibrance: 25,
|
|
45
50
|
});
|
|
46
51
|
|
|
52
|
+
// 检查当前使用的后端
|
|
53
|
+
console.log(processor.getBackendType()); // 'webgl' | 'webgpu'
|
|
54
|
+
|
|
47
55
|
// 导出为 Data URL
|
|
48
56
|
const dataUrl = processor.toDataURL();
|
|
49
57
|
|
|
@@ -80,10 +88,22 @@ processor.applyPreset('auto'); // 自动优化(等同于 autoFix)
|
|
|
80
88
|
#### 构造函数
|
|
81
89
|
|
|
82
90
|
```typescript
|
|
83
|
-
const processor = new ImageColorGrading(
|
|
91
|
+
const processor = new ImageColorGrading(options?: ProcessorOptions);
|
|
84
92
|
```
|
|
85
93
|
|
|
86
|
-
|
|
94
|
+
**ProcessorOptions:**
|
|
95
|
+
|
|
96
|
+
| 参数 | 类型 | 默认值 | 说明 |
|
|
97
|
+
|------|------|--------|------|
|
|
98
|
+
| `canvas` | `HTMLCanvasElement` | - | 自定义 canvas 元素 |
|
|
99
|
+
| `backend` | `'auto' \| 'webgpu' \| 'webgl'` | `'auto'` | 后端选择,auto 优先使用 WebGPU |
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
// 示例
|
|
103
|
+
const processor = new ImageColorGrading({
|
|
104
|
+
backend: 'webgpu',
|
|
105
|
+
});
|
|
106
|
+
```
|
|
87
107
|
|
|
88
108
|
#### 方法
|
|
89
109
|
|
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var e="\nprecision highp float;\nattribute vec2 aPosition;\nattribute vec2 aTexCoord;\nvarying vec2 vUv;\nvoid main() {\n vUv = aTexCoord;\n gl_Position = vec4(aPosition, 0.0, 1.0);\n}\n",n="\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform vec2 uTexel;\nuniform float uKernel[9];\nuniform float uAmount;\nvoid main(void) {\n vec4 c11 = texture2D(uTexture, vUv - uTexel);\n vec4 c12 = texture2D(uTexture, vec2(vUv.x, vUv.y - uTexel.y));\n vec4 c13 = texture2D(uTexture, vec2(vUv.x + uTexel.x, vUv.y - uTexel.y));\n vec4 c21 = texture2D(uTexture, vec2(vUv.x - uTexel.x, vUv.y));\n vec4 c22 = texture2D(uTexture, vUv);\n vec4 c23 = texture2D(uTexture, vec2(vUv.x + uTexel.x, vUv.y));\n vec4 c31 = texture2D(uTexture, vec2(vUv.x - uTexel.x, vUv.y + uTexel.y));\n vec4 c32 = texture2D(uTexture, vec2(vUv.x, vUv.y + uTexel.y));\n vec4 c33 = texture2D(uTexture, vUv + uTexel);\n vec4 color = c11 * uKernel[0] + c12 * uKernel[1] + c13 * uKernel[2] +\n c21 * uKernel[3] + c22 * uKernel[4] + c23 * uKernel[5] +\n c31 * uKernel[6] + c32 * uKernel[7] + c33 * uKernel[8];\n gl_FragColor = color * uAmount + (c22 * (1.0 - uAmount));\n}\n";function t(e,n,t){const r=e.createShader(n);return r?(e.shaderSource(r,t),e.compileShader(r),e.getShaderParameter(r,e.COMPILE_STATUS)?r:(e.deleteShader(r),null)):null}function r(e,n,r,o){const a=t(e,e.VERTEX_SHADER,n),i=t(e,e.FRAGMENT_SHADER,r);if(!a||!i)throw new Error("Shader compile failed.");const c=function(e,n,t){const r=e.createProgram();return r?(e.attachShader(r,n),e.attachShader(r,t),e.linkProgram(r),e.getProgramParameter(r,e.LINK_STATUS)?r:(e.deleteProgram(r),null)):null}(e,a,i);if(!c)throw new Error("Program link failed.");const u={aPosition:e.getAttribLocation(c,"aPosition"),aTexCoord:e.getAttribLocation(c,"aTexCoord"),apos:e.getAttribLocation(c,"apos"),auv:e.getAttribLocation(c,"auv")},l={};return o.forEach(n=>{l[n]=e.getUniformLocation(c,n)}),{program:c,attribs:u,uniforms:l}}function o(e,n,t){const r=e.createTexture();if(!r)throw new Error("Unable to create texture");e.bindTexture(e.TEXTURE_2D,r),e.texImage2D(e.TEXTURE_2D,0,e.RGBA,n,t,0,e.RGBA,e.UNSIGNED_BYTE,null),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.LINEAR),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_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 o=e.createFramebuffer();if(!o)throw new Error("Unable to create framebuffer");return e.bindFramebuffer(e.FRAMEBUFFER,o),e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,r,0),{framebuffer:o,texture:r}}var a=e=>Math.min(1,Math.max(0,e)),i=(e,n,t,r,o)=>{const a=1-e;return a*a*a*n+3*a*a*e*t+3*a*e*e*r+e*e*e*o},c=e=>{const n=Math.max(-100,Math.min(100,e))/100;return(e=>{const n=new Uint8Array(768);for(let t=0;t<256;t+=1){const r=i(t/255,0,e,.66,1),o=Math.round(255*a(r)),c=3*t;n[c]=o,n[c+1]=o,n[c+2]=o}return n})(a(.33-.35*n))},u={vibrance:0,saturation:0,temperature:0,tint:0,hue:0,brightness:0,exposure:0,contrast:0,blacks:0,whites:0,highlights:0,shadows:0,dehaze:0,bloom:0,glamour:0,clarity:0,sharpen:0,smooth:0,blur:0,vignette:0,grain:0},l={auto:{},blackAndWhite:{saturation:-100,contrast:20,exposure:10,clarity:10},pop:{highlights:50,shadows:-50,vibrance:50,saturation:20,exposure:20,clarity:20},vintage:{saturation:-20,contrast:10,temperature:15,grain:30,vignette:25},vivid:{vibrance:40,saturation:20,contrast:15,clarity:20},cinematic:{contrast:25,highlights:-20,shadows:15,temperature:-10,vignette:30}};function s(e){const{data:n,width:t,height:r}=e,o=new Array(256).fill(0);for(let e=0;e<n.length;e+=4)o[n[e]]+=1,o[n[e+1]]+=1,o[n[e+2]]+=1;const a=Math.round(t*r/1e3);let i=0;for(let e=0;e<256;e++)if(o[e]>a){i=e;break}let c=255;for(let e=255;e>=0;e--)if(o[e]>a){c=e;break}return i>100&&(i=100),c<155&&(c=155),{black:i,white:c}}function v(e){const{data:n,width:t,height:r}=e;let o=1,a=1;for(let e=0;e<n.length;e+=4){const t=n[e],r=n[e+1],i=n[e+2],c=Math.min(t,r,i),u=Math.max(t,r,i);a+=u/255;const l=u-c;l>0&&(o+=l/u)}return(o+a)/(t*r*2)}function m(e){return{levels:s(e),vibrance:v(e)}}exports.ImageColorGrading=class{constructor(e){this.resources=null,this.settings={...u},this.imageLoaded=!1,this.canvas=e||document.createElement("canvas")}getCanvas(){return this.canvas}getSettings(){return{...this.settings}}setSettings(e){this.settings={...this.settings,...e},this.resources&&this.render()}resetSettings(){this.settings={...u},this.resources&&this.render()}loadImage(e){return new Promise((n,t)=>{const r=new Image;r.crossOrigin="anonymous",r.onload=()=>{this.initFromImage(r),n()},r.onerror=()=>{t(new Error(`Failed to load image: ${e}`))},r.src=e})}loadFromImage(e){this.initFromImage(e)}loadFromFile(e){return new Promise((n,t)=>{const r=URL.createObjectURL(e);this.loadImage(r).then(()=>{URL.revokeObjectURL(r),n()}).catch(e=>{URL.revokeObjectURL(r),t(e)})})}loadFromImageData(e){const{width:n,height:t,data:r}=e;this.canvas.width=n,this.canvas.height=t;const o=this.getWebGLContext();if(!o)throw new Error("WebGL not supported");this.disposeResources(),o.viewport(0,0,n,t),o.pixelStorei(o.UNPACK_FLIP_Y_WEBGL,1);const a=o.createTexture();if(!a)throw new Error("Failed to create texture");o.bindTexture(o.TEXTURE_2D,a),o.texImage2D(o.TEXTURE_2D,0,o.RGBA,n,t,0,o.RGBA,o.UNSIGNED_BYTE,r),o.texParameteri(o.TEXTURE_2D,o.TEXTURE_MIN_FILTER,o.LINEAR),o.texParameteri(o.TEXTURE_2D,o.TEXTURE_MAG_FILTER,o.LINEAR),o.texParameteri(o.TEXTURE_2D,o.TEXTURE_WRAP_S,o.CLAMP_TO_EDGE),o.texParameteri(o.TEXTURE_2D,o.TEXTURE_WRAP_T,o.CLAMP_TO_EDGE),this.initResources(o,n,t,a)}render(){this.resources&&this.drawFrame(this.resources,this.settings)}toDataURL(e){const n=e?.format||"image/png",t=e?.quality;return this.canvas.toDataURL(n,t)}toBlob(e){return new Promise((n,t)=>{const r=e?.format||"image/png",o=e?.quality;this.canvas.toBlob(e=>{e?n(e):t(new Error("Failed to create blob"))},r,o)})}getImageData(){const e=this.canvas.getContext("2d");if(e)return e.getImageData(0,0,this.canvas.width,this.canvas.height);const n=this.canvas.getContext("webgl");if(n){const e=new Uint8ClampedArray(this.canvas.width*this.canvas.height*4);return n.readPixels(0,0,this.canvas.width,this.canvas.height,n.RGBA,n.UNSIGNED_BYTE,e),new ImageData(e,this.canvas.width,this.canvas.height)}throw new Error("Cannot get ImageData")}getSize(){return{width:this.canvas.width,height:this.canvas.height}}isLoaded(){return this.imageLoaded}dispose(){this.disposeResources(),this.imageLoaded=!1}analyze(){if(!this.imageLoaded)throw new Error("No image loaded");const e={...this.settings};this.settings={...u},this.render();const n=m(this.getImageData());return this.settings=e,this.render(),n}autoFix(){if(!this.imageLoaded)throw new Error("No image loaded");this.settings={...u},this.render();const e=this.getImageData(),n=s(e),t=v(e),r={...u};if(r.whites=Math.round(255-n.white),r.blacks=Math.round(n.black),t<.7){const e=Math.round(100*(.7-t));r.vibrance=Math.min(e,50)}return this.settings=r,this.render(),r}applyPreset(e){if("auto"===e)return this.autoFix();const n=l[e],t={...u,...n};return this.settings=t,this.resources&&this.render(),t}getWebGLContext(){return this.canvas.getContext("webgl",{antialias:!0,premultipliedAlpha:!1,preserveDrawingBuffer:!0})}initFromImage(e){const n=e.naturalWidth||e.width,t=e.naturalHeight||e.height;this.canvas.width=n,this.canvas.height=t;const r=this.getWebGLContext();if(!r)throw new Error("WebGL not supported");this.disposeResources(),r.disable(r.DEPTH_TEST),r.viewport(0,0,n,t),r.pixelStorei(r.UNPACK_FLIP_Y_WEBGL,1);const o=r.createTexture();if(!o)throw new Error("Failed to create texture");r.bindTexture(r.TEXTURE_2D,o),r.texImage2D(r.TEXTURE_2D,0,r.RGBA,r.RGBA,r.UNSIGNED_BYTE,e),r.texParameteri(r.TEXTURE_2D,r.TEXTURE_MIN_FILTER,r.LINEAR),r.texParameteri(r.TEXTURE_2D,r.TEXTURE_MAG_FILTER,r.LINEAR),r.texParameteri(r.TEXTURE_2D,r.TEXTURE_WRAP_S,r.CLAMP_TO_EDGE),r.texParameteri(r.TEXTURE_2D,r.TEXTURE_WRAP_T,r.CLAMP_TO_EDGE),this.initResources(r,n,t,o)}initResources(t,a,i,u){const l=((e,n)=>{const t=e.createTexture();if(!t)throw new Error("Unable to create palette texture");return e.bindTexture(e.TEXTURE_2D,t),e.texImage2D(e.TEXTURE_2D,0,e.RGB,256,1,0,e.RGB,e.UNSIGNED_BYTE,n),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.NEAREST),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.NEAREST),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),t})(t,c(0)),s=t.createBuffer(),v=t.createBuffer();if(!s||!v)throw new Error("Failed to create buffers");t.bindBuffer(t.ARRAY_BUFFER,s),t.bufferData(t.ARRAY_BUFFER,new Float32Array([-1,-1,1,-1,-1,1,1,1]),t.STATIC_DRAW),t.bindBuffer(t.ARRAY_BUFFER,v),t.bufferData(t.ARRAY_BUFFER,new Float32Array([0,0,1,0,0,1,1,1]),t.STATIC_DRAW);const m={pass:r(t,e,"\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nvoid main() {\n gl_FragColor = texture2D(uTexture, vUv);\n}\n",["uTexture"]),vibrance:r(t,e,"\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uAmount;\nvoid main() {\n vec4 col = texture2D(uTexture, vUv);\n vec3 color = col.rgb;\n float luminance = color.r * 0.299 + color.g * 0.587 + color.b * 0.114;\n float mn = min(min(color.r, color.g), color.b);\n float mx = max(max(color.r, color.g), color.b);\n float sat = (1.0 - (mx - mn)) * (1.0 - mx) * luminance * 5.0;\n vec3 lightness = vec3((mn + mx) / 2.0);\n color = mix(color, mix(color, lightness, -uAmount), sat);\n gl_FragColor = vec4(\n mix(color, lightness, (1.0 - lightness) * (1.0 - uAmount) / 2.0 * abs(uAmount)),\n col.a\n );\n}\n",["uTexture","uAmount"]),saturation:r(t,e,"\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uMatrix[20];\nvoid main(void) {\n vec4 c = texture2D(uTexture, vUv);\n gl_FragColor.r = uMatrix[0] * c.r + uMatrix[1] * c.g + uMatrix[2] * c.b + uMatrix[3] * c.a + uMatrix[4];\n gl_FragColor.g = uMatrix[5] * c.r + uMatrix[6] * c.g + uMatrix[7] * c.b + uMatrix[8] * c.a + uMatrix[9];\n gl_FragColor.b = uMatrix[10] * c.r + uMatrix[11] * c.g + uMatrix[12] * c.b + uMatrix[13] * c.a + uMatrix[14];\n gl_FragColor.a = uMatrix[15] * c.r + uMatrix[16] * c.g + uMatrix[17] * c.b + uMatrix[18] * c.a + uMatrix[19];\n}\n",["uTexture","uMatrix[0]"]),temperature:r(t,e,"\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uAmount;\nvoid main() {\n vec4 color = texture2D(uTexture, vUv);\n color.r = clamp(color.r + uAmount, 0.0, 1.0);\n color.b = clamp(color.b - uAmount, 0.0, 1.0);\n gl_FragColor = color;\n}\n",["uTexture","uAmount"]),tint:r(t,e,"\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uAmount;\nvoid main() {\n vec4 color = texture2D(uTexture, vUv);\n color.g = clamp(color.g + uAmount, 0.0, 1.0);\n gl_FragColor = color;\n}\n",["uTexture","uAmount"]),hue:r(t,e,"\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uRotation;\nvec3 rgb2hsv(vec3 c) {\n vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\n vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));\n vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));\n float d = q.x - min(q.w, q.y);\n float e = 1.0e-10;\n return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\n}\nvec3 hsv2rgb(vec3 c) {\n vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\n return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);\n}\nvoid main() {\n lowp vec4 base = texture2D(uTexture, vUv);\n vec3 hsv = rgb2hsv(base.rgb);\n hsv.x = fract(hsv.x + uRotation);\n gl_FragColor = vec4(hsv2rgb(hsv), base.a);\n}\n",["uTexture","uRotation"]),brightness:r(t,e,"\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uAmount;\nconst float PI = 3.1415926535897932384626433832795;\nvoid main() {\n vec4 color = texture2D(uTexture, vUv);\n if (uAmount >= 0.0) {\n color.r = color.r + uAmount * sin(color.r * PI);\n color.g = color.g + uAmount * sin(color.g * PI);\n color.b = color.b + uAmount * sin(color.b * PI);\n } else {\n color.r = (1.0 + uAmount) * color.r;\n color.g = (1.0 + uAmount) * color.g;\n color.b = (1.0 + uAmount) * color.b;\n }\n gl_FragColor = color;\n}\n",["uTexture","uAmount"]),exposure:r(t,e,"\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uAmount;\nconst float epsilon = 0.000001;\nconst float mx = 1.0 - epsilon;\nconst mat3 matRGBtoROMM = mat3(\n 0.5293459296226501, 0.3300727903842926, 0.14058130979537964,\n 0.09837432950735092, 0.8734610080718994, 0.028164653107523918,\n 0.01688321679830551, 0.11767247319221497, 0.8654443025588989\n);\nconst mat3 matROMMtoRGB = mat3(\n 2.0340757369995117, -0.727334201335907, -0.3067416846752167,\n -0.22881317138671875, 1.2317301034927368, -0.0029169507324695587,\n -0.008569774217903614, -0.1532866358757019, 1.1618564128875732\n);\nfloat ramp(in float t) {\n t *= 2.0;\n if (t >= 1.0) {\n t -= 1.0;\n t = log(0.5) / log(0.5 * (1.0 - t) + 0.9332 * t);\n }\n return clamp(t, 0.001, 10.0);\n}\nvec3 rgb2hsv(in vec3 c) {\n vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\n vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));\n vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));\n float d = q.x - min(q.w, q.y);\n float e = 1.0e-10;\n return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\n}\nvec3 hsv2rgb(in vec3 c) {\n vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\n return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);\n}\nvec3 setHue(in vec3 res, in vec3 base) {\n vec3 hsv = rgb2hsv(base);\n vec3 res_hsv = rgb2hsv(res);\n return hsv2rgb(vec3(hsv.x, res_hsv.y, res_hsv.z));\n}\nvoid main() {\n lowp vec4 col = texture2D(uTexture, vUv);\n vec3 base = col.rgb * matRGBtoROMM;\n float a = abs(uAmount) * col.a + epsilon;\n float v = pow(2.0, a * 2.0 + 1.0) - 2.0;\n float m = mx - exp(-v);\n vec3 res = (uAmount > 0.0) ? (1.0 - exp(-v * base)) / m : log(1.0 - base * m) / -v;\n res = mix(base, res, min(a * 100.0, 1.0));\n res = setHue(res, base);\n res = pow(res, vec3(ramp(1.0 - (0.0 * col.a + 1.0) / 2.0)));\n res = res * matROMMtoRGB;\n gl_FragColor = vec4(res, col.a);\n}\n",["uTexture","uAmount"]),contrast:r(t,e,"\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uMatrix[20];\nvoid main(void) {\n vec4 c = texture2D(uTexture, vUv);\n gl_FragColor.r = uMatrix[0] * c.r + uMatrix[1] * c.g + uMatrix[2] * c.b + uMatrix[3] * c.a + uMatrix[4];\n gl_FragColor.g = uMatrix[5] * c.r + uMatrix[6] * c.g + uMatrix[7] * c.b + uMatrix[8] * c.a + uMatrix[9];\n gl_FragColor.b = uMatrix[10] * c.r + uMatrix[11] * c.g + uMatrix[12] * c.b + uMatrix[13] * c.a + uMatrix[14];\n gl_FragColor.a = uMatrix[15] * c.r + uMatrix[16] * c.g + uMatrix[17] * c.b + uMatrix[18] * c.a + uMatrix[19];\n}\n",["uTexture","uMatrix[0]"]),blacks:r(t,"\nprecision highp float;\nattribute vec2 apos;\nattribute vec2 auv;\nvarying vec2 uv;\nuniform vec4 transform;\nvoid main(void) {\n uv = auv;\n gl_Position = vec4(\n apos.x * transform.x + transform.z,\n apos.y * transform.y + transform.w,\n 0.0,\n 1.0\n );\n}\n","\nprecision highp float;\nvarying vec2 uv;\nuniform sampler2D uTexture;\nuniform sampler2D uPaletteMap;\nvoid main() {\n lowp vec4 base = texture2D(uTexture, uv.xy);\n float r = texture2D(uPaletteMap, vec2(base.r, 0.0)).r;\n float g = texture2D(uPaletteMap, vec2(base.g, 0.0)).g;\n float b = texture2D(uPaletteMap, vec2(base.b, 0.0)).b;\n gl_FragColor = vec4(r, g, b, base.a);\n}\n",["uTexture","uPaletteMap","transform"]),whites:r(t,e,"\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uAmount;\nconst vec3 RGB2Y = vec3(0.2126, 0.7152, 0.0722);\nvoid main() {\n vec4 base = texture2D(uTexture, vUv.xy);\n vec3 color = base.rgb;\n float lum = dot(color, RGB2Y);\n float whiteMask = smoothstep(0.5, 1.0, lum);\n color += uAmount * whiteMask;\n gl_FragColor = vec4(clamp(color, 0.0, 1.0), base.a);\n}\n",["uTexture","uAmount"]),highlights:r(t,e,"\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uAmount;\nconst float epsilon = 0.000001;\nconst float mx = 1.0 - epsilon;\nconst float PI = 3.1415926535897932384626433832795;\nconst mat3 matRGBtoROMM = mat3(\n 0.5293459296226501, 0.3300727903842926, 0.14058130979537964,\n 0.09837432950735092, 0.8734610080718994, 0.028164653107523918,\n 0.01688321679830551, 0.11767247319221497, 0.8654443025588989\n);\nconst mat3 matROMMtoRGB = mat3(\n 2.0340757369995117, -0.727334201335907, -0.3067416846752167,\n -0.22881317138671875, 1.2317301034927368, -0.0029169507324695587,\n -0.008569774217903614, -0.1532866358757019, 1.1618564128875732\n);\nfloat luma_romm(in vec3 color) {\n return dot(color, vec3(0.242655, 0.755158, 0.002187));\n}\nfloat luma(in vec3 color) {\n return dot(color, vec3(0.298839, 0.586811, 0.11435));\n}\nvec3 rgb2hsv(in vec3 c) {\n vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\n vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));\n vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));\n float d = q.x - min(q.w, q.y);\n float e = 1.0e-10;\n return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\n}\nvec3 hsv2rgb(in vec3 c) {\n vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\n return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);\n}\nvec3 setHue(in vec3 res, in vec3 base) {\n vec3 hsv = rgb2hsv(base);\n vec3 res_hsv = rgb2hsv(res);\n return hsv2rgb(vec3(hsv.x, res_hsv.y, res_hsv.z));\n}\nfloat gaussian(in float x) {\n return 1.0 - exp(-PI * 2.0 * x * x);\n}\nvoid main() {\n lowp vec4 col = texture2D(uTexture, vUv);\n lowp vec3 map = col.rgb;\n vec3 base = col.rgb * matRGBtoROMM;\n float base_lum = luma(col.rgb);\n float map_lum = luma_romm(map * matRGBtoROMM);\n float exposure = mix(uAmount, 0.0, 1.0 - map_lum) * col.a;\n float a = abs(exposure) * col.a + epsilon;\n float v = pow(2.0, a + 1.0) - 2.0;\n float m = mx - exp(-v);\n vec3 res = (exposure > 0.0) ? (1.0 - exp(-v * base)) / m : log(1.0 - base * m) / -v;\n res = mix(base, res, min(a * 100.0, 1.0));\n res = setHue(res, base);\n res = res * matROMMtoRGB;\n gl_FragColor = vec4(res, col.a);\n}\n",["uTexture","uAmount"]),shadows:r(t,e,"\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uAmount;\nconst float epsilon = 0.000001;\nconst float mx = 1.0 - epsilon;\nconst float PI = 3.1415926535897932384626433832795;\nconst mat3 matRGBtoROMM = mat3(\n 0.5293459296226501, 0.3300727903842926, 0.14058130979537964,\n 0.09837432950735092, 0.8734610080718994, 0.028164653107523918,\n 0.01688321679830551, 0.11767247319221497, 0.8654443025588989\n);\nconst mat3 matROMMtoRGB = mat3(\n 2.0340757369995117, -0.727334201335907, -0.3067416846752167,\n -0.22881317138671875, 1.2317301034927368, -0.0029169507324695587,\n -0.008569774217903614, -0.1532866358757019, 1.1618564128875732\n);\nfloat luma_romm(in vec3 color) {\n return dot(color, vec3(0.242655, 0.755158, 0.002187));\n}\nfloat luma(in vec3 color) {\n return dot(color, vec3(0.298839, 0.586811, 0.11435));\n}\nvec3 rgb2hsv(in vec3 c) {\n vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\n vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));\n vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));\n float d = q.x - min(q.w, q.y);\n float e = 1.0e-10;\n return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\n}\nvec3 hsv2rgb(in vec3 c) {\n vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\n return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);\n}\nvec3 setHue(in vec3 res, in vec3 base) {\n vec3 hsv = rgb2hsv(base);\n vec3 res_hsv = rgb2hsv(res);\n return hsv2rgb(vec3(hsv.x, res_hsv.y, res_hsv.z));\n}\nfloat gaussian(in float x) {\n return 1.0 - exp(-PI * 2.0 * x * x);\n}\nvoid main() {\n lowp vec4 col = texture2D(uTexture, vUv);\n lowp vec3 map = col.rgb;\n vec3 base = col.rgb * matRGBtoROMM;\n float base_lum = luma(col.rgb);\n float map_lum = luma_romm(map * matRGBtoROMM);\n float exposure = mix(0.0, uAmount, 1.0 - map_lum) * col.a;\n float a = abs(exposure) * col.a + epsilon;\n float v = pow(2.0, a + 1.0) - 2.0;\n float m = mx - exp(-v);\n vec3 res = (exposure > 0.0) ? (1.0 - exp(-v * base)) / m : log(1.0 - base * m) / -v;\n res = mix(base, res, min(a * 100.0, 1.0));\n res = setHue(res, base);\n res = res * matROMMtoRGB;\n gl_FragColor = vec4(res, col.a);\n}\n",["uTexture","uAmount"]),dehaze:r(t,e,"\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uAmount;\nuniform vec2 uSize;\n\nfloat hazeMap(vec2 coord) {\n vec3 color = vec3(1.0);\n vec2 stepSize = vec2(1.0 / uSize.x, 1.0 / uSize.y);\n for (int i = -1; i <= 1; ++i) {\n for (int j = -1; j <= 1; ++j) {\n vec2 offset = vec2(float(i), float(j)) * stepSize;\n vec2 uv = clamp(coord + offset, 0.0, 1.0);\n vec3 sample = texture2D(uTexture, uv).rgb;\n color = min(color, sample);\n }\n }\n return min(color.r, min(color.g, color.b));\n}\n\nvoid main() {\n vec4 base = texture2D(uTexture, vUv);\n float haze = hazeMap(vUv);\n float transmission = 1.0 - 0.95 * haze;\n const float A = 0.95;\n const float t0 = 0.1;\n float t = mix(1.0, max(t0, transmission), uAmount);\n vec3 J = (base.rgb - A) / t + A;\n gl_FragColor = vec4(J, base.a);\n}\n",["uTexture","uAmount","uSize"]),bloom:r(t,e,"\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uAmount;\nuniform vec2 uTexel;\nuniform float uThreshold;\n\nvoid main() {\n vec4 sum = vec4(0.0);\n int j = -2;\n for (int i = -2; i <= 2; i++) sum += texture2D(uTexture, vUv + vec2(float(i), float(j)) * uTexel);\n j = -1;\n for (int i = -2; i <= 2; i++) sum += texture2D(uTexture, vUv + vec2(float(i), float(j)) * uTexel);\n j = 0;\n for (int i = -2; i <= 2; i++) sum += texture2D(uTexture, vUv + vec2(float(i), float(j)) * uTexel);\n j = 1;\n for (int i = -2; i <= 2; i++) sum += texture2D(uTexture, vUv + vec2(float(i), float(j)) * uTexel);\n j = 2;\n for (int i = -2; i <= 2; i++) sum += texture2D(uTexture, vUv + vec2(float(i), float(j)) * uTexel);\n sum /= 25.0;\n vec4 base = texture2D(uTexture, vUv);\n if (length(sum.rgb) > uThreshold) {\n base += sum * uAmount;\n }\n gl_FragColor = base;\n}\n",["uTexture","uAmount","uTexel","uThreshold"]),glamour:r(t,e,"\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uAmount;\nuniform vec2 uTexel;\n\nfloat normpdf(in float x, in float sigma) {\n return 0.39894 * exp(-0.5 * x * x / (sigma * sigma)) / sigma;\n}\n\nvec3 blurMap() {\n const int mSize = 11;\n const int kSize = (mSize - 1) / 2;\n float kernel[mSize];\n vec3 final_colour = vec3(0.0);\n float sigma = 7.0;\n float Z = 0.0;\n for (int j = 0; j <= kSize; ++j) {\n kernel[kSize + j] = kernel[kSize - j] = normpdf(float(j), sigma);\n }\n for (int j = 0; j < mSize; ++j) {\n Z += kernel[j];\n }\n for (int i = -kSize; i <= kSize; ++i) {\n for (int j = -kSize; j <= kSize; ++j) {\n final_colour += kernel[kSize + j] * kernel[kSize + i] *\n texture2D(uTexture, vUv + vec2(float(i), float(j)) * uTexel).rgb;\n }\n }\n return vec3(final_colour / (Z * Z));\n}\n\nfloat luma(vec3 color) {\n return dot(color, vec3(0.299, 0.587, 0.114));\n}\n\nvoid main() {\n vec4 base = texture2D(uTexture, vUv);\n vec3 color = blurMap();\n color = vec3(luma(color));\n color = vec3(\n (base.r <= 0.5) ? (2.0 * base.r * color.r) : (1.0 - 2.0 * (1.0 - base.r) * (1.0 - color.r)),\n (base.g <= 0.5) ? (2.0 * base.g * color.g) : (1.0 - 2.0 * (1.0 - base.g) * (1.0 - color.g)),\n (base.b <= 0.5) ? (2.0 * base.b * color.b) : (1.0 - 2.0 * (1.0 - base.b) * (1.0 - color.b))\n );\n gl_FragColor = mix(base, vec4(color, base.a), uAmount);\n}\n",["uTexture","uAmount","uTexel"]),clarity:r(t,e,"\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uAmount;\nuniform vec2 uTexel;\n\nfloat Lum(vec3 c) {\n return 0.299 * c.r + 0.587 * c.g + 0.114 * c.b;\n}\nfloat BlendOverlayf(float base, float blend) {\n return (base < 0.5 ? (2.0 * base * blend) : (1.0 - 2.0 * (1.0 - base) * (1.0 - blend)));\n}\nvec3 BlendOverlay(vec3 base, vec3 blend) {\n return vec3(BlendOverlayf(base.r, blend.r), BlendOverlayf(base.g, blend.g), BlendOverlayf(base.b, blend.b));\n}\nfloat BlendVividLightf(float base, float blend) {\n float BlendColorBurnf = (((2.0 * blend) == 0.0) ? (2.0 * blend) : max((1.0 - ((1.0 - base) / (2.0 * blend))), 0.0));\n float BlendColorDodgef = (((2.0 * (blend - 0.5)) == 1.0) ? (2.0 * (blend - 0.5)) : min(base / (1.0 - (2.0 * (blend - 0.5))), 1.0));\n return ((blend < 0.5) ? BlendColorBurnf : BlendColorDodgef);\n}\nvec3 BlendVividLight(vec3 base, vec3 blend) {\n return vec3(BlendVividLightf(base.r, blend.r), BlendVividLightf(base.g, blend.g), BlendVividLightf(base.b, blend.b));\n}\nfloat normpdf(in float x, in float sigma) {\n return 0.39894 * exp(-0.5 * x * x / (sigma * sigma)) / sigma;\n}\nvec3 blurMap() {\n const int mSize = 11;\n const int kSize = (mSize - 1) / 2;\n float kernel[mSize];\n vec3 final_colour = vec3(0.0);\n float sigma = 7.0;\n float Z = 0.0;\n for (int j = 0; j <= kSize; ++j) {\n kernel[kSize + j] = kernel[kSize - j] = normpdf(float(j), sigma);\n }\n for (int j = 0; j < mSize; ++j) {\n Z += kernel[j];\n }\n for (int i = -kSize; i <= kSize; ++i) {\n for (int j = -kSize; j <= kSize; ++j) {\n final_colour += kernel[kSize + j] * kernel[kSize + i] *\n texture2D(uTexture, vUv + vec2(float(i), float(j)) * uTexel).rgb;\n }\n }\n return vec3(final_colour / (Z * Z));\n}\nvoid main() {\n vec4 base4 = texture2D(uTexture, vUv);\n vec3 blur = blurMap();\n vec3 base = base4.rgb;\n float intensity = (uAmount < 0.0) ? (uAmount / 2.0) : uAmount;\n float lum = Lum(base);\n vec3 col = vec3(lum);\n vec3 mask = vec3(1.0 - pow(lum, 1.8));\n vec3 layer = vec3(1.0 - Lum(blur));\n vec3 detail = clamp(BlendVividLight(col, layer), 0.0, 1.0);\n vec3 inverse = mix(1.0 - detail, detail, (intensity + 1.0) / 2.0);\n gl_FragColor = vec4(BlendOverlay(base, mix(vec3(0.5), inverse, mask)), base4.a);\n}\n",["uTexture","uAmount","uTexel"]),sharpen:r(t,e,n,["uTexture","uTexel","uKernel[0]","uAmount"]),smooth:r(t,e,n,["uTexture","uTexel","uKernel[0]","uAmount"]),blur:r(t,e,"\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform vec2 uSize;\nfloat random(vec3 scale, float seed) {\n return fract(sin(dot(gl_FragCoord.xyz + seed, scale)) * 43758.5453 + seed);\n}\nvoid main() {\n vec4 color = vec4(0.0);\n float total = 0.0;\n float offset = random(vec3(12.9898, 78.233, 151.7182), 0.0);\n for (int t = -30; t <= 30; t++) {\n float percent = (float(t) + offset - 0.5) / 30.0;\n float weight = 1.0 - abs(percent);\n vec4 sample = texture2D(uTexture, vUv + uSize * percent);\n sample.rgb *= sample.a;\n color += sample * weight;\n total += weight;\n }\n gl_FragColor = color / total;\n gl_FragColor.rgb /= gl_FragColor.a + 0.00001;\n}\n",["uTexture","uSize"]),vignette:r(t,e,"\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uAmount;\nuniform float uSize;\nvoid main() {\n vec4 color = texture2D(uTexture, vUv);\n float dist = distance(vUv, vec2(0.5, 0.5));\n float amt = clamp(uAmount, -1.0, 1.0);\n float edge = dist * (abs(amt) * 0.75 + uSize * 2.0);\n float vignette = smoothstep(0.8, uSize * 0.799, edge);\n if (amt < 0.0) {\n vignette = 1.0 + (1.0 - vignette) * (-amt);\n } else {\n vignette = mix(1.0, vignette, amt);\n }\n color.rgb *= vignette;\n gl_FragColor = color;\n}\n",["uTexture","uAmount","uSize"]),grain:r(t,e,"\nprecision highp float;\nuniform sampler2D uTexture;\nvarying vec2 vUv;\nuniform vec2 uResolution;\nuniform float uAmount;\nuniform float uTime;\nconst float permTexUnit = 1.0 / 256.0;\nconst float permTexUnitHalf = 0.5 / 256.0;\nfloat grainsize = 1.8;\nfloat lumamount = 1.0;\n\nvec4 rnm(in vec2 tc) {\n float noise = sin(dot(tc + vec2(uTime, uTime), vec2(12.9898, 78.233))) * 43758.5453;\n float noiseR = fract(noise) * 2.0 - 1.0;\n float noiseG = fract(noise * 1.2154) * 2.0 - 1.0;\n float noiseB = fract(noise * 1.3453) * 2.0 - 1.0;\n float noiseA = fract(noise * 1.3647) * 2.0 - 1.0;\n return vec4(noiseR, noiseG, noiseB, noiseA);\n}\nfloat fade(in float t) {\n return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);\n}\nfloat pnoise3D(in vec3 p) {\n vec3 pi = permTexUnit * floor(p) + permTexUnitHalf;\n vec3 pf = fract(p);\n float perm00 = rnm(pi.xy).a;\n vec3 grad000 = rnm(vec2(perm00, pi.z)).rgb * 4.0 - 1.0;\n float n000 = dot(grad000, pf);\n vec3 grad001 = rnm(vec2(perm00, pi.z + permTexUnit)).rgb * 4.0 - 1.0;\n float n001 = dot(grad001, pf - vec3(0.0, 0.0, 1.0));\n float perm01 = rnm(pi.xy + vec2(0.0, permTexUnit)).a;\n vec3 grad010 = rnm(vec2(perm01, pi.z)).rgb * 4.0 - 1.0;\n float n010 = dot(grad010, pf - vec3(0.0, 1.0, 0.0));\n vec3 grad011 = rnm(vec2(perm01, pi.z + permTexUnit)).rgb * 4.0 - 1.0;\n float n011 = dot(grad011, pf - vec3(0.0, 1.0, 1.0));\n float perm10 = rnm(pi.xy + vec2(permTexUnit, 0.0)).a;\n vec3 grad100 = rnm(vec2(perm10, pi.z)).rgb * 4.0 - 1.0;\n float n100 = dot(grad100, pf - vec3(1.0, 0.0, 0.0));\n vec3 grad101 = rnm(vec2(perm10, pi.z + permTexUnit)).rgb * 4.0 - 1.0;\n float n101 = dot(grad101, pf - vec3(1.0, 0.0, 1.0));\n float perm11 = rnm(pi.xy + vec2(permTexUnit, permTexUnit)).a;\n vec3 grad110 = rnm(vec2(perm11, pi.z)).rgb * 4.0 - 1.0;\n float n110 = dot(grad110, pf - vec3(1.0, 1.0, 0.0));\n vec3 grad111 = rnm(vec2(perm11, pi.z + permTexUnit)).rgb * 4.0 - 1.0;\n float n111 = dot(grad111, pf - vec3(1.0, 1.0, 1.0));\n vec4 n_x = mix(vec4(n000, n001, n010, n011), vec4(n100, n101, n110, n111), fade(pf.x));\n vec2 n_xy = mix(n_x.xy, n_x.zw, fade(pf.y));\n float n_xyz = mix(n_xy.x, n_xy.y, fade(pf.z));\n return n_xyz;\n}\nvec2 coordRot(in vec2 tc, in float angle) {\n float aspect = uResolution.x / uResolution.y;\n float rotX = ((tc.x * 2.0 - 1.0) * aspect * cos(angle)) - ((tc.y * 2.0 - 1.0) * sin(angle));\n float rotY = ((tc.y * 2.0 - 1.0) * cos(angle)) + ((tc.x * 2.0 - 1.0) * aspect * sin(angle));\n rotX = ((rotX / aspect) * 0.5 + 0.5);\n rotY = rotY * 0.5 + 0.5;\n return vec2(rotX, rotY);\n}\nvoid main() {\n vec3 rotOffset = vec3(1.425, 3.892, 5.835);\n vec2 rotCoordsR = coordRot(vUv, uTime + rotOffset.x);\n vec3 noise = vec3(pnoise3D(vec3(rotCoordsR * vec2(uResolution.x / grainsize, uResolution.y / grainsize), 0.0)));\n vec4 tex = texture2D(uTexture, vUv);\n vec3 col = tex.rgb;\n vec3 lumcoeff = vec3(0.299, 0.587, 0.114);\n float luminance = mix(0.0, dot(col, lumcoeff), lumamount);\n float lum = smoothstep(0.2, 0.0, luminance);\n lum += luminance;\n noise = mix(noise, vec3(0.0), pow(lum, 4.0));\n col = col + noise * uAmount;\n gl_FragColor = vec4(col, tex.a);\n}\n",["uTexture","uResolution","uAmount","uTime"])},x=[o(t,a,i),o(t,a,i)];this.resources={gl:t,width:a,height:i,sourceTexture:u,blackPalette:l,quad:{positionBuffer:s,texCoordBuffer:v},programs:m,targets:x},this.imageLoaded=!0,this.render()}disposeResources(){if(!this.resources)return;const{gl:e,sourceTexture:n,blackPalette:t,quad:r,programs:o,targets:a}=this.resources;e.deleteTexture(n),e.deleteTexture(t),e.deleteBuffer(r.positionBuffer),e.deleteBuffer(r.texCoordBuffer),a.forEach(n=>{e.deleteFramebuffer(n.framebuffer),e.deleteTexture(n.texture)}),Object.values(o).forEach(n=>{e.deleteProgram(n.program)}),this.resources=null}drawFrame(e,n){const{gl:t,width:r,height:o,sourceTexture:a,blackPalette:i,quad:u,programs:l,targets:s}=e;t.viewport(0,0,r,o);const v=[1/r,1/o];let m=a,x=0;const f=(e,n,r)=>{t.useProgram(e.program),(e=>{t.bindBuffer(t.ARRAY_BUFFER,u.positionBuffer);const n=e.attribs.aPosition>=0?e.attribs.aPosition:e.attribs.apos;n>=0&&(t.enableVertexAttribArray(n),t.vertexAttribPointer(n,2,t.FLOAT,!1,0,0)),t.bindBuffer(t.ARRAY_BUFFER,u.texCoordBuffer);const r=e.attribs.aTexCoord>=0?e.attribs.aTexCoord:e.attribs.auv;r>=0&&(t.enableVertexAttribArray(r),t.vertexAttribPointer(r,2,t.FLOAT,!1,0,0))})(e),t.activeTexture(t.TEXTURE0),t.bindTexture(t.TEXTURE_2D,m);const o=e.uniforms.uTexture;o&&t.uniform1i(o,0),n(),t.bindFramebuffer(t.FRAMEBUFFER,r?r.framebuffer:null),t.drawArrays(t.TRIANGLE_STRIP,0,4),m=r?r.texture:m},g=()=>{const e=s[x%2];return x+=1,e};Math.abs(n.vibrance)>.5&&f(l.vibrance,()=>{t.uniform1f(l.vibrance.uniforms.uAmount,n.vibrance/100)},g()),Math.abs(n.saturation)>.5&&f(l.saturation,()=>{const e=(e=>{const n=1+Math.max(-100,Math.min(100,e))/100,t=.299,r=.587,o=.114,a=1-n;return new Float32Array([a*t+n,a*r,a*o,0,0,a*t,a*r+n,a*o,0,0,a*t,a*r,a*o+n,0,0,0,0,0,1,0])})(n.saturation);t.uniform1fv(l.saturation.uniforms["uMatrix[0]"],e)},g()),Math.abs(n.temperature)>.5&&f(l.temperature,()=>{t.uniform1f(l.temperature.uniforms.uAmount,n.temperature/500)},g()),Math.abs(n.tint)>.5&&f(l.tint,()=>{t.uniform1f(l.tint.uniforms.uAmount,n.tint/500)},g()),Math.abs(n.hue)>.5&&f(l.hue,()=>{t.uniform1f(l.hue.uniforms.uRotation,n.hue/200)},g()),f(l.brightness,()=>{t.uniform1f(l.brightness.uniforms.uAmount,n.brightness/200)},g()),Math.abs(n.exposure)>.5&&f(l.exposure,()=>{t.uniform1f(l.exposure.uniforms.uAmount,n.exposure/100)},g()),Math.abs(n.contrast)>.5&&f(l.contrast,()=>{const e=(e=>{const n=1+Math.max(-100,Math.min(100,e))/100,t=.5*(1-n);return new Float32Array([n,0,0,0,t,0,n,0,0,t,0,0,n,0,t,0,0,0,1,0])})(n.contrast);t.uniform1fv(l.contrast.uniforms["uMatrix[0]"],e)},g()),Math.abs(n.blacks)>.5&&(((e,n,t)=>{e.bindTexture(e.TEXTURE_2D,n),e.texSubImage2D(e.TEXTURE_2D,0,0,0,256,1,e.RGB,e.UNSIGNED_BYTE,t)})(t,i,c(n.blacks)),f(l.blacks,()=>{t.activeTexture(t.TEXTURE1),t.bindTexture(t.TEXTURE_2D,i),t.uniform1i(l.blacks.uniforms.uPaletteMap,1),t.uniform4f(l.blacks.uniforms.transform,1,1,0,0),t.activeTexture(t.TEXTURE0)},g())),Math.abs(n.whites)>.5&&f(l.whites,()=>{t.uniform1f(l.whites.uniforms.uAmount,n.whites/400)},g()),Math.abs(n.highlights)>.5&&f(l.highlights,()=>{t.uniform1f(l.highlights.uniforms.uAmount,n.highlights/100)},g()),Math.abs(n.shadows)>.5&&f(l.shadows,()=>{t.uniform1f(l.shadows.uniforms.uAmount,n.shadows/100)},g()),Math.abs(n.dehaze)>.5&&f(l.dehaze,()=>{t.uniform1f(l.dehaze.uniforms.uAmount,n.dehaze/100),t.uniform2f(l.dehaze.uniforms.uSize,r,o)},g()),n.bloom>.5&&f(l.bloom,()=>{t.uniform1f(l.bloom.uniforms.uAmount,n.bloom/100),t.uniform2f(l.bloom.uniforms.uTexel,v[0],v[1]),t.uniform1f(l.bloom.uniforms.uThreshold,.5)},g()),n.glamour>.5&&f(l.glamour,()=>{t.uniform1f(l.glamour.uniforms.uAmount,n.glamour/100),t.uniform2f(l.glamour.uniforms.uTexel,v[0],v[1])},g()),Math.abs(n.clarity)>.5&&f(l.clarity,()=>{t.uniform1f(l.clarity.uniforms.uAmount,n.clarity/100),t.uniform2f(l.clarity.uniforms.uTexel,v[0],v[1])},g()),n.sharpen>.5&&f(l.sharpen,()=>{t.uniform2f(l.sharpen.uniforms.uTexel,v[0],v[1]),t.uniform1f(l.sharpen.uniforms.uAmount,n.sharpen/100),t.uniform1fv(l.sharpen.uniforms["uKernel[0]"],new Float32Array([0,-1,0,-1,5,-1,0,-1,0]))},g()),n.smooth>.5&&f(l.smooth,()=>{t.uniform2f(l.smooth.uniforms.uTexel,v[0],v[1]),t.uniform1f(l.smooth.uniforms.uAmount,n.smooth/100),t.uniform1fv(l.smooth.uniforms["uKernel[0]"],new Float32Array([1/9,1/9,1/9,1/9,1/9,1/9,1/9,1/9,1/9]))},g());const p=n.blur;f(l.blur,()=>{t.uniform2f(l.blur.uniforms.uSize,p/r,0)},g()),f(l.blur,()=>{t.uniform2f(l.blur.uniforms.uSize,0,p/o)},g()),f(l.vignette,()=>{t.uniform1f(l.vignette.uniforms.uAmount,n.vignette/100),t.uniform1f(l.vignette.uniforms.uSize,.25)},g()),f(l.grain,()=>{t.uniform2f(l.grain.uniforms.uResolution,r,o),t.uniform1f(l.grain.uniforms.uAmount,n.grain/800),t.uniform1f(l.grain.uniforms.uTime,0)},g()),f(l.pass,()=>{},null)}},exports.analyzeImage=m,exports.analyzeImageLevels=s,exports.analyzeImageVibrance=v,exports.defaultSettings=u,exports.presets=l;
|
|
1
|
+
var e=class{constructor(e,n={}){this.width=0,this.height=0,this.initialized=!1,this.canvas=e,this.options=n}static isSupported(){return!1}getSize(){return{width:this.width,height:this.height}}isInitialized(){return this.initialized}};function n(){return"undefined"!=typeof navigator&&"gpu"in navigator}function t(){if("undefined"==typeof document)return!1;try{const e=document.createElement("canvas");return!(!e.getContext("webgl")&&!e.getContext("experimental-webgl"))}catch{return!1}}function r(e){if("webgpu"===e&&n())return"webgpu";if("webgl"===e&&t())return"webgl";if("auto"===e||void 0===e){if(n())return"webgpu";if(t())return"webgl"}throw new Error("No supported graphics backend available")}var a="\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform vec2 uTexel;\nuniform float uKernel[9];\nuniform float uAmount;\nvoid main(void) {\n vec4 c11 = texture2D(uTexture, vUv - uTexel);\n vec4 c12 = texture2D(uTexture, vec2(vUv.x, vUv.y - uTexel.y));\n vec4 c13 = texture2D(uTexture, vec2(vUv.x + uTexel.x, vUv.y - uTexel.y));\n vec4 c21 = texture2D(uTexture, vec2(vUv.x - uTexel.x, vUv.y));\n vec4 c22 = texture2D(uTexture, vUv);\n vec4 c23 = texture2D(uTexture, vec2(vUv.x + uTexel.x, vUv.y));\n vec4 c31 = texture2D(uTexture, vec2(vUv.x - uTexel.x, vUv.y + uTexel.y));\n vec4 c32 = texture2D(uTexture, vec2(vUv.x, vUv.y + uTexel.y));\n vec4 c33 = texture2D(uTexture, vUv + uTexel);\n vec4 color = c11 * uKernel[0] + c12 * uKernel[1] + c13 * uKernel[2] +\n c21 * uKernel[3] + c22 * uKernel[4] + c23 * uKernel[5] +\n c31 * uKernel[6] + c32 * uKernel[7] + c33 * uKernel[8];\n gl_FragColor = color * uAmount + (c22 * (1.0 - uAmount));\n}\n";function o(e,n,t){const r=e.createShader(n);return r?(e.shaderSource(r,t),e.compileShader(r),e.getShaderParameter(r,e.COMPILE_STATUS)?r:(e.deleteShader(r),null)):null}function i(e,n,t,r){const a=o(e,e.VERTEX_SHADER,n),i=o(e,e.FRAGMENT_SHADER,t);if(!a||!i)throw new Error("Shader compile failed.");const s=function(e,n,t){const r=e.createProgram();return r?(e.attachShader(r,n),e.attachShader(r,t),e.linkProgram(r),e.getProgramParameter(r,e.LINK_STATUS)?r:(e.deleteProgram(r),null)):null}(e,a,i);if(!s)throw new Error("Program link failed.");const l={aPosition:e.getAttribLocation(s,"aPosition"),aTexCoord:e.getAttribLocation(s,"aTexCoord"),apos:e.getAttribLocation(s,"apos"),auv:e.getAttribLocation(s,"auv")},u={};return r.forEach(n=>{u[n]=e.getUniformLocation(s,n)}),{program:s,attribs:l,uniforms:u}}function s(e,n,t){const r=e.createTexture();if(!r)throw new Error("Unable to create texture");e.bindTexture(e.TEXTURE_2D,r),e.texImage2D(e.TEXTURE_2D,0,e.RGBA,n,t,0,e.RGBA,e.UNSIGNED_BYTE,null),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.LINEAR),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_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 a=e.createFramebuffer();if(!a)throw new Error("Unable to create framebuffer");return e.bindFramebuffer(e.FRAMEBUFFER,a),e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,r,0),{framebuffer:a,texture:r}}var l=e=>Math.min(1,Math.max(0,e)),u=(e,n,t,r,a)=>{const o=1-e;return o*o*o*n+3*o*o*e*t+3*o*e*e*r+e*e*e*a},c=e=>{const n=Math.max(-100,Math.min(100,e))/100;return(e=>{const n=new Uint8Array(768);for(let t=0;t<256;t+=1){const r=u(t/255,0,e,.66,1),a=Math.round(255*l(r)),o=3*t;n[o]=a,n[o+1]=a,n[o+2]=a}return n})(l(.33-.35*n))},m=class extends e{constructor(e,n={}){super(e,n),this.gl=null,this.resources=null}getType(){return"webgl"}static isSupported(){if("undefined"==typeof document)return!1;try{const e=document.createElement("canvas");return!(!e.getContext("webgl")&&!e.getContext("experimental-webgl"))}catch{return!1}}init(){if(this.gl=this.canvas.getContext("webgl",{antialias:!0,premultipliedAlpha:!1,preserveDrawingBuffer:!0}),!this.gl)throw new Error("WebGL not supported");this.initialized=!0}loadFromImage(e){this.gl||this.init();const n=this.gl,t=e.naturalWidth||e.width,r=e.naturalHeight||e.height;this.width=t,this.height=r,this.canvas.width=t,this.canvas.height=r,this.disposeResources(),n.disable(n.DEPTH_TEST),n.viewport(0,0,t,r),n.pixelStorei(n.UNPACK_FLIP_Y_WEBGL,1);const a=n.createTexture();if(!a)throw new Error("Failed to create texture");n.bindTexture(n.TEXTURE_2D,a),n.texImage2D(n.TEXTURE_2D,0,n.RGBA,n.RGBA,n.UNSIGNED_BYTE,e),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_MIN_FILTER,n.LINEAR),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_MAG_FILTER,n.LINEAR),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_WRAP_S,n.CLAMP_TO_EDGE),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_WRAP_T,n.CLAMP_TO_EDGE),this.initResources(n,t,r,a)}loadFromImageData(e){this.gl||this.init();const n=this.gl,{width:t,height:r,data:a}=e;this.width=t,this.height=r,this.canvas.width=t,this.canvas.height=r,this.disposeResources(),n.viewport(0,0,t,r),n.pixelStorei(n.UNPACK_FLIP_Y_WEBGL,1);const o=n.createTexture();if(!o)throw new Error("Failed to create texture");n.bindTexture(n.TEXTURE_2D,o),n.texImage2D(n.TEXTURE_2D,0,n.RGBA,t,r,0,n.RGBA,n.UNSIGNED_BYTE,a),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_MIN_FILTER,n.LINEAR),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_MAG_FILTER,n.LINEAR),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_WRAP_S,n.CLAMP_TO_EDGE),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_WRAP_T,n.CLAMP_TO_EDGE),this.initResources(n,t,r,o)}render(e){this.resources&&this.drawFrame(this.resources,e)}getImageData(){const e=this.gl;if(e){const n=new Uint8ClampedArray(this.width*this.height*4);return e.readPixels(0,0,this.width,this.height,e.RGBA,e.UNSIGNED_BYTE,n),new ImageData(n,this.width,this.height)}throw new Error("Cannot get ImageData")}dispose(){this.disposeResources(),this.gl=null,this.initialized=!1}getShaderSource(e){return e}initResources(e,n,t,r){const o=((e,n)=>{const t=e.createTexture();if(!t)throw new Error("Unable to create palette texture");return e.bindTexture(e.TEXTURE_2D,t),e.texImage2D(e.TEXTURE_2D,0,e.RGB,256,1,0,e.RGB,e.UNSIGNED_BYTE,n),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.NEAREST),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.NEAREST),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),t})(e,c(0)),l=e.createBuffer(),u=e.createBuffer();if(!l||!u)throw new Error("Failed to create buffers");e.bindBuffer(e.ARRAY_BUFFER,l),e.bufferData(e.ARRAY_BUFFER,new Float32Array([-1,-1,1,-1,-1,1,1,1]),e.STATIC_DRAW),e.bindBuffer(e.ARRAY_BUFFER,u),e.bufferData(e.ARRAY_BUFFER,new Float32Array([0,0,1,0,0,1,1,1]),e.STATIC_DRAW);const m=this.getShaderSource("\nprecision highp float;\nattribute vec2 aPosition;\nattribute vec2 aTexCoord;\nvarying vec2 vUv;\nvoid main() {\n vUv = aTexCoord;\n gl_Position = vec4(aPosition, 0.0, 1.0);\n}\n"),v=this.getShaderSource("\nprecision highp float;\nattribute vec2 apos;\nattribute vec2 auv;\nvarying vec2 uv;\nuniform vec4 transform;\nvoid main(void) {\n uv = auv;\n gl_Position = vec4(\n apos.x * transform.x + transform.z,\n apos.y * transform.y + transform.w,\n 0.0,\n 1.0\n );\n}\n"),f={pass:i(e,m,this.getShaderSource("\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nvoid main() {\n gl_FragColor = texture2D(uTexture, vUv);\n}\n"),["uTexture"]),vibrance:i(e,m,this.getShaderSource("\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uAmount;\nvoid main() {\n vec4 col = texture2D(uTexture, vUv);\n vec3 color = col.rgb;\n float luminance = color.r * 0.299 + color.g * 0.587 + color.b * 0.114;\n float mn = min(min(color.r, color.g), color.b);\n float mx = max(max(color.r, color.g), color.b);\n float sat = (1.0 - (mx - mn)) * (1.0 - mx) * luminance * 5.0;\n vec3 lightness = vec3((mn + mx) / 2.0);\n color = mix(color, mix(color, lightness, -uAmount), sat);\n gl_FragColor = vec4(\n mix(color, lightness, (1.0 - lightness) * (1.0 - uAmount) / 2.0 * abs(uAmount)),\n col.a\n );\n}\n"),["uTexture","uAmount"]),saturation:i(e,m,this.getShaderSource("\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uMatrix[20];\nvoid main(void) {\n vec4 c = texture2D(uTexture, vUv);\n gl_FragColor.r = uMatrix[0] * c.r + uMatrix[1] * c.g + uMatrix[2] * c.b + uMatrix[3] * c.a + uMatrix[4];\n gl_FragColor.g = uMatrix[5] * c.r + uMatrix[6] * c.g + uMatrix[7] * c.b + uMatrix[8] * c.a + uMatrix[9];\n gl_FragColor.b = uMatrix[10] * c.r + uMatrix[11] * c.g + uMatrix[12] * c.b + uMatrix[13] * c.a + uMatrix[14];\n gl_FragColor.a = uMatrix[15] * c.r + uMatrix[16] * c.g + uMatrix[17] * c.b + uMatrix[18] * c.a + uMatrix[19];\n}\n"),["uTexture","uMatrix[0]"]),temperature:i(e,m,this.getShaderSource("\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uAmount;\nvoid main() {\n vec4 color = texture2D(uTexture, vUv);\n color.r = clamp(color.r + uAmount, 0.0, 1.0);\n color.b = clamp(color.b - uAmount, 0.0, 1.0);\n gl_FragColor = color;\n}\n"),["uTexture","uAmount"]),tint:i(e,m,this.getShaderSource("\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uAmount;\nvoid main() {\n vec4 color = texture2D(uTexture, vUv);\n color.g = clamp(color.g + uAmount, 0.0, 1.0);\n gl_FragColor = color;\n}\n"),["uTexture","uAmount"]),hue:i(e,m,this.getShaderSource("\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uRotation;\nvec3 rgb2hsv(vec3 c) {\n vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\n vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));\n vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));\n float d = q.x - min(q.w, q.y);\n float e = 1.0e-10;\n return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\n}\nvec3 hsv2rgb(vec3 c) {\n vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\n return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);\n}\nvoid main() {\n lowp vec4 base = texture2D(uTexture, vUv);\n vec3 hsv = rgb2hsv(base.rgb);\n hsv.x = fract(hsv.x + uRotation);\n gl_FragColor = vec4(hsv2rgb(hsv), base.a);\n}\n"),["uTexture","uRotation"]),brightness:i(e,m,this.getShaderSource("\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uAmount;\nconst float PI = 3.1415926535897932384626433832795;\nvoid main() {\n vec4 color = texture2D(uTexture, vUv);\n if (uAmount >= 0.0) {\n color.r = color.r + uAmount * sin(color.r * PI);\n color.g = color.g + uAmount * sin(color.g * PI);\n color.b = color.b + uAmount * sin(color.b * PI);\n } else {\n color.r = (1.0 + uAmount) * color.r;\n color.g = (1.0 + uAmount) * color.g;\n color.b = (1.0 + uAmount) * color.b;\n }\n gl_FragColor = color;\n}\n"),["uTexture","uAmount"]),exposure:i(e,m,this.getShaderSource("\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uAmount;\nconst float epsilon = 0.000001;\nconst float mx = 1.0 - epsilon;\nconst mat3 matRGBtoROMM = mat3(\n 0.5293459296226501, 0.3300727903842926, 0.14058130979537964,\n 0.09837432950735092, 0.8734610080718994, 0.028164653107523918,\n 0.01688321679830551, 0.11767247319221497, 0.8654443025588989\n);\nconst mat3 matROMMtoRGB = mat3(\n 2.0340757369995117, -0.727334201335907, -0.3067416846752167,\n -0.22881317138671875, 1.2317301034927368, -0.0029169507324695587,\n -0.008569774217903614, -0.1532866358757019, 1.1618564128875732\n);\nfloat ramp(in float t) {\n t *= 2.0;\n if (t >= 1.0) {\n t -= 1.0;\n t = log(0.5) / log(0.5 * (1.0 - t) + 0.9332 * t);\n }\n return clamp(t, 0.001, 10.0);\n}\nvec3 rgb2hsv(in vec3 c) {\n vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\n vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));\n vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));\n float d = q.x - min(q.w, q.y);\n float e = 1.0e-10;\n return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\n}\nvec3 hsv2rgb(in vec3 c) {\n vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\n return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);\n}\nvec3 setHue(in vec3 res, in vec3 base) {\n vec3 hsv = rgb2hsv(base);\n vec3 res_hsv = rgb2hsv(res);\n return hsv2rgb(vec3(hsv.x, res_hsv.y, res_hsv.z));\n}\nvoid main() {\n lowp vec4 col = texture2D(uTexture, vUv);\n vec3 base = col.rgb * matRGBtoROMM;\n float a = abs(uAmount) * col.a + epsilon;\n float v = pow(2.0, a * 2.0 + 1.0) - 2.0;\n float m = mx - exp(-v);\n vec3 res = (uAmount > 0.0) ? (1.0 - exp(-v * base)) / m : log(1.0 - base * m) / -v;\n res = mix(base, res, min(a * 100.0, 1.0));\n res = setHue(res, base);\n res = pow(res, vec3(ramp(1.0 - (0.0 * col.a + 1.0) / 2.0)));\n res = res * matROMMtoRGB;\n gl_FragColor = vec4(res, col.a);\n}\n"),["uTexture","uAmount"]),contrast:i(e,m,this.getShaderSource("\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uMatrix[20];\nvoid main(void) {\n vec4 c = texture2D(uTexture, vUv);\n gl_FragColor.r = uMatrix[0] * c.r + uMatrix[1] * c.g + uMatrix[2] * c.b + uMatrix[3] * c.a + uMatrix[4];\n gl_FragColor.g = uMatrix[5] * c.r + uMatrix[6] * c.g + uMatrix[7] * c.b + uMatrix[8] * c.a + uMatrix[9];\n gl_FragColor.b = uMatrix[10] * c.r + uMatrix[11] * c.g + uMatrix[12] * c.b + uMatrix[13] * c.a + uMatrix[14];\n gl_FragColor.a = uMatrix[15] * c.r + uMatrix[16] * c.g + uMatrix[17] * c.b + uMatrix[18] * c.a + uMatrix[19];\n}\n"),["uTexture","uMatrix[0]"]),blacks:i(e,v,this.getShaderSource("\nprecision highp float;\nvarying vec2 uv;\nuniform sampler2D uTexture;\nuniform sampler2D uPaletteMap;\nvoid main() {\n lowp vec4 base = texture2D(uTexture, uv.xy);\n float r = texture2D(uPaletteMap, vec2(base.r, 0.0)).r;\n float g = texture2D(uPaletteMap, vec2(base.g, 0.0)).g;\n float b = texture2D(uPaletteMap, vec2(base.b, 0.0)).b;\n gl_FragColor = vec4(r, g, b, base.a);\n}\n"),["uTexture","uPaletteMap","transform"]),whites:i(e,m,this.getShaderSource("\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uAmount;\nconst vec3 RGB2Y = vec3(0.2126, 0.7152, 0.0722);\nvoid main() {\n vec4 base = texture2D(uTexture, vUv.xy);\n vec3 color = base.rgb;\n float lum = dot(color, RGB2Y);\n float whiteMask = smoothstep(0.5, 1.0, lum);\n color += uAmount * whiteMask;\n gl_FragColor = vec4(clamp(color, 0.0, 1.0), base.a);\n}\n"),["uTexture","uAmount"]),highlights:i(e,m,this.getShaderSource("\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uAmount;\nconst float epsilon = 0.000001;\nconst float mx = 1.0 - epsilon;\nconst float PI = 3.1415926535897932384626433832795;\nconst mat3 matRGBtoROMM = mat3(\n 0.5293459296226501, 0.3300727903842926, 0.14058130979537964,\n 0.09837432950735092, 0.8734610080718994, 0.028164653107523918,\n 0.01688321679830551, 0.11767247319221497, 0.8654443025588989\n);\nconst mat3 matROMMtoRGB = mat3(\n 2.0340757369995117, -0.727334201335907, -0.3067416846752167,\n -0.22881317138671875, 1.2317301034927368, -0.0029169507324695587,\n -0.008569774217903614, -0.1532866358757019, 1.1618564128875732\n);\nfloat luma_romm(in vec3 color) {\n return dot(color, vec3(0.242655, 0.755158, 0.002187));\n}\nfloat luma(in vec3 color) {\n return dot(color, vec3(0.298839, 0.586811, 0.11435));\n}\nvec3 rgb2hsv(in vec3 c) {\n vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\n vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));\n vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));\n float d = q.x - min(q.w, q.y);\n float e = 1.0e-10;\n return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\n}\nvec3 hsv2rgb(in vec3 c) {\n vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\n return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);\n}\nvec3 setHue(in vec3 res, in vec3 base) {\n vec3 hsv = rgb2hsv(base);\n vec3 res_hsv = rgb2hsv(res);\n return hsv2rgb(vec3(hsv.x, res_hsv.y, res_hsv.z));\n}\nfloat gaussian(in float x) {\n return 1.0 - exp(-PI * 2.0 * x * x);\n}\nvoid main() {\n lowp vec4 col = texture2D(uTexture, vUv);\n lowp vec3 map = col.rgb;\n vec3 base = col.rgb * matRGBtoROMM;\n float base_lum = luma(col.rgb);\n float map_lum = luma_romm(map * matRGBtoROMM);\n float exposure = mix(uAmount, 0.0, 1.0 - map_lum) * col.a;\n float a = abs(exposure) * col.a + epsilon;\n float v = pow(2.0, a + 1.0) - 2.0;\n float m = mx - exp(-v);\n vec3 res = (exposure > 0.0) ? (1.0 - exp(-v * base)) / m : log(1.0 - base * m) / -v;\n res = mix(base, res, min(a * 100.0, 1.0));\n res = setHue(res, base);\n res = res * matROMMtoRGB;\n gl_FragColor = vec4(res, col.a);\n}\n"),["uTexture","uAmount"]),shadows:i(e,m,this.getShaderSource("\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uAmount;\nconst float epsilon = 0.000001;\nconst float mx = 1.0 - epsilon;\nconst float PI = 3.1415926535897932384626433832795;\nconst mat3 matRGBtoROMM = mat3(\n 0.5293459296226501, 0.3300727903842926, 0.14058130979537964,\n 0.09837432950735092, 0.8734610080718994, 0.028164653107523918,\n 0.01688321679830551, 0.11767247319221497, 0.8654443025588989\n);\nconst mat3 matROMMtoRGB = mat3(\n 2.0340757369995117, -0.727334201335907, -0.3067416846752167,\n -0.22881317138671875, 1.2317301034927368, -0.0029169507324695587,\n -0.008569774217903614, -0.1532866358757019, 1.1618564128875732\n);\nfloat luma_romm(in vec3 color) {\n return dot(color, vec3(0.242655, 0.755158, 0.002187));\n}\nfloat luma(in vec3 color) {\n return dot(color, vec3(0.298839, 0.586811, 0.11435));\n}\nvec3 rgb2hsv(in vec3 c) {\n vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\n vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));\n vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));\n float d = q.x - min(q.w, q.y);\n float e = 1.0e-10;\n return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\n}\nvec3 hsv2rgb(in vec3 c) {\n vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\n return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);\n}\nvec3 setHue(in vec3 res, in vec3 base) {\n vec3 hsv = rgb2hsv(base);\n vec3 res_hsv = rgb2hsv(res);\n return hsv2rgb(vec3(hsv.x, res_hsv.y, res_hsv.z));\n}\nfloat gaussian(in float x) {\n return 1.0 - exp(-PI * 2.0 * x * x);\n}\nvoid main() {\n lowp vec4 col = texture2D(uTexture, vUv);\n lowp vec3 map = col.rgb;\n vec3 base = col.rgb * matRGBtoROMM;\n float base_lum = luma(col.rgb);\n float map_lum = luma_romm(map * matRGBtoROMM);\n float exposure = mix(0.0, uAmount, 1.0 - map_lum) * col.a;\n float a = abs(exposure) * col.a + epsilon;\n float v = pow(2.0, a + 1.0) - 2.0;\n float m = mx - exp(-v);\n vec3 res = (exposure > 0.0) ? (1.0 - exp(-v * base)) / m : log(1.0 - base * m) / -v;\n res = mix(base, res, min(a * 100.0, 1.0));\n res = setHue(res, base);\n res = res * matROMMtoRGB;\n gl_FragColor = vec4(res, col.a);\n}\n"),["uTexture","uAmount"]),dehaze:i(e,m,this.getShaderSource("\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uAmount;\nuniform vec2 uSize;\n\nfloat hazeMap(vec2 coord) {\n vec3 color = vec3(1.0);\n vec2 stepSize = vec2(1.0 / uSize.x, 1.0 / uSize.y);\n for (int i = -1; i <= 1; ++i) {\n for (int j = -1; j <= 1; ++j) {\n vec2 offset = vec2(float(i), float(j)) * stepSize;\n vec2 uv = clamp(coord + offset, 0.0, 1.0);\n vec3 sample = texture2D(uTexture, uv).rgb;\n color = min(color, sample);\n }\n }\n return min(color.r, min(color.g, color.b));\n}\n\nvoid main() {\n vec4 base = texture2D(uTexture, vUv);\n float haze = hazeMap(vUv);\n float transmission = 1.0 - 0.95 * haze;\n const float A = 0.95;\n const float t0 = 0.1;\n float t = mix(1.0, max(t0, transmission), uAmount);\n vec3 J = (base.rgb - A) / t + A;\n gl_FragColor = vec4(J, base.a);\n}\n"),["uTexture","uAmount","uSize"]),bloom:i(e,m,this.getShaderSource("\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uAmount;\nuniform vec2 uTexel;\nuniform float uThreshold;\n\nvoid main() {\n vec4 sum = vec4(0.0);\n int j = -2;\n for (int i = -2; i <= 2; i++) sum += texture2D(uTexture, vUv + vec2(float(i), float(j)) * uTexel);\n j = -1;\n for (int i = -2; i <= 2; i++) sum += texture2D(uTexture, vUv + vec2(float(i), float(j)) * uTexel);\n j = 0;\n for (int i = -2; i <= 2; i++) sum += texture2D(uTexture, vUv + vec2(float(i), float(j)) * uTexel);\n j = 1;\n for (int i = -2; i <= 2; i++) sum += texture2D(uTexture, vUv + vec2(float(i), float(j)) * uTexel);\n j = 2;\n for (int i = -2; i <= 2; i++) sum += texture2D(uTexture, vUv + vec2(float(i), float(j)) * uTexel);\n sum /= 25.0;\n vec4 base = texture2D(uTexture, vUv);\n if (length(sum.rgb) > uThreshold) {\n base += sum * uAmount;\n }\n gl_FragColor = base;\n}\n"),["uTexture","uAmount","uTexel","uThreshold"]),glamour:i(e,m,this.getShaderSource("\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uAmount;\nuniform vec2 uTexel;\n\nfloat normpdf(in float x, in float sigma) {\n return 0.39894 * exp(-0.5 * x * x / (sigma * sigma)) / sigma;\n}\n\nvec3 blurMap() {\n const int mSize = 11;\n const int kSize = (mSize - 1) / 2;\n float kernel[mSize];\n vec3 final_colour = vec3(0.0);\n float sigma = 7.0;\n float Z = 0.0;\n for (int j = 0; j <= kSize; ++j) {\n kernel[kSize + j] = kernel[kSize - j] = normpdf(float(j), sigma);\n }\n for (int j = 0; j < mSize; ++j) {\n Z += kernel[j];\n }\n for (int i = -kSize; i <= kSize; ++i) {\n for (int j = -kSize; j <= kSize; ++j) {\n final_colour += kernel[kSize + j] * kernel[kSize + i] *\n texture2D(uTexture, vUv + vec2(float(i), float(j)) * uTexel).rgb;\n }\n }\n return vec3(final_colour / (Z * Z));\n}\n\nfloat luma(vec3 color) {\n return dot(color, vec3(0.299, 0.587, 0.114));\n}\n\nvoid main() {\n vec4 base = texture2D(uTexture, vUv);\n vec3 color = blurMap();\n color = vec3(luma(color));\n color = vec3(\n (base.r <= 0.5) ? (2.0 * base.r * color.r) : (1.0 - 2.0 * (1.0 - base.r) * (1.0 - color.r)),\n (base.g <= 0.5) ? (2.0 * base.g * color.g) : (1.0 - 2.0 * (1.0 - base.g) * (1.0 - color.g)),\n (base.b <= 0.5) ? (2.0 * base.b * color.b) : (1.0 - 2.0 * (1.0 - base.b) * (1.0 - color.b))\n );\n gl_FragColor = mix(base, vec4(color, base.a), uAmount);\n}\n"),["uTexture","uAmount","uTexel"]),clarity:i(e,m,this.getShaderSource("\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uAmount;\nuniform vec2 uTexel;\n\nfloat Lum(vec3 c) {\n return 0.299 * c.r + 0.587 * c.g + 0.114 * c.b;\n}\nfloat BlendOverlayf(float base, float blend) {\n return (base < 0.5 ? (2.0 * base * blend) : (1.0 - 2.0 * (1.0 - base) * (1.0 - blend)));\n}\nvec3 BlendOverlay(vec3 base, vec3 blend) {\n return vec3(BlendOverlayf(base.r, blend.r), BlendOverlayf(base.g, blend.g), BlendOverlayf(base.b, blend.b));\n}\nfloat BlendVividLightf(float base, float blend) {\n float BlendColorBurnf = (((2.0 * blend) == 0.0) ? (2.0 * blend) : max((1.0 - ((1.0 - base) / (2.0 * blend))), 0.0));\n float BlendColorDodgef = (((2.0 * (blend - 0.5)) == 1.0) ? (2.0 * (blend - 0.5)) : min(base / (1.0 - (2.0 * (blend - 0.5))), 1.0));\n return ((blend < 0.5) ? BlendColorBurnf : BlendColorDodgef);\n}\nvec3 BlendVividLight(vec3 base, vec3 blend) {\n return vec3(BlendVividLightf(base.r, blend.r), BlendVividLightf(base.g, blend.g), BlendVividLightf(base.b, blend.b));\n}\nfloat normpdf(in float x, in float sigma) {\n return 0.39894 * exp(-0.5 * x * x / (sigma * sigma)) / sigma;\n}\nvec3 blurMap() {\n const int mSize = 11;\n const int kSize = (mSize - 1) / 2;\n float kernel[mSize];\n vec3 final_colour = vec3(0.0);\n float sigma = 7.0;\n float Z = 0.0;\n for (int j = 0; j <= kSize; ++j) {\n kernel[kSize + j] = kernel[kSize - j] = normpdf(float(j), sigma);\n }\n for (int j = 0; j < mSize; ++j) {\n Z += kernel[j];\n }\n for (int i = -kSize; i <= kSize; ++i) {\n for (int j = -kSize; j <= kSize; ++j) {\n final_colour += kernel[kSize + j] * kernel[kSize + i] *\n texture2D(uTexture, vUv + vec2(float(i), float(j)) * uTexel).rgb;\n }\n }\n return vec3(final_colour / (Z * Z));\n}\nvoid main() {\n vec4 base4 = texture2D(uTexture, vUv);\n vec3 blur = blurMap();\n vec3 base = base4.rgb;\n float intensity = (uAmount < 0.0) ? (uAmount / 2.0) : uAmount;\n float lum = Lum(base);\n vec3 col = vec3(lum);\n vec3 mask = vec3(1.0 - pow(lum, 1.8));\n vec3 layer = vec3(1.0 - Lum(blur));\n vec3 detail = clamp(BlendVividLight(col, layer), 0.0, 1.0);\n vec3 inverse = mix(1.0 - detail, detail, (intensity + 1.0) / 2.0);\n gl_FragColor = vec4(BlendOverlay(base, mix(vec3(0.5), inverse, mask)), base4.a);\n}\n"),["uTexture","uAmount","uTexel"]),sharpen:i(e,m,this.getShaderSource(a),["uTexture","uTexel","uKernel[0]","uAmount"]),smooth:i(e,m,this.getShaderSource(a),["uTexture","uTexel","uKernel[0]","uAmount"]),blur:i(e,m,this.getShaderSource("\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform vec2 uSize;\nfloat random(vec3 scale, float seed) {\n return fract(sin(dot(gl_FragCoord.xyz + seed, scale)) * 43758.5453 + seed);\n}\nvoid main() {\n vec4 color = vec4(0.0);\n float total = 0.0;\n float offset = random(vec3(12.9898, 78.233, 151.7182), 0.0);\n for (int t = -30; t <= 30; t++) {\n float percent = (float(t) + offset - 0.5) / 30.0;\n float weight = 1.0 - abs(percent);\n vec4 sample = texture2D(uTexture, vUv + uSize * percent);\n sample.rgb *= sample.a;\n color += sample * weight;\n total += weight;\n }\n gl_FragColor = color / total;\n gl_FragColor.rgb /= gl_FragColor.a + 0.00001;\n}\n"),["uTexture","uSize"]),vignette:i(e,m,this.getShaderSource("\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uAmount;\nuniform float uSize;\nvoid main() {\n vec4 color = texture2D(uTexture, vUv);\n float dist = distance(vUv, vec2(0.5, 0.5));\n float amt = clamp(uAmount, -1.0, 1.0);\n float edge = dist * (abs(amt) * 0.75 + uSize * 2.0);\n float vignette = smoothstep(0.8, uSize * 0.799, edge);\n if (amt < 0.0) {\n vignette = 1.0 + (1.0 - vignette) * (-amt);\n } else {\n vignette = mix(1.0, vignette, amt);\n }\n color.rgb *= vignette;\n gl_FragColor = color;\n}\n"),["uTexture","uAmount","uSize"]),grain:i(e,m,this.getShaderSource("\nprecision highp float;\nuniform sampler2D uTexture;\nvarying vec2 vUv;\nuniform vec2 uResolution;\nuniform float uAmount;\nuniform float uTime;\nconst float permTexUnit = 1.0 / 256.0;\nconst float permTexUnitHalf = 0.5 / 256.0;\nfloat grainsize = 1.8;\nfloat lumamount = 1.0;\n\nvec4 rnm(in vec2 tc) {\n float noise = sin(dot(tc + vec2(uTime, uTime), vec2(12.9898, 78.233))) * 43758.5453;\n float noiseR = fract(noise) * 2.0 - 1.0;\n float noiseG = fract(noise * 1.2154) * 2.0 - 1.0;\n float noiseB = fract(noise * 1.3453) * 2.0 - 1.0;\n float noiseA = fract(noise * 1.3647) * 2.0 - 1.0;\n return vec4(noiseR, noiseG, noiseB, noiseA);\n}\nfloat fade(in float t) {\n return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);\n}\nfloat pnoise3D(in vec3 p) {\n vec3 pi = permTexUnit * floor(p) + permTexUnitHalf;\n vec3 pf = fract(p);\n float perm00 = rnm(pi.xy).a;\n vec3 grad000 = rnm(vec2(perm00, pi.z)).rgb * 4.0 - 1.0;\n float n000 = dot(grad000, pf);\n vec3 grad001 = rnm(vec2(perm00, pi.z + permTexUnit)).rgb * 4.0 - 1.0;\n float n001 = dot(grad001, pf - vec3(0.0, 0.0, 1.0));\n float perm01 = rnm(pi.xy + vec2(0.0, permTexUnit)).a;\n vec3 grad010 = rnm(vec2(perm01, pi.z)).rgb * 4.0 - 1.0;\n float n010 = dot(grad010, pf - vec3(0.0, 1.0, 0.0));\n vec3 grad011 = rnm(vec2(perm01, pi.z + permTexUnit)).rgb * 4.0 - 1.0;\n float n011 = dot(grad011, pf - vec3(0.0, 1.0, 1.0));\n float perm10 = rnm(pi.xy + vec2(permTexUnit, 0.0)).a;\n vec3 grad100 = rnm(vec2(perm10, pi.z)).rgb * 4.0 - 1.0;\n float n100 = dot(grad100, pf - vec3(1.0, 0.0, 0.0));\n vec3 grad101 = rnm(vec2(perm10, pi.z + permTexUnit)).rgb * 4.0 - 1.0;\n float n101 = dot(grad101, pf - vec3(1.0, 0.0, 1.0));\n float perm11 = rnm(pi.xy + vec2(permTexUnit, permTexUnit)).a;\n vec3 grad110 = rnm(vec2(perm11, pi.z)).rgb * 4.0 - 1.0;\n float n110 = dot(grad110, pf - vec3(1.0, 1.0, 0.0));\n vec3 grad111 = rnm(vec2(perm11, pi.z + permTexUnit)).rgb * 4.0 - 1.0;\n float n111 = dot(grad111, pf - vec3(1.0, 1.0, 1.0));\n vec4 n_x = mix(vec4(n000, n001, n010, n011), vec4(n100, n101, n110, n111), fade(pf.x));\n vec2 n_xy = mix(n_x.xy, n_x.zw, fade(pf.y));\n float n_xyz = mix(n_xy.x, n_xy.y, fade(pf.z));\n return n_xyz;\n}\nvec2 coordRot(in vec2 tc, in float angle) {\n float aspect = uResolution.x / uResolution.y;\n float rotX = ((tc.x * 2.0 - 1.0) * aspect * cos(angle)) - ((tc.y * 2.0 - 1.0) * sin(angle));\n float rotY = ((tc.y * 2.0 - 1.0) * cos(angle)) + ((tc.x * 2.0 - 1.0) * aspect * sin(angle));\n rotX = ((rotX / aspect) * 0.5 + 0.5);\n rotY = rotY * 0.5 + 0.5;\n return vec2(rotX, rotY);\n}\nvoid main() {\n vec3 rotOffset = vec3(1.425, 3.892, 5.835);\n vec2 rotCoordsR = coordRot(vUv, uTime + rotOffset.x);\n vec3 noise = vec3(pnoise3D(vec3(rotCoordsR * vec2(uResolution.x / grainsize, uResolution.y / grainsize), 0.0)));\n vec4 tex = texture2D(uTexture, vUv);\n vec3 col = tex.rgb;\n vec3 lumcoeff = vec3(0.299, 0.587, 0.114);\n float luminance = mix(0.0, dot(col, lumcoeff), lumamount);\n float lum = smoothstep(0.2, 0.0, luminance);\n lum += luminance;\n noise = mix(noise, vec3(0.0), pow(lum, 4.0));\n col = col + noise * uAmount;\n gl_FragColor = vec4(col, tex.a);\n}\n"),["uTexture","uResolution","uAmount","uTime"])},x=[s(e,n,t),s(e,n,t)];this.resources={gl:e,width:n,height:t,sourceTexture:r,blackPalette:o,quad:{positionBuffer:l,texCoordBuffer:u},programs:f,targets:x}}disposeResources(){if(!this.resources)return;const{gl:e,sourceTexture:n,blackPalette:t,quad:r,programs:a,targets:o}=this.resources;e.deleteTexture(n),e.deleteTexture(t),e.deleteBuffer(r.positionBuffer),e.deleteBuffer(r.texCoordBuffer),o.forEach(n=>{e.deleteFramebuffer(n.framebuffer),e.deleteTexture(n.texture)}),Object.values(a).forEach(n=>{e.deleteProgram(n.program)}),this.resources=null}drawFrame(e,n){const{gl:t,width:r,height:a,sourceTexture:o,blackPalette:i,quad:s,programs:l,targets:u}=e;t.viewport(0,0,r,a);const m=[1/r,1/a];let v=o,f=0;const x=(e,n,r)=>{t.useProgram(e.program),(e=>{t.bindBuffer(t.ARRAY_BUFFER,s.positionBuffer);const n=e.attribs.aPosition>=0?e.attribs.aPosition:e.attribs.apos;n>=0&&(t.enableVertexAttribArray(n),t.vertexAttribPointer(n,2,t.FLOAT,!1,0,0)),t.bindBuffer(t.ARRAY_BUFFER,s.texCoordBuffer);const r=e.attribs.aTexCoord>=0?e.attribs.aTexCoord:e.attribs.auv;r>=0&&(t.enableVertexAttribArray(r),t.vertexAttribPointer(r,2,t.FLOAT,!1,0,0))})(e),t.activeTexture(t.TEXTURE0),t.bindTexture(t.TEXTURE_2D,v);const a=e.uniforms.uTexture;a&&t.uniform1i(a,0),n(),t.bindFramebuffer(t.FRAMEBUFFER,r?r.framebuffer:null),t.drawArrays(t.TRIANGLE_STRIP,0,4),v=r?r.texture:v},p=()=>{const e=u[f%2];return f+=1,e};Math.abs(n.vibrance)>.5&&x(l.vibrance,()=>{t.uniform1f(l.vibrance.uniforms.uAmount,n.vibrance/100)},p()),Math.abs(n.saturation)>.5&&x(l.saturation,()=>{const e=(e=>{const n=1+Math.max(-100,Math.min(100,e))/100,t=.299,r=.587,a=.114,o=1-n;return new Float32Array([o*t+n,o*r,o*a,0,0,o*t,o*r+n,o*a,0,0,o*t,o*r,o*a+n,0,0,0,0,0,1,0])})(n.saturation);t.uniform1fv(l.saturation.uniforms["uMatrix[0]"],e)},p()),Math.abs(n.temperature)>.5&&x(l.temperature,()=>{t.uniform1f(l.temperature.uniforms.uAmount,n.temperature/500)},p()),Math.abs(n.tint)>.5&&x(l.tint,()=>{t.uniform1f(l.tint.uniforms.uAmount,n.tint/500)},p()),Math.abs(n.hue)>.5&&x(l.hue,()=>{t.uniform1f(l.hue.uniforms.uRotation,n.hue/200)},p()),x(l.brightness,()=>{t.uniform1f(l.brightness.uniforms.uAmount,n.brightness/200)},p()),Math.abs(n.exposure)>.5&&x(l.exposure,()=>{t.uniform1f(l.exposure.uniforms.uAmount,n.exposure/100)},p()),Math.abs(n.contrast)>.5&&x(l.contrast,()=>{const e=(e=>{const n=1+Math.max(-100,Math.min(100,e))/100,t=.5*(1-n);return new Float32Array([n,0,0,0,t,0,n,0,0,t,0,0,n,0,t,0,0,0,1,0])})(n.contrast);t.uniform1fv(l.contrast.uniforms["uMatrix[0]"],e)},p()),Math.abs(n.blacks)>.5&&(((e,n,t)=>{e.bindTexture(e.TEXTURE_2D,n),e.texSubImage2D(e.TEXTURE_2D,0,0,0,256,1,e.RGB,e.UNSIGNED_BYTE,t)})(t,i,c(n.blacks)),x(l.blacks,()=>{t.activeTexture(t.TEXTURE1),t.bindTexture(t.TEXTURE_2D,i),t.uniform1i(l.blacks.uniforms.uPaletteMap,1),t.uniform4f(l.blacks.uniforms.transform,1,1,0,0),t.activeTexture(t.TEXTURE0)},p())),Math.abs(n.whites)>.5&&x(l.whites,()=>{t.uniform1f(l.whites.uniforms.uAmount,n.whites/400)},p()),Math.abs(n.highlights)>.5&&x(l.highlights,()=>{t.uniform1f(l.highlights.uniforms.uAmount,n.highlights/100)},p()),Math.abs(n.shadows)>.5&&x(l.shadows,()=>{t.uniform1f(l.shadows.uniforms.uAmount,n.shadows/100)},p()),Math.abs(n.dehaze)>.5&&x(l.dehaze,()=>{t.uniform1f(l.dehaze.uniforms.uAmount,n.dehaze/100),t.uniform2f(l.dehaze.uniforms.uSize,r,a)},p()),n.bloom>.5&&x(l.bloom,()=>{t.uniform1f(l.bloom.uniforms.uAmount,n.bloom/100),t.uniform2f(l.bloom.uniforms.uTexel,m[0],m[1]),t.uniform1f(l.bloom.uniforms.uThreshold,.5)},p()),n.glamour>.5&&x(l.glamour,()=>{t.uniform1f(l.glamour.uniforms.uAmount,n.glamour/100),t.uniform2f(l.glamour.uniforms.uTexel,m[0],m[1])},p()),Math.abs(n.clarity)>.5&&x(l.clarity,()=>{t.uniform1f(l.clarity.uniforms.uAmount,n.clarity/100),t.uniform2f(l.clarity.uniforms.uTexel,m[0],m[1])},p()),n.sharpen>.5&&x(l.sharpen,()=>{t.uniform2f(l.sharpen.uniforms.uTexel,m[0],m[1]),t.uniform1f(l.sharpen.uniforms.uAmount,n.sharpen/100),t.uniform1fv(l.sharpen.uniforms["uKernel[0]"],new Float32Array([0,-1,0,-1,5,-1,0,-1,0]))},p()),n.smooth>.5&&x(l.smooth,()=>{t.uniform2f(l.smooth.uniforms.uTexel,m[0],m[1]),t.uniform1f(l.smooth.uniforms.uAmount,n.smooth/100),t.uniform1fv(l.smooth.uniforms["uKernel[0]"],new Float32Array([1/9,1/9,1/9,1/9,1/9,1/9,1/9,1/9,1/9]))},p());const g=n.blur;x(l.blur,()=>{t.uniform2f(l.blur.uniforms.uSize,g/r,0)},p()),x(l.blur,()=>{t.uniform2f(l.blur.uniforms.uSize,0,g/a)},p()),x(l.vignette,()=>{t.uniform1f(l.vignette.uniforms.uAmount,n.vignette/100),t.uniform1f(l.vignette.uniforms.uSize,.25)},p()),x(l.grain,()=>{t.uniform2f(l.grain.uniforms.uResolution,r,a),t.uniform1f(l.grain.uniforms.uAmount,n.grain/800),t.uniform1f(l.grain.uniforms.uTime,0)},p()),x(l.pass,()=>{},null)}},v="\nstruct Params {\n matrix: array<vec4<f32>, 5>,\n}\n\n@group(0) @binding(0) var uTexture: texture_2d<f32>;\n@group(0) @binding(1) var uSampler: sampler;\n@group(0) @binding(2) var<uniform> params: Params;\n\n@fragment\nfn main(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {\n let c = textureSample(uTexture, uSampler, uv);\n var result: vec4<f32>;\n result.r = params.matrix[0].x * c.r + params.matrix[0].y * c.g + params.matrix[0].z * c.b + params.matrix[0].w * c.a + params.matrix[1].x;\n result.g = params.matrix[1].y * c.r + params.matrix[1].z * c.g + params.matrix[1].w * c.b + params.matrix[2].x * c.a + params.matrix[2].y;\n result.b = params.matrix[2].z * c.r + params.matrix[2].w * c.g + params.matrix[3].x * c.b + params.matrix[3].y * c.a + params.matrix[3].z;\n result.a = params.matrix[3].w * c.r + params.matrix[4].x * c.g + params.matrix[4].y * c.b + params.matrix[4].z * c.a + params.matrix[4].w;\n return result;\n}\n",f=v,x=e=>Math.min(1,Math.max(0,e)),p=(e,n,t,r,a)=>{const o=1-e;return o*o*o*n+3*o*o*e*t+3*o*e*e*r+e*e*e*a},g=class extends e{constructor(e,n={}){super(e,n),this.device=null,this.resources=null}getType(){return"webgpu"}static isSupported(){return"undefined"!=typeof navigator&&"gpu"in navigator}async init(){if(!navigator.gpu)throw new Error("WebGPU not supported");const e=await navigator.gpu.requestAdapter();if(!e)throw new Error("No WebGPU adapter found");this.device=await e.requestDevice(),this.initialized=!0}loadFromImage(e){if(!this.device)throw new Error("WebGPU not initialized. Call init() first.");const n=e.naturalWidth||e.width,t=e.naturalHeight||e.height;this.width=n,this.height=t,this.canvas.width=n,this.canvas.height=t,this.disposeResources(),this.initResources(this.device,n,t,e)}loadFromImageData(e){if(!this.device)throw new Error("WebGPU not initialized. Call init() first.");const{width:n,height:t}=e;this.width=n,this.height=t,this.canvas.width=n,this.canvas.height=t,this.disposeResources(),this.initResourcesFromImageData(this.device,n,t,e)}render(e){this.resources&&this.drawFrame(this.resources,e)}getImageData(){if(!this.resources)throw new Error("No image loaded");const e=document.createElement("canvas").getContext("2d");if(!e)throw new Error("Cannot create 2D context");const{width:n,height:t}=this.resources;return e.canvas.width=n,e.canvas.height=t,e.drawImage(this.canvas,0,0),e.getImageData(0,0,n,t)}async getImageDataAsync(){if(!this.resources)throw new Error("No image loaded");const{device:e,width:n,height:t,targets:r}=this.resources,a=256*Math.ceil(4*n/256),o=a*t,i=e.createBuffer({size:o,usage:GPUBufferUsage.COPY_DST|GPUBufferUsage.MAP_READ}),s=e.createCommandEncoder();s.copyTextureToBuffer({texture:r[0].texture},{buffer:i,bytesPerRow:a},{width:n,height:t}),e.queue.submit([s.finish()]),await i.mapAsync(GPUMapMode.READ);const l=new Uint8Array(i.getMappedRange()),u=new Uint8ClampedArray(n*t*4);for(let e=0;e<t;e++){const t=e*a,r=e*n*4;u.set(l.subarray(t,t+4*n),r)}return i.unmap(),i.destroy(),new ImageData(u,n,t)}dispose(){this.disposeResources(),this.device=null,this.initialized=!1}getShaderSource(e){return e}createPipeline(e,n,t,r=!0,a=!1){const o=[{binding:0,visibility:GPUShaderStage.FRAGMENT,texture:{sampleType:"float"}},{binding:1,visibility:GPUShaderStage.FRAGMENT,sampler:{type:"filtering"}}];r&&o.push({binding:2,visibility:GPUShaderStage.FRAGMENT,buffer:{type:"uniform"}}),a&&o.push({binding:2,visibility:GPUShaderStage.FRAGMENT,texture:{sampleType:"float"}},{binding:3,visibility:GPUShaderStage.FRAGMENT,sampler:{type:"filtering"}});const i=e.createBindGroupLayout({entries:o}),s=e.createPipelineLayout({bindGroupLayouts:[i]}),l=e.createShaderModule({code:this.getShaderSource("\nstruct VertexOutput {\n @builtin(position) position: vec4<f32>,\n @location(0) uv: vec2<f32>,\n}\n\n@vertex\nfn main(@location(0) position: vec2<f32>, @location(1) uv: vec2<f32>) -> VertexOutput {\n var output: VertexOutput;\n output.position = vec4<f32>(position, 0.0, 1.0);\n output.uv = uv;\n return output;\n}\n")}),u=e.createShaderModule({code:this.getShaderSource(t)});return{pipeline:e.createRenderPipeline({layout:s,vertex:{module:l,entryPoint:"main",buffers:[{arrayStride:16,attributes:[{shaderLocation:0,offset:0,format:"float32x2"},{shaderLocation:1,offset:8,format:"float32x2"}]}]},fragment:{module:u,entryPoint:"main",targets:[{format:n}]},primitive:{topology:"triangle-strip"}}),bindGroupLayout:i}}createRenderTarget(e,n,t,r){const a=e.createTexture({size:{width:n,height:t},format:r,usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.RENDER_ATTACHMENT|GPUTextureUsage.COPY_SRC});return{texture:a,view:a.createView()}}initResources(e,n,t,r){const a=this.canvas.getContext("webgpu");if(!a)throw new Error("Failed to get WebGPU context");const o=navigator.gpu.getPreferredCanvasFormat();a.configure({device:e,format:o,alphaMode:"opaque"});const i=e.createTexture({size:{width:n,height:t},format:"rgba8unorm",usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.COPY_DST|GPUTextureUsage.RENDER_ATTACHMENT}),s=document.createElement("canvas");s.width=n,s.height=t;const l=s.getContext("2d");l.drawImage(r,0,0);const u=l.getImageData(0,0,n,t);e.queue.writeTexture({texture:i},u.data,{bytesPerRow:4*n},{width:n,height:t}),this.setupResources(e,a,o,n,t,i)}initResourcesFromImageData(e,n,t,r){const a=this.canvas.getContext("webgpu");if(!a)throw new Error("Failed to get WebGPU context");const o=navigator.gpu.getPreferredCanvasFormat();a.configure({device:e,format:o,alphaMode:"opaque"});const i=e.createTexture({size:{width:n,height:t},format:"rgba8unorm",usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.COPY_DST|GPUTextureUsage.RENDER_ATTACHMENT});e.queue.writeTexture({texture:i},r.data,{bytesPerRow:4*n},{width:n,height:t}),this.setupResources(e,a,o,n,t,i)}setupResources(e,n,t,r,a,o){const i=e.createSampler({magFilter:"linear",minFilter:"linear",addressModeU:"clamp-to-edge",addressModeV:"clamp-to-edge"}),s=new Float32Array([-1,-1,0,1,1,-1,1,1,-1,1,0,0,1,1,1,0]),l=e.createBuffer({size:s.byteLength,usage:GPUBufferUsage.VERTEX|GPUBufferUsage.COPY_DST});e.queue.writeBuffer(l,0,s);const u="rgba8unorm",c={pass:this.createPipeline(e,t,"\n@group(0) @binding(0) var uTexture: texture_2d<f32>;\n@group(0) @binding(1) var uSampler: sampler;\n\n@fragment\nfn main(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {\n return textureSample(uTexture, uSampler, uv);\n}\n",!1),vibrance:this.createPipeline(e,u,"\nstruct Params {\n amount: f32,\n}\n\n@group(0) @binding(0) var uTexture: texture_2d<f32>;\n@group(0) @binding(1) var uSampler: sampler;\n@group(0) @binding(2) var<uniform> params: Params;\n\n@fragment\nfn main(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {\n let col = textureSample(uTexture, uSampler, uv);\n var color = col.rgb;\n let luminance = color.r * 0.299 + color.g * 0.587 + color.b * 0.114;\n let mn = min(min(color.r, color.g), color.b);\n let mx = max(max(color.r, color.g), color.b);\n let sat = (1.0 - (mx - mn)) * (1.0 - mx) * luminance * 5.0;\n let lightness = vec3<f32>((mn + mx) / 2.0);\n color = mix(color, mix(color, lightness, -params.amount), sat);\n return vec4<f32>(\n mix(color, lightness, (1.0 - lightness) * (1.0 - params.amount) / 2.0 * abs(params.amount)),\n col.a\n );\n}\n"),saturation:this.createPipeline(e,u,v),temperature:this.createPipeline(e,u,"\nstruct Params {\n amount: f32,\n}\n\n@group(0) @binding(0) var uTexture: texture_2d<f32>;\n@group(0) @binding(1) var uSampler: sampler;\n@group(0) @binding(2) var<uniform> params: Params;\n\n@fragment\nfn main(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {\n var color = textureSample(uTexture, uSampler, uv);\n color.r = clamp(color.r + params.amount, 0.0, 1.0);\n color.b = clamp(color.b - params.amount, 0.0, 1.0);\n return color;\n}\n"),tint:this.createPipeline(e,u,"\nstruct Params {\n amount: f32,\n}\n\n@group(0) @binding(0) var uTexture: texture_2d<f32>;\n@group(0) @binding(1) var uSampler: sampler;\n@group(0) @binding(2) var<uniform> params: Params;\n\n@fragment\nfn main(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {\n var color = textureSample(uTexture, uSampler, uv);\n color.g = clamp(color.g + params.amount, 0.0, 1.0);\n return color;\n}\n"),hue:this.createPipeline(e,u,"\nstruct Params {\n rotation: f32,\n}\n\n@group(0) @binding(0) var uTexture: texture_2d<f32>;\n@group(0) @binding(1) var uSampler: sampler;\n@group(0) @binding(2) var<uniform> params: Params;\n\nfn rgb2hsv(c: vec3<f32>) -> vec3<f32> {\n let K = vec4<f32>(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\n let p = mix(vec4<f32>(c.bg, K.wz), vec4<f32>(c.gb, K.xy), vec4<f32>(step(c.b, c.g)));\n let q = mix(vec4<f32>(p.xyw, c.r), vec4<f32>(c.r, p.yzx), vec4<f32>(step(p.x, c.r)));\n let d = q.x - min(q.w, q.y);\n let e = 1.0e-10;\n return vec3<f32>(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\n}\n\nfn hsv2rgb(c: vec3<f32>) -> vec3<f32> {\n let K = vec4<f32>(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n let p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\n return c.z * mix(K.xxx, clamp(p - K.xxx, vec3<f32>(0.0), vec3<f32>(1.0)), c.y);\n}\n\n@fragment\nfn main(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {\n let base = textureSample(uTexture, uSampler, uv);\n var hsv = rgb2hsv(base.rgb);\n hsv.x = fract(hsv.x + params.rotation);\n return vec4<f32>(hsv2rgb(hsv), base.a);\n}\n"),brightness:this.createPipeline(e,u,"\nstruct Params {\n amount: f32,\n}\n\n@group(0) @binding(0) var uTexture: texture_2d<f32>;\n@group(0) @binding(1) var uSampler: sampler;\n@group(0) @binding(2) var<uniform> params: Params;\n\nconst PI: f32 = 3.1415926535897932384626433832795;\n\n@fragment\nfn main(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {\n var color = textureSample(uTexture, uSampler, uv);\n if (params.amount >= 0.0) {\n color.r = color.r + params.amount * sin(color.r * PI);\n color.g = color.g + params.amount * sin(color.g * PI);\n color.b = color.b + params.amount * sin(color.b * PI);\n } else {\n color.r = (1.0 + params.amount) * color.r;\n color.g = (1.0 + params.amount) * color.g;\n color.b = (1.0 + params.amount) * color.b;\n }\n return color;\n}\n"),exposure:this.createPipeline(e,u,"\nstruct Params {\n amount: f32,\n}\n\n@group(0) @binding(0) var uTexture: texture_2d<f32>;\n@group(0) @binding(1) var uSampler: sampler;\n@group(0) @binding(2) var<uniform> params: Params;\n\nconst epsilon: f32 = 0.000001;\nconst mx: f32 = 1.0 - 0.000001;\n\n// GLSL mat3 列主序: mat3(col0_elem0, col0_elem1, col0_elem2, col1_elem0, ...)\n// WGSL mat3x3 也是列主序: mat3x3(vec3_col0, vec3_col1, vec3_col2)\nconst matRGBtoROMM = mat3x3<f32>(\n vec3<f32>(0.5293459296226501, 0.3300727903842926, 0.14058130979537964), // 第一列\n vec3<f32>(0.09837432950735092, 0.8734610080718994, 0.028164653107523918), // 第二列\n vec3<f32>(0.01688321679830551, 0.11767247319221497, 0.8654443025588989) // 第三列\n);\n\nconst matROMMtoRGB = mat3x3<f32>(\n vec3<f32>(2.0340757369995117, -0.727334201335907, -0.3067416846752167), // 第一列\n vec3<f32>(-0.22881317138671875, 1.2317301034927368, -0.0029169507324695587), // 第二列\n vec3<f32>(-0.008569774217903614, -0.1532866358757019, 1.1618564128875732) // 第三列\n);\n\nfn rgb2hsv(c: vec3<f32>) -> vec3<f32> {\n let K = vec4<f32>(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\n let p = mix(vec4<f32>(c.bg, K.wz), vec4<f32>(c.gb, K.xy), vec4<f32>(step(c.b, c.g)));\n let q = mix(vec4<f32>(p.xyw, c.r), vec4<f32>(c.r, p.yzx), vec4<f32>(step(p.x, c.r)));\n let d = q.x - min(q.w, q.y);\n let e = 1.0e-10;\n return vec3<f32>(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\n}\n\nfn hsv2rgb(c: vec3<f32>) -> vec3<f32> {\n let K = vec4<f32>(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n let p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\n return c.z * mix(K.xxx, clamp(p - K.xxx, vec3<f32>(0.0), vec3<f32>(1.0)), c.y);\n}\n\nfn setHue(res: vec3<f32>, base: vec3<f32>) -> vec3<f32> {\n let hsv = rgb2hsv(base);\n let res_hsv = rgb2hsv(res);\n return hsv2rgb(vec3<f32>(hsv.x, res_hsv.y, res_hsv.z));\n}\n\nfn ramp(t_in: f32) -> f32 {\n var t = t_in * 2.0;\n if (t >= 1.0) {\n t = t - 1.0;\n t = log(0.5) / log(0.5 * (1.0 - t) + 0.9332 * t);\n }\n return clamp(t, 0.001, 10.0);\n}\n\n@fragment\nfn main(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {\n let col = textureSample(uTexture, uSampler, uv);\n var base = col.rgb * matRGBtoROMM;\n let a = abs(params.amount) * col.a + epsilon;\n let v = pow(2.0, a * 2.0 + 1.0) - 2.0;\n let m = mx - exp(-v);\n var res: vec3<f32>;\n if (params.amount > 0.0) {\n res = (1.0 - exp(-v * base)) / m;\n } else {\n res = log(1.0 - base * m) / -v;\n }\n res = mix(base, res, min(a * 100.0, 1.0));\n res = setHue(res, base);\n res = pow(res, vec3<f32>(ramp(1.0 - (0.0 * col.a + 1.0) / 2.0)));\n res = res * matROMMtoRGB;\n return vec4<f32>(res, col.a);\n}\n"),contrast:this.createPipeline(e,u,f),blacks:this.createPipeline(e,u,"\n@group(0) @binding(0) var uTexture: texture_2d<f32>;\n@group(0) @binding(1) var uSampler: sampler;\n@group(0) @binding(2) var uPaletteMap: texture_2d<f32>;\n@group(0) @binding(3) var uPaletteSampler: sampler;\n\n@fragment\nfn main(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {\n let base = textureSample(uTexture, uSampler, uv);\n let r = textureSample(uPaletteMap, uPaletteSampler, vec2<f32>(base.r, 0.0)).r;\n let g = textureSample(uPaletteMap, uPaletteSampler, vec2<f32>(base.g, 0.0)).g;\n let b = textureSample(uPaletteMap, uPaletteSampler, vec2<f32>(base.b, 0.0)).b;\n return vec4<f32>(r, g, b, base.a);\n}\n",!1,!0),whites:this.createPipeline(e,u,"\nstruct Params {\n amount: f32,\n}\n\n@group(0) @binding(0) var uTexture: texture_2d<f32>;\n@group(0) @binding(1) var uSampler: sampler;\n@group(0) @binding(2) var<uniform> params: Params;\n\nconst RGB2Y = vec3<f32>(0.2126, 0.7152, 0.0722);\n\n@fragment\nfn main(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {\n let base = textureSample(uTexture, uSampler, uv);\n var color = base.rgb;\n let lum = dot(color, RGB2Y);\n let whiteMask = smoothstep(0.5, 1.0, lum);\n color = color + params.amount * whiteMask;\n return vec4<f32>(clamp(color, vec3<f32>(0.0), vec3<f32>(1.0)), base.a);\n}\n"),highlights:this.createPipeline(e,u,"\nstruct Params {\n amount: f32,\n}\n\n@group(0) @binding(0) var uTexture: texture_2d<f32>;\n@group(0) @binding(1) var uSampler: sampler;\n@group(0) @binding(2) var<uniform> params: Params;\n\nconst epsilon: f32 = 0.000001;\nconst mx: f32 = 1.0 - 0.000001;\n\nconst matRGBtoROMM = mat3x3<f32>(\n vec3<f32>(0.5293459296226501, 0.3300727903842926, 0.14058130979537964),\n vec3<f32>(0.09837432950735092, 0.8734610080718994, 0.028164653107523918),\n vec3<f32>(0.01688321679830551, 0.11767247319221497, 0.8654443025588989)\n);\n\nconst matROMMtoRGB = mat3x3<f32>(\n vec3<f32>(2.0340757369995117, -0.727334201335907, -0.3067416846752167),\n vec3<f32>(-0.22881317138671875, 1.2317301034927368, -0.0029169507324695587),\n vec3<f32>(-0.008569774217903614, -0.1532866358757019, 1.1618564128875732)\n);\n\nfn luma_romm(color: vec3<f32>) -> f32 {\n return dot(color, vec3<f32>(0.242655, 0.755158, 0.002187));\n}\n\nfn rgb2hsv(c: vec3<f32>) -> vec3<f32> {\n let K = vec4<f32>(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\n let p = mix(vec4<f32>(c.bg, K.wz), vec4<f32>(c.gb, K.xy), vec4<f32>(step(c.b, c.g)));\n let q = mix(vec4<f32>(p.xyw, c.r), vec4<f32>(c.r, p.yzx), vec4<f32>(step(p.x, c.r)));\n let d = q.x - min(q.w, q.y);\n let e = 1.0e-10;\n return vec3<f32>(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\n}\n\nfn hsv2rgb(c: vec3<f32>) -> vec3<f32> {\n let K = vec4<f32>(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n let p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\n return c.z * mix(K.xxx, clamp(p - K.xxx, vec3<f32>(0.0), vec3<f32>(1.0)), c.y);\n}\n\nfn setHue(res: vec3<f32>, base: vec3<f32>) -> vec3<f32> {\n let hsv = rgb2hsv(base);\n let res_hsv = rgb2hsv(res);\n return hsv2rgb(vec3<f32>(hsv.x, res_hsv.y, res_hsv.z));\n}\n\n@fragment\nfn main(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {\n let col = textureSample(uTexture, uSampler, uv);\n let map = col.rgb;\n var base = col.rgb * matRGBtoROMM;\n let map_lum = luma_romm(map * matRGBtoROMM);\n let exposure = mix(params.amount, 0.0, 1.0 - map_lum) * col.a;\n let a = abs(exposure) * col.a + epsilon;\n let v = pow(2.0, a + 1.0) - 2.0;\n let m = mx - exp(-v);\n var res: vec3<f32>;\n if (exposure > 0.0) {\n res = (1.0 - exp(-v * base)) / m;\n } else {\n res = log(1.0 - base * m) / -v;\n }\n res = mix(base, res, min(a * 100.0, 1.0));\n res = setHue(res, base);\n res = res * matROMMtoRGB;\n return vec4<f32>(res, col.a);\n}\n"),shadows:this.createPipeline(e,u,"\nstruct Params {\n amount: f32,\n}\n\n@group(0) @binding(0) var uTexture: texture_2d<f32>;\n@group(0) @binding(1) var uSampler: sampler;\n@group(0) @binding(2) var<uniform> params: Params;\n\nconst epsilon: f32 = 0.000001;\nconst mx: f32 = 1.0 - 0.000001;\n\nconst matRGBtoROMM = mat3x3<f32>(\n vec3<f32>(0.5293459296226501, 0.3300727903842926, 0.14058130979537964),\n vec3<f32>(0.09837432950735092, 0.8734610080718994, 0.028164653107523918),\n vec3<f32>(0.01688321679830551, 0.11767247319221497, 0.8654443025588989)\n);\n\nconst matROMMtoRGB = mat3x3<f32>(\n vec3<f32>(2.0340757369995117, -0.727334201335907, -0.3067416846752167),\n vec3<f32>(-0.22881317138671875, 1.2317301034927368, -0.0029169507324695587),\n vec3<f32>(-0.008569774217903614, -0.1532866358757019, 1.1618564128875732)\n);\n\nfn luma_romm(color: vec3<f32>) -> f32 {\n return dot(color, vec3<f32>(0.242655, 0.755158, 0.002187));\n}\n\nfn rgb2hsv(c: vec3<f32>) -> vec3<f32> {\n let K = vec4<f32>(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\n let p = mix(vec4<f32>(c.bg, K.wz), vec4<f32>(c.gb, K.xy), vec4<f32>(step(c.b, c.g)));\n let q = mix(vec4<f32>(p.xyw, c.r), vec4<f32>(c.r, p.yzx), vec4<f32>(step(p.x, c.r)));\n let d = q.x - min(q.w, q.y);\n let e = 1.0e-10;\n return vec3<f32>(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\n}\n\nfn hsv2rgb(c: vec3<f32>) -> vec3<f32> {\n let K = vec4<f32>(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n let p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\n return c.z * mix(K.xxx, clamp(p - K.xxx, vec3<f32>(0.0), vec3<f32>(1.0)), c.y);\n}\n\nfn setHue(res: vec3<f32>, base: vec3<f32>) -> vec3<f32> {\n let hsv = rgb2hsv(base);\n let res_hsv = rgb2hsv(res);\n return hsv2rgb(vec3<f32>(hsv.x, res_hsv.y, res_hsv.z));\n}\n\n@fragment\nfn main(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {\n let col = textureSample(uTexture, uSampler, uv);\n let map = col.rgb;\n var base = col.rgb * matRGBtoROMM;\n let map_lum = luma_romm(map * matRGBtoROMM);\n let exposure = mix(0.0, params.amount, 1.0 - map_lum) * col.a;\n let a = abs(exposure) * col.a + epsilon;\n let v = pow(2.0, a + 1.0) - 2.0;\n let m = mx - exp(-v);\n var res: vec3<f32>;\n if (exposure > 0.0) {\n res = (1.0 - exp(-v * base)) / m;\n } else {\n res = log(1.0 - base * m) / -v;\n }\n res = mix(base, res, min(a * 100.0, 1.0));\n res = setHue(res, base);\n res = res * matROMMtoRGB;\n return vec4<f32>(res, col.a);\n}\n"),dehaze:this.createPipeline(e,u,"\nstruct Params {\n amount: f32,\n width: f32,\n height: f32,\n _pad: f32,\n}\n\n@group(0) @binding(0) var uTexture: texture_2d<f32>;\n@group(0) @binding(1) var uSampler: sampler;\n@group(0) @binding(2) var<uniform> params: Params;\n\nfn hazeMap(coord: vec2<f32>) -> f32 {\n var color = vec3<f32>(1.0);\n let stepSize = vec2<f32>(1.0 / params.width, 1.0 / params.height);\n for (var i: i32 = -1; i <= 1; i = i + 1) {\n for (var j: i32 = -1; j <= 1; j = j + 1) {\n let offset = vec2<f32>(f32(i), f32(j)) * stepSize;\n let uv = clamp(coord + offset, vec2<f32>(0.0), vec2<f32>(1.0));\n let sample = textureSample(uTexture, uSampler, uv).rgb;\n color = min(color, sample);\n }\n }\n return min(color.r, min(color.g, color.b));\n}\n\n@fragment\nfn main(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {\n let base = textureSample(uTexture, uSampler, uv);\n let haze = hazeMap(uv);\n let transmission = 1.0 - 0.95 * haze;\n let A = 0.95;\n let t0 = 0.1;\n let t = mix(1.0, max(t0, transmission), params.amount);\n let J = (base.rgb - A) / t + A;\n return vec4<f32>(J, base.a);\n}\n"),bloom:this.createPipeline(e,u,"\nstruct Params {\n amount: f32,\n texelX: f32,\n texelY: f32,\n threshold: f32,\n}\n\n@group(0) @binding(0) var uTexture: texture_2d<f32>;\n@group(0) @binding(1) var uSampler: sampler;\n@group(0) @binding(2) var<uniform> params: Params;\n\n@fragment\nfn main(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {\n var sum = vec4<f32>(0.0);\n let texel = vec2<f32>(params.texelX, params.texelY);\n \n for (var j: i32 = -2; j <= 2; j = j + 1) {\n for (var i: i32 = -2; i <= 2; i = i + 1) {\n sum = sum + textureSample(uTexture, uSampler, uv + vec2<f32>(f32(i), f32(j)) * texel);\n }\n }\n sum = sum / 25.0;\n \n var base = textureSample(uTexture, uSampler, uv);\n if (length(sum.rgb) > params.threshold) {\n base = base + sum * params.amount;\n }\n return base;\n}\n"),glamour:this.createPipeline(e,u,"\nstruct Params {\n amount: f32,\n texelX: f32,\n texelY: f32,\n _pad: f32,\n}\n\n@group(0) @binding(0) var uTexture: texture_2d<f32>;\n@group(0) @binding(1) var uSampler: sampler;\n@group(0) @binding(2) var<uniform> params: Params;\n\nfn normpdf(x: f32, sigma: f32) -> f32 {\n return 0.39894 * exp(-0.5 * x * x / (sigma * sigma)) / sigma;\n}\n\nfn luma(color: vec3<f32>) -> f32 {\n return dot(color, vec3<f32>(0.299, 0.587, 0.114));\n}\n\n@fragment\nfn main(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {\n let texel = vec2<f32>(params.texelX, params.texelY);\n let sigma = 7.0;\n var final_colour = vec3<f32>(0.0);\n var Z = 0.0;\n \n // 简化版高斯模糊\n for (var i: i32 = -5; i <= 5; i = i + 1) {\n for (var j: i32 = -5; j <= 5; j = j + 1) {\n let weight = normpdf(f32(i), sigma) * normpdf(f32(j), sigma);\n final_colour = final_colour + weight * textureSample(uTexture, uSampler, uv + vec2<f32>(f32(i), f32(j)) * texel).rgb;\n Z = Z + weight;\n }\n }\n final_colour = final_colour / Z;\n \n let base = textureSample(uTexture, uSampler, uv);\n var color = vec3<f32>(luma(final_colour));\n \n // Soft light blend\n color = vec3<f32>(\n select(1.0 - 2.0 * (1.0 - base.r) * (1.0 - color.r), 2.0 * base.r * color.r, base.r <= 0.5),\n select(1.0 - 2.0 * (1.0 - base.g) * (1.0 - color.g), 2.0 * base.g * color.g, base.g <= 0.5),\n select(1.0 - 2.0 * (1.0 - base.b) * (1.0 - color.b), 2.0 * base.b * color.b, base.b <= 0.5)\n );\n \n return mix(base, vec4<f32>(color, base.a), params.amount);\n}\n"),clarity:this.createPipeline(e,u,"\nstruct Params {\n amount: f32,\n texelX: f32,\n texelY: f32,\n _pad: f32,\n}\n\n@group(0) @binding(0) var uTexture: texture_2d<f32>;\n@group(0) @binding(1) var uSampler: sampler;\n@group(0) @binding(2) var<uniform> params: Params;\n\nfn Lum(c: vec3<f32>) -> f32 {\n return 0.299 * c.r + 0.587 * c.g + 0.114 * c.b;\n}\n\nfn BlendOverlayf(base: f32, blend: f32) -> f32 {\n return select(1.0 - 2.0 * (1.0 - base) * (1.0 - blend), 2.0 * base * blend, base < 0.5);\n}\n\nfn BlendOverlay(base: vec3<f32>, blend: vec3<f32>) -> vec3<f32> {\n return vec3<f32>(BlendOverlayf(base.r, blend.r), BlendOverlayf(base.g, blend.g), BlendOverlayf(base.b, blend.b));\n}\n\nfn BlendVividLightf(base: f32, blend: f32) -> f32 {\n let BlendColorBurnf = select(max(1.0 - ((1.0 - base) / (2.0 * blend)), 0.0), 2.0 * blend, (2.0 * blend) == 0.0);\n let BlendColorDodgef = select(min(base / (1.0 - (2.0 * (blend - 0.5))), 1.0), 2.0 * (blend - 0.5), (2.0 * (blend - 0.5)) == 1.0);\n return select(BlendColorDodgef, BlendColorBurnf, blend < 0.5);\n}\n\nfn BlendVividLight(base: vec3<f32>, blend: vec3<f32>) -> vec3<f32> {\n return vec3<f32>(BlendVividLightf(base.r, blend.r), BlendVividLightf(base.g, blend.g), BlendVividLightf(base.b, blend.b));\n}\n\nfn normpdf(x: f32, sigma: f32) -> f32 {\n return 0.39894 * exp(-0.5 * x * x / (sigma * sigma)) / sigma;\n}\n\n@fragment\nfn main(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {\n let texel = vec2<f32>(params.texelX, params.texelY);\n let sigma = 7.0;\n var blur = vec3<f32>(0.0);\n var Z = 0.0;\n \n for (var i: i32 = -5; i <= 5; i = i + 1) {\n for (var j: i32 = -5; j <= 5; j = j + 1) {\n let weight = normpdf(f32(i), sigma) * normpdf(f32(j), sigma);\n blur = blur + weight * textureSample(uTexture, uSampler, uv + vec2<f32>(f32(i), f32(j)) * texel).rgb;\n Z = Z + weight;\n }\n }\n blur = blur / Z;\n \n let base4 = textureSample(uTexture, uSampler, uv);\n let base = base4.rgb;\n var intensity = params.amount;\n if (params.amount < 0.0) {\n intensity = params.amount / 2.0;\n }\n \n let lum = Lum(base);\n let col = vec3<f32>(lum);\n let mask = vec3<f32>(1.0 - pow(lum, 1.8));\n let layer = vec3<f32>(1.0 - Lum(blur));\n let detail = clamp(BlendVividLight(col, layer), vec3<f32>(0.0), vec3<f32>(1.0));\n let inverse = mix(1.0 - detail, detail, (intensity + 1.0) / 2.0);\n \n return vec4<f32>(BlendOverlay(base, mix(vec3<f32>(0.5), inverse, mask)), base4.a);\n}\n"),kernel:this.createPipeline(e,u,"\nstruct Params {\n texelX: f32,\n texelY: f32,\n amount: f32,\n _pad: f32,\n kernel: array<f32, 12>, // 9 + 3 padding\n}\n\n@group(0) @binding(0) var uTexture: texture_2d<f32>;\n@group(0) @binding(1) var uSampler: sampler;\n@group(0) @binding(2) var<uniform> params: Params;\n\n@fragment\nfn main(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {\n let texel = vec2<f32>(params.texelX, params.texelY);\n \n let c11 = textureSample(uTexture, uSampler, uv - texel);\n let c12 = textureSample(uTexture, uSampler, vec2<f32>(uv.x, uv.y - texel.y));\n let c13 = textureSample(uTexture, uSampler, vec2<f32>(uv.x + texel.x, uv.y - texel.y));\n let c21 = textureSample(uTexture, uSampler, vec2<f32>(uv.x - texel.x, uv.y));\n let c22 = textureSample(uTexture, uSampler, uv);\n let c23 = textureSample(uTexture, uSampler, vec2<f32>(uv.x + texel.x, uv.y));\n let c31 = textureSample(uTexture, uSampler, vec2<f32>(uv.x - texel.x, uv.y + texel.y));\n let c32 = textureSample(uTexture, uSampler, vec2<f32>(uv.x, uv.y + texel.y));\n let c33 = textureSample(uTexture, uSampler, uv + texel);\n \n let color = c11 * params.kernel[0] + c12 * params.kernel[1] + c13 * params.kernel[2] +\n c21 * params.kernel[3] + c22 * params.kernel[4] + c23 * params.kernel[5] +\n c31 * params.kernel[6] + c32 * params.kernel[7] + c33 * params.kernel[8];\n \n return color * params.amount + (c22 * (1.0 - params.amount));\n}\n"),blur:this.createPipeline(e,u,"\nstruct Params {\n sizeX: f32,\n sizeY: f32,\n _pad1: f32,\n _pad2: f32,\n}\n\n@group(0) @binding(0) var uTexture: texture_2d<f32>;\n@group(0) @binding(1) var uSampler: sampler;\n@group(0) @binding(2) var<uniform> params: Params;\n\nfn random(scale: vec3<f32>, seed: f32, coord: vec3<f32>) -> f32 {\n return fract(sin(dot(coord + seed, scale)) * 43758.5453 + seed);\n}\n\n@fragment\nfn main(@location(0) uv: vec2<f32>, @builtin(position) fragCoord: vec4<f32>) -> @location(0) vec4<f32> {\n var color = vec4<f32>(0.0);\n var total = 0.0;\n let size = vec2<f32>(params.sizeX, params.sizeY);\n let offset = random(vec3<f32>(12.9898, 78.233, 151.7182), 0.0, fragCoord.xyz);\n \n for (var t: i32 = -30; t <= 30; t = t + 1) {\n let percent = (f32(t) + offset - 0.5) / 30.0;\n let weight = 1.0 - abs(percent);\n var sample = textureSample(uTexture, uSampler, uv + size * percent);\n sample = vec4<f32>(sample.rgb * sample.a, sample.a);\n color = color + sample * weight;\n total = total + weight;\n }\n \n color = color / total;\n return vec4<f32>(color.rgb / (color.a + 0.00001), color.a);\n}\n"),vignette:this.createPipeline(e,u,"\nstruct Params {\n amount: f32,\n size: f32,\n _pad1: f32,\n _pad2: f32,\n}\n\n@group(0) @binding(0) var uTexture: texture_2d<f32>;\n@group(0) @binding(1) var uSampler: sampler;\n@group(0) @binding(2) var<uniform> params: Params;\n\n@fragment\nfn main(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {\n var color = textureSample(uTexture, uSampler, uv);\n let dist = distance(uv, vec2<f32>(0.5, 0.5));\n let amt = clamp(params.amount, -1.0, 1.0);\n let edge = dist * (abs(amt) * 0.75 + params.size * 2.0);\n var vignette = smoothstep(0.8, params.size * 0.799, edge);\n \n if (amt < 0.0) {\n vignette = 1.0 + (1.0 - vignette) * (-amt);\n } else {\n vignette = mix(1.0, vignette, amt);\n }\n \n color = vec4<f32>(color.rgb * vignette, color.a);\n return color;\n}\n"),grain:this.createPipeline(e,u,"\nstruct Params {\n width: f32,\n height: f32,\n amount: f32,\n time: f32,\n}\n\n@group(0) @binding(0) var uTexture: texture_2d<f32>;\n@group(0) @binding(1) var uSampler: sampler;\n@group(0) @binding(2) var<uniform> params: Params;\n\nfn rnm(tc: vec2<f32>) -> vec4<f32> {\n let noise = sin(dot(tc + vec2<f32>(params.time), vec2<f32>(12.9898, 78.233))) * 43758.5453;\n return vec4<f32>(\n fract(noise) * 2.0 - 1.0,\n fract(noise * 1.2154) * 2.0 - 1.0,\n fract(noise * 1.3453) * 2.0 - 1.0,\n fract(noise * 1.3647) * 2.0 - 1.0\n );\n}\n\nfn fade(t: f32) -> f32 {\n return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);\n}\n\n@fragment\nfn main(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {\n let grainsize = 1.8;\n let lumamount = 1.0;\n \n let rotCoordsR = uv;\n let noiseScale = vec2<f32>(params.width / grainsize, params.height / grainsize);\n let noise = vec3<f32>(rnm(rotCoordsR * noiseScale).rgb);\n \n let tex = textureSample(uTexture, uSampler, uv);\n var col = tex.rgb;\n let lumcoeff = vec3<f32>(0.299, 0.587, 0.114);\n let luminance = mix(0.0, dot(col, lumcoeff), lumamount);\n var lum = smoothstep(0.2, 0.0, luminance);\n lum = lum + luminance;\n let finalNoise = mix(noise, vec3<f32>(0.0), pow(lum, 4.0));\n col = col + finalNoise * params.amount;\n \n return vec4<f32>(col, tex.a);\n}\n")},m=e.createTexture({size:{width:256,height:1},format:"rgba8unorm",usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.COPY_DST}),x=[this.createRenderTarget(e,r,a,"rgba8unorm"),this.createRenderTarget(e,r,a,"rgba8unorm")];this.resources={device:e,context:n,format:t,width:r,height:a,sourceTexture:o,sourceTextureView:o.createView(),sampler:i,vertexBuffer:l,pipelines:c,targets:x,paletteTexture:m,paletteTextureView:m.createView()}}disposeResources(){if(!this.resources)return;const{sourceTexture:e,vertexBuffer:n,targets:t,paletteTexture:r}=this.resources;e.destroy(),n.destroy(),t.forEach(e=>e.texture.destroy()),r&&r.destroy(),this.resources=null}createUniformBuffer(e,n){const t=e.createBuffer({size:Math.max(n.byteLength,16),usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST});return e.queue.writeBuffer(t,0,n),t}drawFrame(e,n){const{device:t,context:r,width:a,height:o,sourceTextureView:i,sampler:s,vertexBuffer:l,pipelines:u,targets:c,paletteTexture:m,paletteTextureView:v}=e;let f=i,g=0;const h=()=>{const e=c[g%2];return g++,e},b=(e,n,r)=>{const a=u[e];if(!a)return;const o=r?null:h(),i=r||o.view,c=[{binding:0,resource:f},{binding:1,resource:s}];let m=null;n&&(m=this.createUniformBuffer(t,n),c.push({binding:2,resource:{buffer:m}}));const v=t.createBindGroup({layout:a.bindGroupLayout,entries:c}),x=t.createCommandEncoder(),p=x.beginRenderPass({colorAttachments:[{view:i,loadOp:"clear",storeOp:"store",clearValue:{r:0,g:0,b:0,a:1}}]});p.setPipeline(a.pipeline),p.setVertexBuffer(0,l),p.setBindGroup(0,v),p.draw(4),p.end(),t.queue.submit([x.finish()]),o&&(f=o.view),m&&m.destroy()};if(Math.abs(n.vibrance)>.5&&b("vibrance",new Float32Array([n.vibrance/100]).buffer),Math.abs(n.saturation)>.5&&b("saturation",(e=>{const n=1+Math.max(-100,Math.min(100,e))/100,t=.299,r=.587,a=.114,o=1-n;return new Float32Array([o*t+n,o*r,o*a,0,0,o*t,o*r+n,o*a,0,0,o*t,o*r,o*a+n,0,0,0,0,0,1,0])})(n.saturation).buffer),Math.abs(n.temperature)>.5&&b("temperature",new Float32Array([n.temperature/500]).buffer),Math.abs(n.tint)>.5&&b("tint",new Float32Array([n.tint/500]).buffer),Math.abs(n.hue)>.5&&b("hue",new Float32Array([n.hue/200]).buffer),b("brightness",new Float32Array([n.brightness/200]).buffer),Math.abs(n.exposure)>.5&&b("exposure",new Float32Array([n.exposure/100]).buffer),Math.abs(n.contrast)>.5&&b("contrast",(e=>{const n=1+Math.max(-100,Math.min(100,e))/100,t=.5*(1-n);return new Float32Array([n,0,0,0,t,0,n,0,0,t,0,0,n,0,t,0,0,0,1,0])})(n.contrast).buffer),Math.abs(n.blacks)>.5&&m&&v){const e=(e=>{const n=Math.max(-100,Math.min(100,e))/100;return(e=>{const n=new Uint8Array(768);for(let t=0;t<256;t+=1){const r=p(t/255,0,e,.66,1),a=Math.round(255*x(r)),o=3*t;n[o]=a,n[o+1]=a,n[o+2]=a}return n})(x(.33-.35*n))})(n.blacks),r=new Uint8Array(1024);for(let n=0;n<256;n++)r[4*n]=e[3*n],r[4*n+1]=e[3*n+1],r[4*n+2]=e[3*n+2],r[4*n+3]=255;t.queue.writeTexture({texture:m},r,{bytesPerRow:1024},{width:256,height:1});const a=u.blacks,o=h(),i=o.view,c=t.createBindGroup({layout:a.bindGroupLayout,entries:[{binding:0,resource:f},{binding:1,resource:s},{binding:2,resource:v},{binding:3,resource:s}]}),g=t.createCommandEncoder(),b=g.beginRenderPass({colorAttachments:[{view:i,loadOp:"clear",storeOp:"store",clearValue:{r:0,g:0,b:0,a:1}}]});b.setPipeline(a.pipeline),b.setVertexBuffer(0,l),b.setBindGroup(0,c),b.draw(4),b.end(),t.queue.submit([g.finish()]),f=o.view}if(Math.abs(n.whites)>.5&&b("whites",new Float32Array([n.whites/400]).buffer),Math.abs(n.highlights)>.5&&b("highlights",new Float32Array([n.highlights/100]).buffer),Math.abs(n.shadows)>.5&&b("shadows",new Float32Array([n.shadows/100]).buffer),Math.abs(n.dehaze)>.5&&b("dehaze",new Float32Array([n.dehaze/100,a,o,0]).buffer),n.bloom>.5&&b("bloom",new Float32Array([n.bloom/100,1/a,1/o,.5]).buffer),n.glamour>.5&&b("glamour",new Float32Array([n.glamour/100,1/a,1/o,0]).buffer),Math.abs(n.clarity)>.5&&b("clarity",new Float32Array([n.clarity/100,1/a,1/o,0]).buffer),n.sharpen>.5&&b("kernel",new Float32Array([1/a,1/o,n.sharpen/100,0,0,-1,0,-1,5,-1,0,-1,0,0,0,0]).buffer),n.smooth>.5){const e=1/9;b("kernel",new Float32Array([1/a,1/o,n.smooth/100,0,e,e,e,e,e,e,e,e,e,0,0,0]).buffer)}b("blur",new Float32Array([n.blur/a,0,0,0]).buffer),b("blur",new Float32Array([0,n.blur/o,0,0]).buffer),b("vignette",new Float32Array([n.vignette/100,.25,0,0]).buffer),b("grain",new Float32Array([a,o,n.grain/800,0]).buffer),b("pass",void 0,r.getCurrentTexture().createView())}},h={vibrance:0,saturation:0,temperature:0,tint:0,hue:0,brightness:0,exposure:0,contrast:0,blacks:0,whites:0,highlights:0,shadows:0,dehaze:0,bloom:0,glamour:0,clarity:0,sharpen:0,smooth:0,blur:0,vignette:0,grain:0},b={auto:{},blackAndWhite:{saturation:-100,contrast:20,exposure:10,clarity:10},pop:{highlights:50,shadows:-50,vibrance:50,saturation:20,exposure:20,clarity:20},vintage:{saturation:-20,contrast:10,temperature:15,grain:30,vignette:25},vivid:{vibrance:40,saturation:20,contrast:15,clarity:20},cinematic:{contrast:25,highlights:-20,shadows:15,temperature:-10,vignette:30}};function d(e){const{data:n,width:t,height:r}=e,a=new Array(256).fill(0);for(let e=0;e<n.length;e+=4)a[n[e]]+=1,a[n[e+1]]+=1,a[n[e+2]]+=1;const o=Math.round(t*r/1e3);let i=0;for(let e=0;e<256;e++)if(a[e]>o){i=e;break}let s=255;for(let e=255;e>=0;e--)if(a[e]>o){s=e;break}return i>100&&(i=100),s<155&&(s=155),{black:i,white:s}}function w(e){const{data:n,width:t,height:r}=e;let a=1,o=1;for(let e=0;e<n.length;e+=4){const t=n[e],r=n[e+1],i=n[e+2],s=Math.min(t,r,i),l=Math.max(t,r,i);o+=l/255;const u=l-s;u>0&&(a+=u/l)}return(a+o)/(t*r*2)}function y(e){return{levels:d(e),vibrance:w(e)}}exports.BaseBackend=e,exports.ImageColorGrading=class{constructor(e={}){this.backend=null,this.settings={...h},this.imageLoaded=!1,this.initPromise=null,this.canvas=e.canvas||document.createElement("canvas"),this.backendType=r(e.backend)}getCanvas(){return this.canvas}getBackendType(){return this.backendType}static isWebGPUSupported(){return n()}static isWebGLSupported(){return t()}getSettings(){return{...this.settings}}setSettings(e){this.settings={...this.settings,...e},this.backend&&this.imageLoaded&&this.render()}resetSettings(){this.settings={...h},this.backend&&this.imageLoaded&&this.render()}async initBackend(){if(this.backend)return;const e={};if("webgpu"===this.backendType){this.backend=new g(this.canvas,e);try{await this.backend.init()}catch(n){this.backend=new m(this.canvas,e),this.backend.init(),this.backendType="webgl"}}else this.backend=new m(this.canvas,e),this.backend.init()}async ensureBackend(){this.initPromise||(this.initPromise=this.initBackend()),await this.initPromise}async loadImage(e){return await this.ensureBackend(),new Promise((n,t)=>{const r=new Image;r.crossOrigin="anonymous",r.onload=()=>{this.backend.loadFromImage(r),this.imageLoaded=!0,this.render(),n()},r.onerror=()=>{t(new Error(`Failed to load image: ${e}`))},r.src=e})}async loadFromImage(e){await this.ensureBackend(),this.backend.loadFromImage(e),this.imageLoaded=!0,this.render()}async loadFromFile(e){const n=URL.createObjectURL(e);try{await this.loadImage(n)}finally{URL.revokeObjectURL(n)}}async loadFromImageData(e){await this.ensureBackend(),this.backend.loadFromImageData(e),this.imageLoaded=!0,this.render()}render(){this.backend&&this.imageLoaded&&this.backend.render(this.settings)}toDataURL(e){this.render();const n=e?.format||"image/png",t=e?.quality;return this.canvas.toDataURL(n,t)}toBlob(e){return this.render(),new Promise((n,t)=>{const r=e?.format||"image/png",a=e?.quality;this.canvas.toBlob(e=>{e?n(e):t(new Error("Failed to create blob"))},r,a)})}getImageData(){if(!this.backend)throw new Error("No backend initialized");return this.render(),this.backend.getImageData()}getSize(){return this.backend?this.backend.getSize():{width:0,height:0}}isLoaded(){return this.imageLoaded}dispose(){this.backend&&(this.backend.dispose(),this.backend=null),this.imageLoaded=!1,this.initPromise=null}analyze(){if(!this.imageLoaded||!this.backend)throw new Error("No image loaded");const e={...this.settings};this.settings={...h},this.render();const n=y(this.getImageData());return this.settings=e,this.render(),n}autoFix(){if(!this.imageLoaded||!this.backend)throw new Error("No image loaded");this.settings={...h},this.render();const e=this.getImageData(),n=d(e),t=w(e),r={...h};if(r.whites=Math.round(255-n.white),r.blacks=Math.round(n.black),t<.7){const e=Math.round(100*(.7-t));r.vibrance=Math.min(e,50)}return this.settings=r,this.render(),r}applyPreset(e){if("auto"===e)return this.autoFix();const n=b[e],t={...h,...n};return this.settings=t,this.backend&&this.imageLoaded&&this.render(),t}},exports.WebGLBackend=m,exports.WebGPUBackend=g,exports.analyzeImage=y,exports.analyzeImageLevels=d,exports.analyzeImageVibrance=w,exports.defaultSettings=h,exports.isWebGLSupported=t,exports.isWebGPUSupported=n,exports.presets=b,exports.selectBestBackend=r;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,3 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 后端类型
|
|
3
|
+
*/
|
|
4
|
+
type BackendType$1 = 'webgl' | 'webgpu';
|
|
5
|
+
/**
|
|
6
|
+
* 处理器配置选项
|
|
7
|
+
*/
|
|
8
|
+
interface ProcessorOptions {
|
|
9
|
+
/** canvas 元素 */
|
|
10
|
+
canvas?: HTMLCanvasElement;
|
|
11
|
+
/** 后端选择:'auto' | 'webgpu' | 'webgl' */
|
|
12
|
+
backend?: 'auto' | BackendType$1;
|
|
13
|
+
}
|
|
1
14
|
/**
|
|
2
15
|
* 调色设置参数
|
|
3
16
|
*/
|
|
@@ -112,9 +125,16 @@ declare function analyzeImage(imageData: ImageData): ImageAnalysis;
|
|
|
112
125
|
/**
|
|
113
126
|
* 图像调色处理器
|
|
114
127
|
*
|
|
128
|
+
* 支持 WebGL 和 WebGPU 双后端,自动降级
|
|
129
|
+
*
|
|
115
130
|
* @example
|
|
116
131
|
* ```ts
|
|
132
|
+
* // 默认自动选择后端
|
|
117
133
|
* const processor = new ImageColorGrading();
|
|
134
|
+
*
|
|
135
|
+
* // 指定使用 WebGPU
|
|
136
|
+
* const processor = new ImageColorGrading({ backend: 'webgpu' });
|
|
137
|
+
*
|
|
118
138
|
* await processor.loadImage('path/to/image.jpg');
|
|
119
139
|
* processor.setSettings({ brightness: 20, contrast: 10 });
|
|
120
140
|
* processor.render();
|
|
@@ -123,18 +143,32 @@ declare function analyzeImage(imageData: ImageData): ImageAnalysis;
|
|
|
123
143
|
*/
|
|
124
144
|
declare class ImageColorGrading {
|
|
125
145
|
private canvas;
|
|
126
|
-
private
|
|
146
|
+
private backend;
|
|
147
|
+
private backendType;
|
|
127
148
|
private settings;
|
|
128
149
|
private imageLoaded;
|
|
150
|
+
private initPromise;
|
|
129
151
|
/**
|
|
130
152
|
* 创建图像调色处理器
|
|
131
|
-
* @param
|
|
153
|
+
* @param options - 配置选项
|
|
132
154
|
*/
|
|
133
|
-
constructor(
|
|
155
|
+
constructor(options?: ProcessorOptions);
|
|
134
156
|
/**
|
|
135
157
|
* 获取 canvas 元素
|
|
136
158
|
*/
|
|
137
159
|
getCanvas(): HTMLCanvasElement;
|
|
160
|
+
/**
|
|
161
|
+
* 获取当前后端类型
|
|
162
|
+
*/
|
|
163
|
+
getBackendType(): BackendType$1;
|
|
164
|
+
/**
|
|
165
|
+
* 检查 WebGPU 是否可用
|
|
166
|
+
*/
|
|
167
|
+
static isWebGPUSupported(): boolean;
|
|
168
|
+
/**
|
|
169
|
+
* 检查 WebGL 是否可用
|
|
170
|
+
*/
|
|
171
|
+
static isWebGLSupported(): boolean;
|
|
138
172
|
/**
|
|
139
173
|
* 获取当前设置
|
|
140
174
|
*/
|
|
@@ -148,6 +182,14 @@ declare class ImageColorGrading {
|
|
|
148
182
|
* 重置所有设置为默认值
|
|
149
183
|
*/
|
|
150
184
|
resetSettings(): void;
|
|
185
|
+
/**
|
|
186
|
+
* 初始化后端
|
|
187
|
+
*/
|
|
188
|
+
private initBackend;
|
|
189
|
+
/**
|
|
190
|
+
* 确保后端已初始化
|
|
191
|
+
*/
|
|
192
|
+
private ensureBackend;
|
|
151
193
|
/**
|
|
152
194
|
* 从 URL 加载图像
|
|
153
195
|
* @param url - 图像 URL
|
|
@@ -158,7 +200,7 @@ declare class ImageColorGrading {
|
|
|
158
200
|
* 从 HTMLImageElement 加载图像
|
|
159
201
|
* @param image - 图像元素
|
|
160
202
|
*/
|
|
161
|
-
loadFromImage(image: HTMLImageElement): void
|
|
203
|
+
loadFromImage(image: HTMLImageElement): Promise<void>;
|
|
162
204
|
/**
|
|
163
205
|
* 从 File 对象加载图像
|
|
164
206
|
* @param file - File 对象
|
|
@@ -169,7 +211,7 @@ declare class ImageColorGrading {
|
|
|
169
211
|
* 从 ImageData 加载图像
|
|
170
212
|
* @param imageData - ImageData 对象
|
|
171
213
|
*/
|
|
172
|
-
loadFromImageData(imageData: ImageData): void
|
|
214
|
+
loadFromImageData(imageData: ImageData): Promise<void>;
|
|
173
215
|
/**
|
|
174
216
|
* 渲染图像
|
|
175
217
|
*/
|
|
@@ -223,11 +265,140 @@ declare class ImageColorGrading {
|
|
|
223
265
|
* @returns 应用的设置
|
|
224
266
|
*/
|
|
225
267
|
applyPreset(preset: PresetType): ColorGradingSettings;
|
|
226
|
-
|
|
227
|
-
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* 后端抽象接口
|
|
272
|
+
* 定义 WebGL 和 WebGPU 后端的统一接口
|
|
273
|
+
*/
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* 后端类型
|
|
277
|
+
*/
|
|
278
|
+
type BackendType = 'webgl' | 'webgpu';
|
|
279
|
+
/**
|
|
280
|
+
* 后端初始化选项
|
|
281
|
+
*/
|
|
282
|
+
interface BackendOptions {
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* 后端抽象基类
|
|
286
|
+
*/
|
|
287
|
+
declare abstract class BaseBackend {
|
|
288
|
+
protected canvas: HTMLCanvasElement;
|
|
289
|
+
protected width: number;
|
|
290
|
+
protected height: number;
|
|
291
|
+
protected initialized: boolean;
|
|
292
|
+
protected options: BackendOptions;
|
|
293
|
+
constructor(canvas: HTMLCanvasElement, options?: BackendOptions);
|
|
294
|
+
/**
|
|
295
|
+
* 获取后端类型
|
|
296
|
+
*/
|
|
297
|
+
abstract getType(): BackendType;
|
|
298
|
+
/**
|
|
299
|
+
* 检查后端是否可用
|
|
300
|
+
*/
|
|
301
|
+
static isSupported(): boolean;
|
|
302
|
+
/**
|
|
303
|
+
* 初始化后端
|
|
304
|
+
*/
|
|
305
|
+
abstract init(): Promise<void> | void;
|
|
306
|
+
/**
|
|
307
|
+
* 从图像元素加载纹理
|
|
308
|
+
*/
|
|
309
|
+
abstract loadFromImage(image: HTMLImageElement): void;
|
|
310
|
+
/**
|
|
311
|
+
* 从 ImageData 加载纹理
|
|
312
|
+
*/
|
|
313
|
+
abstract loadFromImageData(imageData: ImageData): void;
|
|
314
|
+
/**
|
|
315
|
+
* 渲染图像
|
|
316
|
+
*/
|
|
317
|
+
abstract render(settings: ColorGradingSettings): void;
|
|
318
|
+
/**
|
|
319
|
+
* 获取渲染结果的 ImageData
|
|
320
|
+
*/
|
|
321
|
+
abstract getImageData(): ImageData;
|
|
322
|
+
/**
|
|
323
|
+
* 获取图像尺寸
|
|
324
|
+
*/
|
|
325
|
+
getSize(): {
|
|
326
|
+
width: number;
|
|
327
|
+
height: number;
|
|
328
|
+
};
|
|
329
|
+
/**
|
|
330
|
+
* 检查是否已初始化
|
|
331
|
+
*/
|
|
332
|
+
isInitialized(): boolean;
|
|
333
|
+
/**
|
|
334
|
+
* 销毁后端资源
|
|
335
|
+
*/
|
|
336
|
+
abstract dispose(): void;
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* 检测 WebGPU 支持
|
|
340
|
+
*/
|
|
341
|
+
declare function isWebGPUSupported(): boolean;
|
|
342
|
+
/**
|
|
343
|
+
* 检测 WebGL 支持
|
|
344
|
+
*/
|
|
345
|
+
declare function isWebGLSupported(): boolean;
|
|
346
|
+
/**
|
|
347
|
+
* 自动选择最佳后端
|
|
348
|
+
*/
|
|
349
|
+
declare function selectBestBackend(preferred?: 'auto' | BackendType): BackendType;
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* WebGL 后端实现
|
|
353
|
+
*/
|
|
354
|
+
|
|
355
|
+
declare class WebGLBackend extends BaseBackend {
|
|
356
|
+
private gl;
|
|
357
|
+
private resources;
|
|
358
|
+
constructor(canvas: HTMLCanvasElement, options?: BackendOptions);
|
|
359
|
+
getType(): BackendType;
|
|
360
|
+
static isSupported(): boolean;
|
|
361
|
+
init(): void;
|
|
362
|
+
loadFromImage(image: HTMLImageElement): void;
|
|
363
|
+
loadFromImageData(imageData: ImageData): void;
|
|
364
|
+
render(settings: ColorGradingSettings): void;
|
|
365
|
+
getImageData(): ImageData;
|
|
366
|
+
dispose(): void;
|
|
367
|
+
private getShaderSource;
|
|
368
|
+
private initResources;
|
|
369
|
+
private disposeResources;
|
|
370
|
+
private drawFrame;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* WebGPU 后端实现
|
|
375
|
+
*/
|
|
376
|
+
|
|
377
|
+
declare class WebGPUBackend extends BaseBackend {
|
|
378
|
+
private device;
|
|
379
|
+
private resources;
|
|
380
|
+
constructor(canvas: HTMLCanvasElement, options?: BackendOptions);
|
|
381
|
+
getType(): BackendType;
|
|
382
|
+
static isSupported(): boolean;
|
|
383
|
+
init(): Promise<void>;
|
|
384
|
+
loadFromImage(image: HTMLImageElement): void;
|
|
385
|
+
loadFromImageData(imageData: ImageData): void;
|
|
386
|
+
render(settings: ColorGradingSettings): void;
|
|
387
|
+
getImageData(): ImageData;
|
|
388
|
+
/**
|
|
389
|
+
* 异步获取 ImageData
|
|
390
|
+
*/
|
|
391
|
+
getImageDataAsync(): Promise<ImageData>;
|
|
392
|
+
dispose(): void;
|
|
393
|
+
private getShaderSource;
|
|
394
|
+
private createPipeline;
|
|
395
|
+
private createRenderTarget;
|
|
228
396
|
private initResources;
|
|
397
|
+
private initResourcesFromImageData;
|
|
398
|
+
private setupResources;
|
|
229
399
|
private disposeResources;
|
|
400
|
+
private createUniformBuffer;
|
|
230
401
|
private drawFrame;
|
|
231
402
|
}
|
|
232
403
|
|
|
233
|
-
export { type ColorGradingSettings, type ExportOptions, type ImageAnalysis, ImageColorGrading, type ImageLevels, type PartialColorGradingSettings, type PresetType, analyzeImage, analyzeImageLevels, analyzeImageVibrance, defaultSettings, presets };
|
|
404
|
+
export { type BackendType$1 as BackendType, BaseBackend, type ColorGradingSettings, type ExportOptions, type ImageAnalysis, ImageColorGrading, type ImageLevels, type PartialColorGradingSettings, type PresetType, type ProcessorOptions, WebGLBackend, WebGPUBackend, analyzeImage, analyzeImageLevels, analyzeImageVibrance, defaultSettings, isWebGLSupported, isWebGPUSupported, presets, selectBestBackend };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 后端类型
|
|
3
|
+
*/
|
|
4
|
+
type BackendType$1 = 'webgl' | 'webgpu';
|
|
5
|
+
/**
|
|
6
|
+
* 处理器配置选项
|
|
7
|
+
*/
|
|
8
|
+
interface ProcessorOptions {
|
|
9
|
+
/** canvas 元素 */
|
|
10
|
+
canvas?: HTMLCanvasElement;
|
|
11
|
+
/** 后端选择:'auto' | 'webgpu' | 'webgl' */
|
|
12
|
+
backend?: 'auto' | BackendType$1;
|
|
13
|
+
}
|
|
1
14
|
/**
|
|
2
15
|
* 调色设置参数
|
|
3
16
|
*/
|
|
@@ -112,9 +125,16 @@ declare function analyzeImage(imageData: ImageData): ImageAnalysis;
|
|
|
112
125
|
/**
|
|
113
126
|
* 图像调色处理器
|
|
114
127
|
*
|
|
128
|
+
* 支持 WebGL 和 WebGPU 双后端,自动降级
|
|
129
|
+
*
|
|
115
130
|
* @example
|
|
116
131
|
* ```ts
|
|
132
|
+
* // 默认自动选择后端
|
|
117
133
|
* const processor = new ImageColorGrading();
|
|
134
|
+
*
|
|
135
|
+
* // 指定使用 WebGPU
|
|
136
|
+
* const processor = new ImageColorGrading({ backend: 'webgpu' });
|
|
137
|
+
*
|
|
118
138
|
* await processor.loadImage('path/to/image.jpg');
|
|
119
139
|
* processor.setSettings({ brightness: 20, contrast: 10 });
|
|
120
140
|
* processor.render();
|
|
@@ -123,18 +143,32 @@ declare function analyzeImage(imageData: ImageData): ImageAnalysis;
|
|
|
123
143
|
*/
|
|
124
144
|
declare class ImageColorGrading {
|
|
125
145
|
private canvas;
|
|
126
|
-
private
|
|
146
|
+
private backend;
|
|
147
|
+
private backendType;
|
|
127
148
|
private settings;
|
|
128
149
|
private imageLoaded;
|
|
150
|
+
private initPromise;
|
|
129
151
|
/**
|
|
130
152
|
* 创建图像调色处理器
|
|
131
|
-
* @param
|
|
153
|
+
* @param options - 配置选项
|
|
132
154
|
*/
|
|
133
|
-
constructor(
|
|
155
|
+
constructor(options?: ProcessorOptions);
|
|
134
156
|
/**
|
|
135
157
|
* 获取 canvas 元素
|
|
136
158
|
*/
|
|
137
159
|
getCanvas(): HTMLCanvasElement;
|
|
160
|
+
/**
|
|
161
|
+
* 获取当前后端类型
|
|
162
|
+
*/
|
|
163
|
+
getBackendType(): BackendType$1;
|
|
164
|
+
/**
|
|
165
|
+
* 检查 WebGPU 是否可用
|
|
166
|
+
*/
|
|
167
|
+
static isWebGPUSupported(): boolean;
|
|
168
|
+
/**
|
|
169
|
+
* 检查 WebGL 是否可用
|
|
170
|
+
*/
|
|
171
|
+
static isWebGLSupported(): boolean;
|
|
138
172
|
/**
|
|
139
173
|
* 获取当前设置
|
|
140
174
|
*/
|
|
@@ -148,6 +182,14 @@ declare class ImageColorGrading {
|
|
|
148
182
|
* 重置所有设置为默认值
|
|
149
183
|
*/
|
|
150
184
|
resetSettings(): void;
|
|
185
|
+
/**
|
|
186
|
+
* 初始化后端
|
|
187
|
+
*/
|
|
188
|
+
private initBackend;
|
|
189
|
+
/**
|
|
190
|
+
* 确保后端已初始化
|
|
191
|
+
*/
|
|
192
|
+
private ensureBackend;
|
|
151
193
|
/**
|
|
152
194
|
* 从 URL 加载图像
|
|
153
195
|
* @param url - 图像 URL
|
|
@@ -158,7 +200,7 @@ declare class ImageColorGrading {
|
|
|
158
200
|
* 从 HTMLImageElement 加载图像
|
|
159
201
|
* @param image - 图像元素
|
|
160
202
|
*/
|
|
161
|
-
loadFromImage(image: HTMLImageElement): void
|
|
203
|
+
loadFromImage(image: HTMLImageElement): Promise<void>;
|
|
162
204
|
/**
|
|
163
205
|
* 从 File 对象加载图像
|
|
164
206
|
* @param file - File 对象
|
|
@@ -169,7 +211,7 @@ declare class ImageColorGrading {
|
|
|
169
211
|
* 从 ImageData 加载图像
|
|
170
212
|
* @param imageData - ImageData 对象
|
|
171
213
|
*/
|
|
172
|
-
loadFromImageData(imageData: ImageData): void
|
|
214
|
+
loadFromImageData(imageData: ImageData): Promise<void>;
|
|
173
215
|
/**
|
|
174
216
|
* 渲染图像
|
|
175
217
|
*/
|
|
@@ -223,11 +265,140 @@ declare class ImageColorGrading {
|
|
|
223
265
|
* @returns 应用的设置
|
|
224
266
|
*/
|
|
225
267
|
applyPreset(preset: PresetType): ColorGradingSettings;
|
|
226
|
-
|
|
227
|
-
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* 后端抽象接口
|
|
272
|
+
* 定义 WebGL 和 WebGPU 后端的统一接口
|
|
273
|
+
*/
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* 后端类型
|
|
277
|
+
*/
|
|
278
|
+
type BackendType = 'webgl' | 'webgpu';
|
|
279
|
+
/**
|
|
280
|
+
* 后端初始化选项
|
|
281
|
+
*/
|
|
282
|
+
interface BackendOptions {
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* 后端抽象基类
|
|
286
|
+
*/
|
|
287
|
+
declare abstract class BaseBackend {
|
|
288
|
+
protected canvas: HTMLCanvasElement;
|
|
289
|
+
protected width: number;
|
|
290
|
+
protected height: number;
|
|
291
|
+
protected initialized: boolean;
|
|
292
|
+
protected options: BackendOptions;
|
|
293
|
+
constructor(canvas: HTMLCanvasElement, options?: BackendOptions);
|
|
294
|
+
/**
|
|
295
|
+
* 获取后端类型
|
|
296
|
+
*/
|
|
297
|
+
abstract getType(): BackendType;
|
|
298
|
+
/**
|
|
299
|
+
* 检查后端是否可用
|
|
300
|
+
*/
|
|
301
|
+
static isSupported(): boolean;
|
|
302
|
+
/**
|
|
303
|
+
* 初始化后端
|
|
304
|
+
*/
|
|
305
|
+
abstract init(): Promise<void> | void;
|
|
306
|
+
/**
|
|
307
|
+
* 从图像元素加载纹理
|
|
308
|
+
*/
|
|
309
|
+
abstract loadFromImage(image: HTMLImageElement): void;
|
|
310
|
+
/**
|
|
311
|
+
* 从 ImageData 加载纹理
|
|
312
|
+
*/
|
|
313
|
+
abstract loadFromImageData(imageData: ImageData): void;
|
|
314
|
+
/**
|
|
315
|
+
* 渲染图像
|
|
316
|
+
*/
|
|
317
|
+
abstract render(settings: ColorGradingSettings): void;
|
|
318
|
+
/**
|
|
319
|
+
* 获取渲染结果的 ImageData
|
|
320
|
+
*/
|
|
321
|
+
abstract getImageData(): ImageData;
|
|
322
|
+
/**
|
|
323
|
+
* 获取图像尺寸
|
|
324
|
+
*/
|
|
325
|
+
getSize(): {
|
|
326
|
+
width: number;
|
|
327
|
+
height: number;
|
|
328
|
+
};
|
|
329
|
+
/**
|
|
330
|
+
* 检查是否已初始化
|
|
331
|
+
*/
|
|
332
|
+
isInitialized(): boolean;
|
|
333
|
+
/**
|
|
334
|
+
* 销毁后端资源
|
|
335
|
+
*/
|
|
336
|
+
abstract dispose(): void;
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* 检测 WebGPU 支持
|
|
340
|
+
*/
|
|
341
|
+
declare function isWebGPUSupported(): boolean;
|
|
342
|
+
/**
|
|
343
|
+
* 检测 WebGL 支持
|
|
344
|
+
*/
|
|
345
|
+
declare function isWebGLSupported(): boolean;
|
|
346
|
+
/**
|
|
347
|
+
* 自动选择最佳后端
|
|
348
|
+
*/
|
|
349
|
+
declare function selectBestBackend(preferred?: 'auto' | BackendType): BackendType;
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* WebGL 后端实现
|
|
353
|
+
*/
|
|
354
|
+
|
|
355
|
+
declare class WebGLBackend extends BaseBackend {
|
|
356
|
+
private gl;
|
|
357
|
+
private resources;
|
|
358
|
+
constructor(canvas: HTMLCanvasElement, options?: BackendOptions);
|
|
359
|
+
getType(): BackendType;
|
|
360
|
+
static isSupported(): boolean;
|
|
361
|
+
init(): void;
|
|
362
|
+
loadFromImage(image: HTMLImageElement): void;
|
|
363
|
+
loadFromImageData(imageData: ImageData): void;
|
|
364
|
+
render(settings: ColorGradingSettings): void;
|
|
365
|
+
getImageData(): ImageData;
|
|
366
|
+
dispose(): void;
|
|
367
|
+
private getShaderSource;
|
|
368
|
+
private initResources;
|
|
369
|
+
private disposeResources;
|
|
370
|
+
private drawFrame;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* WebGPU 后端实现
|
|
375
|
+
*/
|
|
376
|
+
|
|
377
|
+
declare class WebGPUBackend extends BaseBackend {
|
|
378
|
+
private device;
|
|
379
|
+
private resources;
|
|
380
|
+
constructor(canvas: HTMLCanvasElement, options?: BackendOptions);
|
|
381
|
+
getType(): BackendType;
|
|
382
|
+
static isSupported(): boolean;
|
|
383
|
+
init(): Promise<void>;
|
|
384
|
+
loadFromImage(image: HTMLImageElement): void;
|
|
385
|
+
loadFromImageData(imageData: ImageData): void;
|
|
386
|
+
render(settings: ColorGradingSettings): void;
|
|
387
|
+
getImageData(): ImageData;
|
|
388
|
+
/**
|
|
389
|
+
* 异步获取 ImageData
|
|
390
|
+
*/
|
|
391
|
+
getImageDataAsync(): Promise<ImageData>;
|
|
392
|
+
dispose(): void;
|
|
393
|
+
private getShaderSource;
|
|
394
|
+
private createPipeline;
|
|
395
|
+
private createRenderTarget;
|
|
228
396
|
private initResources;
|
|
397
|
+
private initResourcesFromImageData;
|
|
398
|
+
private setupResources;
|
|
229
399
|
private disposeResources;
|
|
400
|
+
private createUniformBuffer;
|
|
230
401
|
private drawFrame;
|
|
231
402
|
}
|
|
232
403
|
|
|
233
|
-
export { type ColorGradingSettings, type ExportOptions, type ImageAnalysis, ImageColorGrading, type ImageLevels, type PartialColorGradingSettings, type PresetType, analyzeImage, analyzeImageLevels, analyzeImageVibrance, defaultSettings, presets };
|
|
404
|
+
export { type BackendType$1 as BackendType, BaseBackend, type ColorGradingSettings, type ExportOptions, type ImageAnalysis, ImageColorGrading, type ImageLevels, type PartialColorGradingSettings, type PresetType, type ProcessorOptions, WebGLBackend, WebGPUBackend, analyzeImage, analyzeImageLevels, analyzeImageVibrance, defaultSettings, isWebGLSupported, isWebGPUSupported, presets, selectBestBackend };
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var e="\nprecision highp float;\nattribute vec2 aPosition;\nattribute vec2 aTexCoord;\nvarying vec2 vUv;\nvoid main() {\n vUv = aTexCoord;\n gl_Position = vec4(aPosition, 0.0, 1.0);\n}\n",n="\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform vec2 uTexel;\nuniform float uKernel[9];\nuniform float uAmount;\nvoid main(void) {\n vec4 c11 = texture2D(uTexture, vUv - uTexel);\n vec4 c12 = texture2D(uTexture, vec2(vUv.x, vUv.y - uTexel.y));\n vec4 c13 = texture2D(uTexture, vec2(vUv.x + uTexel.x, vUv.y - uTexel.y));\n vec4 c21 = texture2D(uTexture, vec2(vUv.x - uTexel.x, vUv.y));\n vec4 c22 = texture2D(uTexture, vUv);\n vec4 c23 = texture2D(uTexture, vec2(vUv.x + uTexel.x, vUv.y));\n vec4 c31 = texture2D(uTexture, vec2(vUv.x - uTexel.x, vUv.y + uTexel.y));\n vec4 c32 = texture2D(uTexture, vec2(vUv.x, vUv.y + uTexel.y));\n vec4 c33 = texture2D(uTexture, vUv + uTexel);\n vec4 color = c11 * uKernel[0] + c12 * uKernel[1] + c13 * uKernel[2] +\n c21 * uKernel[3] + c22 * uKernel[4] + c23 * uKernel[5] +\n c31 * uKernel[6] + c32 * uKernel[7] + c33 * uKernel[8];\n gl_FragColor = color * uAmount + (c22 * (1.0 - uAmount));\n}\n";function t(e,n,t){const r=e.createShader(n);return r?(e.shaderSource(r,t),e.compileShader(r),e.getShaderParameter(r,e.COMPILE_STATUS)?r:(e.deleteShader(r),null)):null}function r(e,n,r,o){const a=t(e,e.VERTEX_SHADER,n),i=t(e,e.FRAGMENT_SHADER,r);if(!a||!i)throw new Error("Shader compile failed.");const c=function(e,n,t){const r=e.createProgram();return r?(e.attachShader(r,n),e.attachShader(r,t),e.linkProgram(r),e.getProgramParameter(r,e.LINK_STATUS)?r:(e.deleteProgram(r),null)):null}(e,a,i);if(!c)throw new Error("Program link failed.");const u={aPosition:e.getAttribLocation(c,"aPosition"),aTexCoord:e.getAttribLocation(c,"aTexCoord"),apos:e.getAttribLocation(c,"apos"),auv:e.getAttribLocation(c,"auv")},l={};return o.forEach(n=>{l[n]=e.getUniformLocation(c,n)}),{program:c,attribs:u,uniforms:l}}function o(e,n,t){const r=e.createTexture();if(!r)throw new Error("Unable to create texture");e.bindTexture(e.TEXTURE_2D,r),e.texImage2D(e.TEXTURE_2D,0,e.RGBA,n,t,0,e.RGBA,e.UNSIGNED_BYTE,null),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.LINEAR),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_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 o=e.createFramebuffer();if(!o)throw new Error("Unable to create framebuffer");return e.bindFramebuffer(e.FRAMEBUFFER,o),e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,r,0),{framebuffer:o,texture:r}}var a=e=>Math.min(1,Math.max(0,e)),i=(e,n,t,r,o)=>{const a=1-e;return a*a*a*n+3*a*a*e*t+3*a*e*e*r+e*e*e*o},c=e=>{const n=Math.max(-100,Math.min(100,e))/100;return(e=>{const n=new Uint8Array(768);for(let t=0;t<256;t+=1){const r=i(t/255,0,e,.66,1),o=Math.round(255*a(r)),c=3*t;n[c]=o,n[c+1]=o,n[c+2]=o}return n})(a(.33-.35*n))},u={vibrance:0,saturation:0,temperature:0,tint:0,hue:0,brightness:0,exposure:0,contrast:0,blacks:0,whites:0,highlights:0,shadows:0,dehaze:0,bloom:0,glamour:0,clarity:0,sharpen:0,smooth:0,blur:0,vignette:0,grain:0},l={auto:{},blackAndWhite:{saturation:-100,contrast:20,exposure:10,clarity:10},pop:{highlights:50,shadows:-50,vibrance:50,saturation:20,exposure:20,clarity:20},vintage:{saturation:-20,contrast:10,temperature:15,grain:30,vignette:25},vivid:{vibrance:40,saturation:20,contrast:15,clarity:20},cinematic:{contrast:25,highlights:-20,shadows:15,temperature:-10,vignette:30}};function s(e){const{data:n,width:t,height:r}=e,o=new Array(256).fill(0);for(let e=0;e<n.length;e+=4)o[n[e]]+=1,o[n[e+1]]+=1,o[n[e+2]]+=1;const a=Math.round(t*r/1e3);let i=0;for(let e=0;e<256;e++)if(o[e]>a){i=e;break}let c=255;for(let e=255;e>=0;e--)if(o[e]>a){c=e;break}return i>100&&(i=100),c<155&&(c=155),{black:i,white:c}}function v(e){const{data:n,width:t,height:r}=e;let o=1,a=1;for(let e=0;e<n.length;e+=4){const t=n[e],r=n[e+1],i=n[e+2],c=Math.min(t,r,i),u=Math.max(t,r,i);a+=u/255;const l=u-c;l>0&&(o+=l/u)}return(o+a)/(t*r*2)}function m(e){return{levels:s(e),vibrance:v(e)}}var x=class{constructor(e){this.resources=null,this.settings={...u},this.imageLoaded=!1,this.canvas=e||document.createElement("canvas")}getCanvas(){return this.canvas}getSettings(){return{...this.settings}}setSettings(e){this.settings={...this.settings,...e},this.resources&&this.render()}resetSettings(){this.settings={...u},this.resources&&this.render()}loadImage(e){return new Promise((n,t)=>{const r=new Image;r.crossOrigin="anonymous",r.onload=()=>{this.initFromImage(r),n()},r.onerror=()=>{t(new Error(`Failed to load image: ${e}`))},r.src=e})}loadFromImage(e){this.initFromImage(e)}loadFromFile(e){return new Promise((n,t)=>{const r=URL.createObjectURL(e);this.loadImage(r).then(()=>{URL.revokeObjectURL(r),n()}).catch(e=>{URL.revokeObjectURL(r),t(e)})})}loadFromImageData(e){const{width:n,height:t,data:r}=e;this.canvas.width=n,this.canvas.height=t;const o=this.getWebGLContext();if(!o)throw new Error("WebGL not supported");this.disposeResources(),o.viewport(0,0,n,t),o.pixelStorei(o.UNPACK_FLIP_Y_WEBGL,1);const a=o.createTexture();if(!a)throw new Error("Failed to create texture");o.bindTexture(o.TEXTURE_2D,a),o.texImage2D(o.TEXTURE_2D,0,o.RGBA,n,t,0,o.RGBA,o.UNSIGNED_BYTE,r),o.texParameteri(o.TEXTURE_2D,o.TEXTURE_MIN_FILTER,o.LINEAR),o.texParameteri(o.TEXTURE_2D,o.TEXTURE_MAG_FILTER,o.LINEAR),o.texParameteri(o.TEXTURE_2D,o.TEXTURE_WRAP_S,o.CLAMP_TO_EDGE),o.texParameteri(o.TEXTURE_2D,o.TEXTURE_WRAP_T,o.CLAMP_TO_EDGE),this.initResources(o,n,t,a)}render(){this.resources&&this.drawFrame(this.resources,this.settings)}toDataURL(e){const n=e?.format||"image/png",t=e?.quality;return this.canvas.toDataURL(n,t)}toBlob(e){return new Promise((n,t)=>{const r=e?.format||"image/png",o=e?.quality;this.canvas.toBlob(e=>{e?n(e):t(new Error("Failed to create blob"))},r,o)})}getImageData(){const e=this.canvas.getContext("2d");if(e)return e.getImageData(0,0,this.canvas.width,this.canvas.height);const n=this.canvas.getContext("webgl");if(n){const e=new Uint8ClampedArray(this.canvas.width*this.canvas.height*4);return n.readPixels(0,0,this.canvas.width,this.canvas.height,n.RGBA,n.UNSIGNED_BYTE,e),new ImageData(e,this.canvas.width,this.canvas.height)}throw new Error("Cannot get ImageData")}getSize(){return{width:this.canvas.width,height:this.canvas.height}}isLoaded(){return this.imageLoaded}dispose(){this.disposeResources(),this.imageLoaded=!1}analyze(){if(!this.imageLoaded)throw new Error("No image loaded");const e={...this.settings};this.settings={...u},this.render();const n=m(this.getImageData());return this.settings=e,this.render(),n}autoFix(){if(!this.imageLoaded)throw new Error("No image loaded");this.settings={...u},this.render();const e=this.getImageData(),n=s(e),t=v(e),r={...u};if(r.whites=Math.round(255-n.white),r.blacks=Math.round(n.black),t<.7){const e=Math.round(100*(.7-t));r.vibrance=Math.min(e,50)}return this.settings=r,this.render(),r}applyPreset(e){if("auto"===e)return this.autoFix();const n=l[e],t={...u,...n};return this.settings=t,this.resources&&this.render(),t}getWebGLContext(){return this.canvas.getContext("webgl",{antialias:!0,premultipliedAlpha:!1,preserveDrawingBuffer:!0})}initFromImage(e){const n=e.naturalWidth||e.width,t=e.naturalHeight||e.height;this.canvas.width=n,this.canvas.height=t;const r=this.getWebGLContext();if(!r)throw new Error("WebGL not supported");this.disposeResources(),r.disable(r.DEPTH_TEST),r.viewport(0,0,n,t),r.pixelStorei(r.UNPACK_FLIP_Y_WEBGL,1);const o=r.createTexture();if(!o)throw new Error("Failed to create texture");r.bindTexture(r.TEXTURE_2D,o),r.texImage2D(r.TEXTURE_2D,0,r.RGBA,r.RGBA,r.UNSIGNED_BYTE,e),r.texParameteri(r.TEXTURE_2D,r.TEXTURE_MIN_FILTER,r.LINEAR),r.texParameteri(r.TEXTURE_2D,r.TEXTURE_MAG_FILTER,r.LINEAR),r.texParameteri(r.TEXTURE_2D,r.TEXTURE_WRAP_S,r.CLAMP_TO_EDGE),r.texParameteri(r.TEXTURE_2D,r.TEXTURE_WRAP_T,r.CLAMP_TO_EDGE),this.initResources(r,n,t,o)}initResources(t,a,i,u){const l=((e,n)=>{const t=e.createTexture();if(!t)throw new Error("Unable to create palette texture");return e.bindTexture(e.TEXTURE_2D,t),e.texImage2D(e.TEXTURE_2D,0,e.RGB,256,1,0,e.RGB,e.UNSIGNED_BYTE,n),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.NEAREST),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.NEAREST),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),t})(t,c(0)),s=t.createBuffer(),v=t.createBuffer();if(!s||!v)throw new Error("Failed to create buffers");t.bindBuffer(t.ARRAY_BUFFER,s),t.bufferData(t.ARRAY_BUFFER,new Float32Array([-1,-1,1,-1,-1,1,1,1]),t.STATIC_DRAW),t.bindBuffer(t.ARRAY_BUFFER,v),t.bufferData(t.ARRAY_BUFFER,new Float32Array([0,0,1,0,0,1,1,1]),t.STATIC_DRAW);const m={pass:r(t,e,"\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nvoid main() {\n gl_FragColor = texture2D(uTexture, vUv);\n}\n",["uTexture"]),vibrance:r(t,e,"\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uAmount;\nvoid main() {\n vec4 col = texture2D(uTexture, vUv);\n vec3 color = col.rgb;\n float luminance = color.r * 0.299 + color.g * 0.587 + color.b * 0.114;\n float mn = min(min(color.r, color.g), color.b);\n float mx = max(max(color.r, color.g), color.b);\n float sat = (1.0 - (mx - mn)) * (1.0 - mx) * luminance * 5.0;\n vec3 lightness = vec3((mn + mx) / 2.0);\n color = mix(color, mix(color, lightness, -uAmount), sat);\n gl_FragColor = vec4(\n mix(color, lightness, (1.0 - lightness) * (1.0 - uAmount) / 2.0 * abs(uAmount)),\n col.a\n );\n}\n",["uTexture","uAmount"]),saturation:r(t,e,"\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uMatrix[20];\nvoid main(void) {\n vec4 c = texture2D(uTexture, vUv);\n gl_FragColor.r = uMatrix[0] * c.r + uMatrix[1] * c.g + uMatrix[2] * c.b + uMatrix[3] * c.a + uMatrix[4];\n gl_FragColor.g = uMatrix[5] * c.r + uMatrix[6] * c.g + uMatrix[7] * c.b + uMatrix[8] * c.a + uMatrix[9];\n gl_FragColor.b = uMatrix[10] * c.r + uMatrix[11] * c.g + uMatrix[12] * c.b + uMatrix[13] * c.a + uMatrix[14];\n gl_FragColor.a = uMatrix[15] * c.r + uMatrix[16] * c.g + uMatrix[17] * c.b + uMatrix[18] * c.a + uMatrix[19];\n}\n",["uTexture","uMatrix[0]"]),temperature:r(t,e,"\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uAmount;\nvoid main() {\n vec4 color = texture2D(uTexture, vUv);\n color.r = clamp(color.r + uAmount, 0.0, 1.0);\n color.b = clamp(color.b - uAmount, 0.0, 1.0);\n gl_FragColor = color;\n}\n",["uTexture","uAmount"]),tint:r(t,e,"\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uAmount;\nvoid main() {\n vec4 color = texture2D(uTexture, vUv);\n color.g = clamp(color.g + uAmount, 0.0, 1.0);\n gl_FragColor = color;\n}\n",["uTexture","uAmount"]),hue:r(t,e,"\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uRotation;\nvec3 rgb2hsv(vec3 c) {\n vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\n vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));\n vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));\n float d = q.x - min(q.w, q.y);\n float e = 1.0e-10;\n return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\n}\nvec3 hsv2rgb(vec3 c) {\n vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\n return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);\n}\nvoid main() {\n lowp vec4 base = texture2D(uTexture, vUv);\n vec3 hsv = rgb2hsv(base.rgb);\n hsv.x = fract(hsv.x + uRotation);\n gl_FragColor = vec4(hsv2rgb(hsv), base.a);\n}\n",["uTexture","uRotation"]),brightness:r(t,e,"\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uAmount;\nconst float PI = 3.1415926535897932384626433832795;\nvoid main() {\n vec4 color = texture2D(uTexture, vUv);\n if (uAmount >= 0.0) {\n color.r = color.r + uAmount * sin(color.r * PI);\n color.g = color.g + uAmount * sin(color.g * PI);\n color.b = color.b + uAmount * sin(color.b * PI);\n } else {\n color.r = (1.0 + uAmount) * color.r;\n color.g = (1.0 + uAmount) * color.g;\n color.b = (1.0 + uAmount) * color.b;\n }\n gl_FragColor = color;\n}\n",["uTexture","uAmount"]),exposure:r(t,e,"\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uAmount;\nconst float epsilon = 0.000001;\nconst float mx = 1.0 - epsilon;\nconst mat3 matRGBtoROMM = mat3(\n 0.5293459296226501, 0.3300727903842926, 0.14058130979537964,\n 0.09837432950735092, 0.8734610080718994, 0.028164653107523918,\n 0.01688321679830551, 0.11767247319221497, 0.8654443025588989\n);\nconst mat3 matROMMtoRGB = mat3(\n 2.0340757369995117, -0.727334201335907, -0.3067416846752167,\n -0.22881317138671875, 1.2317301034927368, -0.0029169507324695587,\n -0.008569774217903614, -0.1532866358757019, 1.1618564128875732\n);\nfloat ramp(in float t) {\n t *= 2.0;\n if (t >= 1.0) {\n t -= 1.0;\n t = log(0.5) / log(0.5 * (1.0 - t) + 0.9332 * t);\n }\n return clamp(t, 0.001, 10.0);\n}\nvec3 rgb2hsv(in vec3 c) {\n vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\n vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));\n vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));\n float d = q.x - min(q.w, q.y);\n float e = 1.0e-10;\n return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\n}\nvec3 hsv2rgb(in vec3 c) {\n vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\n return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);\n}\nvec3 setHue(in vec3 res, in vec3 base) {\n vec3 hsv = rgb2hsv(base);\n vec3 res_hsv = rgb2hsv(res);\n return hsv2rgb(vec3(hsv.x, res_hsv.y, res_hsv.z));\n}\nvoid main() {\n lowp vec4 col = texture2D(uTexture, vUv);\n vec3 base = col.rgb * matRGBtoROMM;\n float a = abs(uAmount) * col.a + epsilon;\n float v = pow(2.0, a * 2.0 + 1.0) - 2.0;\n float m = mx - exp(-v);\n vec3 res = (uAmount > 0.0) ? (1.0 - exp(-v * base)) / m : log(1.0 - base * m) / -v;\n res = mix(base, res, min(a * 100.0, 1.0));\n res = setHue(res, base);\n res = pow(res, vec3(ramp(1.0 - (0.0 * col.a + 1.0) / 2.0)));\n res = res * matROMMtoRGB;\n gl_FragColor = vec4(res, col.a);\n}\n",["uTexture","uAmount"]),contrast:r(t,e,"\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uMatrix[20];\nvoid main(void) {\n vec4 c = texture2D(uTexture, vUv);\n gl_FragColor.r = uMatrix[0] * c.r + uMatrix[1] * c.g + uMatrix[2] * c.b + uMatrix[3] * c.a + uMatrix[4];\n gl_FragColor.g = uMatrix[5] * c.r + uMatrix[6] * c.g + uMatrix[7] * c.b + uMatrix[8] * c.a + uMatrix[9];\n gl_FragColor.b = uMatrix[10] * c.r + uMatrix[11] * c.g + uMatrix[12] * c.b + uMatrix[13] * c.a + uMatrix[14];\n gl_FragColor.a = uMatrix[15] * c.r + uMatrix[16] * c.g + uMatrix[17] * c.b + uMatrix[18] * c.a + uMatrix[19];\n}\n",["uTexture","uMatrix[0]"]),blacks:r(t,"\nprecision highp float;\nattribute vec2 apos;\nattribute vec2 auv;\nvarying vec2 uv;\nuniform vec4 transform;\nvoid main(void) {\n uv = auv;\n gl_Position = vec4(\n apos.x * transform.x + transform.z,\n apos.y * transform.y + transform.w,\n 0.0,\n 1.0\n );\n}\n","\nprecision highp float;\nvarying vec2 uv;\nuniform sampler2D uTexture;\nuniform sampler2D uPaletteMap;\nvoid main() {\n lowp vec4 base = texture2D(uTexture, uv.xy);\n float r = texture2D(uPaletteMap, vec2(base.r, 0.0)).r;\n float g = texture2D(uPaletteMap, vec2(base.g, 0.0)).g;\n float b = texture2D(uPaletteMap, vec2(base.b, 0.0)).b;\n gl_FragColor = vec4(r, g, b, base.a);\n}\n",["uTexture","uPaletteMap","transform"]),whites:r(t,e,"\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uAmount;\nconst vec3 RGB2Y = vec3(0.2126, 0.7152, 0.0722);\nvoid main() {\n vec4 base = texture2D(uTexture, vUv.xy);\n vec3 color = base.rgb;\n float lum = dot(color, RGB2Y);\n float whiteMask = smoothstep(0.5, 1.0, lum);\n color += uAmount * whiteMask;\n gl_FragColor = vec4(clamp(color, 0.0, 1.0), base.a);\n}\n",["uTexture","uAmount"]),highlights:r(t,e,"\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uAmount;\nconst float epsilon = 0.000001;\nconst float mx = 1.0 - epsilon;\nconst float PI = 3.1415926535897932384626433832795;\nconst mat3 matRGBtoROMM = mat3(\n 0.5293459296226501, 0.3300727903842926, 0.14058130979537964,\n 0.09837432950735092, 0.8734610080718994, 0.028164653107523918,\n 0.01688321679830551, 0.11767247319221497, 0.8654443025588989\n);\nconst mat3 matROMMtoRGB = mat3(\n 2.0340757369995117, -0.727334201335907, -0.3067416846752167,\n -0.22881317138671875, 1.2317301034927368, -0.0029169507324695587,\n -0.008569774217903614, -0.1532866358757019, 1.1618564128875732\n);\nfloat luma_romm(in vec3 color) {\n return dot(color, vec3(0.242655, 0.755158, 0.002187));\n}\nfloat luma(in vec3 color) {\n return dot(color, vec3(0.298839, 0.586811, 0.11435));\n}\nvec3 rgb2hsv(in vec3 c) {\n vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\n vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));\n vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));\n float d = q.x - min(q.w, q.y);\n float e = 1.0e-10;\n return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\n}\nvec3 hsv2rgb(in vec3 c) {\n vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\n return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);\n}\nvec3 setHue(in vec3 res, in vec3 base) {\n vec3 hsv = rgb2hsv(base);\n vec3 res_hsv = rgb2hsv(res);\n return hsv2rgb(vec3(hsv.x, res_hsv.y, res_hsv.z));\n}\nfloat gaussian(in float x) {\n return 1.0 - exp(-PI * 2.0 * x * x);\n}\nvoid main() {\n lowp vec4 col = texture2D(uTexture, vUv);\n lowp vec3 map = col.rgb;\n vec3 base = col.rgb * matRGBtoROMM;\n float base_lum = luma(col.rgb);\n float map_lum = luma_romm(map * matRGBtoROMM);\n float exposure = mix(uAmount, 0.0, 1.0 - map_lum) * col.a;\n float a = abs(exposure) * col.a + epsilon;\n float v = pow(2.0, a + 1.0) - 2.0;\n float m = mx - exp(-v);\n vec3 res = (exposure > 0.0) ? (1.0 - exp(-v * base)) / m : log(1.0 - base * m) / -v;\n res = mix(base, res, min(a * 100.0, 1.0));\n res = setHue(res, base);\n res = res * matROMMtoRGB;\n gl_FragColor = vec4(res, col.a);\n}\n",["uTexture","uAmount"]),shadows:r(t,e,"\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uAmount;\nconst float epsilon = 0.000001;\nconst float mx = 1.0 - epsilon;\nconst float PI = 3.1415926535897932384626433832795;\nconst mat3 matRGBtoROMM = mat3(\n 0.5293459296226501, 0.3300727903842926, 0.14058130979537964,\n 0.09837432950735092, 0.8734610080718994, 0.028164653107523918,\n 0.01688321679830551, 0.11767247319221497, 0.8654443025588989\n);\nconst mat3 matROMMtoRGB = mat3(\n 2.0340757369995117, -0.727334201335907, -0.3067416846752167,\n -0.22881317138671875, 1.2317301034927368, -0.0029169507324695587,\n -0.008569774217903614, -0.1532866358757019, 1.1618564128875732\n);\nfloat luma_romm(in vec3 color) {\n return dot(color, vec3(0.242655, 0.755158, 0.002187));\n}\nfloat luma(in vec3 color) {\n return dot(color, vec3(0.298839, 0.586811, 0.11435));\n}\nvec3 rgb2hsv(in vec3 c) {\n vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\n vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));\n vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));\n float d = q.x - min(q.w, q.y);\n float e = 1.0e-10;\n return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\n}\nvec3 hsv2rgb(in vec3 c) {\n vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\n return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);\n}\nvec3 setHue(in vec3 res, in vec3 base) {\n vec3 hsv = rgb2hsv(base);\n vec3 res_hsv = rgb2hsv(res);\n return hsv2rgb(vec3(hsv.x, res_hsv.y, res_hsv.z));\n}\nfloat gaussian(in float x) {\n return 1.0 - exp(-PI * 2.0 * x * x);\n}\nvoid main() {\n lowp vec4 col = texture2D(uTexture, vUv);\n lowp vec3 map = col.rgb;\n vec3 base = col.rgb * matRGBtoROMM;\n float base_lum = luma(col.rgb);\n float map_lum = luma_romm(map * matRGBtoROMM);\n float exposure = mix(0.0, uAmount, 1.0 - map_lum) * col.a;\n float a = abs(exposure) * col.a + epsilon;\n float v = pow(2.0, a + 1.0) - 2.0;\n float m = mx - exp(-v);\n vec3 res = (exposure > 0.0) ? (1.0 - exp(-v * base)) / m : log(1.0 - base * m) / -v;\n res = mix(base, res, min(a * 100.0, 1.0));\n res = setHue(res, base);\n res = res * matROMMtoRGB;\n gl_FragColor = vec4(res, col.a);\n}\n",["uTexture","uAmount"]),dehaze:r(t,e,"\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uAmount;\nuniform vec2 uSize;\n\nfloat hazeMap(vec2 coord) {\n vec3 color = vec3(1.0);\n vec2 stepSize = vec2(1.0 / uSize.x, 1.0 / uSize.y);\n for (int i = -1; i <= 1; ++i) {\n for (int j = -1; j <= 1; ++j) {\n vec2 offset = vec2(float(i), float(j)) * stepSize;\n vec2 uv = clamp(coord + offset, 0.0, 1.0);\n vec3 sample = texture2D(uTexture, uv).rgb;\n color = min(color, sample);\n }\n }\n return min(color.r, min(color.g, color.b));\n}\n\nvoid main() {\n vec4 base = texture2D(uTexture, vUv);\n float haze = hazeMap(vUv);\n float transmission = 1.0 - 0.95 * haze;\n const float A = 0.95;\n const float t0 = 0.1;\n float t = mix(1.0, max(t0, transmission), uAmount);\n vec3 J = (base.rgb - A) / t + A;\n gl_FragColor = vec4(J, base.a);\n}\n",["uTexture","uAmount","uSize"]),bloom:r(t,e,"\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uAmount;\nuniform vec2 uTexel;\nuniform float uThreshold;\n\nvoid main() {\n vec4 sum = vec4(0.0);\n int j = -2;\n for (int i = -2; i <= 2; i++) sum += texture2D(uTexture, vUv + vec2(float(i), float(j)) * uTexel);\n j = -1;\n for (int i = -2; i <= 2; i++) sum += texture2D(uTexture, vUv + vec2(float(i), float(j)) * uTexel);\n j = 0;\n for (int i = -2; i <= 2; i++) sum += texture2D(uTexture, vUv + vec2(float(i), float(j)) * uTexel);\n j = 1;\n for (int i = -2; i <= 2; i++) sum += texture2D(uTexture, vUv + vec2(float(i), float(j)) * uTexel);\n j = 2;\n for (int i = -2; i <= 2; i++) sum += texture2D(uTexture, vUv + vec2(float(i), float(j)) * uTexel);\n sum /= 25.0;\n vec4 base = texture2D(uTexture, vUv);\n if (length(sum.rgb) > uThreshold) {\n base += sum * uAmount;\n }\n gl_FragColor = base;\n}\n",["uTexture","uAmount","uTexel","uThreshold"]),glamour:r(t,e,"\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uAmount;\nuniform vec2 uTexel;\n\nfloat normpdf(in float x, in float sigma) {\n return 0.39894 * exp(-0.5 * x * x / (sigma * sigma)) / sigma;\n}\n\nvec3 blurMap() {\n const int mSize = 11;\n const int kSize = (mSize - 1) / 2;\n float kernel[mSize];\n vec3 final_colour = vec3(0.0);\n float sigma = 7.0;\n float Z = 0.0;\n for (int j = 0; j <= kSize; ++j) {\n kernel[kSize + j] = kernel[kSize - j] = normpdf(float(j), sigma);\n }\n for (int j = 0; j < mSize; ++j) {\n Z += kernel[j];\n }\n for (int i = -kSize; i <= kSize; ++i) {\n for (int j = -kSize; j <= kSize; ++j) {\n final_colour += kernel[kSize + j] * kernel[kSize + i] *\n texture2D(uTexture, vUv + vec2(float(i), float(j)) * uTexel).rgb;\n }\n }\n return vec3(final_colour / (Z * Z));\n}\n\nfloat luma(vec3 color) {\n return dot(color, vec3(0.299, 0.587, 0.114));\n}\n\nvoid main() {\n vec4 base = texture2D(uTexture, vUv);\n vec3 color = blurMap();\n color = vec3(luma(color));\n color = vec3(\n (base.r <= 0.5) ? (2.0 * base.r * color.r) : (1.0 - 2.0 * (1.0 - base.r) * (1.0 - color.r)),\n (base.g <= 0.5) ? (2.0 * base.g * color.g) : (1.0 - 2.0 * (1.0 - base.g) * (1.0 - color.g)),\n (base.b <= 0.5) ? (2.0 * base.b * color.b) : (1.0 - 2.0 * (1.0 - base.b) * (1.0 - color.b))\n );\n gl_FragColor = mix(base, vec4(color, base.a), uAmount);\n}\n",["uTexture","uAmount","uTexel"]),clarity:r(t,e,"\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uAmount;\nuniform vec2 uTexel;\n\nfloat Lum(vec3 c) {\n return 0.299 * c.r + 0.587 * c.g + 0.114 * c.b;\n}\nfloat BlendOverlayf(float base, float blend) {\n return (base < 0.5 ? (2.0 * base * blend) : (1.0 - 2.0 * (1.0 - base) * (1.0 - blend)));\n}\nvec3 BlendOverlay(vec3 base, vec3 blend) {\n return vec3(BlendOverlayf(base.r, blend.r), BlendOverlayf(base.g, blend.g), BlendOverlayf(base.b, blend.b));\n}\nfloat BlendVividLightf(float base, float blend) {\n float BlendColorBurnf = (((2.0 * blend) == 0.0) ? (2.0 * blend) : max((1.0 - ((1.0 - base) / (2.0 * blend))), 0.0));\n float BlendColorDodgef = (((2.0 * (blend - 0.5)) == 1.0) ? (2.0 * (blend - 0.5)) : min(base / (1.0 - (2.0 * (blend - 0.5))), 1.0));\n return ((blend < 0.5) ? BlendColorBurnf : BlendColorDodgef);\n}\nvec3 BlendVividLight(vec3 base, vec3 blend) {\n return vec3(BlendVividLightf(base.r, blend.r), BlendVividLightf(base.g, blend.g), BlendVividLightf(base.b, blend.b));\n}\nfloat normpdf(in float x, in float sigma) {\n return 0.39894 * exp(-0.5 * x * x / (sigma * sigma)) / sigma;\n}\nvec3 blurMap() {\n const int mSize = 11;\n const int kSize = (mSize - 1) / 2;\n float kernel[mSize];\n vec3 final_colour = vec3(0.0);\n float sigma = 7.0;\n float Z = 0.0;\n for (int j = 0; j <= kSize; ++j) {\n kernel[kSize + j] = kernel[kSize - j] = normpdf(float(j), sigma);\n }\n for (int j = 0; j < mSize; ++j) {\n Z += kernel[j];\n }\n for (int i = -kSize; i <= kSize; ++i) {\n for (int j = -kSize; j <= kSize; ++j) {\n final_colour += kernel[kSize + j] * kernel[kSize + i] *\n texture2D(uTexture, vUv + vec2(float(i), float(j)) * uTexel).rgb;\n }\n }\n return vec3(final_colour / (Z * Z));\n}\nvoid main() {\n vec4 base4 = texture2D(uTexture, vUv);\n vec3 blur = blurMap();\n vec3 base = base4.rgb;\n float intensity = (uAmount < 0.0) ? (uAmount / 2.0) : uAmount;\n float lum = Lum(base);\n vec3 col = vec3(lum);\n vec3 mask = vec3(1.0 - pow(lum, 1.8));\n vec3 layer = vec3(1.0 - Lum(blur));\n vec3 detail = clamp(BlendVividLight(col, layer), 0.0, 1.0);\n vec3 inverse = mix(1.0 - detail, detail, (intensity + 1.0) / 2.0);\n gl_FragColor = vec4(BlendOverlay(base, mix(vec3(0.5), inverse, mask)), base4.a);\n}\n",["uTexture","uAmount","uTexel"]),sharpen:r(t,e,n,["uTexture","uTexel","uKernel[0]","uAmount"]),smooth:r(t,e,n,["uTexture","uTexel","uKernel[0]","uAmount"]),blur:r(t,e,"\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform vec2 uSize;\nfloat random(vec3 scale, float seed) {\n return fract(sin(dot(gl_FragCoord.xyz + seed, scale)) * 43758.5453 + seed);\n}\nvoid main() {\n vec4 color = vec4(0.0);\n float total = 0.0;\n float offset = random(vec3(12.9898, 78.233, 151.7182), 0.0);\n for (int t = -30; t <= 30; t++) {\n float percent = (float(t) + offset - 0.5) / 30.0;\n float weight = 1.0 - abs(percent);\n vec4 sample = texture2D(uTexture, vUv + uSize * percent);\n sample.rgb *= sample.a;\n color += sample * weight;\n total += weight;\n }\n gl_FragColor = color / total;\n gl_FragColor.rgb /= gl_FragColor.a + 0.00001;\n}\n",["uTexture","uSize"]),vignette:r(t,e,"\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uAmount;\nuniform float uSize;\nvoid main() {\n vec4 color = texture2D(uTexture, vUv);\n float dist = distance(vUv, vec2(0.5, 0.5));\n float amt = clamp(uAmount, -1.0, 1.0);\n float edge = dist * (abs(amt) * 0.75 + uSize * 2.0);\n float vignette = smoothstep(0.8, uSize * 0.799, edge);\n if (amt < 0.0) {\n vignette = 1.0 + (1.0 - vignette) * (-amt);\n } else {\n vignette = mix(1.0, vignette, amt);\n }\n color.rgb *= vignette;\n gl_FragColor = color;\n}\n",["uTexture","uAmount","uSize"]),grain:r(t,e,"\nprecision highp float;\nuniform sampler2D uTexture;\nvarying vec2 vUv;\nuniform vec2 uResolution;\nuniform float uAmount;\nuniform float uTime;\nconst float permTexUnit = 1.0 / 256.0;\nconst float permTexUnitHalf = 0.5 / 256.0;\nfloat grainsize = 1.8;\nfloat lumamount = 1.0;\n\nvec4 rnm(in vec2 tc) {\n float noise = sin(dot(tc + vec2(uTime, uTime), vec2(12.9898, 78.233))) * 43758.5453;\n float noiseR = fract(noise) * 2.0 - 1.0;\n float noiseG = fract(noise * 1.2154) * 2.0 - 1.0;\n float noiseB = fract(noise * 1.3453) * 2.0 - 1.0;\n float noiseA = fract(noise * 1.3647) * 2.0 - 1.0;\n return vec4(noiseR, noiseG, noiseB, noiseA);\n}\nfloat fade(in float t) {\n return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);\n}\nfloat pnoise3D(in vec3 p) {\n vec3 pi = permTexUnit * floor(p) + permTexUnitHalf;\n vec3 pf = fract(p);\n float perm00 = rnm(pi.xy).a;\n vec3 grad000 = rnm(vec2(perm00, pi.z)).rgb * 4.0 - 1.0;\n float n000 = dot(grad000, pf);\n vec3 grad001 = rnm(vec2(perm00, pi.z + permTexUnit)).rgb * 4.0 - 1.0;\n float n001 = dot(grad001, pf - vec3(0.0, 0.0, 1.0));\n float perm01 = rnm(pi.xy + vec2(0.0, permTexUnit)).a;\n vec3 grad010 = rnm(vec2(perm01, pi.z)).rgb * 4.0 - 1.0;\n float n010 = dot(grad010, pf - vec3(0.0, 1.0, 0.0));\n vec3 grad011 = rnm(vec2(perm01, pi.z + permTexUnit)).rgb * 4.0 - 1.0;\n float n011 = dot(grad011, pf - vec3(0.0, 1.0, 1.0));\n float perm10 = rnm(pi.xy + vec2(permTexUnit, 0.0)).a;\n vec3 grad100 = rnm(vec2(perm10, pi.z)).rgb * 4.0 - 1.0;\n float n100 = dot(grad100, pf - vec3(1.0, 0.0, 0.0));\n vec3 grad101 = rnm(vec2(perm10, pi.z + permTexUnit)).rgb * 4.0 - 1.0;\n float n101 = dot(grad101, pf - vec3(1.0, 0.0, 1.0));\n float perm11 = rnm(pi.xy + vec2(permTexUnit, permTexUnit)).a;\n vec3 grad110 = rnm(vec2(perm11, pi.z)).rgb * 4.0 - 1.0;\n float n110 = dot(grad110, pf - vec3(1.0, 1.0, 0.0));\n vec3 grad111 = rnm(vec2(perm11, pi.z + permTexUnit)).rgb * 4.0 - 1.0;\n float n111 = dot(grad111, pf - vec3(1.0, 1.0, 1.0));\n vec4 n_x = mix(vec4(n000, n001, n010, n011), vec4(n100, n101, n110, n111), fade(pf.x));\n vec2 n_xy = mix(n_x.xy, n_x.zw, fade(pf.y));\n float n_xyz = mix(n_xy.x, n_xy.y, fade(pf.z));\n return n_xyz;\n}\nvec2 coordRot(in vec2 tc, in float angle) {\n float aspect = uResolution.x / uResolution.y;\n float rotX = ((tc.x * 2.0 - 1.0) * aspect * cos(angle)) - ((tc.y * 2.0 - 1.0) * sin(angle));\n float rotY = ((tc.y * 2.0 - 1.0) * cos(angle)) + ((tc.x * 2.0 - 1.0) * aspect * sin(angle));\n rotX = ((rotX / aspect) * 0.5 + 0.5);\n rotY = rotY * 0.5 + 0.5;\n return vec2(rotX, rotY);\n}\nvoid main() {\n vec3 rotOffset = vec3(1.425, 3.892, 5.835);\n vec2 rotCoordsR = coordRot(vUv, uTime + rotOffset.x);\n vec3 noise = vec3(pnoise3D(vec3(rotCoordsR * vec2(uResolution.x / grainsize, uResolution.y / grainsize), 0.0)));\n vec4 tex = texture2D(uTexture, vUv);\n vec3 col = tex.rgb;\n vec3 lumcoeff = vec3(0.299, 0.587, 0.114);\n float luminance = mix(0.0, dot(col, lumcoeff), lumamount);\n float lum = smoothstep(0.2, 0.0, luminance);\n lum += luminance;\n noise = mix(noise, vec3(0.0), pow(lum, 4.0));\n col = col + noise * uAmount;\n gl_FragColor = vec4(col, tex.a);\n}\n",["uTexture","uResolution","uAmount","uTime"])},x=[o(t,a,i),o(t,a,i)];this.resources={gl:t,width:a,height:i,sourceTexture:u,blackPalette:l,quad:{positionBuffer:s,texCoordBuffer:v},programs:m,targets:x},this.imageLoaded=!0,this.render()}disposeResources(){if(!this.resources)return;const{gl:e,sourceTexture:n,blackPalette:t,quad:r,programs:o,targets:a}=this.resources;e.deleteTexture(n),e.deleteTexture(t),e.deleteBuffer(r.positionBuffer),e.deleteBuffer(r.texCoordBuffer),a.forEach(n=>{e.deleteFramebuffer(n.framebuffer),e.deleteTexture(n.texture)}),Object.values(o).forEach(n=>{e.deleteProgram(n.program)}),this.resources=null}drawFrame(e,n){const{gl:t,width:r,height:o,sourceTexture:a,blackPalette:i,quad:u,programs:l,targets:s}=e;t.viewport(0,0,r,o);const v=[1/r,1/o];let m=a,x=0;const f=(e,n,r)=>{t.useProgram(e.program),(e=>{t.bindBuffer(t.ARRAY_BUFFER,u.positionBuffer);const n=e.attribs.aPosition>=0?e.attribs.aPosition:e.attribs.apos;n>=0&&(t.enableVertexAttribArray(n),t.vertexAttribPointer(n,2,t.FLOAT,!1,0,0)),t.bindBuffer(t.ARRAY_BUFFER,u.texCoordBuffer);const r=e.attribs.aTexCoord>=0?e.attribs.aTexCoord:e.attribs.auv;r>=0&&(t.enableVertexAttribArray(r),t.vertexAttribPointer(r,2,t.FLOAT,!1,0,0))})(e),t.activeTexture(t.TEXTURE0),t.bindTexture(t.TEXTURE_2D,m);const o=e.uniforms.uTexture;o&&t.uniform1i(o,0),n(),t.bindFramebuffer(t.FRAMEBUFFER,r?r.framebuffer:null),t.drawArrays(t.TRIANGLE_STRIP,0,4),m=r?r.texture:m},g=()=>{const e=s[x%2];return x+=1,e};Math.abs(n.vibrance)>.5&&f(l.vibrance,()=>{t.uniform1f(l.vibrance.uniforms.uAmount,n.vibrance/100)},g()),Math.abs(n.saturation)>.5&&f(l.saturation,()=>{const e=(e=>{const n=1+Math.max(-100,Math.min(100,e))/100,t=.299,r=.587,o=.114,a=1-n;return new Float32Array([a*t+n,a*r,a*o,0,0,a*t,a*r+n,a*o,0,0,a*t,a*r,a*o+n,0,0,0,0,0,1,0])})(n.saturation);t.uniform1fv(l.saturation.uniforms["uMatrix[0]"],e)},g()),Math.abs(n.temperature)>.5&&f(l.temperature,()=>{t.uniform1f(l.temperature.uniforms.uAmount,n.temperature/500)},g()),Math.abs(n.tint)>.5&&f(l.tint,()=>{t.uniform1f(l.tint.uniforms.uAmount,n.tint/500)},g()),Math.abs(n.hue)>.5&&f(l.hue,()=>{t.uniform1f(l.hue.uniforms.uRotation,n.hue/200)},g()),f(l.brightness,()=>{t.uniform1f(l.brightness.uniforms.uAmount,n.brightness/200)},g()),Math.abs(n.exposure)>.5&&f(l.exposure,()=>{t.uniform1f(l.exposure.uniforms.uAmount,n.exposure/100)},g()),Math.abs(n.contrast)>.5&&f(l.contrast,()=>{const e=(e=>{const n=1+Math.max(-100,Math.min(100,e))/100,t=.5*(1-n);return new Float32Array([n,0,0,0,t,0,n,0,0,t,0,0,n,0,t,0,0,0,1,0])})(n.contrast);t.uniform1fv(l.contrast.uniforms["uMatrix[0]"],e)},g()),Math.abs(n.blacks)>.5&&(((e,n,t)=>{e.bindTexture(e.TEXTURE_2D,n),e.texSubImage2D(e.TEXTURE_2D,0,0,0,256,1,e.RGB,e.UNSIGNED_BYTE,t)})(t,i,c(n.blacks)),f(l.blacks,()=>{t.activeTexture(t.TEXTURE1),t.bindTexture(t.TEXTURE_2D,i),t.uniform1i(l.blacks.uniforms.uPaletteMap,1),t.uniform4f(l.blacks.uniforms.transform,1,1,0,0),t.activeTexture(t.TEXTURE0)},g())),Math.abs(n.whites)>.5&&f(l.whites,()=>{t.uniform1f(l.whites.uniforms.uAmount,n.whites/400)},g()),Math.abs(n.highlights)>.5&&f(l.highlights,()=>{t.uniform1f(l.highlights.uniforms.uAmount,n.highlights/100)},g()),Math.abs(n.shadows)>.5&&f(l.shadows,()=>{t.uniform1f(l.shadows.uniforms.uAmount,n.shadows/100)},g()),Math.abs(n.dehaze)>.5&&f(l.dehaze,()=>{t.uniform1f(l.dehaze.uniforms.uAmount,n.dehaze/100),t.uniform2f(l.dehaze.uniforms.uSize,r,o)},g()),n.bloom>.5&&f(l.bloom,()=>{t.uniform1f(l.bloom.uniforms.uAmount,n.bloom/100),t.uniform2f(l.bloom.uniforms.uTexel,v[0],v[1]),t.uniform1f(l.bloom.uniforms.uThreshold,.5)},g()),n.glamour>.5&&f(l.glamour,()=>{t.uniform1f(l.glamour.uniforms.uAmount,n.glamour/100),t.uniform2f(l.glamour.uniforms.uTexel,v[0],v[1])},g()),Math.abs(n.clarity)>.5&&f(l.clarity,()=>{t.uniform1f(l.clarity.uniforms.uAmount,n.clarity/100),t.uniform2f(l.clarity.uniforms.uTexel,v[0],v[1])},g()),n.sharpen>.5&&f(l.sharpen,()=>{t.uniform2f(l.sharpen.uniforms.uTexel,v[0],v[1]),t.uniform1f(l.sharpen.uniforms.uAmount,n.sharpen/100),t.uniform1fv(l.sharpen.uniforms["uKernel[0]"],new Float32Array([0,-1,0,-1,5,-1,0,-1,0]))},g()),n.smooth>.5&&f(l.smooth,()=>{t.uniform2f(l.smooth.uniforms.uTexel,v[0],v[1]),t.uniform1f(l.smooth.uniforms.uAmount,n.smooth/100),t.uniform1fv(l.smooth.uniforms["uKernel[0]"],new Float32Array([1/9,1/9,1/9,1/9,1/9,1/9,1/9,1/9,1/9]))},g());const p=n.blur;f(l.blur,()=>{t.uniform2f(l.blur.uniforms.uSize,p/r,0)},g()),f(l.blur,()=>{t.uniform2f(l.blur.uniforms.uSize,0,p/o)},g()),f(l.vignette,()=>{t.uniform1f(l.vignette.uniforms.uAmount,n.vignette/100),t.uniform1f(l.vignette.uniforms.uSize,.25)},g()),f(l.grain,()=>{t.uniform2f(l.grain.uniforms.uResolution,r,o),t.uniform1f(l.grain.uniforms.uAmount,n.grain/800),t.uniform1f(l.grain.uniforms.uTime,0)},g()),f(l.pass,()=>{},null)}};export{x as ImageColorGrading,m as analyzeImage,s as analyzeImageLevels,v as analyzeImageVibrance,u as defaultSettings,l as presets};
|
|
1
|
+
var e=class{constructor(e,n={}){this.width=0,this.height=0,this.initialized=!1,this.canvas=e,this.options=n}static isSupported(){return!1}getSize(){return{width:this.width,height:this.height}}isInitialized(){return this.initialized}};function n(){return"undefined"!=typeof navigator&&"gpu"in navigator}function t(){if("undefined"==typeof document)return!1;try{const e=document.createElement("canvas");return!(!e.getContext("webgl")&&!e.getContext("experimental-webgl"))}catch{return!1}}function r(e){if("webgpu"===e&&n())return"webgpu";if("webgl"===e&&t())return"webgl";if("auto"===e||void 0===e){if(n())return"webgpu";if(t())return"webgl"}throw new Error("No supported graphics backend available")}var a="\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform vec2 uTexel;\nuniform float uKernel[9];\nuniform float uAmount;\nvoid main(void) {\n vec4 c11 = texture2D(uTexture, vUv - uTexel);\n vec4 c12 = texture2D(uTexture, vec2(vUv.x, vUv.y - uTexel.y));\n vec4 c13 = texture2D(uTexture, vec2(vUv.x + uTexel.x, vUv.y - uTexel.y));\n vec4 c21 = texture2D(uTexture, vec2(vUv.x - uTexel.x, vUv.y));\n vec4 c22 = texture2D(uTexture, vUv);\n vec4 c23 = texture2D(uTexture, vec2(vUv.x + uTexel.x, vUv.y));\n vec4 c31 = texture2D(uTexture, vec2(vUv.x - uTexel.x, vUv.y + uTexel.y));\n vec4 c32 = texture2D(uTexture, vec2(vUv.x, vUv.y + uTexel.y));\n vec4 c33 = texture2D(uTexture, vUv + uTexel);\n vec4 color = c11 * uKernel[0] + c12 * uKernel[1] + c13 * uKernel[2] +\n c21 * uKernel[3] + c22 * uKernel[4] + c23 * uKernel[5] +\n c31 * uKernel[6] + c32 * uKernel[7] + c33 * uKernel[8];\n gl_FragColor = color * uAmount + (c22 * (1.0 - uAmount));\n}\n";function o(e,n,t){const r=e.createShader(n);return r?(e.shaderSource(r,t),e.compileShader(r),e.getShaderParameter(r,e.COMPILE_STATUS)?r:(e.deleteShader(r),null)):null}function i(e,n,t,r){const a=o(e,e.VERTEX_SHADER,n),i=o(e,e.FRAGMENT_SHADER,t);if(!a||!i)throw new Error("Shader compile failed.");const s=function(e,n,t){const r=e.createProgram();return r?(e.attachShader(r,n),e.attachShader(r,t),e.linkProgram(r),e.getProgramParameter(r,e.LINK_STATUS)?r:(e.deleteProgram(r),null)):null}(e,a,i);if(!s)throw new Error("Program link failed.");const l={aPosition:e.getAttribLocation(s,"aPosition"),aTexCoord:e.getAttribLocation(s,"aTexCoord"),apos:e.getAttribLocation(s,"apos"),auv:e.getAttribLocation(s,"auv")},u={};return r.forEach(n=>{u[n]=e.getUniformLocation(s,n)}),{program:s,attribs:l,uniforms:u}}function s(e,n,t){const r=e.createTexture();if(!r)throw new Error("Unable to create texture");e.bindTexture(e.TEXTURE_2D,r),e.texImage2D(e.TEXTURE_2D,0,e.RGBA,n,t,0,e.RGBA,e.UNSIGNED_BYTE,null),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.LINEAR),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_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 a=e.createFramebuffer();if(!a)throw new Error("Unable to create framebuffer");return e.bindFramebuffer(e.FRAMEBUFFER,a),e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,r,0),{framebuffer:a,texture:r}}var l=e=>Math.min(1,Math.max(0,e)),u=(e,n,t,r,a)=>{const o=1-e;return o*o*o*n+3*o*o*e*t+3*o*e*e*r+e*e*e*a},c=e=>{const n=Math.max(-100,Math.min(100,e))/100;return(e=>{const n=new Uint8Array(768);for(let t=0;t<256;t+=1){const r=u(t/255,0,e,.66,1),a=Math.round(255*l(r)),o=3*t;n[o]=a,n[o+1]=a,n[o+2]=a}return n})(l(.33-.35*n))},m=class extends e{constructor(e,n={}){super(e,n),this.gl=null,this.resources=null}getType(){return"webgl"}static isSupported(){if("undefined"==typeof document)return!1;try{const e=document.createElement("canvas");return!(!e.getContext("webgl")&&!e.getContext("experimental-webgl"))}catch{return!1}}init(){if(this.gl=this.canvas.getContext("webgl",{antialias:!0,premultipliedAlpha:!1,preserveDrawingBuffer:!0}),!this.gl)throw new Error("WebGL not supported");this.initialized=!0}loadFromImage(e){this.gl||this.init();const n=this.gl,t=e.naturalWidth||e.width,r=e.naturalHeight||e.height;this.width=t,this.height=r,this.canvas.width=t,this.canvas.height=r,this.disposeResources(),n.disable(n.DEPTH_TEST),n.viewport(0,0,t,r),n.pixelStorei(n.UNPACK_FLIP_Y_WEBGL,1);const a=n.createTexture();if(!a)throw new Error("Failed to create texture");n.bindTexture(n.TEXTURE_2D,a),n.texImage2D(n.TEXTURE_2D,0,n.RGBA,n.RGBA,n.UNSIGNED_BYTE,e),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_MIN_FILTER,n.LINEAR),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_MAG_FILTER,n.LINEAR),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_WRAP_S,n.CLAMP_TO_EDGE),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_WRAP_T,n.CLAMP_TO_EDGE),this.initResources(n,t,r,a)}loadFromImageData(e){this.gl||this.init();const n=this.gl,{width:t,height:r,data:a}=e;this.width=t,this.height=r,this.canvas.width=t,this.canvas.height=r,this.disposeResources(),n.viewport(0,0,t,r),n.pixelStorei(n.UNPACK_FLIP_Y_WEBGL,1);const o=n.createTexture();if(!o)throw new Error("Failed to create texture");n.bindTexture(n.TEXTURE_2D,o),n.texImage2D(n.TEXTURE_2D,0,n.RGBA,t,r,0,n.RGBA,n.UNSIGNED_BYTE,a),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_MIN_FILTER,n.LINEAR),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_MAG_FILTER,n.LINEAR),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_WRAP_S,n.CLAMP_TO_EDGE),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_WRAP_T,n.CLAMP_TO_EDGE),this.initResources(n,t,r,o)}render(e){this.resources&&this.drawFrame(this.resources,e)}getImageData(){const e=this.gl;if(e){const n=new Uint8ClampedArray(this.width*this.height*4);return e.readPixels(0,0,this.width,this.height,e.RGBA,e.UNSIGNED_BYTE,n),new ImageData(n,this.width,this.height)}throw new Error("Cannot get ImageData")}dispose(){this.disposeResources(),this.gl=null,this.initialized=!1}getShaderSource(e){return e}initResources(e,n,t,r){const o=((e,n)=>{const t=e.createTexture();if(!t)throw new Error("Unable to create palette texture");return e.bindTexture(e.TEXTURE_2D,t),e.texImage2D(e.TEXTURE_2D,0,e.RGB,256,1,0,e.RGB,e.UNSIGNED_BYTE,n),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.NEAREST),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.NEAREST),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),t})(e,c(0)),l=e.createBuffer(),u=e.createBuffer();if(!l||!u)throw new Error("Failed to create buffers");e.bindBuffer(e.ARRAY_BUFFER,l),e.bufferData(e.ARRAY_BUFFER,new Float32Array([-1,-1,1,-1,-1,1,1,1]),e.STATIC_DRAW),e.bindBuffer(e.ARRAY_BUFFER,u),e.bufferData(e.ARRAY_BUFFER,new Float32Array([0,0,1,0,0,1,1,1]),e.STATIC_DRAW);const m=this.getShaderSource("\nprecision highp float;\nattribute vec2 aPosition;\nattribute vec2 aTexCoord;\nvarying vec2 vUv;\nvoid main() {\n vUv = aTexCoord;\n gl_Position = vec4(aPosition, 0.0, 1.0);\n}\n"),v=this.getShaderSource("\nprecision highp float;\nattribute vec2 apos;\nattribute vec2 auv;\nvarying vec2 uv;\nuniform vec4 transform;\nvoid main(void) {\n uv = auv;\n gl_Position = vec4(\n apos.x * transform.x + transform.z,\n apos.y * transform.y + transform.w,\n 0.0,\n 1.0\n );\n}\n"),f={pass:i(e,m,this.getShaderSource("\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nvoid main() {\n gl_FragColor = texture2D(uTexture, vUv);\n}\n"),["uTexture"]),vibrance:i(e,m,this.getShaderSource("\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uAmount;\nvoid main() {\n vec4 col = texture2D(uTexture, vUv);\n vec3 color = col.rgb;\n float luminance = color.r * 0.299 + color.g * 0.587 + color.b * 0.114;\n float mn = min(min(color.r, color.g), color.b);\n float mx = max(max(color.r, color.g), color.b);\n float sat = (1.0 - (mx - mn)) * (1.0 - mx) * luminance * 5.0;\n vec3 lightness = vec3((mn + mx) / 2.0);\n color = mix(color, mix(color, lightness, -uAmount), sat);\n gl_FragColor = vec4(\n mix(color, lightness, (1.0 - lightness) * (1.0 - uAmount) / 2.0 * abs(uAmount)),\n col.a\n );\n}\n"),["uTexture","uAmount"]),saturation:i(e,m,this.getShaderSource("\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uMatrix[20];\nvoid main(void) {\n vec4 c = texture2D(uTexture, vUv);\n gl_FragColor.r = uMatrix[0] * c.r + uMatrix[1] * c.g + uMatrix[2] * c.b + uMatrix[3] * c.a + uMatrix[4];\n gl_FragColor.g = uMatrix[5] * c.r + uMatrix[6] * c.g + uMatrix[7] * c.b + uMatrix[8] * c.a + uMatrix[9];\n gl_FragColor.b = uMatrix[10] * c.r + uMatrix[11] * c.g + uMatrix[12] * c.b + uMatrix[13] * c.a + uMatrix[14];\n gl_FragColor.a = uMatrix[15] * c.r + uMatrix[16] * c.g + uMatrix[17] * c.b + uMatrix[18] * c.a + uMatrix[19];\n}\n"),["uTexture","uMatrix[0]"]),temperature:i(e,m,this.getShaderSource("\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uAmount;\nvoid main() {\n vec4 color = texture2D(uTexture, vUv);\n color.r = clamp(color.r + uAmount, 0.0, 1.0);\n color.b = clamp(color.b - uAmount, 0.0, 1.0);\n gl_FragColor = color;\n}\n"),["uTexture","uAmount"]),tint:i(e,m,this.getShaderSource("\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uAmount;\nvoid main() {\n vec4 color = texture2D(uTexture, vUv);\n color.g = clamp(color.g + uAmount, 0.0, 1.0);\n gl_FragColor = color;\n}\n"),["uTexture","uAmount"]),hue:i(e,m,this.getShaderSource("\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uRotation;\nvec3 rgb2hsv(vec3 c) {\n vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\n vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));\n vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));\n float d = q.x - min(q.w, q.y);\n float e = 1.0e-10;\n return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\n}\nvec3 hsv2rgb(vec3 c) {\n vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\n return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);\n}\nvoid main() {\n lowp vec4 base = texture2D(uTexture, vUv);\n vec3 hsv = rgb2hsv(base.rgb);\n hsv.x = fract(hsv.x + uRotation);\n gl_FragColor = vec4(hsv2rgb(hsv), base.a);\n}\n"),["uTexture","uRotation"]),brightness:i(e,m,this.getShaderSource("\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uAmount;\nconst float PI = 3.1415926535897932384626433832795;\nvoid main() {\n vec4 color = texture2D(uTexture, vUv);\n if (uAmount >= 0.0) {\n color.r = color.r + uAmount * sin(color.r * PI);\n color.g = color.g + uAmount * sin(color.g * PI);\n color.b = color.b + uAmount * sin(color.b * PI);\n } else {\n color.r = (1.0 + uAmount) * color.r;\n color.g = (1.0 + uAmount) * color.g;\n color.b = (1.0 + uAmount) * color.b;\n }\n gl_FragColor = color;\n}\n"),["uTexture","uAmount"]),exposure:i(e,m,this.getShaderSource("\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uAmount;\nconst float epsilon = 0.000001;\nconst float mx = 1.0 - epsilon;\nconst mat3 matRGBtoROMM = mat3(\n 0.5293459296226501, 0.3300727903842926, 0.14058130979537964,\n 0.09837432950735092, 0.8734610080718994, 0.028164653107523918,\n 0.01688321679830551, 0.11767247319221497, 0.8654443025588989\n);\nconst mat3 matROMMtoRGB = mat3(\n 2.0340757369995117, -0.727334201335907, -0.3067416846752167,\n -0.22881317138671875, 1.2317301034927368, -0.0029169507324695587,\n -0.008569774217903614, -0.1532866358757019, 1.1618564128875732\n);\nfloat ramp(in float t) {\n t *= 2.0;\n if (t >= 1.0) {\n t -= 1.0;\n t = log(0.5) / log(0.5 * (1.0 - t) + 0.9332 * t);\n }\n return clamp(t, 0.001, 10.0);\n}\nvec3 rgb2hsv(in vec3 c) {\n vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\n vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));\n vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));\n float d = q.x - min(q.w, q.y);\n float e = 1.0e-10;\n return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\n}\nvec3 hsv2rgb(in vec3 c) {\n vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\n return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);\n}\nvec3 setHue(in vec3 res, in vec3 base) {\n vec3 hsv = rgb2hsv(base);\n vec3 res_hsv = rgb2hsv(res);\n return hsv2rgb(vec3(hsv.x, res_hsv.y, res_hsv.z));\n}\nvoid main() {\n lowp vec4 col = texture2D(uTexture, vUv);\n vec3 base = col.rgb * matRGBtoROMM;\n float a = abs(uAmount) * col.a + epsilon;\n float v = pow(2.0, a * 2.0 + 1.0) - 2.0;\n float m = mx - exp(-v);\n vec3 res = (uAmount > 0.0) ? (1.0 - exp(-v * base)) / m : log(1.0 - base * m) / -v;\n res = mix(base, res, min(a * 100.0, 1.0));\n res = setHue(res, base);\n res = pow(res, vec3(ramp(1.0 - (0.0 * col.a + 1.0) / 2.0)));\n res = res * matROMMtoRGB;\n gl_FragColor = vec4(res, col.a);\n}\n"),["uTexture","uAmount"]),contrast:i(e,m,this.getShaderSource("\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uMatrix[20];\nvoid main(void) {\n vec4 c = texture2D(uTexture, vUv);\n gl_FragColor.r = uMatrix[0] * c.r + uMatrix[1] * c.g + uMatrix[2] * c.b + uMatrix[3] * c.a + uMatrix[4];\n gl_FragColor.g = uMatrix[5] * c.r + uMatrix[6] * c.g + uMatrix[7] * c.b + uMatrix[8] * c.a + uMatrix[9];\n gl_FragColor.b = uMatrix[10] * c.r + uMatrix[11] * c.g + uMatrix[12] * c.b + uMatrix[13] * c.a + uMatrix[14];\n gl_FragColor.a = uMatrix[15] * c.r + uMatrix[16] * c.g + uMatrix[17] * c.b + uMatrix[18] * c.a + uMatrix[19];\n}\n"),["uTexture","uMatrix[0]"]),blacks:i(e,v,this.getShaderSource("\nprecision highp float;\nvarying vec2 uv;\nuniform sampler2D uTexture;\nuniform sampler2D uPaletteMap;\nvoid main() {\n lowp vec4 base = texture2D(uTexture, uv.xy);\n float r = texture2D(uPaletteMap, vec2(base.r, 0.0)).r;\n float g = texture2D(uPaletteMap, vec2(base.g, 0.0)).g;\n float b = texture2D(uPaletteMap, vec2(base.b, 0.0)).b;\n gl_FragColor = vec4(r, g, b, base.a);\n}\n"),["uTexture","uPaletteMap","transform"]),whites:i(e,m,this.getShaderSource("\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uAmount;\nconst vec3 RGB2Y = vec3(0.2126, 0.7152, 0.0722);\nvoid main() {\n vec4 base = texture2D(uTexture, vUv.xy);\n vec3 color = base.rgb;\n float lum = dot(color, RGB2Y);\n float whiteMask = smoothstep(0.5, 1.0, lum);\n color += uAmount * whiteMask;\n gl_FragColor = vec4(clamp(color, 0.0, 1.0), base.a);\n}\n"),["uTexture","uAmount"]),highlights:i(e,m,this.getShaderSource("\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uAmount;\nconst float epsilon = 0.000001;\nconst float mx = 1.0 - epsilon;\nconst float PI = 3.1415926535897932384626433832795;\nconst mat3 matRGBtoROMM = mat3(\n 0.5293459296226501, 0.3300727903842926, 0.14058130979537964,\n 0.09837432950735092, 0.8734610080718994, 0.028164653107523918,\n 0.01688321679830551, 0.11767247319221497, 0.8654443025588989\n);\nconst mat3 matROMMtoRGB = mat3(\n 2.0340757369995117, -0.727334201335907, -0.3067416846752167,\n -0.22881317138671875, 1.2317301034927368, -0.0029169507324695587,\n -0.008569774217903614, -0.1532866358757019, 1.1618564128875732\n);\nfloat luma_romm(in vec3 color) {\n return dot(color, vec3(0.242655, 0.755158, 0.002187));\n}\nfloat luma(in vec3 color) {\n return dot(color, vec3(0.298839, 0.586811, 0.11435));\n}\nvec3 rgb2hsv(in vec3 c) {\n vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\n vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));\n vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));\n float d = q.x - min(q.w, q.y);\n float e = 1.0e-10;\n return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\n}\nvec3 hsv2rgb(in vec3 c) {\n vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\n return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);\n}\nvec3 setHue(in vec3 res, in vec3 base) {\n vec3 hsv = rgb2hsv(base);\n vec3 res_hsv = rgb2hsv(res);\n return hsv2rgb(vec3(hsv.x, res_hsv.y, res_hsv.z));\n}\nfloat gaussian(in float x) {\n return 1.0 - exp(-PI * 2.0 * x * x);\n}\nvoid main() {\n lowp vec4 col = texture2D(uTexture, vUv);\n lowp vec3 map = col.rgb;\n vec3 base = col.rgb * matRGBtoROMM;\n float base_lum = luma(col.rgb);\n float map_lum = luma_romm(map * matRGBtoROMM);\n float exposure = mix(uAmount, 0.0, 1.0 - map_lum) * col.a;\n float a = abs(exposure) * col.a + epsilon;\n float v = pow(2.0, a + 1.0) - 2.0;\n float m = mx - exp(-v);\n vec3 res = (exposure > 0.0) ? (1.0 - exp(-v * base)) / m : log(1.0 - base * m) / -v;\n res = mix(base, res, min(a * 100.0, 1.0));\n res = setHue(res, base);\n res = res * matROMMtoRGB;\n gl_FragColor = vec4(res, col.a);\n}\n"),["uTexture","uAmount"]),shadows:i(e,m,this.getShaderSource("\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uAmount;\nconst float epsilon = 0.000001;\nconst float mx = 1.0 - epsilon;\nconst float PI = 3.1415926535897932384626433832795;\nconst mat3 matRGBtoROMM = mat3(\n 0.5293459296226501, 0.3300727903842926, 0.14058130979537964,\n 0.09837432950735092, 0.8734610080718994, 0.028164653107523918,\n 0.01688321679830551, 0.11767247319221497, 0.8654443025588989\n);\nconst mat3 matROMMtoRGB = mat3(\n 2.0340757369995117, -0.727334201335907, -0.3067416846752167,\n -0.22881317138671875, 1.2317301034927368, -0.0029169507324695587,\n -0.008569774217903614, -0.1532866358757019, 1.1618564128875732\n);\nfloat luma_romm(in vec3 color) {\n return dot(color, vec3(0.242655, 0.755158, 0.002187));\n}\nfloat luma(in vec3 color) {\n return dot(color, vec3(0.298839, 0.586811, 0.11435));\n}\nvec3 rgb2hsv(in vec3 c) {\n vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\n vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));\n vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));\n float d = q.x - min(q.w, q.y);\n float e = 1.0e-10;\n return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\n}\nvec3 hsv2rgb(in vec3 c) {\n vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\n return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);\n}\nvec3 setHue(in vec3 res, in vec3 base) {\n vec3 hsv = rgb2hsv(base);\n vec3 res_hsv = rgb2hsv(res);\n return hsv2rgb(vec3(hsv.x, res_hsv.y, res_hsv.z));\n}\nfloat gaussian(in float x) {\n return 1.0 - exp(-PI * 2.0 * x * x);\n}\nvoid main() {\n lowp vec4 col = texture2D(uTexture, vUv);\n lowp vec3 map = col.rgb;\n vec3 base = col.rgb * matRGBtoROMM;\n float base_lum = luma(col.rgb);\n float map_lum = luma_romm(map * matRGBtoROMM);\n float exposure = mix(0.0, uAmount, 1.0 - map_lum) * col.a;\n float a = abs(exposure) * col.a + epsilon;\n float v = pow(2.0, a + 1.0) - 2.0;\n float m = mx - exp(-v);\n vec3 res = (exposure > 0.0) ? (1.0 - exp(-v * base)) / m : log(1.0 - base * m) / -v;\n res = mix(base, res, min(a * 100.0, 1.0));\n res = setHue(res, base);\n res = res * matROMMtoRGB;\n gl_FragColor = vec4(res, col.a);\n}\n"),["uTexture","uAmount"]),dehaze:i(e,m,this.getShaderSource("\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uAmount;\nuniform vec2 uSize;\n\nfloat hazeMap(vec2 coord) {\n vec3 color = vec3(1.0);\n vec2 stepSize = vec2(1.0 / uSize.x, 1.0 / uSize.y);\n for (int i = -1; i <= 1; ++i) {\n for (int j = -1; j <= 1; ++j) {\n vec2 offset = vec2(float(i), float(j)) * stepSize;\n vec2 uv = clamp(coord + offset, 0.0, 1.0);\n vec3 sample = texture2D(uTexture, uv).rgb;\n color = min(color, sample);\n }\n }\n return min(color.r, min(color.g, color.b));\n}\n\nvoid main() {\n vec4 base = texture2D(uTexture, vUv);\n float haze = hazeMap(vUv);\n float transmission = 1.0 - 0.95 * haze;\n const float A = 0.95;\n const float t0 = 0.1;\n float t = mix(1.0, max(t0, transmission), uAmount);\n vec3 J = (base.rgb - A) / t + A;\n gl_FragColor = vec4(J, base.a);\n}\n"),["uTexture","uAmount","uSize"]),bloom:i(e,m,this.getShaderSource("\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uAmount;\nuniform vec2 uTexel;\nuniform float uThreshold;\n\nvoid main() {\n vec4 sum = vec4(0.0);\n int j = -2;\n for (int i = -2; i <= 2; i++) sum += texture2D(uTexture, vUv + vec2(float(i), float(j)) * uTexel);\n j = -1;\n for (int i = -2; i <= 2; i++) sum += texture2D(uTexture, vUv + vec2(float(i), float(j)) * uTexel);\n j = 0;\n for (int i = -2; i <= 2; i++) sum += texture2D(uTexture, vUv + vec2(float(i), float(j)) * uTexel);\n j = 1;\n for (int i = -2; i <= 2; i++) sum += texture2D(uTexture, vUv + vec2(float(i), float(j)) * uTexel);\n j = 2;\n for (int i = -2; i <= 2; i++) sum += texture2D(uTexture, vUv + vec2(float(i), float(j)) * uTexel);\n sum /= 25.0;\n vec4 base = texture2D(uTexture, vUv);\n if (length(sum.rgb) > uThreshold) {\n base += sum * uAmount;\n }\n gl_FragColor = base;\n}\n"),["uTexture","uAmount","uTexel","uThreshold"]),glamour:i(e,m,this.getShaderSource("\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uAmount;\nuniform vec2 uTexel;\n\nfloat normpdf(in float x, in float sigma) {\n return 0.39894 * exp(-0.5 * x * x / (sigma * sigma)) / sigma;\n}\n\nvec3 blurMap() {\n const int mSize = 11;\n const int kSize = (mSize - 1) / 2;\n float kernel[mSize];\n vec3 final_colour = vec3(0.0);\n float sigma = 7.0;\n float Z = 0.0;\n for (int j = 0; j <= kSize; ++j) {\n kernel[kSize + j] = kernel[kSize - j] = normpdf(float(j), sigma);\n }\n for (int j = 0; j < mSize; ++j) {\n Z += kernel[j];\n }\n for (int i = -kSize; i <= kSize; ++i) {\n for (int j = -kSize; j <= kSize; ++j) {\n final_colour += kernel[kSize + j] * kernel[kSize + i] *\n texture2D(uTexture, vUv + vec2(float(i), float(j)) * uTexel).rgb;\n }\n }\n return vec3(final_colour / (Z * Z));\n}\n\nfloat luma(vec3 color) {\n return dot(color, vec3(0.299, 0.587, 0.114));\n}\n\nvoid main() {\n vec4 base = texture2D(uTexture, vUv);\n vec3 color = blurMap();\n color = vec3(luma(color));\n color = vec3(\n (base.r <= 0.5) ? (2.0 * base.r * color.r) : (1.0 - 2.0 * (1.0 - base.r) * (1.0 - color.r)),\n (base.g <= 0.5) ? (2.0 * base.g * color.g) : (1.0 - 2.0 * (1.0 - base.g) * (1.0 - color.g)),\n (base.b <= 0.5) ? (2.0 * base.b * color.b) : (1.0 - 2.0 * (1.0 - base.b) * (1.0 - color.b))\n );\n gl_FragColor = mix(base, vec4(color, base.a), uAmount);\n}\n"),["uTexture","uAmount","uTexel"]),clarity:i(e,m,this.getShaderSource("\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uAmount;\nuniform vec2 uTexel;\n\nfloat Lum(vec3 c) {\n return 0.299 * c.r + 0.587 * c.g + 0.114 * c.b;\n}\nfloat BlendOverlayf(float base, float blend) {\n return (base < 0.5 ? (2.0 * base * blend) : (1.0 - 2.0 * (1.0 - base) * (1.0 - blend)));\n}\nvec3 BlendOverlay(vec3 base, vec3 blend) {\n return vec3(BlendOverlayf(base.r, blend.r), BlendOverlayf(base.g, blend.g), BlendOverlayf(base.b, blend.b));\n}\nfloat BlendVividLightf(float base, float blend) {\n float BlendColorBurnf = (((2.0 * blend) == 0.0) ? (2.0 * blend) : max((1.0 - ((1.0 - base) / (2.0 * blend))), 0.0));\n float BlendColorDodgef = (((2.0 * (blend - 0.5)) == 1.0) ? (2.0 * (blend - 0.5)) : min(base / (1.0 - (2.0 * (blend - 0.5))), 1.0));\n return ((blend < 0.5) ? BlendColorBurnf : BlendColorDodgef);\n}\nvec3 BlendVividLight(vec3 base, vec3 blend) {\n return vec3(BlendVividLightf(base.r, blend.r), BlendVividLightf(base.g, blend.g), BlendVividLightf(base.b, blend.b));\n}\nfloat normpdf(in float x, in float sigma) {\n return 0.39894 * exp(-0.5 * x * x / (sigma * sigma)) / sigma;\n}\nvec3 blurMap() {\n const int mSize = 11;\n const int kSize = (mSize - 1) / 2;\n float kernel[mSize];\n vec3 final_colour = vec3(0.0);\n float sigma = 7.0;\n float Z = 0.0;\n for (int j = 0; j <= kSize; ++j) {\n kernel[kSize + j] = kernel[kSize - j] = normpdf(float(j), sigma);\n }\n for (int j = 0; j < mSize; ++j) {\n Z += kernel[j];\n }\n for (int i = -kSize; i <= kSize; ++i) {\n for (int j = -kSize; j <= kSize; ++j) {\n final_colour += kernel[kSize + j] * kernel[kSize + i] *\n texture2D(uTexture, vUv + vec2(float(i), float(j)) * uTexel).rgb;\n }\n }\n return vec3(final_colour / (Z * Z));\n}\nvoid main() {\n vec4 base4 = texture2D(uTexture, vUv);\n vec3 blur = blurMap();\n vec3 base = base4.rgb;\n float intensity = (uAmount < 0.0) ? (uAmount / 2.0) : uAmount;\n float lum = Lum(base);\n vec3 col = vec3(lum);\n vec3 mask = vec3(1.0 - pow(lum, 1.8));\n vec3 layer = vec3(1.0 - Lum(blur));\n vec3 detail = clamp(BlendVividLight(col, layer), 0.0, 1.0);\n vec3 inverse = mix(1.0 - detail, detail, (intensity + 1.0) / 2.0);\n gl_FragColor = vec4(BlendOverlay(base, mix(vec3(0.5), inverse, mask)), base4.a);\n}\n"),["uTexture","uAmount","uTexel"]),sharpen:i(e,m,this.getShaderSource(a),["uTexture","uTexel","uKernel[0]","uAmount"]),smooth:i(e,m,this.getShaderSource(a),["uTexture","uTexel","uKernel[0]","uAmount"]),blur:i(e,m,this.getShaderSource("\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform vec2 uSize;\nfloat random(vec3 scale, float seed) {\n return fract(sin(dot(gl_FragCoord.xyz + seed, scale)) * 43758.5453 + seed);\n}\nvoid main() {\n vec4 color = vec4(0.0);\n float total = 0.0;\n float offset = random(vec3(12.9898, 78.233, 151.7182), 0.0);\n for (int t = -30; t <= 30; t++) {\n float percent = (float(t) + offset - 0.5) / 30.0;\n float weight = 1.0 - abs(percent);\n vec4 sample = texture2D(uTexture, vUv + uSize * percent);\n sample.rgb *= sample.a;\n color += sample * weight;\n total += weight;\n }\n gl_FragColor = color / total;\n gl_FragColor.rgb /= gl_FragColor.a + 0.00001;\n}\n"),["uTexture","uSize"]),vignette:i(e,m,this.getShaderSource("\nprecision highp float;\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform float uAmount;\nuniform float uSize;\nvoid main() {\n vec4 color = texture2D(uTexture, vUv);\n float dist = distance(vUv, vec2(0.5, 0.5));\n float amt = clamp(uAmount, -1.0, 1.0);\n float edge = dist * (abs(amt) * 0.75 + uSize * 2.0);\n float vignette = smoothstep(0.8, uSize * 0.799, edge);\n if (amt < 0.0) {\n vignette = 1.0 + (1.0 - vignette) * (-amt);\n } else {\n vignette = mix(1.0, vignette, amt);\n }\n color.rgb *= vignette;\n gl_FragColor = color;\n}\n"),["uTexture","uAmount","uSize"]),grain:i(e,m,this.getShaderSource("\nprecision highp float;\nuniform sampler2D uTexture;\nvarying vec2 vUv;\nuniform vec2 uResolution;\nuniform float uAmount;\nuniform float uTime;\nconst float permTexUnit = 1.0 / 256.0;\nconst float permTexUnitHalf = 0.5 / 256.0;\nfloat grainsize = 1.8;\nfloat lumamount = 1.0;\n\nvec4 rnm(in vec2 tc) {\n float noise = sin(dot(tc + vec2(uTime, uTime), vec2(12.9898, 78.233))) * 43758.5453;\n float noiseR = fract(noise) * 2.0 - 1.0;\n float noiseG = fract(noise * 1.2154) * 2.0 - 1.0;\n float noiseB = fract(noise * 1.3453) * 2.0 - 1.0;\n float noiseA = fract(noise * 1.3647) * 2.0 - 1.0;\n return vec4(noiseR, noiseG, noiseB, noiseA);\n}\nfloat fade(in float t) {\n return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);\n}\nfloat pnoise3D(in vec3 p) {\n vec3 pi = permTexUnit * floor(p) + permTexUnitHalf;\n vec3 pf = fract(p);\n float perm00 = rnm(pi.xy).a;\n vec3 grad000 = rnm(vec2(perm00, pi.z)).rgb * 4.0 - 1.0;\n float n000 = dot(grad000, pf);\n vec3 grad001 = rnm(vec2(perm00, pi.z + permTexUnit)).rgb * 4.0 - 1.0;\n float n001 = dot(grad001, pf - vec3(0.0, 0.0, 1.0));\n float perm01 = rnm(pi.xy + vec2(0.0, permTexUnit)).a;\n vec3 grad010 = rnm(vec2(perm01, pi.z)).rgb * 4.0 - 1.0;\n float n010 = dot(grad010, pf - vec3(0.0, 1.0, 0.0));\n vec3 grad011 = rnm(vec2(perm01, pi.z + permTexUnit)).rgb * 4.0 - 1.0;\n float n011 = dot(grad011, pf - vec3(0.0, 1.0, 1.0));\n float perm10 = rnm(pi.xy + vec2(permTexUnit, 0.0)).a;\n vec3 grad100 = rnm(vec2(perm10, pi.z)).rgb * 4.0 - 1.0;\n float n100 = dot(grad100, pf - vec3(1.0, 0.0, 0.0));\n vec3 grad101 = rnm(vec2(perm10, pi.z + permTexUnit)).rgb * 4.0 - 1.0;\n float n101 = dot(grad101, pf - vec3(1.0, 0.0, 1.0));\n float perm11 = rnm(pi.xy + vec2(permTexUnit, permTexUnit)).a;\n vec3 grad110 = rnm(vec2(perm11, pi.z)).rgb * 4.0 - 1.0;\n float n110 = dot(grad110, pf - vec3(1.0, 1.0, 0.0));\n vec3 grad111 = rnm(vec2(perm11, pi.z + permTexUnit)).rgb * 4.0 - 1.0;\n float n111 = dot(grad111, pf - vec3(1.0, 1.0, 1.0));\n vec4 n_x = mix(vec4(n000, n001, n010, n011), vec4(n100, n101, n110, n111), fade(pf.x));\n vec2 n_xy = mix(n_x.xy, n_x.zw, fade(pf.y));\n float n_xyz = mix(n_xy.x, n_xy.y, fade(pf.z));\n return n_xyz;\n}\nvec2 coordRot(in vec2 tc, in float angle) {\n float aspect = uResolution.x / uResolution.y;\n float rotX = ((tc.x * 2.0 - 1.0) * aspect * cos(angle)) - ((tc.y * 2.0 - 1.0) * sin(angle));\n float rotY = ((tc.y * 2.0 - 1.0) * cos(angle)) + ((tc.x * 2.0 - 1.0) * aspect * sin(angle));\n rotX = ((rotX / aspect) * 0.5 + 0.5);\n rotY = rotY * 0.5 + 0.5;\n return vec2(rotX, rotY);\n}\nvoid main() {\n vec3 rotOffset = vec3(1.425, 3.892, 5.835);\n vec2 rotCoordsR = coordRot(vUv, uTime + rotOffset.x);\n vec3 noise = vec3(pnoise3D(vec3(rotCoordsR * vec2(uResolution.x / grainsize, uResolution.y / grainsize), 0.0)));\n vec4 tex = texture2D(uTexture, vUv);\n vec3 col = tex.rgb;\n vec3 lumcoeff = vec3(0.299, 0.587, 0.114);\n float luminance = mix(0.0, dot(col, lumcoeff), lumamount);\n float lum = smoothstep(0.2, 0.0, luminance);\n lum += luminance;\n noise = mix(noise, vec3(0.0), pow(lum, 4.0));\n col = col + noise * uAmount;\n gl_FragColor = vec4(col, tex.a);\n}\n"),["uTexture","uResolution","uAmount","uTime"])},x=[s(e,n,t),s(e,n,t)];this.resources={gl:e,width:n,height:t,sourceTexture:r,blackPalette:o,quad:{positionBuffer:l,texCoordBuffer:u},programs:f,targets:x}}disposeResources(){if(!this.resources)return;const{gl:e,sourceTexture:n,blackPalette:t,quad:r,programs:a,targets:o}=this.resources;e.deleteTexture(n),e.deleteTexture(t),e.deleteBuffer(r.positionBuffer),e.deleteBuffer(r.texCoordBuffer),o.forEach(n=>{e.deleteFramebuffer(n.framebuffer),e.deleteTexture(n.texture)}),Object.values(a).forEach(n=>{e.deleteProgram(n.program)}),this.resources=null}drawFrame(e,n){const{gl:t,width:r,height:a,sourceTexture:o,blackPalette:i,quad:s,programs:l,targets:u}=e;t.viewport(0,0,r,a);const m=[1/r,1/a];let v=o,f=0;const x=(e,n,r)=>{t.useProgram(e.program),(e=>{t.bindBuffer(t.ARRAY_BUFFER,s.positionBuffer);const n=e.attribs.aPosition>=0?e.attribs.aPosition:e.attribs.apos;n>=0&&(t.enableVertexAttribArray(n),t.vertexAttribPointer(n,2,t.FLOAT,!1,0,0)),t.bindBuffer(t.ARRAY_BUFFER,s.texCoordBuffer);const r=e.attribs.aTexCoord>=0?e.attribs.aTexCoord:e.attribs.auv;r>=0&&(t.enableVertexAttribArray(r),t.vertexAttribPointer(r,2,t.FLOAT,!1,0,0))})(e),t.activeTexture(t.TEXTURE0),t.bindTexture(t.TEXTURE_2D,v);const a=e.uniforms.uTexture;a&&t.uniform1i(a,0),n(),t.bindFramebuffer(t.FRAMEBUFFER,r?r.framebuffer:null),t.drawArrays(t.TRIANGLE_STRIP,0,4),v=r?r.texture:v},p=()=>{const e=u[f%2];return f+=1,e};Math.abs(n.vibrance)>.5&&x(l.vibrance,()=>{t.uniform1f(l.vibrance.uniforms.uAmount,n.vibrance/100)},p()),Math.abs(n.saturation)>.5&&x(l.saturation,()=>{const e=(e=>{const n=1+Math.max(-100,Math.min(100,e))/100,t=.299,r=.587,a=.114,o=1-n;return new Float32Array([o*t+n,o*r,o*a,0,0,o*t,o*r+n,o*a,0,0,o*t,o*r,o*a+n,0,0,0,0,0,1,0])})(n.saturation);t.uniform1fv(l.saturation.uniforms["uMatrix[0]"],e)},p()),Math.abs(n.temperature)>.5&&x(l.temperature,()=>{t.uniform1f(l.temperature.uniforms.uAmount,n.temperature/500)},p()),Math.abs(n.tint)>.5&&x(l.tint,()=>{t.uniform1f(l.tint.uniforms.uAmount,n.tint/500)},p()),Math.abs(n.hue)>.5&&x(l.hue,()=>{t.uniform1f(l.hue.uniforms.uRotation,n.hue/200)},p()),x(l.brightness,()=>{t.uniform1f(l.brightness.uniforms.uAmount,n.brightness/200)},p()),Math.abs(n.exposure)>.5&&x(l.exposure,()=>{t.uniform1f(l.exposure.uniforms.uAmount,n.exposure/100)},p()),Math.abs(n.contrast)>.5&&x(l.contrast,()=>{const e=(e=>{const n=1+Math.max(-100,Math.min(100,e))/100,t=.5*(1-n);return new Float32Array([n,0,0,0,t,0,n,0,0,t,0,0,n,0,t,0,0,0,1,0])})(n.contrast);t.uniform1fv(l.contrast.uniforms["uMatrix[0]"],e)},p()),Math.abs(n.blacks)>.5&&(((e,n,t)=>{e.bindTexture(e.TEXTURE_2D,n),e.texSubImage2D(e.TEXTURE_2D,0,0,0,256,1,e.RGB,e.UNSIGNED_BYTE,t)})(t,i,c(n.blacks)),x(l.blacks,()=>{t.activeTexture(t.TEXTURE1),t.bindTexture(t.TEXTURE_2D,i),t.uniform1i(l.blacks.uniforms.uPaletteMap,1),t.uniform4f(l.blacks.uniforms.transform,1,1,0,0),t.activeTexture(t.TEXTURE0)},p())),Math.abs(n.whites)>.5&&x(l.whites,()=>{t.uniform1f(l.whites.uniforms.uAmount,n.whites/400)},p()),Math.abs(n.highlights)>.5&&x(l.highlights,()=>{t.uniform1f(l.highlights.uniforms.uAmount,n.highlights/100)},p()),Math.abs(n.shadows)>.5&&x(l.shadows,()=>{t.uniform1f(l.shadows.uniforms.uAmount,n.shadows/100)},p()),Math.abs(n.dehaze)>.5&&x(l.dehaze,()=>{t.uniform1f(l.dehaze.uniforms.uAmount,n.dehaze/100),t.uniform2f(l.dehaze.uniforms.uSize,r,a)},p()),n.bloom>.5&&x(l.bloom,()=>{t.uniform1f(l.bloom.uniforms.uAmount,n.bloom/100),t.uniform2f(l.bloom.uniforms.uTexel,m[0],m[1]),t.uniform1f(l.bloom.uniforms.uThreshold,.5)},p()),n.glamour>.5&&x(l.glamour,()=>{t.uniform1f(l.glamour.uniforms.uAmount,n.glamour/100),t.uniform2f(l.glamour.uniforms.uTexel,m[0],m[1])},p()),Math.abs(n.clarity)>.5&&x(l.clarity,()=>{t.uniform1f(l.clarity.uniforms.uAmount,n.clarity/100),t.uniform2f(l.clarity.uniforms.uTexel,m[0],m[1])},p()),n.sharpen>.5&&x(l.sharpen,()=>{t.uniform2f(l.sharpen.uniforms.uTexel,m[0],m[1]),t.uniform1f(l.sharpen.uniforms.uAmount,n.sharpen/100),t.uniform1fv(l.sharpen.uniforms["uKernel[0]"],new Float32Array([0,-1,0,-1,5,-1,0,-1,0]))},p()),n.smooth>.5&&x(l.smooth,()=>{t.uniform2f(l.smooth.uniforms.uTexel,m[0],m[1]),t.uniform1f(l.smooth.uniforms.uAmount,n.smooth/100),t.uniform1fv(l.smooth.uniforms["uKernel[0]"],new Float32Array([1/9,1/9,1/9,1/9,1/9,1/9,1/9,1/9,1/9]))},p());const g=n.blur;x(l.blur,()=>{t.uniform2f(l.blur.uniforms.uSize,g/r,0)},p()),x(l.blur,()=>{t.uniform2f(l.blur.uniforms.uSize,0,g/a)},p()),x(l.vignette,()=>{t.uniform1f(l.vignette.uniforms.uAmount,n.vignette/100),t.uniform1f(l.vignette.uniforms.uSize,.25)},p()),x(l.grain,()=>{t.uniform2f(l.grain.uniforms.uResolution,r,a),t.uniform1f(l.grain.uniforms.uAmount,n.grain/800),t.uniform1f(l.grain.uniforms.uTime,0)},p()),x(l.pass,()=>{},null)}},v="\nstruct Params {\n matrix: array<vec4<f32>, 5>,\n}\n\n@group(0) @binding(0) var uTexture: texture_2d<f32>;\n@group(0) @binding(1) var uSampler: sampler;\n@group(0) @binding(2) var<uniform> params: Params;\n\n@fragment\nfn main(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {\n let c = textureSample(uTexture, uSampler, uv);\n var result: vec4<f32>;\n result.r = params.matrix[0].x * c.r + params.matrix[0].y * c.g + params.matrix[0].z * c.b + params.matrix[0].w * c.a + params.matrix[1].x;\n result.g = params.matrix[1].y * c.r + params.matrix[1].z * c.g + params.matrix[1].w * c.b + params.matrix[2].x * c.a + params.matrix[2].y;\n result.b = params.matrix[2].z * c.r + params.matrix[2].w * c.g + params.matrix[3].x * c.b + params.matrix[3].y * c.a + params.matrix[3].z;\n result.a = params.matrix[3].w * c.r + params.matrix[4].x * c.g + params.matrix[4].y * c.b + params.matrix[4].z * c.a + params.matrix[4].w;\n return result;\n}\n",f=v,x=e=>Math.min(1,Math.max(0,e)),p=(e,n,t,r,a)=>{const o=1-e;return o*o*o*n+3*o*o*e*t+3*o*e*e*r+e*e*e*a},g=class extends e{constructor(e,n={}){super(e,n),this.device=null,this.resources=null}getType(){return"webgpu"}static isSupported(){return"undefined"!=typeof navigator&&"gpu"in navigator}async init(){if(!navigator.gpu)throw new Error("WebGPU not supported");const e=await navigator.gpu.requestAdapter();if(!e)throw new Error("No WebGPU adapter found");this.device=await e.requestDevice(),this.initialized=!0}loadFromImage(e){if(!this.device)throw new Error("WebGPU not initialized. Call init() first.");const n=e.naturalWidth||e.width,t=e.naturalHeight||e.height;this.width=n,this.height=t,this.canvas.width=n,this.canvas.height=t,this.disposeResources(),this.initResources(this.device,n,t,e)}loadFromImageData(e){if(!this.device)throw new Error("WebGPU not initialized. Call init() first.");const{width:n,height:t}=e;this.width=n,this.height=t,this.canvas.width=n,this.canvas.height=t,this.disposeResources(),this.initResourcesFromImageData(this.device,n,t,e)}render(e){this.resources&&this.drawFrame(this.resources,e)}getImageData(){if(!this.resources)throw new Error("No image loaded");const e=document.createElement("canvas").getContext("2d");if(!e)throw new Error("Cannot create 2D context");const{width:n,height:t}=this.resources;return e.canvas.width=n,e.canvas.height=t,e.drawImage(this.canvas,0,0),e.getImageData(0,0,n,t)}async getImageDataAsync(){if(!this.resources)throw new Error("No image loaded");const{device:e,width:n,height:t,targets:r}=this.resources,a=256*Math.ceil(4*n/256),o=a*t,i=e.createBuffer({size:o,usage:GPUBufferUsage.COPY_DST|GPUBufferUsage.MAP_READ}),s=e.createCommandEncoder();s.copyTextureToBuffer({texture:r[0].texture},{buffer:i,bytesPerRow:a},{width:n,height:t}),e.queue.submit([s.finish()]),await i.mapAsync(GPUMapMode.READ);const l=new Uint8Array(i.getMappedRange()),u=new Uint8ClampedArray(n*t*4);for(let e=0;e<t;e++){const t=e*a,r=e*n*4;u.set(l.subarray(t,t+4*n),r)}return i.unmap(),i.destroy(),new ImageData(u,n,t)}dispose(){this.disposeResources(),this.device=null,this.initialized=!1}getShaderSource(e){return e}createPipeline(e,n,t,r=!0,a=!1){const o=[{binding:0,visibility:GPUShaderStage.FRAGMENT,texture:{sampleType:"float"}},{binding:1,visibility:GPUShaderStage.FRAGMENT,sampler:{type:"filtering"}}];r&&o.push({binding:2,visibility:GPUShaderStage.FRAGMENT,buffer:{type:"uniform"}}),a&&o.push({binding:2,visibility:GPUShaderStage.FRAGMENT,texture:{sampleType:"float"}},{binding:3,visibility:GPUShaderStage.FRAGMENT,sampler:{type:"filtering"}});const i=e.createBindGroupLayout({entries:o}),s=e.createPipelineLayout({bindGroupLayouts:[i]}),l=e.createShaderModule({code:this.getShaderSource("\nstruct VertexOutput {\n @builtin(position) position: vec4<f32>,\n @location(0) uv: vec2<f32>,\n}\n\n@vertex\nfn main(@location(0) position: vec2<f32>, @location(1) uv: vec2<f32>) -> VertexOutput {\n var output: VertexOutput;\n output.position = vec4<f32>(position, 0.0, 1.0);\n output.uv = uv;\n return output;\n}\n")}),u=e.createShaderModule({code:this.getShaderSource(t)});return{pipeline:e.createRenderPipeline({layout:s,vertex:{module:l,entryPoint:"main",buffers:[{arrayStride:16,attributes:[{shaderLocation:0,offset:0,format:"float32x2"},{shaderLocation:1,offset:8,format:"float32x2"}]}]},fragment:{module:u,entryPoint:"main",targets:[{format:n}]},primitive:{topology:"triangle-strip"}}),bindGroupLayout:i}}createRenderTarget(e,n,t,r){const a=e.createTexture({size:{width:n,height:t},format:r,usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.RENDER_ATTACHMENT|GPUTextureUsage.COPY_SRC});return{texture:a,view:a.createView()}}initResources(e,n,t,r){const a=this.canvas.getContext("webgpu");if(!a)throw new Error("Failed to get WebGPU context");const o=navigator.gpu.getPreferredCanvasFormat();a.configure({device:e,format:o,alphaMode:"opaque"});const i=e.createTexture({size:{width:n,height:t},format:"rgba8unorm",usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.COPY_DST|GPUTextureUsage.RENDER_ATTACHMENT}),s=document.createElement("canvas");s.width=n,s.height=t;const l=s.getContext("2d");l.drawImage(r,0,0);const u=l.getImageData(0,0,n,t);e.queue.writeTexture({texture:i},u.data,{bytesPerRow:4*n},{width:n,height:t}),this.setupResources(e,a,o,n,t,i)}initResourcesFromImageData(e,n,t,r){const a=this.canvas.getContext("webgpu");if(!a)throw new Error("Failed to get WebGPU context");const o=navigator.gpu.getPreferredCanvasFormat();a.configure({device:e,format:o,alphaMode:"opaque"});const i=e.createTexture({size:{width:n,height:t},format:"rgba8unorm",usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.COPY_DST|GPUTextureUsage.RENDER_ATTACHMENT});e.queue.writeTexture({texture:i},r.data,{bytesPerRow:4*n},{width:n,height:t}),this.setupResources(e,a,o,n,t,i)}setupResources(e,n,t,r,a,o){const i=e.createSampler({magFilter:"linear",minFilter:"linear",addressModeU:"clamp-to-edge",addressModeV:"clamp-to-edge"}),s=new Float32Array([-1,-1,0,1,1,-1,1,1,-1,1,0,0,1,1,1,0]),l=e.createBuffer({size:s.byteLength,usage:GPUBufferUsage.VERTEX|GPUBufferUsage.COPY_DST});e.queue.writeBuffer(l,0,s);const u="rgba8unorm",c={pass:this.createPipeline(e,t,"\n@group(0) @binding(0) var uTexture: texture_2d<f32>;\n@group(0) @binding(1) var uSampler: sampler;\n\n@fragment\nfn main(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {\n return textureSample(uTexture, uSampler, uv);\n}\n",!1),vibrance:this.createPipeline(e,u,"\nstruct Params {\n amount: f32,\n}\n\n@group(0) @binding(0) var uTexture: texture_2d<f32>;\n@group(0) @binding(1) var uSampler: sampler;\n@group(0) @binding(2) var<uniform> params: Params;\n\n@fragment\nfn main(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {\n let col = textureSample(uTexture, uSampler, uv);\n var color = col.rgb;\n let luminance = color.r * 0.299 + color.g * 0.587 + color.b * 0.114;\n let mn = min(min(color.r, color.g), color.b);\n let mx = max(max(color.r, color.g), color.b);\n let sat = (1.0 - (mx - mn)) * (1.0 - mx) * luminance * 5.0;\n let lightness = vec3<f32>((mn + mx) / 2.0);\n color = mix(color, mix(color, lightness, -params.amount), sat);\n return vec4<f32>(\n mix(color, lightness, (1.0 - lightness) * (1.0 - params.amount) / 2.0 * abs(params.amount)),\n col.a\n );\n}\n"),saturation:this.createPipeline(e,u,v),temperature:this.createPipeline(e,u,"\nstruct Params {\n amount: f32,\n}\n\n@group(0) @binding(0) var uTexture: texture_2d<f32>;\n@group(0) @binding(1) var uSampler: sampler;\n@group(0) @binding(2) var<uniform> params: Params;\n\n@fragment\nfn main(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {\n var color = textureSample(uTexture, uSampler, uv);\n color.r = clamp(color.r + params.amount, 0.0, 1.0);\n color.b = clamp(color.b - params.amount, 0.0, 1.0);\n return color;\n}\n"),tint:this.createPipeline(e,u,"\nstruct Params {\n amount: f32,\n}\n\n@group(0) @binding(0) var uTexture: texture_2d<f32>;\n@group(0) @binding(1) var uSampler: sampler;\n@group(0) @binding(2) var<uniform> params: Params;\n\n@fragment\nfn main(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {\n var color = textureSample(uTexture, uSampler, uv);\n color.g = clamp(color.g + params.amount, 0.0, 1.0);\n return color;\n}\n"),hue:this.createPipeline(e,u,"\nstruct Params {\n rotation: f32,\n}\n\n@group(0) @binding(0) var uTexture: texture_2d<f32>;\n@group(0) @binding(1) var uSampler: sampler;\n@group(0) @binding(2) var<uniform> params: Params;\n\nfn rgb2hsv(c: vec3<f32>) -> vec3<f32> {\n let K = vec4<f32>(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\n let p = mix(vec4<f32>(c.bg, K.wz), vec4<f32>(c.gb, K.xy), vec4<f32>(step(c.b, c.g)));\n let q = mix(vec4<f32>(p.xyw, c.r), vec4<f32>(c.r, p.yzx), vec4<f32>(step(p.x, c.r)));\n let d = q.x - min(q.w, q.y);\n let e = 1.0e-10;\n return vec3<f32>(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\n}\n\nfn hsv2rgb(c: vec3<f32>) -> vec3<f32> {\n let K = vec4<f32>(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n let p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\n return c.z * mix(K.xxx, clamp(p - K.xxx, vec3<f32>(0.0), vec3<f32>(1.0)), c.y);\n}\n\n@fragment\nfn main(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {\n let base = textureSample(uTexture, uSampler, uv);\n var hsv = rgb2hsv(base.rgb);\n hsv.x = fract(hsv.x + params.rotation);\n return vec4<f32>(hsv2rgb(hsv), base.a);\n}\n"),brightness:this.createPipeline(e,u,"\nstruct Params {\n amount: f32,\n}\n\n@group(0) @binding(0) var uTexture: texture_2d<f32>;\n@group(0) @binding(1) var uSampler: sampler;\n@group(0) @binding(2) var<uniform> params: Params;\n\nconst PI: f32 = 3.1415926535897932384626433832795;\n\n@fragment\nfn main(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {\n var color = textureSample(uTexture, uSampler, uv);\n if (params.amount >= 0.0) {\n color.r = color.r + params.amount * sin(color.r * PI);\n color.g = color.g + params.amount * sin(color.g * PI);\n color.b = color.b + params.amount * sin(color.b * PI);\n } else {\n color.r = (1.0 + params.amount) * color.r;\n color.g = (1.0 + params.amount) * color.g;\n color.b = (1.0 + params.amount) * color.b;\n }\n return color;\n}\n"),exposure:this.createPipeline(e,u,"\nstruct Params {\n amount: f32,\n}\n\n@group(0) @binding(0) var uTexture: texture_2d<f32>;\n@group(0) @binding(1) var uSampler: sampler;\n@group(0) @binding(2) var<uniform> params: Params;\n\nconst epsilon: f32 = 0.000001;\nconst mx: f32 = 1.0 - 0.000001;\n\n// GLSL mat3 列主序: mat3(col0_elem0, col0_elem1, col0_elem2, col1_elem0, ...)\n// WGSL mat3x3 也是列主序: mat3x3(vec3_col0, vec3_col1, vec3_col2)\nconst matRGBtoROMM = mat3x3<f32>(\n vec3<f32>(0.5293459296226501, 0.3300727903842926, 0.14058130979537964), // 第一列\n vec3<f32>(0.09837432950735092, 0.8734610080718994, 0.028164653107523918), // 第二列\n vec3<f32>(0.01688321679830551, 0.11767247319221497, 0.8654443025588989) // 第三列\n);\n\nconst matROMMtoRGB = mat3x3<f32>(\n vec3<f32>(2.0340757369995117, -0.727334201335907, -0.3067416846752167), // 第一列\n vec3<f32>(-0.22881317138671875, 1.2317301034927368, -0.0029169507324695587), // 第二列\n vec3<f32>(-0.008569774217903614, -0.1532866358757019, 1.1618564128875732) // 第三列\n);\n\nfn rgb2hsv(c: vec3<f32>) -> vec3<f32> {\n let K = vec4<f32>(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\n let p = mix(vec4<f32>(c.bg, K.wz), vec4<f32>(c.gb, K.xy), vec4<f32>(step(c.b, c.g)));\n let q = mix(vec4<f32>(p.xyw, c.r), vec4<f32>(c.r, p.yzx), vec4<f32>(step(p.x, c.r)));\n let d = q.x - min(q.w, q.y);\n let e = 1.0e-10;\n return vec3<f32>(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\n}\n\nfn hsv2rgb(c: vec3<f32>) -> vec3<f32> {\n let K = vec4<f32>(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n let p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\n return c.z * mix(K.xxx, clamp(p - K.xxx, vec3<f32>(0.0), vec3<f32>(1.0)), c.y);\n}\n\nfn setHue(res: vec3<f32>, base: vec3<f32>) -> vec3<f32> {\n let hsv = rgb2hsv(base);\n let res_hsv = rgb2hsv(res);\n return hsv2rgb(vec3<f32>(hsv.x, res_hsv.y, res_hsv.z));\n}\n\nfn ramp(t_in: f32) -> f32 {\n var t = t_in * 2.0;\n if (t >= 1.0) {\n t = t - 1.0;\n t = log(0.5) / log(0.5 * (1.0 - t) + 0.9332 * t);\n }\n return clamp(t, 0.001, 10.0);\n}\n\n@fragment\nfn main(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {\n let col = textureSample(uTexture, uSampler, uv);\n var base = col.rgb * matRGBtoROMM;\n let a = abs(params.amount) * col.a + epsilon;\n let v = pow(2.0, a * 2.0 + 1.0) - 2.0;\n let m = mx - exp(-v);\n var res: vec3<f32>;\n if (params.amount > 0.0) {\n res = (1.0 - exp(-v * base)) / m;\n } else {\n res = log(1.0 - base * m) / -v;\n }\n res = mix(base, res, min(a * 100.0, 1.0));\n res = setHue(res, base);\n res = pow(res, vec3<f32>(ramp(1.0 - (0.0 * col.a + 1.0) / 2.0)));\n res = res * matROMMtoRGB;\n return vec4<f32>(res, col.a);\n}\n"),contrast:this.createPipeline(e,u,f),blacks:this.createPipeline(e,u,"\n@group(0) @binding(0) var uTexture: texture_2d<f32>;\n@group(0) @binding(1) var uSampler: sampler;\n@group(0) @binding(2) var uPaletteMap: texture_2d<f32>;\n@group(0) @binding(3) var uPaletteSampler: sampler;\n\n@fragment\nfn main(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {\n let base = textureSample(uTexture, uSampler, uv);\n let r = textureSample(uPaletteMap, uPaletteSampler, vec2<f32>(base.r, 0.0)).r;\n let g = textureSample(uPaletteMap, uPaletteSampler, vec2<f32>(base.g, 0.0)).g;\n let b = textureSample(uPaletteMap, uPaletteSampler, vec2<f32>(base.b, 0.0)).b;\n return vec4<f32>(r, g, b, base.a);\n}\n",!1,!0),whites:this.createPipeline(e,u,"\nstruct Params {\n amount: f32,\n}\n\n@group(0) @binding(0) var uTexture: texture_2d<f32>;\n@group(0) @binding(1) var uSampler: sampler;\n@group(0) @binding(2) var<uniform> params: Params;\n\nconst RGB2Y = vec3<f32>(0.2126, 0.7152, 0.0722);\n\n@fragment\nfn main(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {\n let base = textureSample(uTexture, uSampler, uv);\n var color = base.rgb;\n let lum = dot(color, RGB2Y);\n let whiteMask = smoothstep(0.5, 1.0, lum);\n color = color + params.amount * whiteMask;\n return vec4<f32>(clamp(color, vec3<f32>(0.0), vec3<f32>(1.0)), base.a);\n}\n"),highlights:this.createPipeline(e,u,"\nstruct Params {\n amount: f32,\n}\n\n@group(0) @binding(0) var uTexture: texture_2d<f32>;\n@group(0) @binding(1) var uSampler: sampler;\n@group(0) @binding(2) var<uniform> params: Params;\n\nconst epsilon: f32 = 0.000001;\nconst mx: f32 = 1.0 - 0.000001;\n\nconst matRGBtoROMM = mat3x3<f32>(\n vec3<f32>(0.5293459296226501, 0.3300727903842926, 0.14058130979537964),\n vec3<f32>(0.09837432950735092, 0.8734610080718994, 0.028164653107523918),\n vec3<f32>(0.01688321679830551, 0.11767247319221497, 0.8654443025588989)\n);\n\nconst matROMMtoRGB = mat3x3<f32>(\n vec3<f32>(2.0340757369995117, -0.727334201335907, -0.3067416846752167),\n vec3<f32>(-0.22881317138671875, 1.2317301034927368, -0.0029169507324695587),\n vec3<f32>(-0.008569774217903614, -0.1532866358757019, 1.1618564128875732)\n);\n\nfn luma_romm(color: vec3<f32>) -> f32 {\n return dot(color, vec3<f32>(0.242655, 0.755158, 0.002187));\n}\n\nfn rgb2hsv(c: vec3<f32>) -> vec3<f32> {\n let K = vec4<f32>(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\n let p = mix(vec4<f32>(c.bg, K.wz), vec4<f32>(c.gb, K.xy), vec4<f32>(step(c.b, c.g)));\n let q = mix(vec4<f32>(p.xyw, c.r), vec4<f32>(c.r, p.yzx), vec4<f32>(step(p.x, c.r)));\n let d = q.x - min(q.w, q.y);\n let e = 1.0e-10;\n return vec3<f32>(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\n}\n\nfn hsv2rgb(c: vec3<f32>) -> vec3<f32> {\n let K = vec4<f32>(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n let p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\n return c.z * mix(K.xxx, clamp(p - K.xxx, vec3<f32>(0.0), vec3<f32>(1.0)), c.y);\n}\n\nfn setHue(res: vec3<f32>, base: vec3<f32>) -> vec3<f32> {\n let hsv = rgb2hsv(base);\n let res_hsv = rgb2hsv(res);\n return hsv2rgb(vec3<f32>(hsv.x, res_hsv.y, res_hsv.z));\n}\n\n@fragment\nfn main(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {\n let col = textureSample(uTexture, uSampler, uv);\n let map = col.rgb;\n var base = col.rgb * matRGBtoROMM;\n let map_lum = luma_romm(map * matRGBtoROMM);\n let exposure = mix(params.amount, 0.0, 1.0 - map_lum) * col.a;\n let a = abs(exposure) * col.a + epsilon;\n let v = pow(2.0, a + 1.0) - 2.0;\n let m = mx - exp(-v);\n var res: vec3<f32>;\n if (exposure > 0.0) {\n res = (1.0 - exp(-v * base)) / m;\n } else {\n res = log(1.0 - base * m) / -v;\n }\n res = mix(base, res, min(a * 100.0, 1.0));\n res = setHue(res, base);\n res = res * matROMMtoRGB;\n return vec4<f32>(res, col.a);\n}\n"),shadows:this.createPipeline(e,u,"\nstruct Params {\n amount: f32,\n}\n\n@group(0) @binding(0) var uTexture: texture_2d<f32>;\n@group(0) @binding(1) var uSampler: sampler;\n@group(0) @binding(2) var<uniform> params: Params;\n\nconst epsilon: f32 = 0.000001;\nconst mx: f32 = 1.0 - 0.000001;\n\nconst matRGBtoROMM = mat3x3<f32>(\n vec3<f32>(0.5293459296226501, 0.3300727903842926, 0.14058130979537964),\n vec3<f32>(0.09837432950735092, 0.8734610080718994, 0.028164653107523918),\n vec3<f32>(0.01688321679830551, 0.11767247319221497, 0.8654443025588989)\n);\n\nconst matROMMtoRGB = mat3x3<f32>(\n vec3<f32>(2.0340757369995117, -0.727334201335907, -0.3067416846752167),\n vec3<f32>(-0.22881317138671875, 1.2317301034927368, -0.0029169507324695587),\n vec3<f32>(-0.008569774217903614, -0.1532866358757019, 1.1618564128875732)\n);\n\nfn luma_romm(color: vec3<f32>) -> f32 {\n return dot(color, vec3<f32>(0.242655, 0.755158, 0.002187));\n}\n\nfn rgb2hsv(c: vec3<f32>) -> vec3<f32> {\n let K = vec4<f32>(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\n let p = mix(vec4<f32>(c.bg, K.wz), vec4<f32>(c.gb, K.xy), vec4<f32>(step(c.b, c.g)));\n let q = mix(vec4<f32>(p.xyw, c.r), vec4<f32>(c.r, p.yzx), vec4<f32>(step(p.x, c.r)));\n let d = q.x - min(q.w, q.y);\n let e = 1.0e-10;\n return vec3<f32>(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\n}\n\nfn hsv2rgb(c: vec3<f32>) -> vec3<f32> {\n let K = vec4<f32>(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n let p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\n return c.z * mix(K.xxx, clamp(p - K.xxx, vec3<f32>(0.0), vec3<f32>(1.0)), c.y);\n}\n\nfn setHue(res: vec3<f32>, base: vec3<f32>) -> vec3<f32> {\n let hsv = rgb2hsv(base);\n let res_hsv = rgb2hsv(res);\n return hsv2rgb(vec3<f32>(hsv.x, res_hsv.y, res_hsv.z));\n}\n\n@fragment\nfn main(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {\n let col = textureSample(uTexture, uSampler, uv);\n let map = col.rgb;\n var base = col.rgb * matRGBtoROMM;\n let map_lum = luma_romm(map * matRGBtoROMM);\n let exposure = mix(0.0, params.amount, 1.0 - map_lum) * col.a;\n let a = abs(exposure) * col.a + epsilon;\n let v = pow(2.0, a + 1.0) - 2.0;\n let m = mx - exp(-v);\n var res: vec3<f32>;\n if (exposure > 0.0) {\n res = (1.0 - exp(-v * base)) / m;\n } else {\n res = log(1.0 - base * m) / -v;\n }\n res = mix(base, res, min(a * 100.0, 1.0));\n res = setHue(res, base);\n res = res * matROMMtoRGB;\n return vec4<f32>(res, col.a);\n}\n"),dehaze:this.createPipeline(e,u,"\nstruct Params {\n amount: f32,\n width: f32,\n height: f32,\n _pad: f32,\n}\n\n@group(0) @binding(0) var uTexture: texture_2d<f32>;\n@group(0) @binding(1) var uSampler: sampler;\n@group(0) @binding(2) var<uniform> params: Params;\n\nfn hazeMap(coord: vec2<f32>) -> f32 {\n var color = vec3<f32>(1.0);\n let stepSize = vec2<f32>(1.0 / params.width, 1.0 / params.height);\n for (var i: i32 = -1; i <= 1; i = i + 1) {\n for (var j: i32 = -1; j <= 1; j = j + 1) {\n let offset = vec2<f32>(f32(i), f32(j)) * stepSize;\n let uv = clamp(coord + offset, vec2<f32>(0.0), vec2<f32>(1.0));\n let sample = textureSample(uTexture, uSampler, uv).rgb;\n color = min(color, sample);\n }\n }\n return min(color.r, min(color.g, color.b));\n}\n\n@fragment\nfn main(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {\n let base = textureSample(uTexture, uSampler, uv);\n let haze = hazeMap(uv);\n let transmission = 1.0 - 0.95 * haze;\n let A = 0.95;\n let t0 = 0.1;\n let t = mix(1.0, max(t0, transmission), params.amount);\n let J = (base.rgb - A) / t + A;\n return vec4<f32>(J, base.a);\n}\n"),bloom:this.createPipeline(e,u,"\nstruct Params {\n amount: f32,\n texelX: f32,\n texelY: f32,\n threshold: f32,\n}\n\n@group(0) @binding(0) var uTexture: texture_2d<f32>;\n@group(0) @binding(1) var uSampler: sampler;\n@group(0) @binding(2) var<uniform> params: Params;\n\n@fragment\nfn main(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {\n var sum = vec4<f32>(0.0);\n let texel = vec2<f32>(params.texelX, params.texelY);\n \n for (var j: i32 = -2; j <= 2; j = j + 1) {\n for (var i: i32 = -2; i <= 2; i = i + 1) {\n sum = sum + textureSample(uTexture, uSampler, uv + vec2<f32>(f32(i), f32(j)) * texel);\n }\n }\n sum = sum / 25.0;\n \n var base = textureSample(uTexture, uSampler, uv);\n if (length(sum.rgb) > params.threshold) {\n base = base + sum * params.amount;\n }\n return base;\n}\n"),glamour:this.createPipeline(e,u,"\nstruct Params {\n amount: f32,\n texelX: f32,\n texelY: f32,\n _pad: f32,\n}\n\n@group(0) @binding(0) var uTexture: texture_2d<f32>;\n@group(0) @binding(1) var uSampler: sampler;\n@group(0) @binding(2) var<uniform> params: Params;\n\nfn normpdf(x: f32, sigma: f32) -> f32 {\n return 0.39894 * exp(-0.5 * x * x / (sigma * sigma)) / sigma;\n}\n\nfn luma(color: vec3<f32>) -> f32 {\n return dot(color, vec3<f32>(0.299, 0.587, 0.114));\n}\n\n@fragment\nfn main(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {\n let texel = vec2<f32>(params.texelX, params.texelY);\n let sigma = 7.0;\n var final_colour = vec3<f32>(0.0);\n var Z = 0.0;\n \n // 简化版高斯模糊\n for (var i: i32 = -5; i <= 5; i = i + 1) {\n for (var j: i32 = -5; j <= 5; j = j + 1) {\n let weight = normpdf(f32(i), sigma) * normpdf(f32(j), sigma);\n final_colour = final_colour + weight * textureSample(uTexture, uSampler, uv + vec2<f32>(f32(i), f32(j)) * texel).rgb;\n Z = Z + weight;\n }\n }\n final_colour = final_colour / Z;\n \n let base = textureSample(uTexture, uSampler, uv);\n var color = vec3<f32>(luma(final_colour));\n \n // Soft light blend\n color = vec3<f32>(\n select(1.0 - 2.0 * (1.0 - base.r) * (1.0 - color.r), 2.0 * base.r * color.r, base.r <= 0.5),\n select(1.0 - 2.0 * (1.0 - base.g) * (1.0 - color.g), 2.0 * base.g * color.g, base.g <= 0.5),\n select(1.0 - 2.0 * (1.0 - base.b) * (1.0 - color.b), 2.0 * base.b * color.b, base.b <= 0.5)\n );\n \n return mix(base, vec4<f32>(color, base.a), params.amount);\n}\n"),clarity:this.createPipeline(e,u,"\nstruct Params {\n amount: f32,\n texelX: f32,\n texelY: f32,\n _pad: f32,\n}\n\n@group(0) @binding(0) var uTexture: texture_2d<f32>;\n@group(0) @binding(1) var uSampler: sampler;\n@group(0) @binding(2) var<uniform> params: Params;\n\nfn Lum(c: vec3<f32>) -> f32 {\n return 0.299 * c.r + 0.587 * c.g + 0.114 * c.b;\n}\n\nfn BlendOverlayf(base: f32, blend: f32) -> f32 {\n return select(1.0 - 2.0 * (1.0 - base) * (1.0 - blend), 2.0 * base * blend, base < 0.5);\n}\n\nfn BlendOverlay(base: vec3<f32>, blend: vec3<f32>) -> vec3<f32> {\n return vec3<f32>(BlendOverlayf(base.r, blend.r), BlendOverlayf(base.g, blend.g), BlendOverlayf(base.b, blend.b));\n}\n\nfn BlendVividLightf(base: f32, blend: f32) -> f32 {\n let BlendColorBurnf = select(max(1.0 - ((1.0 - base) / (2.0 * blend)), 0.0), 2.0 * blend, (2.0 * blend) == 0.0);\n let BlendColorDodgef = select(min(base / (1.0 - (2.0 * (blend - 0.5))), 1.0), 2.0 * (blend - 0.5), (2.0 * (blend - 0.5)) == 1.0);\n return select(BlendColorDodgef, BlendColorBurnf, blend < 0.5);\n}\n\nfn BlendVividLight(base: vec3<f32>, blend: vec3<f32>) -> vec3<f32> {\n return vec3<f32>(BlendVividLightf(base.r, blend.r), BlendVividLightf(base.g, blend.g), BlendVividLightf(base.b, blend.b));\n}\n\nfn normpdf(x: f32, sigma: f32) -> f32 {\n return 0.39894 * exp(-0.5 * x * x / (sigma * sigma)) / sigma;\n}\n\n@fragment\nfn main(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {\n let texel = vec2<f32>(params.texelX, params.texelY);\n let sigma = 7.0;\n var blur = vec3<f32>(0.0);\n var Z = 0.0;\n \n for (var i: i32 = -5; i <= 5; i = i + 1) {\n for (var j: i32 = -5; j <= 5; j = j + 1) {\n let weight = normpdf(f32(i), sigma) * normpdf(f32(j), sigma);\n blur = blur + weight * textureSample(uTexture, uSampler, uv + vec2<f32>(f32(i), f32(j)) * texel).rgb;\n Z = Z + weight;\n }\n }\n blur = blur / Z;\n \n let base4 = textureSample(uTexture, uSampler, uv);\n let base = base4.rgb;\n var intensity = params.amount;\n if (params.amount < 0.0) {\n intensity = params.amount / 2.0;\n }\n \n let lum = Lum(base);\n let col = vec3<f32>(lum);\n let mask = vec3<f32>(1.0 - pow(lum, 1.8));\n let layer = vec3<f32>(1.0 - Lum(blur));\n let detail = clamp(BlendVividLight(col, layer), vec3<f32>(0.0), vec3<f32>(1.0));\n let inverse = mix(1.0 - detail, detail, (intensity + 1.0) / 2.0);\n \n return vec4<f32>(BlendOverlay(base, mix(vec3<f32>(0.5), inverse, mask)), base4.a);\n}\n"),kernel:this.createPipeline(e,u,"\nstruct Params {\n texelX: f32,\n texelY: f32,\n amount: f32,\n _pad: f32,\n kernel: array<f32, 12>, // 9 + 3 padding\n}\n\n@group(0) @binding(0) var uTexture: texture_2d<f32>;\n@group(0) @binding(1) var uSampler: sampler;\n@group(0) @binding(2) var<uniform> params: Params;\n\n@fragment\nfn main(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {\n let texel = vec2<f32>(params.texelX, params.texelY);\n \n let c11 = textureSample(uTexture, uSampler, uv - texel);\n let c12 = textureSample(uTexture, uSampler, vec2<f32>(uv.x, uv.y - texel.y));\n let c13 = textureSample(uTexture, uSampler, vec2<f32>(uv.x + texel.x, uv.y - texel.y));\n let c21 = textureSample(uTexture, uSampler, vec2<f32>(uv.x - texel.x, uv.y));\n let c22 = textureSample(uTexture, uSampler, uv);\n let c23 = textureSample(uTexture, uSampler, vec2<f32>(uv.x + texel.x, uv.y));\n let c31 = textureSample(uTexture, uSampler, vec2<f32>(uv.x - texel.x, uv.y + texel.y));\n let c32 = textureSample(uTexture, uSampler, vec2<f32>(uv.x, uv.y + texel.y));\n let c33 = textureSample(uTexture, uSampler, uv + texel);\n \n let color = c11 * params.kernel[0] + c12 * params.kernel[1] + c13 * params.kernel[2] +\n c21 * params.kernel[3] + c22 * params.kernel[4] + c23 * params.kernel[5] +\n c31 * params.kernel[6] + c32 * params.kernel[7] + c33 * params.kernel[8];\n \n return color * params.amount + (c22 * (1.0 - params.amount));\n}\n"),blur:this.createPipeline(e,u,"\nstruct Params {\n sizeX: f32,\n sizeY: f32,\n _pad1: f32,\n _pad2: f32,\n}\n\n@group(0) @binding(0) var uTexture: texture_2d<f32>;\n@group(0) @binding(1) var uSampler: sampler;\n@group(0) @binding(2) var<uniform> params: Params;\n\nfn random(scale: vec3<f32>, seed: f32, coord: vec3<f32>) -> f32 {\n return fract(sin(dot(coord + seed, scale)) * 43758.5453 + seed);\n}\n\n@fragment\nfn main(@location(0) uv: vec2<f32>, @builtin(position) fragCoord: vec4<f32>) -> @location(0) vec4<f32> {\n var color = vec4<f32>(0.0);\n var total = 0.0;\n let size = vec2<f32>(params.sizeX, params.sizeY);\n let offset = random(vec3<f32>(12.9898, 78.233, 151.7182), 0.0, fragCoord.xyz);\n \n for (var t: i32 = -30; t <= 30; t = t + 1) {\n let percent = (f32(t) + offset - 0.5) / 30.0;\n let weight = 1.0 - abs(percent);\n var sample = textureSample(uTexture, uSampler, uv + size * percent);\n sample = vec4<f32>(sample.rgb * sample.a, sample.a);\n color = color + sample * weight;\n total = total + weight;\n }\n \n color = color / total;\n return vec4<f32>(color.rgb / (color.a + 0.00001), color.a);\n}\n"),vignette:this.createPipeline(e,u,"\nstruct Params {\n amount: f32,\n size: f32,\n _pad1: f32,\n _pad2: f32,\n}\n\n@group(0) @binding(0) var uTexture: texture_2d<f32>;\n@group(0) @binding(1) var uSampler: sampler;\n@group(0) @binding(2) var<uniform> params: Params;\n\n@fragment\nfn main(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {\n var color = textureSample(uTexture, uSampler, uv);\n let dist = distance(uv, vec2<f32>(0.5, 0.5));\n let amt = clamp(params.amount, -1.0, 1.0);\n let edge = dist * (abs(amt) * 0.75 + params.size * 2.0);\n var vignette = smoothstep(0.8, params.size * 0.799, edge);\n \n if (amt < 0.0) {\n vignette = 1.0 + (1.0 - vignette) * (-amt);\n } else {\n vignette = mix(1.0, vignette, amt);\n }\n \n color = vec4<f32>(color.rgb * vignette, color.a);\n return color;\n}\n"),grain:this.createPipeline(e,u,"\nstruct Params {\n width: f32,\n height: f32,\n amount: f32,\n time: f32,\n}\n\n@group(0) @binding(0) var uTexture: texture_2d<f32>;\n@group(0) @binding(1) var uSampler: sampler;\n@group(0) @binding(2) var<uniform> params: Params;\n\nfn rnm(tc: vec2<f32>) -> vec4<f32> {\n let noise = sin(dot(tc + vec2<f32>(params.time), vec2<f32>(12.9898, 78.233))) * 43758.5453;\n return vec4<f32>(\n fract(noise) * 2.0 - 1.0,\n fract(noise * 1.2154) * 2.0 - 1.0,\n fract(noise * 1.3453) * 2.0 - 1.0,\n fract(noise * 1.3647) * 2.0 - 1.0\n );\n}\n\nfn fade(t: f32) -> f32 {\n return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);\n}\n\n@fragment\nfn main(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {\n let grainsize = 1.8;\n let lumamount = 1.0;\n \n let rotCoordsR = uv;\n let noiseScale = vec2<f32>(params.width / grainsize, params.height / grainsize);\n let noise = vec3<f32>(rnm(rotCoordsR * noiseScale).rgb);\n \n let tex = textureSample(uTexture, uSampler, uv);\n var col = tex.rgb;\n let lumcoeff = vec3<f32>(0.299, 0.587, 0.114);\n let luminance = mix(0.0, dot(col, lumcoeff), lumamount);\n var lum = smoothstep(0.2, 0.0, luminance);\n lum = lum + luminance;\n let finalNoise = mix(noise, vec3<f32>(0.0), pow(lum, 4.0));\n col = col + finalNoise * params.amount;\n \n return vec4<f32>(col, tex.a);\n}\n")},m=e.createTexture({size:{width:256,height:1},format:"rgba8unorm",usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.COPY_DST}),x=[this.createRenderTarget(e,r,a,"rgba8unorm"),this.createRenderTarget(e,r,a,"rgba8unorm")];this.resources={device:e,context:n,format:t,width:r,height:a,sourceTexture:o,sourceTextureView:o.createView(),sampler:i,vertexBuffer:l,pipelines:c,targets:x,paletteTexture:m,paletteTextureView:m.createView()}}disposeResources(){if(!this.resources)return;const{sourceTexture:e,vertexBuffer:n,targets:t,paletteTexture:r}=this.resources;e.destroy(),n.destroy(),t.forEach(e=>e.texture.destroy()),r&&r.destroy(),this.resources=null}createUniformBuffer(e,n){const t=e.createBuffer({size:Math.max(n.byteLength,16),usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST});return e.queue.writeBuffer(t,0,n),t}drawFrame(e,n){const{device:t,context:r,width:a,height:o,sourceTextureView:i,sampler:s,vertexBuffer:l,pipelines:u,targets:c,paletteTexture:m,paletteTextureView:v}=e;let f=i,g=0;const h=()=>{const e=c[g%2];return g++,e},b=(e,n,r)=>{const a=u[e];if(!a)return;const o=r?null:h(),i=r||o.view,c=[{binding:0,resource:f},{binding:1,resource:s}];let m=null;n&&(m=this.createUniformBuffer(t,n),c.push({binding:2,resource:{buffer:m}}));const v=t.createBindGroup({layout:a.bindGroupLayout,entries:c}),x=t.createCommandEncoder(),p=x.beginRenderPass({colorAttachments:[{view:i,loadOp:"clear",storeOp:"store",clearValue:{r:0,g:0,b:0,a:1}}]});p.setPipeline(a.pipeline),p.setVertexBuffer(0,l),p.setBindGroup(0,v),p.draw(4),p.end(),t.queue.submit([x.finish()]),o&&(f=o.view),m&&m.destroy()};if(Math.abs(n.vibrance)>.5&&b("vibrance",new Float32Array([n.vibrance/100]).buffer),Math.abs(n.saturation)>.5&&b("saturation",(e=>{const n=1+Math.max(-100,Math.min(100,e))/100,t=.299,r=.587,a=.114,o=1-n;return new Float32Array([o*t+n,o*r,o*a,0,0,o*t,o*r+n,o*a,0,0,o*t,o*r,o*a+n,0,0,0,0,0,1,0])})(n.saturation).buffer),Math.abs(n.temperature)>.5&&b("temperature",new Float32Array([n.temperature/500]).buffer),Math.abs(n.tint)>.5&&b("tint",new Float32Array([n.tint/500]).buffer),Math.abs(n.hue)>.5&&b("hue",new Float32Array([n.hue/200]).buffer),b("brightness",new Float32Array([n.brightness/200]).buffer),Math.abs(n.exposure)>.5&&b("exposure",new Float32Array([n.exposure/100]).buffer),Math.abs(n.contrast)>.5&&b("contrast",(e=>{const n=1+Math.max(-100,Math.min(100,e))/100,t=.5*(1-n);return new Float32Array([n,0,0,0,t,0,n,0,0,t,0,0,n,0,t,0,0,0,1,0])})(n.contrast).buffer),Math.abs(n.blacks)>.5&&m&&v){const e=(e=>{const n=Math.max(-100,Math.min(100,e))/100;return(e=>{const n=new Uint8Array(768);for(let t=0;t<256;t+=1){const r=p(t/255,0,e,.66,1),a=Math.round(255*x(r)),o=3*t;n[o]=a,n[o+1]=a,n[o+2]=a}return n})(x(.33-.35*n))})(n.blacks),r=new Uint8Array(1024);for(let n=0;n<256;n++)r[4*n]=e[3*n],r[4*n+1]=e[3*n+1],r[4*n+2]=e[3*n+2],r[4*n+3]=255;t.queue.writeTexture({texture:m},r,{bytesPerRow:1024},{width:256,height:1});const a=u.blacks,o=h(),i=o.view,c=t.createBindGroup({layout:a.bindGroupLayout,entries:[{binding:0,resource:f},{binding:1,resource:s},{binding:2,resource:v},{binding:3,resource:s}]}),g=t.createCommandEncoder(),b=g.beginRenderPass({colorAttachments:[{view:i,loadOp:"clear",storeOp:"store",clearValue:{r:0,g:0,b:0,a:1}}]});b.setPipeline(a.pipeline),b.setVertexBuffer(0,l),b.setBindGroup(0,c),b.draw(4),b.end(),t.queue.submit([g.finish()]),f=o.view}if(Math.abs(n.whites)>.5&&b("whites",new Float32Array([n.whites/400]).buffer),Math.abs(n.highlights)>.5&&b("highlights",new Float32Array([n.highlights/100]).buffer),Math.abs(n.shadows)>.5&&b("shadows",new Float32Array([n.shadows/100]).buffer),Math.abs(n.dehaze)>.5&&b("dehaze",new Float32Array([n.dehaze/100,a,o,0]).buffer),n.bloom>.5&&b("bloom",new Float32Array([n.bloom/100,1/a,1/o,.5]).buffer),n.glamour>.5&&b("glamour",new Float32Array([n.glamour/100,1/a,1/o,0]).buffer),Math.abs(n.clarity)>.5&&b("clarity",new Float32Array([n.clarity/100,1/a,1/o,0]).buffer),n.sharpen>.5&&b("kernel",new Float32Array([1/a,1/o,n.sharpen/100,0,0,-1,0,-1,5,-1,0,-1,0,0,0,0]).buffer),n.smooth>.5){const e=1/9;b("kernel",new Float32Array([1/a,1/o,n.smooth/100,0,e,e,e,e,e,e,e,e,e,0,0,0]).buffer)}b("blur",new Float32Array([n.blur/a,0,0,0]).buffer),b("blur",new Float32Array([0,n.blur/o,0,0]).buffer),b("vignette",new Float32Array([n.vignette/100,.25,0,0]).buffer),b("grain",new Float32Array([a,o,n.grain/800,0]).buffer),b("pass",void 0,r.getCurrentTexture().createView())}},h={vibrance:0,saturation:0,temperature:0,tint:0,hue:0,brightness:0,exposure:0,contrast:0,blacks:0,whites:0,highlights:0,shadows:0,dehaze:0,bloom:0,glamour:0,clarity:0,sharpen:0,smooth:0,blur:0,vignette:0,grain:0},b={auto:{},blackAndWhite:{saturation:-100,contrast:20,exposure:10,clarity:10},pop:{highlights:50,shadows:-50,vibrance:50,saturation:20,exposure:20,clarity:20},vintage:{saturation:-20,contrast:10,temperature:15,grain:30,vignette:25},vivid:{vibrance:40,saturation:20,contrast:15,clarity:20},cinematic:{contrast:25,highlights:-20,shadows:15,temperature:-10,vignette:30}};function d(e){const{data:n,width:t,height:r}=e,a=new Array(256).fill(0);for(let e=0;e<n.length;e+=4)a[n[e]]+=1,a[n[e+1]]+=1,a[n[e+2]]+=1;const o=Math.round(t*r/1e3);let i=0;for(let e=0;e<256;e++)if(a[e]>o){i=e;break}let s=255;for(let e=255;e>=0;e--)if(a[e]>o){s=e;break}return i>100&&(i=100),s<155&&(s=155),{black:i,white:s}}function w(e){const{data:n,width:t,height:r}=e;let a=1,o=1;for(let e=0;e<n.length;e+=4){const t=n[e],r=n[e+1],i=n[e+2],s=Math.min(t,r,i),l=Math.max(t,r,i);o+=l/255;const u=l-s;u>0&&(a+=u/l)}return(a+o)/(t*r*2)}function y(e){return{levels:d(e),vibrance:w(e)}}var T=class{constructor(e={}){this.backend=null,this.settings={...h},this.imageLoaded=!1,this.initPromise=null,this.canvas=e.canvas||document.createElement("canvas"),this.backendType=r(e.backend)}getCanvas(){return this.canvas}getBackendType(){return this.backendType}static isWebGPUSupported(){return n()}static isWebGLSupported(){return t()}getSettings(){return{...this.settings}}setSettings(e){this.settings={...this.settings,...e},this.backend&&this.imageLoaded&&this.render()}resetSettings(){this.settings={...h},this.backend&&this.imageLoaded&&this.render()}async initBackend(){if(this.backend)return;const e={};if("webgpu"===this.backendType){this.backend=new g(this.canvas,e);try{await this.backend.init()}catch(n){this.backend=new m(this.canvas,e),this.backend.init(),this.backendType="webgl"}}else this.backend=new m(this.canvas,e),this.backend.init()}async ensureBackend(){this.initPromise||(this.initPromise=this.initBackend()),await this.initPromise}async loadImage(e){return await this.ensureBackend(),new Promise((n,t)=>{const r=new Image;r.crossOrigin="anonymous",r.onload=()=>{this.backend.loadFromImage(r),this.imageLoaded=!0,this.render(),n()},r.onerror=()=>{t(new Error(`Failed to load image: ${e}`))},r.src=e})}async loadFromImage(e){await this.ensureBackend(),this.backend.loadFromImage(e),this.imageLoaded=!0,this.render()}async loadFromFile(e){const n=URL.createObjectURL(e);try{await this.loadImage(n)}finally{URL.revokeObjectURL(n)}}async loadFromImageData(e){await this.ensureBackend(),this.backend.loadFromImageData(e),this.imageLoaded=!0,this.render()}render(){this.backend&&this.imageLoaded&&this.backend.render(this.settings)}toDataURL(e){this.render();const n=e?.format||"image/png",t=e?.quality;return this.canvas.toDataURL(n,t)}toBlob(e){return this.render(),new Promise((n,t)=>{const r=e?.format||"image/png",a=e?.quality;this.canvas.toBlob(e=>{e?n(e):t(new Error("Failed to create blob"))},r,a)})}getImageData(){if(!this.backend)throw new Error("No backend initialized");return this.render(),this.backend.getImageData()}getSize(){return this.backend?this.backend.getSize():{width:0,height:0}}isLoaded(){return this.imageLoaded}dispose(){this.backend&&(this.backend.dispose(),this.backend=null),this.imageLoaded=!1,this.initPromise=null}analyze(){if(!this.imageLoaded||!this.backend)throw new Error("No image loaded");const e={...this.settings};this.settings={...h},this.render();const n=y(this.getImageData());return this.settings=e,this.render(),n}autoFix(){if(!this.imageLoaded||!this.backend)throw new Error("No image loaded");this.settings={...h},this.render();const e=this.getImageData(),n=d(e),t=w(e),r={...h};if(r.whites=Math.round(255-n.white),r.blacks=Math.round(n.black),t<.7){const e=Math.round(100*(.7-t));r.vibrance=Math.min(e,50)}return this.settings=r,this.render(),r}applyPreset(e){if("auto"===e)return this.autoFix();const n=b[e],t={...h,...n};return this.settings=t,this.backend&&this.imageLoaded&&this.render(),t}};export{e as BaseBackend,T as ImageColorGrading,m as WebGLBackend,g as WebGPUBackend,y as analyzeImage,d as analyzeImageLevels,w as analyzeImageVibrance,h as defaultSettings,t as isWebGLSupported,n as isWebGPUSupported,b as presets,r as selectBestBackend};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "image-color-grading",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "基于 WebGL 的高性能图像调色库,支持亮度、对比度、饱和度、色温等 22+ 种调色参数",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -48,6 +48,7 @@
|
|
|
48
48
|
"url": ""
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
|
+
"@webgpu/types": "^0.1.69",
|
|
51
52
|
"terser": "^5.0.0",
|
|
52
53
|
"tsup": "^8.0.0",
|
|
53
54
|
"typescript": "^5.0.0"
|
|
@@ -55,5 +56,8 @@
|
|
|
55
56
|
"engines": {
|
|
56
57
|
"node": ">=16.0.0"
|
|
57
58
|
},
|
|
58
|
-
"sideEffects": false
|
|
59
|
+
"sideEffects": false,
|
|
60
|
+
"dependencies": {
|
|
61
|
+
"glsl-minifier": "^0.0.12"
|
|
62
|
+
}
|
|
59
63
|
}
|