update imagefx

pull/193/head
Vladimir Mandic 2021-10-12 09:48:00 -04:00
parent 93b5dfd3ee
commit c7dbca2856
13 changed files with 5958 additions and 3713 deletions

View File

@ -31,6 +31,9 @@ import jsonView from './helpers/jsonview.js';
let human; let human;
let userConfig = { let userConfig = {
face: { enabled: false },
body: { enabled: false },
hand: { enabled: false },
/* /*
warmup: 'none', warmup: 'none',
backend: 'humangl', backend: 'humangl',
@ -91,7 +94,7 @@ const ui = {
autoPlay: false, // start webcam & detection on load autoPlay: false, // start webcam & detection on load
// internal variables // internal variables
exceptionHandler: true, // should capture all unhandled exceptions exceptionHandler: false, // should capture all unhandled exceptions
busy: false, // internal camera busy flag busy: false, // internal camera busy flag
menuWidth: 0, // internal menuWidth: 0, // internal
menuHeight: 0, // internal menuHeight: 0, // internal
@ -147,6 +150,10 @@ let worker;
let bench; let bench;
let lastDetectedResult = {}; let lastDetectedResult = {};
// helper function: async pause
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
// helper function: translates json to human readable string // helper function: translates json to human readable string
function str(...msg) { function str(...msg) {
if (!Array.isArray(msg)) return msg; if (!Array.isArray(msg)) return msg;
@ -225,15 +232,18 @@ async function calcSimmilarity(result) {
} }
const isLive = (input) => { const isLive = (input) => {
const videoLive = input.readyState > 2; const isCamera = input.srcObject?.getVideoTracks()[0] && input.srcObject?.getVideoTracks()[0].enabled;
const cameraLive = input.srcObject?.getVideoTracks()[0].readyState === 'live'; const isVideoLive = input.readyState > 2;
const live = (videoLive || cameraLive) && (!input.paused); const isCameraLive = input.srcObject?.getVideoTracks()[0].readyState === 'live';
let live = isCamera ? isCameraLive : isVideoLive;
live = live && !input.paused;
return live; return live;
}; };
// draws processed results and starts processing of a next frame // draws processed results and starts processing of a next frame
let lastDraw = performance.now(); let lastDraw = performance.now();
async function drawResults(input) { async function drawResults(input) {
// await delay(25);
const result = lastDetectedResult; const result = lastDetectedResult;
const canvas = document.getElementById('canvas'); const canvas = document.getElementById('canvas');
@ -325,6 +335,7 @@ async function drawResults(input) {
ui.drawThread = requestAnimationFrame(() => drawResults(input)); ui.drawThread = requestAnimationFrame(() => drawResults(input));
} else { } else {
cancelAnimationFrame(ui.drawThread); cancelAnimationFrame(ui.drawThread);
videoPause();
ui.drawThread = null; ui.drawThread = null;
} }
} else { } else {

View File

@ -240,42 +240,147 @@ var version9 = {
// package.json // package.json
var version10 = "2.3.2"; var version10 = "2.3.2";
// src/image/imagefxshaders.ts
var vertexIdentity = `
precision highp float;
attribute vec2 pos;
attribute vec2 uv;
varying vec2 vUv;
uniform float flipY;
void main(void) {
vUv = uv;
gl_Position = vec4(pos.x, pos.y*flipY, 0.0, 1.);
}
`;
var colorMatrixWithAlpha = `
precision highp float;
varying vec2 vUv;
uniform sampler2D texture;
uniform float m[20];
void main(void) {
vec4 c = texture2D(texture, vUv);
gl_FragColor.r = m[0] * c.r + m[1] * c.g + m[2] * c.b + m[3] * c.a + m[4];
gl_FragColor.g = m[5] * c.r + m[6] * c.g + m[7] * c.b + m[8] * c.a + m[9];
gl_FragColor.b = m[10] * c.r + m[11] * c.g + m[12] * c.b + m[13] * c.a + m[14];
gl_FragColor.a = m[15] * c.r + m[16] * c.g + m[17] * c.b + m[18] * c.a + m[19];
}
`;
var colorMatrixWithoutAlpha = `
precision highp float;
varying vec2 vUv;
uniform sampler2D texture;
uniform float m[20];
void main(void) {
vec4 c = texture2D(texture, vUv);
gl_FragColor.r = m[0] * c.r + m[1] * c.g + m[2] * c.b + m[4];
gl_FragColor.g = m[5] * c.r + m[6] * c.g + m[7] * c.b + m[9];
gl_FragColor.b = m[10] * c.r + m[11] * c.g + m[12] * c.b + m[14];
gl_FragColor.a = c.a;
}
`;
var pixelate = `
precision highp float;
varying vec2 vUv;
uniform vec2 size;
uniform sampler2D texture;
vec2 pixelate(vec2 coord, vec2 size) {
return floor( coord / size ) * size;
}
void main(void) {
gl_FragColor = vec4(0.0);
vec2 coord = pixelate(vUv, size);
gl_FragColor += texture2D(texture, coord);
}
`;
var blur = `
precision highp float;
varying vec2 vUv;
uniform sampler2D texture;
uniform vec2 px;
void main(void) {
gl_FragColor = vec4(0.0);
gl_FragColor += texture2D(texture, vUv + vec2(-7.0*px.x, -7.0*px.y))*0.0044299121055113265;
gl_FragColor += texture2D(texture, vUv + vec2(-6.0*px.x, -6.0*px.y))*0.00895781211794;
gl_FragColor += texture2D(texture, vUv + vec2(-5.0*px.x, -5.0*px.y))*0.0215963866053;
gl_FragColor += texture2D(texture, vUv + vec2(-4.0*px.x, -4.0*px.y))*0.0443683338718;
gl_FragColor += texture2D(texture, vUv + vec2(-3.0*px.x, -3.0*px.y))*0.0776744219933;
gl_FragColor += texture2D(texture, vUv + vec2(-2.0*px.x, -2.0*px.y))*0.115876621105;
gl_FragColor += texture2D(texture, vUv + vec2(-1.0*px.x, -1.0*px.y))*0.147308056121;
gl_FragColor += texture2D(texture, vUv )*0.159576912161;
gl_FragColor += texture2D(texture, vUv + vec2( 1.0*px.x, 1.0*px.y))*0.147308056121;
gl_FragColor += texture2D(texture, vUv + vec2( 2.0*px.x, 2.0*px.y))*0.115876621105;
gl_FragColor += texture2D(texture, vUv + vec2( 3.0*px.x, 3.0*px.y))*0.0776744219933;
gl_FragColor += texture2D(texture, vUv + vec2( 4.0*px.x, 4.0*px.y))*0.0443683338718;
gl_FragColor += texture2D(texture, vUv + vec2( 5.0*px.x, 5.0*px.y))*0.0215963866053;
gl_FragColor += texture2D(texture, vUv + vec2( 6.0*px.x, 6.0*px.y))*0.00895781211794;
gl_FragColor += texture2D(texture, vUv + vec2( 7.0*px.x, 7.0*px.y))*0.0044299121055113265;
}
`;
var convolution = `
precision highp float;
varying vec2 vUv;
uniform sampler2D texture;
uniform vec2 px;
uniform float m[9];
void main(void) {
vec4 c11 = texture2D(texture, vUv - px); // top left
vec4 c12 = texture2D(texture, vec2(vUv.x, vUv.y - px.y)); // top center
vec4 c13 = texture2D(texture, vec2(vUv.x + px.x, vUv.y - px.y)); // top right
vec4 c21 = texture2D(texture, vec2(vUv.x - px.x, vUv.y) ); // mid left
vec4 c22 = texture2D(texture, vUv); // mid center
vec4 c23 = texture2D(texture, vec2(vUv.x + px.x, vUv.y) ); // mid right
vec4 c31 = texture2D(texture, vec2(vUv.x - px.x, vUv.y + px.y) ); // bottom left
vec4 c32 = texture2D(texture, vec2(vUv.x, vUv.y + px.y) ); // bottom center
vec4 c33 = texture2D(texture, vUv + px ); // bottom right
gl_FragColor =
c11 * m[0] + c12 * m[1] + c22 * m[2] +
c21 * m[3] + c22 * m[4] + c23 * m[5] +
c31 * m[6] + c32 * m[7] + c33 * m[8];
gl_FragColor.a = c22.a;
}
`;
// src/image/imagefx.ts // src/image/imagefx.ts
function GLProgram(gl, vertexSource, fragmentSource) { var GLProgram = class {
const _collect = function(source, prefix, collection) { constructor(gl, vertexSource, fragmentSource) {
__publicField(this, "uniform", {});
__publicField(this, "attribute", {});
__publicField(this, "gl");
__publicField(this, "id");
__publicField(this, "collect", (source, prefix, collection) => {
const r = new RegExp("\\b" + prefix + " \\w+ (\\w+)", "ig"); const r = new RegExp("\\b" + prefix + " \\w+ (\\w+)", "ig");
source.replace(r, (match4, name) => { source.replace(r, (match4, name) => {
collection[name] = 0; collection[name] = 0;
return match4; return match4;
}); });
}; });
const _compile = function(source, type) { __publicField(this, "compile", (source, type) => {
const shader = gl.createShader(type); const shader = this.gl.createShader(type);
gl.shaderSource(shader, source); this.gl.shaderSource(shader, source);
gl.compileShader(shader); this.gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) if (!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS))
throw new Error("filter: gl compile failed", gl.getShaderInfoLog(shader)); throw new Error(`filter: gl compile failed: ${this.gl.getShaderInfoLog(shader)}`);
return shader; return shader;
}; });
this.uniform = {}; this.gl = gl;
this.attribute = {}; const _vsh = this.compile(vertexSource, this.gl.VERTEX_SHADER);
const _vsh = _compile(vertexSource, gl.VERTEX_SHADER); const _fsh = this.compile(fragmentSource, this.gl.FRAGMENT_SHADER);
const _fsh = _compile(fragmentSource, gl.FRAGMENT_SHADER); this.id = this.gl.createProgram();
this.id = gl.createProgram(); this.gl.attachShader(this.id, _vsh);
gl.attachShader(this.id, _vsh); this.gl.attachShader(this.id, _fsh);
gl.attachShader(this.id, _fsh); this.gl.linkProgram(this.id);
gl.linkProgram(this.id); if (!this.gl.getProgramParameter(this.id, this.gl.LINK_STATUS))
if (!gl.getProgramParameter(this.id, gl.LINK_STATUS)) throw new Error(`filter: gl link failed: ${this.gl.getProgramInfoLog(this.id)}`);
throw new Error("filter: gl link failed", gl.getProgramInfoLog(this.id)); this.gl.useProgram(this.id);
gl.useProgram(this.id); this.collect(vertexSource, "attribute", this.attribute);
_collect(vertexSource, "attribute", this.attribute);
for (const a in this.attribute) for (const a in this.attribute)
this.attribute[a] = gl.getAttribLocation(this.id, a); this.attribute[a] = this.gl.getAttribLocation(this.id, a);
_collect(vertexSource, "uniform", this.uniform); this.collect(vertexSource, "uniform", this.uniform);
_collect(fragmentSource, "uniform", this.uniform); this.collect(fragmentSource, "uniform", this.uniform);
for (const u in this.uniform) for (const u in this.uniform)
this.uniform[u] = gl.getUniformLocation(this.id, u); this.uniform[u] = this.gl.getUniformLocation(this.id, u);
} }
};
function GLImageFilter(params) { function GLImageFilter(params) {
if (!params) if (!params)
params = {}; params = {};
@ -289,13 +394,12 @@ function GLImageFilter(params) {
let _height = -1; let _height = -1;
let _vertexBuffer = null; let _vertexBuffer = null;
let _currentProgram = null; let _currentProgram = null;
const _filter = {}; const _canvas = params.canvas || typeof OffscreenCanvas !== "undefined" ? new OffscreenCanvas(100, 100) : document.createElement("canvas");
const _canvas = params.canvas || document.createElement("canvas");
const _shaderProgramCache = {}; const _shaderProgramCache = {};
const DRAW = { INTERMEDIATE: 1 }; const DRAW = { INTERMEDIATE: 1 };
const gl = _canvas.getContext("webgl"); const gl = _canvas.getContext("webgl");
if (!gl) if (!gl)
throw new Error("filter: context failed"); throw new Error("filter: cannot get webgl context");
this.addFilter = function(name) { this.addFilter = function(name) {
const args = Array.prototype.slice.call(arguments, 1); const args = Array.prototype.slice.call(arguments, 1);
const filter = _filter[name]; const filter = _filter[name];
@ -305,40 +409,14 @@ function GLImageFilter(params) {
_filterChain = []; _filterChain = [];
}; };
const _resize = function(width, height) { const _resize = function(width, height) {
if (width === _width && height === _height) { if (width === _width && height === _height)
return; return;
}
_canvas.width = width; _canvas.width = width;
_width = width; _width = width;
_canvas.height = height; _canvas.height = height;
_height = height; _height = height;
if (!_vertexBuffer) { if (!_vertexBuffer) {
const vertices = new Float32Array([ const vertices = new Float32Array([-1, -1, 0, 1, 1, -1, 1, 1, -1, 1, 0, 0, -1, 1, 0, 0, 1, -1, 1, 1, 1, 1, 1, 0]);
-1,
-1,
0,
1,
1,
-1,
1,
1,
-1,
1,
0,
0,
-1,
1,
0,
0,
1,
-1,
1,
1,
1,
1,
1,
0
]);
_vertexBuffer = gl.createBuffer(), gl.bindBuffer(gl.ARRAY_BUFFER, _vertexBuffer); _vertexBuffer = gl.createBuffer(), gl.bindBuffer(gl.ARRAY_BUFFER, _vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW); gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true); gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
@ -367,16 +445,17 @@ function GLImageFilter(params) {
_tempFramebuffers[index] = _tempFramebuffers[index] || _createFramebufferTexture(_width, _height); _tempFramebuffers[index] = _tempFramebuffers[index] || _createFramebufferTexture(_width, _height);
return _tempFramebuffers[index]; return _tempFramebuffers[index];
}; };
const _draw = function(flags = null) { const _draw = function(flags = 0) {
var _a, _b; var _a, _b;
if (!_currentProgram)
return;
let source = null; let source = null;
let target = null; let target = null;
let flipY = false; let flipY = false;
if (_drawCount === 0) { if (_drawCount === 0)
source = _sourceTexture; source = _sourceTexture;
} else { else
source = (_a = _getTempFramebuffer(_currentFramebufferIndex)) == null ? void 0 : _a.texture; source = (_a = _getTempFramebuffer(_currentFramebufferIndex)) == null ? void 0 : _a.texture;
}
_drawCount++; _drawCount++;
if (_lastInChain && !(flags & DRAW.INTERMEDIATE)) { if (_lastInChain && !(flags & DRAW.INTERMEDIATE)) {
target = null; target = null;
@ -387,7 +466,7 @@ function GLImageFilter(params) {
} }
gl.bindTexture(gl.TEXTURE_2D, source); gl.bindTexture(gl.TEXTURE_2D, source);
gl.bindFramebuffer(gl.FRAMEBUFFER, target); gl.bindFramebuffer(gl.FRAMEBUFFER, target);
gl.uniform1f(_currentProgram.uniform.flipY, flipY ? -1 : 1); gl.uniform1f(_currentProgram.uniform["flipY"], flipY ? -1 : 1);
gl.drawArrays(gl.TRIANGLES, 0, 6); gl.drawArrays(gl.TRIANGLES, 0, 6);
}; };
this.apply = function(image24) { this.apply = function(image24) {
@ -403,90 +482,44 @@ function GLImageFilter(params) {
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image24); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image24);
if (_filterChain.length === 0) { if (_filterChain.length === 0) {
_draw(); _draw();
return _canvas; } else {
}
for (let i = 0; i < _filterChain.length; i++) { for (let i = 0; i < _filterChain.length; i++) {
_lastInChain = i === _filterChain.length - 1; _lastInChain = i === _filterChain.length - 1;
const f = _filterChain[i]; const f = _filterChain[i];
f.func.apply(this, f.args || []); f.func.apply(this, f.args || []);
} }
}
return _canvas; return _canvas;
}; };
const _compileShader = function(fragmentSource) { const _compileShader = function(fragmentSource) {
if (_shaderProgramCache[fragmentSource]) { if (_shaderProgramCache[fragmentSource]) {
_currentProgram = _shaderProgramCache[fragmentSource]; _currentProgram = _shaderProgramCache[fragmentSource];
gl.useProgram(_currentProgram.id); gl.useProgram(_currentProgram == null ? void 0 : _currentProgram.id);
return _currentProgram; return _currentProgram;
} }
const SHADER = {}; _currentProgram = new GLProgram(gl, vertexIdentity, fragmentSource);
SHADER.VERTEX_IDENTITY = [
"precision highp float;",
"attribute vec2 pos;",
"attribute vec2 uv;",
"varying vec2 vUv;",
"uniform float flipY;",
"void main(void) {",
"vUv = uv;",
"gl_Position = vec4(pos.x, pos.y*flipY, 0.0, 1.);",
"}"
].join("\n");
SHADER.FRAGMENT_IDENTITY = [
"precision highp float;",
"varying vec2 vUv;",
"uniform sampler2D texture;",
"void main(void) {",
"gl_FragColor = texture2D(texture, vUv);",
"}"
].join("\n");
_currentProgram = new GLProgram(gl, SHADER.VERTEX_IDENTITY, fragmentSource);
const floatSize = Float32Array.BYTES_PER_ELEMENT; const floatSize = Float32Array.BYTES_PER_ELEMENT;
const vertSize = 4 * floatSize; const vertSize = 4 * floatSize;
gl.enableVertexAttribArray(_currentProgram.attribute.pos); gl.enableVertexAttribArray(_currentProgram.attribute["pos"]);
gl.vertexAttribPointer(_currentProgram.attribute.pos, 2, gl.FLOAT, false, vertSize, 0 * floatSize); gl.vertexAttribPointer(_currentProgram.attribute["pos"], 2, gl.FLOAT, false, vertSize, 0 * floatSize);
gl.enableVertexAttribArray(_currentProgram.attribute.uv); gl.enableVertexAttribArray(_currentProgram.attribute.uv);
gl.vertexAttribPointer(_currentProgram.attribute.uv, 2, gl.FLOAT, false, vertSize, 2 * floatSize); gl.vertexAttribPointer(_currentProgram.attribute["uv"], 2, gl.FLOAT, false, vertSize, 2 * floatSize);
_shaderProgramCache[fragmentSource] = _currentProgram; _shaderProgramCache[fragmentSource] = _currentProgram;
return _currentProgram; return _currentProgram;
}; };
_filter.colorMatrix = function(matrix) { const _filter = {
colorMatrix: (matrix) => {
const m = new Float32Array(matrix); const m = new Float32Array(matrix);
m[4] /= 255; m[4] /= 255;
m[9] /= 255; m[9] /= 255;
m[14] /= 255; m[14] /= 255;
m[19] /= 255; m[19] /= 255;
const shader = m[18] === 1 && m[3] === 0 && m[8] === 0 && m[13] === 0 && m[15] === 0 && m[16] === 0 && m[17] === 0 && m[19] === 0 ? _filter.colorMatrix.SHADER.WITHOUT_ALPHA : _filter.colorMatrix.SHADER.WITH_ALPHA; const shader = m[18] === 1 && m[3] === 0 && m[8] === 0 && m[13] === 0 && m[15] === 0 && m[16] === 0 && m[17] === 0 && m[19] === 0 ? colorMatrixWithoutAlpha : colorMatrixWithAlpha;
const program = _compileShader(shader); const program = _compileShader(shader);
gl.uniform1fv(program.uniform.m, m); gl.uniform1fv(program == null ? void 0 : program.uniform["m"], m);
_draw(); _draw();
}; },
_filter.colorMatrix.SHADER = {}; brightness: (brightness) => {
_filter.colorMatrix.SHADER.WITH_ALPHA = [
"precision highp float;",
"varying vec2 vUv;",
"uniform sampler2D texture;",
"uniform float m[20];",
"void main(void) {",
"vec4 c = texture2D(texture, vUv);",
"gl_FragColor.r = m[0] * c.r + m[1] * c.g + m[2] * c.b + m[3] * c.a + m[4];",
"gl_FragColor.g = m[5] * c.r + m[6] * c.g + m[7] * c.b + m[8] * c.a + m[9];",
"gl_FragColor.b = m[10] * c.r + m[11] * c.g + m[12] * c.b + m[13] * c.a + m[14];",
"gl_FragColor.a = m[15] * c.r + m[16] * c.g + m[17] * c.b + m[18] * c.a + m[19];",
"}"
].join("\n");
_filter.colorMatrix.SHADER.WITHOUT_ALPHA = [
"precision highp float;",
"varying vec2 vUv;",
"uniform sampler2D texture;",
"uniform float m[20];",
"void main(void) {",
"vec4 c = texture2D(texture, vUv);",
"gl_FragColor.r = m[0] * c.r + m[1] * c.g + m[2] * c.b + m[4];",
"gl_FragColor.g = m[5] * c.r + m[6] * c.g + m[7] * c.b + m[9];",
"gl_FragColor.b = m[10] * c.r + m[11] * c.g + m[12] * c.b + m[14];",
"gl_FragColor.a = c.a;",
"}"
].join("\n");
_filter.brightness = function(brightness) {
const b = (brightness || 0) + 1; const b = (brightness || 0) + 1;
_filter.colorMatrix([ _filter.colorMatrix([
b, b,
@ -510,8 +543,8 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.saturation = function(amount) { saturation: (amount) => {
const x = (amount || 0) * 2 / 3 + 1; const x = (amount || 0) * 2 / 3 + 1;
const y = (x - 1) * -0.5; const y = (x - 1) * -0.5;
_filter.colorMatrix([ _filter.colorMatrix([
@ -536,11 +569,11 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.desaturate = function() { desaturate: () => {
_filter.saturation(-1); _filter.saturation(-1);
}; },
_filter.contrast = function(amount) { contrast: (amount) => {
const v = (amount || 0) + 1; const v = (amount || 0) + 1;
const o = -128 * (v - 1); const o = -128 * (v - 1);
_filter.colorMatrix([ _filter.colorMatrix([
@ -565,11 +598,11 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.negative = function() { negative: () => {
_filter.contrast(-2); _filter.contrast(-2);
}; },
_filter.hue = function(rotation) { hue: (rotation) => {
rotation = (rotation || 0) / 180 * Math.PI; rotation = (rotation || 0) / 180 * Math.PI;
const cos = Math.cos(rotation); const cos = Math.cos(rotation);
const sin = Math.sin(rotation); const sin = Math.sin(rotation);
@ -598,8 +631,8 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.desaturateLuminance = function() { desaturateLuminance: () => {
_filter.colorMatrix([ _filter.colorMatrix([
0.2764723, 0.2764723,
0.929708, 0.929708,
@ -622,8 +655,8 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.sepia = function() { sepia: () => {
_filter.colorMatrix([ _filter.colorMatrix([
0.393, 0.393,
0.7689999, 0.7689999,
@ -646,8 +679,8 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.brownie = function() { brownie: () => {
_filter.colorMatrix([ _filter.colorMatrix([
0.5997023498159715, 0.5997023498159715,
0.34553243048391263, 0.34553243048391263,
@ -670,8 +703,8 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.vintagePinhole = function() { vintagePinhole: () => {
_filter.colorMatrix([ _filter.colorMatrix([
0.6279345635605994, 0.6279345635605994,
0.3202183420819367, 0.3202183420819367,
@ -694,8 +727,8 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.kodachrome = function() { kodachrome: () => {
_filter.colorMatrix([ _filter.colorMatrix([
1.1285582396593525, 1.1285582396593525,
-0.3967382283601348, -0.3967382283601348,
@ -718,8 +751,8 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.technicolor = function() { technicolor: () => {
_filter.colorMatrix([ _filter.colorMatrix([
1.9125277891456083, 1.9125277891456083,
-0.8545344976951645, -0.8545344976951645,
@ -742,8 +775,8 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.polaroid = function() { polaroid: () => {
_filter.colorMatrix([ _filter.colorMatrix([
1.438, 1.438,
-0.062, -0.062,
@ -766,8 +799,8 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.shiftToBGR = function() { shiftToBGR: () => {
_filter.colorMatrix([ _filter.colorMatrix([
0, 0,
0, 0,
@ -790,40 +823,17 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.convolution = function(matrix) { convolution: (matrix) => {
const m = new Float32Array(matrix); const m = new Float32Array(matrix);
const pixelSizeX = 1 / _width; const pixelSizeX = 1 / _width;
const pixelSizeY = 1 / _height; const pixelSizeY = 1 / _height;
const program = _compileShader(_filter.convolution.SHADER); const program = _compileShader(convolution);
gl.uniform1fv(program.uniform.m, m); gl.uniform1fv(program == null ? void 0 : program.uniform["m"], m);
gl.uniform2f(program.uniform.px, pixelSizeX, pixelSizeY); gl.uniform2f(program == null ? void 0 : program.uniform["px"], pixelSizeX, pixelSizeY);
_draw(); _draw();
}; },
_filter.convolution.SHADER = [ detectEdges: () => {
"precision highp float;",
"varying vec2 vUv;",
"uniform sampler2D texture;",
"uniform vec2 px;",
"uniform float m[9];",
"void main(void) {",
"vec4 c11 = texture2D(texture, vUv - px);",
"vec4 c12 = texture2D(texture, vec2(vUv.x, vUv.y - px.y));",
"vec4 c13 = texture2D(texture, vec2(vUv.x + px.x, vUv.y - px.y));",
"vec4 c21 = texture2D(texture, vec2(vUv.x - px.x, vUv.y) );",
"vec4 c22 = texture2D(texture, vUv);",
"vec4 c23 = texture2D(texture, vec2(vUv.x + px.x, vUv.y) );",
"vec4 c31 = texture2D(texture, vec2(vUv.x - px.x, vUv.y + px.y) );",
"vec4 c32 = texture2D(texture, vec2(vUv.x, vUv.y + px.y) );",
"vec4 c33 = texture2D(texture, vUv + px );",
"gl_FragColor = ",
"c11 * m[0] + c12 * m[1] + c22 * m[2] +",
"c21 * m[3] + c22 * m[4] + c23 * m[5] +",
"c31 * m[6] + c32 * m[7] + c33 * m[8];",
"gl_FragColor.a = c22.a;",
"}"
].join("\n");
_filter.detectEdges = function() {
_filter.convolution.call(this, [ _filter.convolution.call(this, [
0, 0,
1, 1,
@ -835,8 +845,8 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.sobelX = function() { sobelX: () => {
_filter.convolution.call(this, [ _filter.convolution.call(this, [
-1, -1,
0, 0,
@ -848,8 +858,8 @@ function GLImageFilter(params) {
0, 0,
1 1
]); ]);
}; },
_filter.sobelY = function() { sobelY: () => {
_filter.convolution.call(this, [ _filter.convolution.call(this, [
-1, -1,
-2, -2,
@ -861,8 +871,8 @@ function GLImageFilter(params) {
2, 2,
1 1
]); ]);
}; },
_filter.sharpen = function(amount) { sharpen: (amount) => {
const a = amount || 1; const a = amount || 1;
_filter.convolution.call(this, [ _filter.convolution.call(this, [
0, 0,
@ -875,8 +885,8 @@ function GLImageFilter(params) {
-1 * a, -1 * a,
0 0
]); ]);
}; },
_filter.emboss = function(size2) { emboss: (size2) => {
const s = size2 || 1; const s = size2 || 1;
_filter.convolution.call(this, [ _filter.convolution.call(this, [
-2 * s, -2 * s,
@ -889,61 +899,24 @@ function GLImageFilter(params) {
1 * s, 1 * s,
2 * s 2 * s
]); ]);
}; },
_filter.blur = function(size2) { blur: (size2) => {
const blurSizeX = size2 / 7 / _width; const blurSizeX = size2 / 7 / _width;
const blurSizeY = size2 / 7 / _height; const blurSizeY = size2 / 7 / _height;
const program = _compileShader(_filter.blur.SHADER); const program = _compileShader(blur);
gl.uniform2f(program.uniform.px, 0, blurSizeY); gl.uniform2f(program == null ? void 0 : program.uniform["px"], 0, blurSizeY);
_draw(DRAW.INTERMEDIATE); _draw(DRAW.INTERMEDIATE);
gl.uniform2f(program.uniform.px, blurSizeX, 0); gl.uniform2f(program == null ? void 0 : program.uniform["px"], blurSizeX, 0);
_draw(); _draw();
}; },
_filter.blur.SHADER = [ pixelate: (size2) => {
"precision highp float;",
"varying vec2 vUv;",
"uniform sampler2D texture;",
"uniform vec2 px;",
"void main(void) {",
"gl_FragColor = vec4(0.0);",
"gl_FragColor += texture2D(texture, vUv + vec2(-7.0*px.x, -7.0*px.y))*0.0044299121055113265;",
"gl_FragColor += texture2D(texture, vUv + vec2(-6.0*px.x, -6.0*px.y))*0.00895781211794;",
"gl_FragColor += texture2D(texture, vUv + vec2(-5.0*px.x, -5.0*px.y))*0.0215963866053;",
"gl_FragColor += texture2D(texture, vUv + vec2(-4.0*px.x, -4.0*px.y))*0.0443683338718;",
"gl_FragColor += texture2D(texture, vUv + vec2(-3.0*px.x, -3.0*px.y))*0.0776744219933;",
"gl_FragColor += texture2D(texture, vUv + vec2(-2.0*px.x, -2.0*px.y))*0.115876621105;",
"gl_FragColor += texture2D(texture, vUv + vec2(-1.0*px.x, -1.0*px.y))*0.147308056121;",
"gl_FragColor += texture2D(texture, vUv )*0.159576912161;",
"gl_FragColor += texture2D(texture, vUv + vec2( 1.0*px.x, 1.0*px.y))*0.147308056121;",
"gl_FragColor += texture2D(texture, vUv + vec2( 2.0*px.x, 2.0*px.y))*0.115876621105;",
"gl_FragColor += texture2D(texture, vUv + vec2( 3.0*px.x, 3.0*px.y))*0.0776744219933;",
"gl_FragColor += texture2D(texture, vUv + vec2( 4.0*px.x, 4.0*px.y))*0.0443683338718;",
"gl_FragColor += texture2D(texture, vUv + vec2( 5.0*px.x, 5.0*px.y))*0.0215963866053;",
"gl_FragColor += texture2D(texture, vUv + vec2( 6.0*px.x, 6.0*px.y))*0.00895781211794;",
"gl_FragColor += texture2D(texture, vUv + vec2( 7.0*px.x, 7.0*px.y))*0.0044299121055113265;",
"}"
].join("\n");
_filter.pixelate = function(size2) {
const blurSizeX = size2 / _width; const blurSizeX = size2 / _width;
const blurSizeY = size2 / _height; const blurSizeY = size2 / _height;
const program = _compileShader(_filter.pixelate.SHADER); const program = _compileShader(pixelate);
gl.uniform2f(program.uniform.size, blurSizeX, blurSizeY); gl.uniform2f(program == null ? void 0 : program.uniform["size"], blurSizeX, blurSizeY);
_draw(); _draw();
}
}; };
_filter.pixelate.SHADER = [
"precision highp float;",
"varying vec2 vUv;",
"uniform vec2 size;",
"uniform sampler2D texture;",
"vec2 pixelate(vec2 coord, vec2 size) {",
"return floor( coord / size ) * size;",
"}",
"void main(void) {",
"gl_FragColor = vec4(0.0);",
"vec2 coord = pixelate(vUv, size);",
"gl_FragColor += texture2D(texture, coord);",
"}"
].join("\n");
} }
// src/util/env.ts // src/util/env.ts
@ -1167,7 +1140,7 @@ function process2(input, config3, getTensor = true) {
fx.addFilter("polaroid"); fx.addFilter("polaroid");
if (config3.filter.pixelate !== 0) if (config3.filter.pixelate !== 0)
fx.addFilter("pixelate", config3.filter.pixelate); fx.addFilter("pixelate", config3.filter.pixelate);
fx.apply(inCanvas); outCanvas = fx.apply(inCanvas);
} else { } else {
copy(inCanvas, outCanvas); copy(inCanvas, outCanvas);
if (fx) if (fx)
@ -1176,6 +1149,8 @@ function process2(input, config3, getTensor = true) {
} }
if (!getTensor) if (!getTensor)
return { tensor: null, canvas: outCanvas }; return { tensor: null, canvas: outCanvas };
if (!outCanvas)
throw new Error("cannot create output canvas");
let pixels; let pixels;
let depth = 3; let depth = 3;
if (typeof ImageData !== "undefined" && input instanceof ImageData || input["data"] && input["width"] && input["height"]) { if (typeof ImageData !== "undefined" && input instanceof ImageData || input["data"] && input["width"] && input["height"]) {

File diff suppressed because one or more lines are too long

443
dist/human.esm.js vendored
View File

@ -67729,42 +67729,147 @@ var version92 = {
// package.json // package.json
var version6 = "2.3.2"; var version6 = "2.3.2";
// src/image/imagefxshaders.ts
var vertexIdentity = `
precision highp float;
attribute vec2 pos;
attribute vec2 uv;
varying vec2 vUv;
uniform float flipY;
void main(void) {
vUv = uv;
gl_Position = vec4(pos.x, pos.y*flipY, 0.0, 1.);
}
`;
var colorMatrixWithAlpha = `
precision highp float;
varying vec2 vUv;
uniform sampler2D texture;
uniform float m[20];
void main(void) {
vec4 c = texture2D(texture, vUv);
gl_FragColor.r = m[0] * c.r + m[1] * c.g + m[2] * c.b + m[3] * c.a + m[4];
gl_FragColor.g = m[5] * c.r + m[6] * c.g + m[7] * c.b + m[8] * c.a + m[9];
gl_FragColor.b = m[10] * c.r + m[11] * c.g + m[12] * c.b + m[13] * c.a + m[14];
gl_FragColor.a = m[15] * c.r + m[16] * c.g + m[17] * c.b + m[18] * c.a + m[19];
}
`;
var colorMatrixWithoutAlpha = `
precision highp float;
varying vec2 vUv;
uniform sampler2D texture;
uniform float m[20];
void main(void) {
vec4 c = texture2D(texture, vUv);
gl_FragColor.r = m[0] * c.r + m[1] * c.g + m[2] * c.b + m[4];
gl_FragColor.g = m[5] * c.r + m[6] * c.g + m[7] * c.b + m[9];
gl_FragColor.b = m[10] * c.r + m[11] * c.g + m[12] * c.b + m[14];
gl_FragColor.a = c.a;
}
`;
var pixelate = `
precision highp float;
varying vec2 vUv;
uniform vec2 size;
uniform sampler2D texture;
vec2 pixelate(vec2 coord, vec2 size) {
return floor( coord / size ) * size;
}
void main(void) {
gl_FragColor = vec4(0.0);
vec2 coord = pixelate(vUv, size);
gl_FragColor += texture2D(texture, coord);
}
`;
var blur = `
precision highp float;
varying vec2 vUv;
uniform sampler2D texture;
uniform vec2 px;
void main(void) {
gl_FragColor = vec4(0.0);
gl_FragColor += texture2D(texture, vUv + vec2(-7.0*px.x, -7.0*px.y))*0.0044299121055113265;
gl_FragColor += texture2D(texture, vUv + vec2(-6.0*px.x, -6.0*px.y))*0.00895781211794;
gl_FragColor += texture2D(texture, vUv + vec2(-5.0*px.x, -5.0*px.y))*0.0215963866053;
gl_FragColor += texture2D(texture, vUv + vec2(-4.0*px.x, -4.0*px.y))*0.0443683338718;
gl_FragColor += texture2D(texture, vUv + vec2(-3.0*px.x, -3.0*px.y))*0.0776744219933;
gl_FragColor += texture2D(texture, vUv + vec2(-2.0*px.x, -2.0*px.y))*0.115876621105;
gl_FragColor += texture2D(texture, vUv + vec2(-1.0*px.x, -1.0*px.y))*0.147308056121;
gl_FragColor += texture2D(texture, vUv )*0.159576912161;
gl_FragColor += texture2D(texture, vUv + vec2( 1.0*px.x, 1.0*px.y))*0.147308056121;
gl_FragColor += texture2D(texture, vUv + vec2( 2.0*px.x, 2.0*px.y))*0.115876621105;
gl_FragColor += texture2D(texture, vUv + vec2( 3.0*px.x, 3.0*px.y))*0.0776744219933;
gl_FragColor += texture2D(texture, vUv + vec2( 4.0*px.x, 4.0*px.y))*0.0443683338718;
gl_FragColor += texture2D(texture, vUv + vec2( 5.0*px.x, 5.0*px.y))*0.0215963866053;
gl_FragColor += texture2D(texture, vUv + vec2( 6.0*px.x, 6.0*px.y))*0.00895781211794;
gl_FragColor += texture2D(texture, vUv + vec2( 7.0*px.x, 7.0*px.y))*0.0044299121055113265;
}
`;
var convolution = `
precision highp float;
varying vec2 vUv;
uniform sampler2D texture;
uniform vec2 px;
uniform float m[9];
void main(void) {
vec4 c11 = texture2D(texture, vUv - px); // top left
vec4 c12 = texture2D(texture, vec2(vUv.x, vUv.y - px.y)); // top center
vec4 c13 = texture2D(texture, vec2(vUv.x + px.x, vUv.y - px.y)); // top right
vec4 c21 = texture2D(texture, vec2(vUv.x - px.x, vUv.y) ); // mid left
vec4 c22 = texture2D(texture, vUv); // mid center
vec4 c23 = texture2D(texture, vec2(vUv.x + px.x, vUv.y) ); // mid right
vec4 c31 = texture2D(texture, vec2(vUv.x - px.x, vUv.y + px.y) ); // bottom left
vec4 c32 = texture2D(texture, vec2(vUv.x, vUv.y + px.y) ); // bottom center
vec4 c33 = texture2D(texture, vUv + px ); // bottom right
gl_FragColor =
c11 * m[0] + c12 * m[1] + c22 * m[2] +
c21 * m[3] + c22 * m[4] + c23 * m[5] +
c31 * m[6] + c32 * m[7] + c33 * m[8];
gl_FragColor.a = c22.a;
}
`;
// src/image/imagefx.ts // src/image/imagefx.ts
function GLProgram(gl, vertexSource, fragmentSource) { var GLProgram = class {
const _collect = function(source, prefix, collection) { constructor(gl, vertexSource, fragmentSource) {
__publicField(this, "uniform", {});
__publicField(this, "attribute", {});
__publicField(this, "gl");
__publicField(this, "id");
__publicField(this, "collect", (source, prefix, collection) => {
const r = new RegExp("\\b" + prefix + " \\w+ (\\w+)", "ig"); const r = new RegExp("\\b" + prefix + " \\w+ (\\w+)", "ig");
source.replace(r, (match4, name) => { source.replace(r, (match4, name) => {
collection[name] = 0; collection[name] = 0;
return match4; return match4;
}); });
}; });
const _compile = function(source, type) { __publicField(this, "compile", (source, type) => {
const shader = gl.createShader(type); const shader = this.gl.createShader(type);
gl.shaderSource(shader, source); this.gl.shaderSource(shader, source);
gl.compileShader(shader); this.gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) if (!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS))
throw new Error("filter: gl compile failed", gl.getShaderInfoLog(shader)); throw new Error(`filter: gl compile failed: ${this.gl.getShaderInfoLog(shader)}`);
return shader; return shader;
}; });
this.uniform = {}; this.gl = gl;
this.attribute = {}; const _vsh = this.compile(vertexSource, this.gl.VERTEX_SHADER);
const _vsh = _compile(vertexSource, gl.VERTEX_SHADER); const _fsh = this.compile(fragmentSource, this.gl.FRAGMENT_SHADER);
const _fsh = _compile(fragmentSource, gl.FRAGMENT_SHADER); this.id = this.gl.createProgram();
this.id = gl.createProgram(); this.gl.attachShader(this.id, _vsh);
gl.attachShader(this.id, _vsh); this.gl.attachShader(this.id, _fsh);
gl.attachShader(this.id, _fsh); this.gl.linkProgram(this.id);
gl.linkProgram(this.id); if (!this.gl.getProgramParameter(this.id, this.gl.LINK_STATUS))
if (!gl.getProgramParameter(this.id, gl.LINK_STATUS)) throw new Error(`filter: gl link failed: ${this.gl.getProgramInfoLog(this.id)}`);
throw new Error("filter: gl link failed", gl.getProgramInfoLog(this.id)); this.gl.useProgram(this.id);
gl.useProgram(this.id); this.collect(vertexSource, "attribute", this.attribute);
_collect(vertexSource, "attribute", this.attribute);
for (const a in this.attribute) for (const a in this.attribute)
this.attribute[a] = gl.getAttribLocation(this.id, a); this.attribute[a] = this.gl.getAttribLocation(this.id, a);
_collect(vertexSource, "uniform", this.uniform); this.collect(vertexSource, "uniform", this.uniform);
_collect(fragmentSource, "uniform", this.uniform); this.collect(fragmentSource, "uniform", this.uniform);
for (const u in this.uniform) for (const u in this.uniform)
this.uniform[u] = gl.getUniformLocation(this.id, u); this.uniform[u] = this.gl.getUniformLocation(this.id, u);
} }
};
function GLImageFilter(params) { function GLImageFilter(params) {
if (!params) if (!params)
params = {}; params = {};
@ -67778,13 +67883,12 @@ function GLImageFilter(params) {
let _height = -1; let _height = -1;
let _vertexBuffer = null; let _vertexBuffer = null;
let _currentProgram = null; let _currentProgram = null;
const _filter = {}; const _canvas = params.canvas || typeof OffscreenCanvas !== "undefined" ? new OffscreenCanvas(100, 100) : document.createElement("canvas");
const _canvas = params.canvas || document.createElement("canvas");
const _shaderProgramCache = {}; const _shaderProgramCache = {};
const DRAW = { INTERMEDIATE: 1 }; const DRAW = { INTERMEDIATE: 1 };
const gl = _canvas.getContext("webgl"); const gl = _canvas.getContext("webgl");
if (!gl) if (!gl)
throw new Error("filter: context failed"); throw new Error("filter: cannot get webgl context");
this.addFilter = function(name) { this.addFilter = function(name) {
const args = Array.prototype.slice.call(arguments, 1); const args = Array.prototype.slice.call(arguments, 1);
const filter = _filter[name]; const filter = _filter[name];
@ -67794,40 +67898,14 @@ function GLImageFilter(params) {
_filterChain = []; _filterChain = [];
}; };
const _resize = function(width, height) { const _resize = function(width, height) {
if (width === _width && height === _height) { if (width === _width && height === _height)
return; return;
}
_canvas.width = width; _canvas.width = width;
_width = width; _width = width;
_canvas.height = height; _canvas.height = height;
_height = height; _height = height;
if (!_vertexBuffer) { if (!_vertexBuffer) {
const vertices = new Float32Array([ const vertices = new Float32Array([-1, -1, 0, 1, 1, -1, 1, 1, -1, 1, 0, 0, -1, 1, 0, 0, 1, -1, 1, 1, 1, 1, 1, 0]);
-1,
-1,
0,
1,
1,
-1,
1,
1,
-1,
1,
0,
0,
-1,
1,
0,
0,
1,
-1,
1,
1,
1,
1,
1,
0
]);
_vertexBuffer = gl.createBuffer(), gl.bindBuffer(gl.ARRAY_BUFFER, _vertexBuffer); _vertexBuffer = gl.createBuffer(), gl.bindBuffer(gl.ARRAY_BUFFER, _vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW); gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true); gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
@ -67856,16 +67934,17 @@ function GLImageFilter(params) {
_tempFramebuffers[index] = _tempFramebuffers[index] || _createFramebufferTexture(_width, _height); _tempFramebuffers[index] = _tempFramebuffers[index] || _createFramebufferTexture(_width, _height);
return _tempFramebuffers[index]; return _tempFramebuffers[index];
}; };
const _draw = function(flags = null) { const _draw = function(flags = 0) {
var _a, _b; var _a, _b;
if (!_currentProgram)
return;
let source = null; let source = null;
let target = null; let target = null;
let flipY = false; let flipY = false;
if (_drawCount === 0) { if (_drawCount === 0)
source = _sourceTexture; source = _sourceTexture;
} else { else
source = (_a = _getTempFramebuffer(_currentFramebufferIndex)) == null ? void 0 : _a.texture; source = (_a = _getTempFramebuffer(_currentFramebufferIndex)) == null ? void 0 : _a.texture;
}
_drawCount++; _drawCount++;
if (_lastInChain && !(flags & DRAW.INTERMEDIATE)) { if (_lastInChain && !(flags & DRAW.INTERMEDIATE)) {
target = null; target = null;
@ -67876,7 +67955,7 @@ function GLImageFilter(params) {
} }
gl.bindTexture(gl.TEXTURE_2D, source); gl.bindTexture(gl.TEXTURE_2D, source);
gl.bindFramebuffer(gl.FRAMEBUFFER, target); gl.bindFramebuffer(gl.FRAMEBUFFER, target);
gl.uniform1f(_currentProgram.uniform.flipY, flipY ? -1 : 1); gl.uniform1f(_currentProgram.uniform["flipY"], flipY ? -1 : 1);
gl.drawArrays(gl.TRIANGLES, 0, 6); gl.drawArrays(gl.TRIANGLES, 0, 6);
}; };
this.apply = function(image7) { this.apply = function(image7) {
@ -67892,90 +67971,44 @@ function GLImageFilter(params) {
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image7); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image7);
if (_filterChain.length === 0) { if (_filterChain.length === 0) {
_draw(); _draw();
return _canvas; } else {
}
for (let i = 0; i < _filterChain.length; i++) { for (let i = 0; i < _filterChain.length; i++) {
_lastInChain = i === _filterChain.length - 1; _lastInChain = i === _filterChain.length - 1;
const f = _filterChain[i]; const f = _filterChain[i];
f.func.apply(this, f.args || []); f.func.apply(this, f.args || []);
} }
}
return _canvas; return _canvas;
}; };
const _compileShader = function(fragmentSource) { const _compileShader = function(fragmentSource) {
if (_shaderProgramCache[fragmentSource]) { if (_shaderProgramCache[fragmentSource]) {
_currentProgram = _shaderProgramCache[fragmentSource]; _currentProgram = _shaderProgramCache[fragmentSource];
gl.useProgram(_currentProgram.id); gl.useProgram(_currentProgram == null ? void 0 : _currentProgram.id);
return _currentProgram; return _currentProgram;
} }
const SHADER = {}; _currentProgram = new GLProgram(gl, vertexIdentity, fragmentSource);
SHADER.VERTEX_IDENTITY = [
"precision highp float;",
"attribute vec2 pos;",
"attribute vec2 uv;",
"varying vec2 vUv;",
"uniform float flipY;",
"void main(void) {",
"vUv = uv;",
"gl_Position = vec4(pos.x, pos.y*flipY, 0.0, 1.);",
"}"
].join("\n");
SHADER.FRAGMENT_IDENTITY = [
"precision highp float;",
"varying vec2 vUv;",
"uniform sampler2D texture;",
"void main(void) {",
"gl_FragColor = texture2D(texture, vUv);",
"}"
].join("\n");
_currentProgram = new GLProgram(gl, SHADER.VERTEX_IDENTITY, fragmentSource);
const floatSize = Float32Array.BYTES_PER_ELEMENT; const floatSize = Float32Array.BYTES_PER_ELEMENT;
const vertSize = 4 * floatSize; const vertSize = 4 * floatSize;
gl.enableVertexAttribArray(_currentProgram.attribute.pos); gl.enableVertexAttribArray(_currentProgram.attribute["pos"]);
gl.vertexAttribPointer(_currentProgram.attribute.pos, 2, gl.FLOAT, false, vertSize, 0 * floatSize); gl.vertexAttribPointer(_currentProgram.attribute["pos"], 2, gl.FLOAT, false, vertSize, 0 * floatSize);
gl.enableVertexAttribArray(_currentProgram.attribute.uv); gl.enableVertexAttribArray(_currentProgram.attribute.uv);
gl.vertexAttribPointer(_currentProgram.attribute.uv, 2, gl.FLOAT, false, vertSize, 2 * floatSize); gl.vertexAttribPointer(_currentProgram.attribute["uv"], 2, gl.FLOAT, false, vertSize, 2 * floatSize);
_shaderProgramCache[fragmentSource] = _currentProgram; _shaderProgramCache[fragmentSource] = _currentProgram;
return _currentProgram; return _currentProgram;
}; };
_filter.colorMatrix = function(matrix) { const _filter = {
colorMatrix: (matrix) => {
const m = new Float32Array(matrix); const m = new Float32Array(matrix);
m[4] /= 255; m[4] /= 255;
m[9] /= 255; m[9] /= 255;
m[14] /= 255; m[14] /= 255;
m[19] /= 255; m[19] /= 255;
const shader = m[18] === 1 && m[3] === 0 && m[8] === 0 && m[13] === 0 && m[15] === 0 && m[16] === 0 && m[17] === 0 && m[19] === 0 ? _filter.colorMatrix.SHADER.WITHOUT_ALPHA : _filter.colorMatrix.SHADER.WITH_ALPHA; const shader = m[18] === 1 && m[3] === 0 && m[8] === 0 && m[13] === 0 && m[15] === 0 && m[16] === 0 && m[17] === 0 && m[19] === 0 ? colorMatrixWithoutAlpha : colorMatrixWithAlpha;
const program = _compileShader(shader); const program = _compileShader(shader);
gl.uniform1fv(program.uniform.m, m); gl.uniform1fv(program == null ? void 0 : program.uniform["m"], m);
_draw(); _draw();
}; },
_filter.colorMatrix.SHADER = {}; brightness: (brightness) => {
_filter.colorMatrix.SHADER.WITH_ALPHA = [
"precision highp float;",
"varying vec2 vUv;",
"uniform sampler2D texture;",
"uniform float m[20];",
"void main(void) {",
"vec4 c = texture2D(texture, vUv);",
"gl_FragColor.r = m[0] * c.r + m[1] * c.g + m[2] * c.b + m[3] * c.a + m[4];",
"gl_FragColor.g = m[5] * c.r + m[6] * c.g + m[7] * c.b + m[8] * c.a + m[9];",
"gl_FragColor.b = m[10] * c.r + m[11] * c.g + m[12] * c.b + m[13] * c.a + m[14];",
"gl_FragColor.a = m[15] * c.r + m[16] * c.g + m[17] * c.b + m[18] * c.a + m[19];",
"}"
].join("\n");
_filter.colorMatrix.SHADER.WITHOUT_ALPHA = [
"precision highp float;",
"varying vec2 vUv;",
"uniform sampler2D texture;",
"uniform float m[20];",
"void main(void) {",
"vec4 c = texture2D(texture, vUv);",
"gl_FragColor.r = m[0] * c.r + m[1] * c.g + m[2] * c.b + m[4];",
"gl_FragColor.g = m[5] * c.r + m[6] * c.g + m[7] * c.b + m[9];",
"gl_FragColor.b = m[10] * c.r + m[11] * c.g + m[12] * c.b + m[14];",
"gl_FragColor.a = c.a;",
"}"
].join("\n");
_filter.brightness = function(brightness) {
const b = (brightness || 0) + 1; const b = (brightness || 0) + 1;
_filter.colorMatrix([ _filter.colorMatrix([
b, b,
@ -67999,8 +68032,8 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.saturation = function(amount) { saturation: (amount) => {
const x = (amount || 0) * 2 / 3 + 1; const x = (amount || 0) * 2 / 3 + 1;
const y = (x - 1) * -0.5; const y = (x - 1) * -0.5;
_filter.colorMatrix([ _filter.colorMatrix([
@ -68025,11 +68058,11 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.desaturate = function() { desaturate: () => {
_filter.saturation(-1); _filter.saturation(-1);
}; },
_filter.contrast = function(amount) { contrast: (amount) => {
const v = (amount || 0) + 1; const v = (amount || 0) + 1;
const o = -128 * (v - 1); const o = -128 * (v - 1);
_filter.colorMatrix([ _filter.colorMatrix([
@ -68054,11 +68087,11 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.negative = function() { negative: () => {
_filter.contrast(-2); _filter.contrast(-2);
}; },
_filter.hue = function(rotation) { hue: (rotation) => {
rotation = (rotation || 0) / 180 * Math.PI; rotation = (rotation || 0) / 180 * Math.PI;
const cos5 = Math.cos(rotation); const cos5 = Math.cos(rotation);
const sin5 = Math.sin(rotation); const sin5 = Math.sin(rotation);
@ -68087,8 +68120,8 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.desaturateLuminance = function() { desaturateLuminance: () => {
_filter.colorMatrix([ _filter.colorMatrix([
0.2764723, 0.2764723,
0.929708, 0.929708,
@ -68111,8 +68144,8 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.sepia = function() { sepia: () => {
_filter.colorMatrix([ _filter.colorMatrix([
0.393, 0.393,
0.7689999, 0.7689999,
@ -68135,8 +68168,8 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.brownie = function() { brownie: () => {
_filter.colorMatrix([ _filter.colorMatrix([
0.5997023498159715, 0.5997023498159715,
0.34553243048391263, 0.34553243048391263,
@ -68159,8 +68192,8 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.vintagePinhole = function() { vintagePinhole: () => {
_filter.colorMatrix([ _filter.colorMatrix([
0.6279345635605994, 0.6279345635605994,
0.3202183420819367, 0.3202183420819367,
@ -68183,8 +68216,8 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.kodachrome = function() { kodachrome: () => {
_filter.colorMatrix([ _filter.colorMatrix([
1.1285582396593525, 1.1285582396593525,
-0.3967382283601348, -0.3967382283601348,
@ -68207,8 +68240,8 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.technicolor = function() { technicolor: () => {
_filter.colorMatrix([ _filter.colorMatrix([
1.9125277891456083, 1.9125277891456083,
-0.8545344976951645, -0.8545344976951645,
@ -68231,8 +68264,8 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.polaroid = function() { polaroid: () => {
_filter.colorMatrix([ _filter.colorMatrix([
1.438, 1.438,
-0.062, -0.062,
@ -68255,8 +68288,8 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.shiftToBGR = function() { shiftToBGR: () => {
_filter.colorMatrix([ _filter.colorMatrix([
0, 0,
0, 0,
@ -68279,40 +68312,17 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.convolution = function(matrix) { convolution: (matrix) => {
const m = new Float32Array(matrix); const m = new Float32Array(matrix);
const pixelSizeX = 1 / _width; const pixelSizeX = 1 / _width;
const pixelSizeY = 1 / _height; const pixelSizeY = 1 / _height;
const program = _compileShader(_filter.convolution.SHADER); const program = _compileShader(convolution);
gl.uniform1fv(program.uniform.m, m); gl.uniform1fv(program == null ? void 0 : program.uniform["m"], m);
gl.uniform2f(program.uniform.px, pixelSizeX, pixelSizeY); gl.uniform2f(program == null ? void 0 : program.uniform["px"], pixelSizeX, pixelSizeY);
_draw(); _draw();
}; },
_filter.convolution.SHADER = [ detectEdges: () => {
"precision highp float;",
"varying vec2 vUv;",
"uniform sampler2D texture;",
"uniform vec2 px;",
"uniform float m[9];",
"void main(void) {",
"vec4 c11 = texture2D(texture, vUv - px);",
"vec4 c12 = texture2D(texture, vec2(vUv.x, vUv.y - px.y));",
"vec4 c13 = texture2D(texture, vec2(vUv.x + px.x, vUv.y - px.y));",
"vec4 c21 = texture2D(texture, vec2(vUv.x - px.x, vUv.y) );",
"vec4 c22 = texture2D(texture, vUv);",
"vec4 c23 = texture2D(texture, vec2(vUv.x + px.x, vUv.y) );",
"vec4 c31 = texture2D(texture, vec2(vUv.x - px.x, vUv.y + px.y) );",
"vec4 c32 = texture2D(texture, vec2(vUv.x, vUv.y + px.y) );",
"vec4 c33 = texture2D(texture, vUv + px );",
"gl_FragColor = ",
"c11 * m[0] + c12 * m[1] + c22 * m[2] +",
"c21 * m[3] + c22 * m[4] + c23 * m[5] +",
"c31 * m[6] + c32 * m[7] + c33 * m[8];",
"gl_FragColor.a = c22.a;",
"}"
].join("\n");
_filter.detectEdges = function() {
_filter.convolution.call(this, [ _filter.convolution.call(this, [
0, 0,
1, 1,
@ -68324,8 +68334,8 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.sobelX = function() { sobelX: () => {
_filter.convolution.call(this, [ _filter.convolution.call(this, [
-1, -1,
0, 0,
@ -68337,8 +68347,8 @@ function GLImageFilter(params) {
0, 0,
1 1
]); ]);
}; },
_filter.sobelY = function() { sobelY: () => {
_filter.convolution.call(this, [ _filter.convolution.call(this, [
-1, -1,
-2, -2,
@ -68350,8 +68360,8 @@ function GLImageFilter(params) {
2, 2,
1 1
]); ]);
}; },
_filter.sharpen = function(amount) { sharpen: (amount) => {
const a = amount || 1; const a = amount || 1;
_filter.convolution.call(this, [ _filter.convolution.call(this, [
0, 0,
@ -68364,8 +68374,8 @@ function GLImageFilter(params) {
-1 * a, -1 * a,
0 0
]); ]);
}; },
_filter.emboss = function(size2) { emboss: (size2) => {
const s = size2 || 1; const s = size2 || 1;
_filter.convolution.call(this, [ _filter.convolution.call(this, [
-2 * s, -2 * s,
@ -68378,61 +68388,24 @@ function GLImageFilter(params) {
1 * s, 1 * s,
2 * s 2 * s
]); ]);
}; },
_filter.blur = function(size2) { blur: (size2) => {
const blurSizeX = size2 / 7 / _width; const blurSizeX = size2 / 7 / _width;
const blurSizeY = size2 / 7 / _height; const blurSizeY = size2 / 7 / _height;
const program = _compileShader(_filter.blur.SHADER); const program = _compileShader(blur);
gl.uniform2f(program.uniform.px, 0, blurSizeY); gl.uniform2f(program == null ? void 0 : program.uniform["px"], 0, blurSizeY);
_draw(DRAW.INTERMEDIATE); _draw(DRAW.INTERMEDIATE);
gl.uniform2f(program.uniform.px, blurSizeX, 0); gl.uniform2f(program == null ? void 0 : program.uniform["px"], blurSizeX, 0);
_draw(); _draw();
}; },
_filter.blur.SHADER = [ pixelate: (size2) => {
"precision highp float;",
"varying vec2 vUv;",
"uniform sampler2D texture;",
"uniform vec2 px;",
"void main(void) {",
"gl_FragColor = vec4(0.0);",
"gl_FragColor += texture2D(texture, vUv + vec2(-7.0*px.x, -7.0*px.y))*0.0044299121055113265;",
"gl_FragColor += texture2D(texture, vUv + vec2(-6.0*px.x, -6.0*px.y))*0.00895781211794;",
"gl_FragColor += texture2D(texture, vUv + vec2(-5.0*px.x, -5.0*px.y))*0.0215963866053;",
"gl_FragColor += texture2D(texture, vUv + vec2(-4.0*px.x, -4.0*px.y))*0.0443683338718;",
"gl_FragColor += texture2D(texture, vUv + vec2(-3.0*px.x, -3.0*px.y))*0.0776744219933;",
"gl_FragColor += texture2D(texture, vUv + vec2(-2.0*px.x, -2.0*px.y))*0.115876621105;",
"gl_FragColor += texture2D(texture, vUv + vec2(-1.0*px.x, -1.0*px.y))*0.147308056121;",
"gl_FragColor += texture2D(texture, vUv )*0.159576912161;",
"gl_FragColor += texture2D(texture, vUv + vec2( 1.0*px.x, 1.0*px.y))*0.147308056121;",
"gl_FragColor += texture2D(texture, vUv + vec2( 2.0*px.x, 2.0*px.y))*0.115876621105;",
"gl_FragColor += texture2D(texture, vUv + vec2( 3.0*px.x, 3.0*px.y))*0.0776744219933;",
"gl_FragColor += texture2D(texture, vUv + vec2( 4.0*px.x, 4.0*px.y))*0.0443683338718;",
"gl_FragColor += texture2D(texture, vUv + vec2( 5.0*px.x, 5.0*px.y))*0.0215963866053;",
"gl_FragColor += texture2D(texture, vUv + vec2( 6.0*px.x, 6.0*px.y))*0.00895781211794;",
"gl_FragColor += texture2D(texture, vUv + vec2( 7.0*px.x, 7.0*px.y))*0.0044299121055113265;",
"}"
].join("\n");
_filter.pixelate = function(size2) {
const blurSizeX = size2 / _width; const blurSizeX = size2 / _width;
const blurSizeY = size2 / _height; const blurSizeY = size2 / _height;
const program = _compileShader(_filter.pixelate.SHADER); const program = _compileShader(pixelate);
gl.uniform2f(program.uniform.size, blurSizeX, blurSizeY); gl.uniform2f(program == null ? void 0 : program.uniform["size"], blurSizeX, blurSizeY);
_draw(); _draw();
}
}; };
_filter.pixelate.SHADER = [
"precision highp float;",
"varying vec2 vUv;",
"uniform vec2 size;",
"uniform sampler2D texture;",
"vec2 pixelate(vec2 coord, vec2 size) {",
"return floor( coord / size ) * size;",
"}",
"void main(void) {",
"gl_FragColor = vec4(0.0);",
"vec2 coord = pixelate(vUv, size);",
"gl_FragColor += texture2D(texture, coord);",
"}"
].join("\n");
} }
// src/util/env.ts // src/util/env.ts
@ -68656,7 +68629,7 @@ function process2(input2, config3, getTensor2 = true) {
fx.addFilter("polaroid"); fx.addFilter("polaroid");
if (config3.filter.pixelate !== 0) if (config3.filter.pixelate !== 0)
fx.addFilter("pixelate", config3.filter.pixelate); fx.addFilter("pixelate", config3.filter.pixelate);
fx.apply(inCanvas); outCanvas = fx.apply(inCanvas);
} else { } else {
copy(inCanvas, outCanvas); copy(inCanvas, outCanvas);
if (fx) if (fx)
@ -68665,6 +68638,8 @@ function process2(input2, config3, getTensor2 = true) {
} }
if (!getTensor2) if (!getTensor2)
return { tensor: null, canvas: outCanvas }; return { tensor: null, canvas: outCanvas };
if (!outCanvas)
throw new Error("cannot create output canvas");
let pixels; let pixels;
let depth = 3; let depth = 3;
if (typeof ImageData !== "undefined" && input2 instanceof ImageData || input2["data"] && input2["width"] && input2["height"]) { if (typeof ImageData !== "undefined" && input2 instanceof ImageData || input2["data"] && input2["width"] && input2["height"]) {

File diff suppressed because one or more lines are too long

679
dist/human.js vendored

File diff suppressed because one or more lines are too long

443
dist/human.node-gpu.js vendored
View File

@ -260,42 +260,147 @@ var tf22 = __toModule(require_tfjs_esm());
// src/image/image.ts // src/image/image.ts
var tf2 = __toModule(require_tfjs_esm()); var tf2 = __toModule(require_tfjs_esm());
// src/image/imagefxshaders.ts
var vertexIdentity = `
precision highp float;
attribute vec2 pos;
attribute vec2 uv;
varying vec2 vUv;
uniform float flipY;
void main(void) {
vUv = uv;
gl_Position = vec4(pos.x, pos.y*flipY, 0.0, 1.);
}
`;
var colorMatrixWithAlpha = `
precision highp float;
varying vec2 vUv;
uniform sampler2D texture;
uniform float m[20];
void main(void) {
vec4 c = texture2D(texture, vUv);
gl_FragColor.r = m[0] * c.r + m[1] * c.g + m[2] * c.b + m[3] * c.a + m[4];
gl_FragColor.g = m[5] * c.r + m[6] * c.g + m[7] * c.b + m[8] * c.a + m[9];
gl_FragColor.b = m[10] * c.r + m[11] * c.g + m[12] * c.b + m[13] * c.a + m[14];
gl_FragColor.a = m[15] * c.r + m[16] * c.g + m[17] * c.b + m[18] * c.a + m[19];
}
`;
var colorMatrixWithoutAlpha = `
precision highp float;
varying vec2 vUv;
uniform sampler2D texture;
uniform float m[20];
void main(void) {
vec4 c = texture2D(texture, vUv);
gl_FragColor.r = m[0] * c.r + m[1] * c.g + m[2] * c.b + m[4];
gl_FragColor.g = m[5] * c.r + m[6] * c.g + m[7] * c.b + m[9];
gl_FragColor.b = m[10] * c.r + m[11] * c.g + m[12] * c.b + m[14];
gl_FragColor.a = c.a;
}
`;
var pixelate = `
precision highp float;
varying vec2 vUv;
uniform vec2 size;
uniform sampler2D texture;
vec2 pixelate(vec2 coord, vec2 size) {
return floor( coord / size ) * size;
}
void main(void) {
gl_FragColor = vec4(0.0);
vec2 coord = pixelate(vUv, size);
gl_FragColor += texture2D(texture, coord);
}
`;
var blur = `
precision highp float;
varying vec2 vUv;
uniform sampler2D texture;
uniform vec2 px;
void main(void) {
gl_FragColor = vec4(0.0);
gl_FragColor += texture2D(texture, vUv + vec2(-7.0*px.x, -7.0*px.y))*0.0044299121055113265;
gl_FragColor += texture2D(texture, vUv + vec2(-6.0*px.x, -6.0*px.y))*0.00895781211794;
gl_FragColor += texture2D(texture, vUv + vec2(-5.0*px.x, -5.0*px.y))*0.0215963866053;
gl_FragColor += texture2D(texture, vUv + vec2(-4.0*px.x, -4.0*px.y))*0.0443683338718;
gl_FragColor += texture2D(texture, vUv + vec2(-3.0*px.x, -3.0*px.y))*0.0776744219933;
gl_FragColor += texture2D(texture, vUv + vec2(-2.0*px.x, -2.0*px.y))*0.115876621105;
gl_FragColor += texture2D(texture, vUv + vec2(-1.0*px.x, -1.0*px.y))*0.147308056121;
gl_FragColor += texture2D(texture, vUv )*0.159576912161;
gl_FragColor += texture2D(texture, vUv + vec2( 1.0*px.x, 1.0*px.y))*0.147308056121;
gl_FragColor += texture2D(texture, vUv + vec2( 2.0*px.x, 2.0*px.y))*0.115876621105;
gl_FragColor += texture2D(texture, vUv + vec2( 3.0*px.x, 3.0*px.y))*0.0776744219933;
gl_FragColor += texture2D(texture, vUv + vec2( 4.0*px.x, 4.0*px.y))*0.0443683338718;
gl_FragColor += texture2D(texture, vUv + vec2( 5.0*px.x, 5.0*px.y))*0.0215963866053;
gl_FragColor += texture2D(texture, vUv + vec2( 6.0*px.x, 6.0*px.y))*0.00895781211794;
gl_FragColor += texture2D(texture, vUv + vec2( 7.0*px.x, 7.0*px.y))*0.0044299121055113265;
}
`;
var convolution = `
precision highp float;
varying vec2 vUv;
uniform sampler2D texture;
uniform vec2 px;
uniform float m[9];
void main(void) {
vec4 c11 = texture2D(texture, vUv - px); // top left
vec4 c12 = texture2D(texture, vec2(vUv.x, vUv.y - px.y)); // top center
vec4 c13 = texture2D(texture, vec2(vUv.x + px.x, vUv.y - px.y)); // top right
vec4 c21 = texture2D(texture, vec2(vUv.x - px.x, vUv.y) ); // mid left
vec4 c22 = texture2D(texture, vUv); // mid center
vec4 c23 = texture2D(texture, vec2(vUv.x + px.x, vUv.y) ); // mid right
vec4 c31 = texture2D(texture, vec2(vUv.x - px.x, vUv.y + px.y) ); // bottom left
vec4 c32 = texture2D(texture, vec2(vUv.x, vUv.y + px.y) ); // bottom center
vec4 c33 = texture2D(texture, vUv + px ); // bottom right
gl_FragColor =
c11 * m[0] + c12 * m[1] + c22 * m[2] +
c21 * m[3] + c22 * m[4] + c23 * m[5] +
c31 * m[6] + c32 * m[7] + c33 * m[8];
gl_FragColor.a = c22.a;
}
`;
// src/image/imagefx.ts // src/image/imagefx.ts
function GLProgram(gl, vertexSource, fragmentSource) { var GLProgram = class {
const _collect = function(source, prefix, collection) { constructor(gl, vertexSource, fragmentSource) {
__publicField(this, "uniform", {});
__publicField(this, "attribute", {});
__publicField(this, "gl");
__publicField(this, "id");
__publicField(this, "collect", (source, prefix, collection) => {
const r = new RegExp("\\b" + prefix + " \\w+ (\\w+)", "ig"); const r = new RegExp("\\b" + prefix + " \\w+ (\\w+)", "ig");
source.replace(r, (match4, name) => { source.replace(r, (match4, name) => {
collection[name] = 0; collection[name] = 0;
return match4; return match4;
}); });
}; });
const _compile = function(source, type) { __publicField(this, "compile", (source, type) => {
const shader = gl.createShader(type); const shader = this.gl.createShader(type);
gl.shaderSource(shader, source); this.gl.shaderSource(shader, source);
gl.compileShader(shader); this.gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) if (!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS))
throw new Error("filter: gl compile failed", gl.getShaderInfoLog(shader)); throw new Error(`filter: gl compile failed: ${this.gl.getShaderInfoLog(shader)}`);
return shader; return shader;
}; });
this.uniform = {}; this.gl = gl;
this.attribute = {}; const _vsh = this.compile(vertexSource, this.gl.VERTEX_SHADER);
const _vsh = _compile(vertexSource, gl.VERTEX_SHADER); const _fsh = this.compile(fragmentSource, this.gl.FRAGMENT_SHADER);
const _fsh = _compile(fragmentSource, gl.FRAGMENT_SHADER); this.id = this.gl.createProgram();
this.id = gl.createProgram(); this.gl.attachShader(this.id, _vsh);
gl.attachShader(this.id, _vsh); this.gl.attachShader(this.id, _fsh);
gl.attachShader(this.id, _fsh); this.gl.linkProgram(this.id);
gl.linkProgram(this.id); if (!this.gl.getProgramParameter(this.id, this.gl.LINK_STATUS))
if (!gl.getProgramParameter(this.id, gl.LINK_STATUS)) throw new Error(`filter: gl link failed: ${this.gl.getProgramInfoLog(this.id)}`);
throw new Error("filter: gl link failed", gl.getProgramInfoLog(this.id)); this.gl.useProgram(this.id);
gl.useProgram(this.id); this.collect(vertexSource, "attribute", this.attribute);
_collect(vertexSource, "attribute", this.attribute);
for (const a in this.attribute) for (const a in this.attribute)
this.attribute[a] = gl.getAttribLocation(this.id, a); this.attribute[a] = this.gl.getAttribLocation(this.id, a);
_collect(vertexSource, "uniform", this.uniform); this.collect(vertexSource, "uniform", this.uniform);
_collect(fragmentSource, "uniform", this.uniform); this.collect(fragmentSource, "uniform", this.uniform);
for (const u in this.uniform) for (const u in this.uniform)
this.uniform[u] = gl.getUniformLocation(this.id, u); this.uniform[u] = this.gl.getUniformLocation(this.id, u);
} }
};
function GLImageFilter(params) { function GLImageFilter(params) {
if (!params) if (!params)
params = {}; params = {};
@ -309,13 +414,12 @@ function GLImageFilter(params) {
let _height = -1; let _height = -1;
let _vertexBuffer = null; let _vertexBuffer = null;
let _currentProgram = null; let _currentProgram = null;
const _filter = {}; const _canvas = params.canvas || typeof OffscreenCanvas !== "undefined" ? new OffscreenCanvas(100, 100) : document.createElement("canvas");
const _canvas = params.canvas || document.createElement("canvas");
const _shaderProgramCache = {}; const _shaderProgramCache = {};
const DRAW = { INTERMEDIATE: 1 }; const DRAW = { INTERMEDIATE: 1 };
const gl = _canvas.getContext("webgl"); const gl = _canvas.getContext("webgl");
if (!gl) if (!gl)
throw new Error("filter: context failed"); throw new Error("filter: cannot get webgl context");
this.addFilter = function(name) { this.addFilter = function(name) {
const args = Array.prototype.slice.call(arguments, 1); const args = Array.prototype.slice.call(arguments, 1);
const filter = _filter[name]; const filter = _filter[name];
@ -325,40 +429,14 @@ function GLImageFilter(params) {
_filterChain = []; _filterChain = [];
}; };
const _resize = function(width, height) { const _resize = function(width, height) {
if (width === _width && height === _height) { if (width === _width && height === _height)
return; return;
}
_canvas.width = width; _canvas.width = width;
_width = width; _width = width;
_canvas.height = height; _canvas.height = height;
_height = height; _height = height;
if (!_vertexBuffer) { if (!_vertexBuffer) {
const vertices = new Float32Array([ const vertices = new Float32Array([-1, -1, 0, 1, 1, -1, 1, 1, -1, 1, 0, 0, -1, 1, 0, 0, 1, -1, 1, 1, 1, 1, 1, 0]);
-1,
-1,
0,
1,
1,
-1,
1,
1,
-1,
1,
0,
0,
-1,
1,
0,
0,
1,
-1,
1,
1,
1,
1,
1,
0
]);
_vertexBuffer = gl.createBuffer(), gl.bindBuffer(gl.ARRAY_BUFFER, _vertexBuffer); _vertexBuffer = gl.createBuffer(), gl.bindBuffer(gl.ARRAY_BUFFER, _vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW); gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true); gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
@ -387,16 +465,17 @@ function GLImageFilter(params) {
_tempFramebuffers[index] = _tempFramebuffers[index] || _createFramebufferTexture(_width, _height); _tempFramebuffers[index] = _tempFramebuffers[index] || _createFramebufferTexture(_width, _height);
return _tempFramebuffers[index]; return _tempFramebuffers[index];
}; };
const _draw = function(flags = null) { const _draw = function(flags = 0) {
var _a, _b; var _a, _b;
if (!_currentProgram)
return;
let source = null; let source = null;
let target = null; let target = null;
let flipY = false; let flipY = false;
if (_drawCount === 0) { if (_drawCount === 0)
source = _sourceTexture; source = _sourceTexture;
} else { else
source = (_a = _getTempFramebuffer(_currentFramebufferIndex)) == null ? void 0 : _a.texture; source = (_a = _getTempFramebuffer(_currentFramebufferIndex)) == null ? void 0 : _a.texture;
}
_drawCount++; _drawCount++;
if (_lastInChain && !(flags & DRAW.INTERMEDIATE)) { if (_lastInChain && !(flags & DRAW.INTERMEDIATE)) {
target = null; target = null;
@ -407,7 +486,7 @@ function GLImageFilter(params) {
} }
gl.bindTexture(gl.TEXTURE_2D, source); gl.bindTexture(gl.TEXTURE_2D, source);
gl.bindFramebuffer(gl.FRAMEBUFFER, target); gl.bindFramebuffer(gl.FRAMEBUFFER, target);
gl.uniform1f(_currentProgram.uniform.flipY, flipY ? -1 : 1); gl.uniform1f(_currentProgram.uniform["flipY"], flipY ? -1 : 1);
gl.drawArrays(gl.TRIANGLES, 0, 6); gl.drawArrays(gl.TRIANGLES, 0, 6);
}; };
this.apply = function(image24) { this.apply = function(image24) {
@ -423,90 +502,44 @@ function GLImageFilter(params) {
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image24); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image24);
if (_filterChain.length === 0) { if (_filterChain.length === 0) {
_draw(); _draw();
return _canvas; } else {
}
for (let i = 0; i < _filterChain.length; i++) { for (let i = 0; i < _filterChain.length; i++) {
_lastInChain = i === _filterChain.length - 1; _lastInChain = i === _filterChain.length - 1;
const f = _filterChain[i]; const f = _filterChain[i];
f.func.apply(this, f.args || []); f.func.apply(this, f.args || []);
} }
}
return _canvas; return _canvas;
}; };
const _compileShader = function(fragmentSource) { const _compileShader = function(fragmentSource) {
if (_shaderProgramCache[fragmentSource]) { if (_shaderProgramCache[fragmentSource]) {
_currentProgram = _shaderProgramCache[fragmentSource]; _currentProgram = _shaderProgramCache[fragmentSource];
gl.useProgram(_currentProgram.id); gl.useProgram(_currentProgram == null ? void 0 : _currentProgram.id);
return _currentProgram; return _currentProgram;
} }
const SHADER = {}; _currentProgram = new GLProgram(gl, vertexIdentity, fragmentSource);
SHADER.VERTEX_IDENTITY = [
"precision highp float;",
"attribute vec2 pos;",
"attribute vec2 uv;",
"varying vec2 vUv;",
"uniform float flipY;",
"void main(void) {",
"vUv = uv;",
"gl_Position = vec4(pos.x, pos.y*flipY, 0.0, 1.);",
"}"
].join("\n");
SHADER.FRAGMENT_IDENTITY = [
"precision highp float;",
"varying vec2 vUv;",
"uniform sampler2D texture;",
"void main(void) {",
"gl_FragColor = texture2D(texture, vUv);",
"}"
].join("\n");
_currentProgram = new GLProgram(gl, SHADER.VERTEX_IDENTITY, fragmentSource);
const floatSize = Float32Array.BYTES_PER_ELEMENT; const floatSize = Float32Array.BYTES_PER_ELEMENT;
const vertSize = 4 * floatSize; const vertSize = 4 * floatSize;
gl.enableVertexAttribArray(_currentProgram.attribute.pos); gl.enableVertexAttribArray(_currentProgram.attribute["pos"]);
gl.vertexAttribPointer(_currentProgram.attribute.pos, 2, gl.FLOAT, false, vertSize, 0 * floatSize); gl.vertexAttribPointer(_currentProgram.attribute["pos"], 2, gl.FLOAT, false, vertSize, 0 * floatSize);
gl.enableVertexAttribArray(_currentProgram.attribute.uv); gl.enableVertexAttribArray(_currentProgram.attribute.uv);
gl.vertexAttribPointer(_currentProgram.attribute.uv, 2, gl.FLOAT, false, vertSize, 2 * floatSize); gl.vertexAttribPointer(_currentProgram.attribute["uv"], 2, gl.FLOAT, false, vertSize, 2 * floatSize);
_shaderProgramCache[fragmentSource] = _currentProgram; _shaderProgramCache[fragmentSource] = _currentProgram;
return _currentProgram; return _currentProgram;
}; };
_filter.colorMatrix = function(matrix) { const _filter = {
colorMatrix: (matrix) => {
const m = new Float32Array(matrix); const m = new Float32Array(matrix);
m[4] /= 255; m[4] /= 255;
m[9] /= 255; m[9] /= 255;
m[14] /= 255; m[14] /= 255;
m[19] /= 255; m[19] /= 255;
const shader = m[18] === 1 && m[3] === 0 && m[8] === 0 && m[13] === 0 && m[15] === 0 && m[16] === 0 && m[17] === 0 && m[19] === 0 ? _filter.colorMatrix.SHADER.WITHOUT_ALPHA : _filter.colorMatrix.SHADER.WITH_ALPHA; const shader = m[18] === 1 && m[3] === 0 && m[8] === 0 && m[13] === 0 && m[15] === 0 && m[16] === 0 && m[17] === 0 && m[19] === 0 ? colorMatrixWithoutAlpha : colorMatrixWithAlpha;
const program = _compileShader(shader); const program = _compileShader(shader);
gl.uniform1fv(program.uniform.m, m); gl.uniform1fv(program == null ? void 0 : program.uniform["m"], m);
_draw(); _draw();
}; },
_filter.colorMatrix.SHADER = {}; brightness: (brightness) => {
_filter.colorMatrix.SHADER.WITH_ALPHA = [
"precision highp float;",
"varying vec2 vUv;",
"uniform sampler2D texture;",
"uniform float m[20];",
"void main(void) {",
"vec4 c = texture2D(texture, vUv);",
"gl_FragColor.r = m[0] * c.r + m[1] * c.g + m[2] * c.b + m[3] * c.a + m[4];",
"gl_FragColor.g = m[5] * c.r + m[6] * c.g + m[7] * c.b + m[8] * c.a + m[9];",
"gl_FragColor.b = m[10] * c.r + m[11] * c.g + m[12] * c.b + m[13] * c.a + m[14];",
"gl_FragColor.a = m[15] * c.r + m[16] * c.g + m[17] * c.b + m[18] * c.a + m[19];",
"}"
].join("\n");
_filter.colorMatrix.SHADER.WITHOUT_ALPHA = [
"precision highp float;",
"varying vec2 vUv;",
"uniform sampler2D texture;",
"uniform float m[20];",
"void main(void) {",
"vec4 c = texture2D(texture, vUv);",
"gl_FragColor.r = m[0] * c.r + m[1] * c.g + m[2] * c.b + m[4];",
"gl_FragColor.g = m[5] * c.r + m[6] * c.g + m[7] * c.b + m[9];",
"gl_FragColor.b = m[10] * c.r + m[11] * c.g + m[12] * c.b + m[14];",
"gl_FragColor.a = c.a;",
"}"
].join("\n");
_filter.brightness = function(brightness) {
const b = (brightness || 0) + 1; const b = (brightness || 0) + 1;
_filter.colorMatrix([ _filter.colorMatrix([
b, b,
@ -530,8 +563,8 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.saturation = function(amount) { saturation: (amount) => {
const x = (amount || 0) * 2 / 3 + 1; const x = (amount || 0) * 2 / 3 + 1;
const y = (x - 1) * -0.5; const y = (x - 1) * -0.5;
_filter.colorMatrix([ _filter.colorMatrix([
@ -556,11 +589,11 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.desaturate = function() { desaturate: () => {
_filter.saturation(-1); _filter.saturation(-1);
}; },
_filter.contrast = function(amount) { contrast: (amount) => {
const v = (amount || 0) + 1; const v = (amount || 0) + 1;
const o = -128 * (v - 1); const o = -128 * (v - 1);
_filter.colorMatrix([ _filter.colorMatrix([
@ -585,11 +618,11 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.negative = function() { negative: () => {
_filter.contrast(-2); _filter.contrast(-2);
}; },
_filter.hue = function(rotation) { hue: (rotation) => {
rotation = (rotation || 0) / 180 * Math.PI; rotation = (rotation || 0) / 180 * Math.PI;
const cos = Math.cos(rotation); const cos = Math.cos(rotation);
const sin = Math.sin(rotation); const sin = Math.sin(rotation);
@ -618,8 +651,8 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.desaturateLuminance = function() { desaturateLuminance: () => {
_filter.colorMatrix([ _filter.colorMatrix([
0.2764723, 0.2764723,
0.929708, 0.929708,
@ -642,8 +675,8 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.sepia = function() { sepia: () => {
_filter.colorMatrix([ _filter.colorMatrix([
0.393, 0.393,
0.7689999, 0.7689999,
@ -666,8 +699,8 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.brownie = function() { brownie: () => {
_filter.colorMatrix([ _filter.colorMatrix([
0.5997023498159715, 0.5997023498159715,
0.34553243048391263, 0.34553243048391263,
@ -690,8 +723,8 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.vintagePinhole = function() { vintagePinhole: () => {
_filter.colorMatrix([ _filter.colorMatrix([
0.6279345635605994, 0.6279345635605994,
0.3202183420819367, 0.3202183420819367,
@ -714,8 +747,8 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.kodachrome = function() { kodachrome: () => {
_filter.colorMatrix([ _filter.colorMatrix([
1.1285582396593525, 1.1285582396593525,
-0.3967382283601348, -0.3967382283601348,
@ -738,8 +771,8 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.technicolor = function() { technicolor: () => {
_filter.colorMatrix([ _filter.colorMatrix([
1.9125277891456083, 1.9125277891456083,
-0.8545344976951645, -0.8545344976951645,
@ -762,8 +795,8 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.polaroid = function() { polaroid: () => {
_filter.colorMatrix([ _filter.colorMatrix([
1.438, 1.438,
-0.062, -0.062,
@ -786,8 +819,8 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.shiftToBGR = function() { shiftToBGR: () => {
_filter.colorMatrix([ _filter.colorMatrix([
0, 0,
0, 0,
@ -810,40 +843,17 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.convolution = function(matrix) { convolution: (matrix) => {
const m = new Float32Array(matrix); const m = new Float32Array(matrix);
const pixelSizeX = 1 / _width; const pixelSizeX = 1 / _width;
const pixelSizeY = 1 / _height; const pixelSizeY = 1 / _height;
const program = _compileShader(_filter.convolution.SHADER); const program = _compileShader(convolution);
gl.uniform1fv(program.uniform.m, m); gl.uniform1fv(program == null ? void 0 : program.uniform["m"], m);
gl.uniform2f(program.uniform.px, pixelSizeX, pixelSizeY); gl.uniform2f(program == null ? void 0 : program.uniform["px"], pixelSizeX, pixelSizeY);
_draw(); _draw();
}; },
_filter.convolution.SHADER = [ detectEdges: () => {
"precision highp float;",
"varying vec2 vUv;",
"uniform sampler2D texture;",
"uniform vec2 px;",
"uniform float m[9];",
"void main(void) {",
"vec4 c11 = texture2D(texture, vUv - px);",
"vec4 c12 = texture2D(texture, vec2(vUv.x, vUv.y - px.y));",
"vec4 c13 = texture2D(texture, vec2(vUv.x + px.x, vUv.y - px.y));",
"vec4 c21 = texture2D(texture, vec2(vUv.x - px.x, vUv.y) );",
"vec4 c22 = texture2D(texture, vUv);",
"vec4 c23 = texture2D(texture, vec2(vUv.x + px.x, vUv.y) );",
"vec4 c31 = texture2D(texture, vec2(vUv.x - px.x, vUv.y + px.y) );",
"vec4 c32 = texture2D(texture, vec2(vUv.x, vUv.y + px.y) );",
"vec4 c33 = texture2D(texture, vUv + px );",
"gl_FragColor = ",
"c11 * m[0] + c12 * m[1] + c22 * m[2] +",
"c21 * m[3] + c22 * m[4] + c23 * m[5] +",
"c31 * m[6] + c32 * m[7] + c33 * m[8];",
"gl_FragColor.a = c22.a;",
"}"
].join("\n");
_filter.detectEdges = function() {
_filter.convolution.call(this, [ _filter.convolution.call(this, [
0, 0,
1, 1,
@ -855,8 +865,8 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.sobelX = function() { sobelX: () => {
_filter.convolution.call(this, [ _filter.convolution.call(this, [
-1, -1,
0, 0,
@ -868,8 +878,8 @@ function GLImageFilter(params) {
0, 0,
1 1
]); ]);
}; },
_filter.sobelY = function() { sobelY: () => {
_filter.convolution.call(this, [ _filter.convolution.call(this, [
-1, -1,
-2, -2,
@ -881,8 +891,8 @@ function GLImageFilter(params) {
2, 2,
1 1
]); ]);
}; },
_filter.sharpen = function(amount) { sharpen: (amount) => {
const a = amount || 1; const a = amount || 1;
_filter.convolution.call(this, [ _filter.convolution.call(this, [
0, 0,
@ -895,8 +905,8 @@ function GLImageFilter(params) {
-1 * a, -1 * a,
0 0
]); ]);
}; },
_filter.emboss = function(size2) { emboss: (size2) => {
const s = size2 || 1; const s = size2 || 1;
_filter.convolution.call(this, [ _filter.convolution.call(this, [
-2 * s, -2 * s,
@ -909,61 +919,24 @@ function GLImageFilter(params) {
1 * s, 1 * s,
2 * s 2 * s
]); ]);
}; },
_filter.blur = function(size2) { blur: (size2) => {
const blurSizeX = size2 / 7 / _width; const blurSizeX = size2 / 7 / _width;
const blurSizeY = size2 / 7 / _height; const blurSizeY = size2 / 7 / _height;
const program = _compileShader(_filter.blur.SHADER); const program = _compileShader(blur);
gl.uniform2f(program.uniform.px, 0, blurSizeY); gl.uniform2f(program == null ? void 0 : program.uniform["px"], 0, blurSizeY);
_draw(DRAW.INTERMEDIATE); _draw(DRAW.INTERMEDIATE);
gl.uniform2f(program.uniform.px, blurSizeX, 0); gl.uniform2f(program == null ? void 0 : program.uniform["px"], blurSizeX, 0);
_draw(); _draw();
}; },
_filter.blur.SHADER = [ pixelate: (size2) => {
"precision highp float;",
"varying vec2 vUv;",
"uniform sampler2D texture;",
"uniform vec2 px;",
"void main(void) {",
"gl_FragColor = vec4(0.0);",
"gl_FragColor += texture2D(texture, vUv + vec2(-7.0*px.x, -7.0*px.y))*0.0044299121055113265;",
"gl_FragColor += texture2D(texture, vUv + vec2(-6.0*px.x, -6.0*px.y))*0.00895781211794;",
"gl_FragColor += texture2D(texture, vUv + vec2(-5.0*px.x, -5.0*px.y))*0.0215963866053;",
"gl_FragColor += texture2D(texture, vUv + vec2(-4.0*px.x, -4.0*px.y))*0.0443683338718;",
"gl_FragColor += texture2D(texture, vUv + vec2(-3.0*px.x, -3.0*px.y))*0.0776744219933;",
"gl_FragColor += texture2D(texture, vUv + vec2(-2.0*px.x, -2.0*px.y))*0.115876621105;",
"gl_FragColor += texture2D(texture, vUv + vec2(-1.0*px.x, -1.0*px.y))*0.147308056121;",
"gl_FragColor += texture2D(texture, vUv )*0.159576912161;",
"gl_FragColor += texture2D(texture, vUv + vec2( 1.0*px.x, 1.0*px.y))*0.147308056121;",
"gl_FragColor += texture2D(texture, vUv + vec2( 2.0*px.x, 2.0*px.y))*0.115876621105;",
"gl_FragColor += texture2D(texture, vUv + vec2( 3.0*px.x, 3.0*px.y))*0.0776744219933;",
"gl_FragColor += texture2D(texture, vUv + vec2( 4.0*px.x, 4.0*px.y))*0.0443683338718;",
"gl_FragColor += texture2D(texture, vUv + vec2( 5.0*px.x, 5.0*px.y))*0.0215963866053;",
"gl_FragColor += texture2D(texture, vUv + vec2( 6.0*px.x, 6.0*px.y))*0.00895781211794;",
"gl_FragColor += texture2D(texture, vUv + vec2( 7.0*px.x, 7.0*px.y))*0.0044299121055113265;",
"}"
].join("\n");
_filter.pixelate = function(size2) {
const blurSizeX = size2 / _width; const blurSizeX = size2 / _width;
const blurSizeY = size2 / _height; const blurSizeY = size2 / _height;
const program = _compileShader(_filter.pixelate.SHADER); const program = _compileShader(pixelate);
gl.uniform2f(program.uniform.size, blurSizeX, blurSizeY); gl.uniform2f(program == null ? void 0 : program.uniform["size"], blurSizeX, blurSizeY);
_draw(); _draw();
}
}; };
_filter.pixelate.SHADER = [
"precision highp float;",
"varying vec2 vUv;",
"uniform vec2 size;",
"uniform sampler2D texture;",
"vec2 pixelate(vec2 coord, vec2 size) {",
"return floor( coord / size ) * size;",
"}",
"void main(void) {",
"gl_FragColor = vec4(0.0);",
"vec2 coord = pixelate(vUv, size);",
"gl_FragColor += texture2D(texture, coord);",
"}"
].join("\n");
} }
// src/util/env.ts // src/util/env.ts
@ -1188,7 +1161,7 @@ function process2(input, config3, getTensor = true) {
fx.addFilter("polaroid"); fx.addFilter("polaroid");
if (config3.filter.pixelate !== 0) if (config3.filter.pixelate !== 0)
fx.addFilter("pixelate", config3.filter.pixelate); fx.addFilter("pixelate", config3.filter.pixelate);
fx.apply(inCanvas); outCanvas = fx.apply(inCanvas);
} else { } else {
copy(inCanvas, outCanvas); copy(inCanvas, outCanvas);
if (fx) if (fx)
@ -1197,6 +1170,8 @@ function process2(input, config3, getTensor = true) {
} }
if (!getTensor) if (!getTensor)
return { tensor: null, canvas: outCanvas }; return { tensor: null, canvas: outCanvas };
if (!outCanvas)
throw new Error("cannot create output canvas");
let pixels; let pixels;
let depth = 3; let depth = 3;
if (typeof ImageData !== "undefined" && input instanceof ImageData || input["data"] && input["width"] && input["height"]) { if (typeof ImageData !== "undefined" && input instanceof ImageData || input["data"] && input["width"] && input["height"]) {

View File

@ -261,42 +261,147 @@ var tf22 = __toModule(require_tfjs_esm());
// src/image/image.ts // src/image/image.ts
var tf2 = __toModule(require_tfjs_esm()); var tf2 = __toModule(require_tfjs_esm());
// src/image/imagefxshaders.ts
var vertexIdentity = `
precision highp float;
attribute vec2 pos;
attribute vec2 uv;
varying vec2 vUv;
uniform float flipY;
void main(void) {
vUv = uv;
gl_Position = vec4(pos.x, pos.y*flipY, 0.0, 1.);
}
`;
var colorMatrixWithAlpha = `
precision highp float;
varying vec2 vUv;
uniform sampler2D texture;
uniform float m[20];
void main(void) {
vec4 c = texture2D(texture, vUv);
gl_FragColor.r = m[0] * c.r + m[1] * c.g + m[2] * c.b + m[3] * c.a + m[4];
gl_FragColor.g = m[5] * c.r + m[6] * c.g + m[7] * c.b + m[8] * c.a + m[9];
gl_FragColor.b = m[10] * c.r + m[11] * c.g + m[12] * c.b + m[13] * c.a + m[14];
gl_FragColor.a = m[15] * c.r + m[16] * c.g + m[17] * c.b + m[18] * c.a + m[19];
}
`;
var colorMatrixWithoutAlpha = `
precision highp float;
varying vec2 vUv;
uniform sampler2D texture;
uniform float m[20];
void main(void) {
vec4 c = texture2D(texture, vUv);
gl_FragColor.r = m[0] * c.r + m[1] * c.g + m[2] * c.b + m[4];
gl_FragColor.g = m[5] * c.r + m[6] * c.g + m[7] * c.b + m[9];
gl_FragColor.b = m[10] * c.r + m[11] * c.g + m[12] * c.b + m[14];
gl_FragColor.a = c.a;
}
`;
var pixelate = `
precision highp float;
varying vec2 vUv;
uniform vec2 size;
uniform sampler2D texture;
vec2 pixelate(vec2 coord, vec2 size) {
return floor( coord / size ) * size;
}
void main(void) {
gl_FragColor = vec4(0.0);
vec2 coord = pixelate(vUv, size);
gl_FragColor += texture2D(texture, coord);
}
`;
var blur = `
precision highp float;
varying vec2 vUv;
uniform sampler2D texture;
uniform vec2 px;
void main(void) {
gl_FragColor = vec4(0.0);
gl_FragColor += texture2D(texture, vUv + vec2(-7.0*px.x, -7.0*px.y))*0.0044299121055113265;
gl_FragColor += texture2D(texture, vUv + vec2(-6.0*px.x, -6.0*px.y))*0.00895781211794;
gl_FragColor += texture2D(texture, vUv + vec2(-5.0*px.x, -5.0*px.y))*0.0215963866053;
gl_FragColor += texture2D(texture, vUv + vec2(-4.0*px.x, -4.0*px.y))*0.0443683338718;
gl_FragColor += texture2D(texture, vUv + vec2(-3.0*px.x, -3.0*px.y))*0.0776744219933;
gl_FragColor += texture2D(texture, vUv + vec2(-2.0*px.x, -2.0*px.y))*0.115876621105;
gl_FragColor += texture2D(texture, vUv + vec2(-1.0*px.x, -1.0*px.y))*0.147308056121;
gl_FragColor += texture2D(texture, vUv )*0.159576912161;
gl_FragColor += texture2D(texture, vUv + vec2( 1.0*px.x, 1.0*px.y))*0.147308056121;
gl_FragColor += texture2D(texture, vUv + vec2( 2.0*px.x, 2.0*px.y))*0.115876621105;
gl_FragColor += texture2D(texture, vUv + vec2( 3.0*px.x, 3.0*px.y))*0.0776744219933;
gl_FragColor += texture2D(texture, vUv + vec2( 4.0*px.x, 4.0*px.y))*0.0443683338718;
gl_FragColor += texture2D(texture, vUv + vec2( 5.0*px.x, 5.0*px.y))*0.0215963866053;
gl_FragColor += texture2D(texture, vUv + vec2( 6.0*px.x, 6.0*px.y))*0.00895781211794;
gl_FragColor += texture2D(texture, vUv + vec2( 7.0*px.x, 7.0*px.y))*0.0044299121055113265;
}
`;
var convolution = `
precision highp float;
varying vec2 vUv;
uniform sampler2D texture;
uniform vec2 px;
uniform float m[9];
void main(void) {
vec4 c11 = texture2D(texture, vUv - px); // top left
vec4 c12 = texture2D(texture, vec2(vUv.x, vUv.y - px.y)); // top center
vec4 c13 = texture2D(texture, vec2(vUv.x + px.x, vUv.y - px.y)); // top right
vec4 c21 = texture2D(texture, vec2(vUv.x - px.x, vUv.y) ); // mid left
vec4 c22 = texture2D(texture, vUv); // mid center
vec4 c23 = texture2D(texture, vec2(vUv.x + px.x, vUv.y) ); // mid right
vec4 c31 = texture2D(texture, vec2(vUv.x - px.x, vUv.y + px.y) ); // bottom left
vec4 c32 = texture2D(texture, vec2(vUv.x, vUv.y + px.y) ); // bottom center
vec4 c33 = texture2D(texture, vUv + px ); // bottom right
gl_FragColor =
c11 * m[0] + c12 * m[1] + c22 * m[2] +
c21 * m[3] + c22 * m[4] + c23 * m[5] +
c31 * m[6] + c32 * m[7] + c33 * m[8];
gl_FragColor.a = c22.a;
}
`;
// src/image/imagefx.ts // src/image/imagefx.ts
function GLProgram(gl, vertexSource, fragmentSource) { var GLProgram = class {
const _collect = function(source, prefix, collection) { constructor(gl, vertexSource, fragmentSource) {
__publicField(this, "uniform", {});
__publicField(this, "attribute", {});
__publicField(this, "gl");
__publicField(this, "id");
__publicField(this, "collect", (source, prefix, collection) => {
const r = new RegExp("\\b" + prefix + " \\w+ (\\w+)", "ig"); const r = new RegExp("\\b" + prefix + " \\w+ (\\w+)", "ig");
source.replace(r, (match4, name) => { source.replace(r, (match4, name) => {
collection[name] = 0; collection[name] = 0;
return match4; return match4;
}); });
}; });
const _compile = function(source, type) { __publicField(this, "compile", (source, type) => {
const shader = gl.createShader(type); const shader = this.gl.createShader(type);
gl.shaderSource(shader, source); this.gl.shaderSource(shader, source);
gl.compileShader(shader); this.gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) if (!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS))
throw new Error("filter: gl compile failed", gl.getShaderInfoLog(shader)); throw new Error(`filter: gl compile failed: ${this.gl.getShaderInfoLog(shader)}`);
return shader; return shader;
}; });
this.uniform = {}; this.gl = gl;
this.attribute = {}; const _vsh = this.compile(vertexSource, this.gl.VERTEX_SHADER);
const _vsh = _compile(vertexSource, gl.VERTEX_SHADER); const _fsh = this.compile(fragmentSource, this.gl.FRAGMENT_SHADER);
const _fsh = _compile(fragmentSource, gl.FRAGMENT_SHADER); this.id = this.gl.createProgram();
this.id = gl.createProgram(); this.gl.attachShader(this.id, _vsh);
gl.attachShader(this.id, _vsh); this.gl.attachShader(this.id, _fsh);
gl.attachShader(this.id, _fsh); this.gl.linkProgram(this.id);
gl.linkProgram(this.id); if (!this.gl.getProgramParameter(this.id, this.gl.LINK_STATUS))
if (!gl.getProgramParameter(this.id, gl.LINK_STATUS)) throw new Error(`filter: gl link failed: ${this.gl.getProgramInfoLog(this.id)}`);
throw new Error("filter: gl link failed", gl.getProgramInfoLog(this.id)); this.gl.useProgram(this.id);
gl.useProgram(this.id); this.collect(vertexSource, "attribute", this.attribute);
_collect(vertexSource, "attribute", this.attribute);
for (const a in this.attribute) for (const a in this.attribute)
this.attribute[a] = gl.getAttribLocation(this.id, a); this.attribute[a] = this.gl.getAttribLocation(this.id, a);
_collect(vertexSource, "uniform", this.uniform); this.collect(vertexSource, "uniform", this.uniform);
_collect(fragmentSource, "uniform", this.uniform); this.collect(fragmentSource, "uniform", this.uniform);
for (const u in this.uniform) for (const u in this.uniform)
this.uniform[u] = gl.getUniformLocation(this.id, u); this.uniform[u] = this.gl.getUniformLocation(this.id, u);
} }
};
function GLImageFilter(params) { function GLImageFilter(params) {
if (!params) if (!params)
params = {}; params = {};
@ -310,13 +415,12 @@ function GLImageFilter(params) {
let _height = -1; let _height = -1;
let _vertexBuffer = null; let _vertexBuffer = null;
let _currentProgram = null; let _currentProgram = null;
const _filter = {}; const _canvas = params.canvas || typeof OffscreenCanvas !== "undefined" ? new OffscreenCanvas(100, 100) : document.createElement("canvas");
const _canvas = params.canvas || document.createElement("canvas");
const _shaderProgramCache = {}; const _shaderProgramCache = {};
const DRAW = { INTERMEDIATE: 1 }; const DRAW = { INTERMEDIATE: 1 };
const gl = _canvas.getContext("webgl"); const gl = _canvas.getContext("webgl");
if (!gl) if (!gl)
throw new Error("filter: context failed"); throw new Error("filter: cannot get webgl context");
this.addFilter = function(name) { this.addFilter = function(name) {
const args = Array.prototype.slice.call(arguments, 1); const args = Array.prototype.slice.call(arguments, 1);
const filter = _filter[name]; const filter = _filter[name];
@ -326,40 +430,14 @@ function GLImageFilter(params) {
_filterChain = []; _filterChain = [];
}; };
const _resize = function(width, height) { const _resize = function(width, height) {
if (width === _width && height === _height) { if (width === _width && height === _height)
return; return;
}
_canvas.width = width; _canvas.width = width;
_width = width; _width = width;
_canvas.height = height; _canvas.height = height;
_height = height; _height = height;
if (!_vertexBuffer) { if (!_vertexBuffer) {
const vertices = new Float32Array([ const vertices = new Float32Array([-1, -1, 0, 1, 1, -1, 1, 1, -1, 1, 0, 0, -1, 1, 0, 0, 1, -1, 1, 1, 1, 1, 1, 0]);
-1,
-1,
0,
1,
1,
-1,
1,
1,
-1,
1,
0,
0,
-1,
1,
0,
0,
1,
-1,
1,
1,
1,
1,
1,
0
]);
_vertexBuffer = gl.createBuffer(), gl.bindBuffer(gl.ARRAY_BUFFER, _vertexBuffer); _vertexBuffer = gl.createBuffer(), gl.bindBuffer(gl.ARRAY_BUFFER, _vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW); gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true); gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
@ -388,16 +466,17 @@ function GLImageFilter(params) {
_tempFramebuffers[index] = _tempFramebuffers[index] || _createFramebufferTexture(_width, _height); _tempFramebuffers[index] = _tempFramebuffers[index] || _createFramebufferTexture(_width, _height);
return _tempFramebuffers[index]; return _tempFramebuffers[index];
}; };
const _draw = function(flags = null) { const _draw = function(flags = 0) {
var _a, _b; var _a, _b;
if (!_currentProgram)
return;
let source = null; let source = null;
let target = null; let target = null;
let flipY = false; let flipY = false;
if (_drawCount === 0) { if (_drawCount === 0)
source = _sourceTexture; source = _sourceTexture;
} else { else
source = (_a = _getTempFramebuffer(_currentFramebufferIndex)) == null ? void 0 : _a.texture; source = (_a = _getTempFramebuffer(_currentFramebufferIndex)) == null ? void 0 : _a.texture;
}
_drawCount++; _drawCount++;
if (_lastInChain && !(flags & DRAW.INTERMEDIATE)) { if (_lastInChain && !(flags & DRAW.INTERMEDIATE)) {
target = null; target = null;
@ -408,7 +487,7 @@ function GLImageFilter(params) {
} }
gl.bindTexture(gl.TEXTURE_2D, source); gl.bindTexture(gl.TEXTURE_2D, source);
gl.bindFramebuffer(gl.FRAMEBUFFER, target); gl.bindFramebuffer(gl.FRAMEBUFFER, target);
gl.uniform1f(_currentProgram.uniform.flipY, flipY ? -1 : 1); gl.uniform1f(_currentProgram.uniform["flipY"], flipY ? -1 : 1);
gl.drawArrays(gl.TRIANGLES, 0, 6); gl.drawArrays(gl.TRIANGLES, 0, 6);
}; };
this.apply = function(image24) { this.apply = function(image24) {
@ -424,90 +503,44 @@ function GLImageFilter(params) {
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image24); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image24);
if (_filterChain.length === 0) { if (_filterChain.length === 0) {
_draw(); _draw();
return _canvas; } else {
}
for (let i = 0; i < _filterChain.length; i++) { for (let i = 0; i < _filterChain.length; i++) {
_lastInChain = i === _filterChain.length - 1; _lastInChain = i === _filterChain.length - 1;
const f = _filterChain[i]; const f = _filterChain[i];
f.func.apply(this, f.args || []); f.func.apply(this, f.args || []);
} }
}
return _canvas; return _canvas;
}; };
const _compileShader = function(fragmentSource) { const _compileShader = function(fragmentSource) {
if (_shaderProgramCache[fragmentSource]) { if (_shaderProgramCache[fragmentSource]) {
_currentProgram = _shaderProgramCache[fragmentSource]; _currentProgram = _shaderProgramCache[fragmentSource];
gl.useProgram(_currentProgram.id); gl.useProgram(_currentProgram == null ? void 0 : _currentProgram.id);
return _currentProgram; return _currentProgram;
} }
const SHADER = {}; _currentProgram = new GLProgram(gl, vertexIdentity, fragmentSource);
SHADER.VERTEX_IDENTITY = [
"precision highp float;",
"attribute vec2 pos;",
"attribute vec2 uv;",
"varying vec2 vUv;",
"uniform float flipY;",
"void main(void) {",
"vUv = uv;",
"gl_Position = vec4(pos.x, pos.y*flipY, 0.0, 1.);",
"}"
].join("\n");
SHADER.FRAGMENT_IDENTITY = [
"precision highp float;",
"varying vec2 vUv;",
"uniform sampler2D texture;",
"void main(void) {",
"gl_FragColor = texture2D(texture, vUv);",
"}"
].join("\n");
_currentProgram = new GLProgram(gl, SHADER.VERTEX_IDENTITY, fragmentSource);
const floatSize = Float32Array.BYTES_PER_ELEMENT; const floatSize = Float32Array.BYTES_PER_ELEMENT;
const vertSize = 4 * floatSize; const vertSize = 4 * floatSize;
gl.enableVertexAttribArray(_currentProgram.attribute.pos); gl.enableVertexAttribArray(_currentProgram.attribute["pos"]);
gl.vertexAttribPointer(_currentProgram.attribute.pos, 2, gl.FLOAT, false, vertSize, 0 * floatSize); gl.vertexAttribPointer(_currentProgram.attribute["pos"], 2, gl.FLOAT, false, vertSize, 0 * floatSize);
gl.enableVertexAttribArray(_currentProgram.attribute.uv); gl.enableVertexAttribArray(_currentProgram.attribute.uv);
gl.vertexAttribPointer(_currentProgram.attribute.uv, 2, gl.FLOAT, false, vertSize, 2 * floatSize); gl.vertexAttribPointer(_currentProgram.attribute["uv"], 2, gl.FLOAT, false, vertSize, 2 * floatSize);
_shaderProgramCache[fragmentSource] = _currentProgram; _shaderProgramCache[fragmentSource] = _currentProgram;
return _currentProgram; return _currentProgram;
}; };
_filter.colorMatrix = function(matrix) { const _filter = {
colorMatrix: (matrix) => {
const m = new Float32Array(matrix); const m = new Float32Array(matrix);
m[4] /= 255; m[4] /= 255;
m[9] /= 255; m[9] /= 255;
m[14] /= 255; m[14] /= 255;
m[19] /= 255; m[19] /= 255;
const shader = m[18] === 1 && m[3] === 0 && m[8] === 0 && m[13] === 0 && m[15] === 0 && m[16] === 0 && m[17] === 0 && m[19] === 0 ? _filter.colorMatrix.SHADER.WITHOUT_ALPHA : _filter.colorMatrix.SHADER.WITH_ALPHA; const shader = m[18] === 1 && m[3] === 0 && m[8] === 0 && m[13] === 0 && m[15] === 0 && m[16] === 0 && m[17] === 0 && m[19] === 0 ? colorMatrixWithoutAlpha : colorMatrixWithAlpha;
const program = _compileShader(shader); const program = _compileShader(shader);
gl.uniform1fv(program.uniform.m, m); gl.uniform1fv(program == null ? void 0 : program.uniform["m"], m);
_draw(); _draw();
}; },
_filter.colorMatrix.SHADER = {}; brightness: (brightness) => {
_filter.colorMatrix.SHADER.WITH_ALPHA = [
"precision highp float;",
"varying vec2 vUv;",
"uniform sampler2D texture;",
"uniform float m[20];",
"void main(void) {",
"vec4 c = texture2D(texture, vUv);",
"gl_FragColor.r = m[0] * c.r + m[1] * c.g + m[2] * c.b + m[3] * c.a + m[4];",
"gl_FragColor.g = m[5] * c.r + m[6] * c.g + m[7] * c.b + m[8] * c.a + m[9];",
"gl_FragColor.b = m[10] * c.r + m[11] * c.g + m[12] * c.b + m[13] * c.a + m[14];",
"gl_FragColor.a = m[15] * c.r + m[16] * c.g + m[17] * c.b + m[18] * c.a + m[19];",
"}"
].join("\n");
_filter.colorMatrix.SHADER.WITHOUT_ALPHA = [
"precision highp float;",
"varying vec2 vUv;",
"uniform sampler2D texture;",
"uniform float m[20];",
"void main(void) {",
"vec4 c = texture2D(texture, vUv);",
"gl_FragColor.r = m[0] * c.r + m[1] * c.g + m[2] * c.b + m[4];",
"gl_FragColor.g = m[5] * c.r + m[6] * c.g + m[7] * c.b + m[9];",
"gl_FragColor.b = m[10] * c.r + m[11] * c.g + m[12] * c.b + m[14];",
"gl_FragColor.a = c.a;",
"}"
].join("\n");
_filter.brightness = function(brightness) {
const b = (brightness || 0) + 1; const b = (brightness || 0) + 1;
_filter.colorMatrix([ _filter.colorMatrix([
b, b,
@ -531,8 +564,8 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.saturation = function(amount) { saturation: (amount) => {
const x = (amount || 0) * 2 / 3 + 1; const x = (amount || 0) * 2 / 3 + 1;
const y = (x - 1) * -0.5; const y = (x - 1) * -0.5;
_filter.colorMatrix([ _filter.colorMatrix([
@ -557,11 +590,11 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.desaturate = function() { desaturate: () => {
_filter.saturation(-1); _filter.saturation(-1);
}; },
_filter.contrast = function(amount) { contrast: (amount) => {
const v = (amount || 0) + 1; const v = (amount || 0) + 1;
const o = -128 * (v - 1); const o = -128 * (v - 1);
_filter.colorMatrix([ _filter.colorMatrix([
@ -586,11 +619,11 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.negative = function() { negative: () => {
_filter.contrast(-2); _filter.contrast(-2);
}; },
_filter.hue = function(rotation) { hue: (rotation) => {
rotation = (rotation || 0) / 180 * Math.PI; rotation = (rotation || 0) / 180 * Math.PI;
const cos = Math.cos(rotation); const cos = Math.cos(rotation);
const sin = Math.sin(rotation); const sin = Math.sin(rotation);
@ -619,8 +652,8 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.desaturateLuminance = function() { desaturateLuminance: () => {
_filter.colorMatrix([ _filter.colorMatrix([
0.2764723, 0.2764723,
0.929708, 0.929708,
@ -643,8 +676,8 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.sepia = function() { sepia: () => {
_filter.colorMatrix([ _filter.colorMatrix([
0.393, 0.393,
0.7689999, 0.7689999,
@ -667,8 +700,8 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.brownie = function() { brownie: () => {
_filter.colorMatrix([ _filter.colorMatrix([
0.5997023498159715, 0.5997023498159715,
0.34553243048391263, 0.34553243048391263,
@ -691,8 +724,8 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.vintagePinhole = function() { vintagePinhole: () => {
_filter.colorMatrix([ _filter.colorMatrix([
0.6279345635605994, 0.6279345635605994,
0.3202183420819367, 0.3202183420819367,
@ -715,8 +748,8 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.kodachrome = function() { kodachrome: () => {
_filter.colorMatrix([ _filter.colorMatrix([
1.1285582396593525, 1.1285582396593525,
-0.3967382283601348, -0.3967382283601348,
@ -739,8 +772,8 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.technicolor = function() { technicolor: () => {
_filter.colorMatrix([ _filter.colorMatrix([
1.9125277891456083, 1.9125277891456083,
-0.8545344976951645, -0.8545344976951645,
@ -763,8 +796,8 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.polaroid = function() { polaroid: () => {
_filter.colorMatrix([ _filter.colorMatrix([
1.438, 1.438,
-0.062, -0.062,
@ -787,8 +820,8 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.shiftToBGR = function() { shiftToBGR: () => {
_filter.colorMatrix([ _filter.colorMatrix([
0, 0,
0, 0,
@ -811,40 +844,17 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.convolution = function(matrix) { convolution: (matrix) => {
const m = new Float32Array(matrix); const m = new Float32Array(matrix);
const pixelSizeX = 1 / _width; const pixelSizeX = 1 / _width;
const pixelSizeY = 1 / _height; const pixelSizeY = 1 / _height;
const program = _compileShader(_filter.convolution.SHADER); const program = _compileShader(convolution);
gl.uniform1fv(program.uniform.m, m); gl.uniform1fv(program == null ? void 0 : program.uniform["m"], m);
gl.uniform2f(program.uniform.px, pixelSizeX, pixelSizeY); gl.uniform2f(program == null ? void 0 : program.uniform["px"], pixelSizeX, pixelSizeY);
_draw(); _draw();
}; },
_filter.convolution.SHADER = [ detectEdges: () => {
"precision highp float;",
"varying vec2 vUv;",
"uniform sampler2D texture;",
"uniform vec2 px;",
"uniform float m[9];",
"void main(void) {",
"vec4 c11 = texture2D(texture, vUv - px);",
"vec4 c12 = texture2D(texture, vec2(vUv.x, vUv.y - px.y));",
"vec4 c13 = texture2D(texture, vec2(vUv.x + px.x, vUv.y - px.y));",
"vec4 c21 = texture2D(texture, vec2(vUv.x - px.x, vUv.y) );",
"vec4 c22 = texture2D(texture, vUv);",
"vec4 c23 = texture2D(texture, vec2(vUv.x + px.x, vUv.y) );",
"vec4 c31 = texture2D(texture, vec2(vUv.x - px.x, vUv.y + px.y) );",
"vec4 c32 = texture2D(texture, vec2(vUv.x, vUv.y + px.y) );",
"vec4 c33 = texture2D(texture, vUv + px );",
"gl_FragColor = ",
"c11 * m[0] + c12 * m[1] + c22 * m[2] +",
"c21 * m[3] + c22 * m[4] + c23 * m[5] +",
"c31 * m[6] + c32 * m[7] + c33 * m[8];",
"gl_FragColor.a = c22.a;",
"}"
].join("\n");
_filter.detectEdges = function() {
_filter.convolution.call(this, [ _filter.convolution.call(this, [
0, 0,
1, 1,
@ -856,8 +866,8 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.sobelX = function() { sobelX: () => {
_filter.convolution.call(this, [ _filter.convolution.call(this, [
-1, -1,
0, 0,
@ -869,8 +879,8 @@ function GLImageFilter(params) {
0, 0,
1 1
]); ]);
}; },
_filter.sobelY = function() { sobelY: () => {
_filter.convolution.call(this, [ _filter.convolution.call(this, [
-1, -1,
-2, -2,
@ -882,8 +892,8 @@ function GLImageFilter(params) {
2, 2,
1 1
]); ]);
}; },
_filter.sharpen = function(amount) { sharpen: (amount) => {
const a = amount || 1; const a = amount || 1;
_filter.convolution.call(this, [ _filter.convolution.call(this, [
0, 0,
@ -896,8 +906,8 @@ function GLImageFilter(params) {
-1 * a, -1 * a,
0 0
]); ]);
}; },
_filter.emboss = function(size2) { emboss: (size2) => {
const s = size2 || 1; const s = size2 || 1;
_filter.convolution.call(this, [ _filter.convolution.call(this, [
-2 * s, -2 * s,
@ -910,61 +920,24 @@ function GLImageFilter(params) {
1 * s, 1 * s,
2 * s 2 * s
]); ]);
}; },
_filter.blur = function(size2) { blur: (size2) => {
const blurSizeX = size2 / 7 / _width; const blurSizeX = size2 / 7 / _width;
const blurSizeY = size2 / 7 / _height; const blurSizeY = size2 / 7 / _height;
const program = _compileShader(_filter.blur.SHADER); const program = _compileShader(blur);
gl.uniform2f(program.uniform.px, 0, blurSizeY); gl.uniform2f(program == null ? void 0 : program.uniform["px"], 0, blurSizeY);
_draw(DRAW.INTERMEDIATE); _draw(DRAW.INTERMEDIATE);
gl.uniform2f(program.uniform.px, blurSizeX, 0); gl.uniform2f(program == null ? void 0 : program.uniform["px"], blurSizeX, 0);
_draw(); _draw();
}; },
_filter.blur.SHADER = [ pixelate: (size2) => {
"precision highp float;",
"varying vec2 vUv;",
"uniform sampler2D texture;",
"uniform vec2 px;",
"void main(void) {",
"gl_FragColor = vec4(0.0);",
"gl_FragColor += texture2D(texture, vUv + vec2(-7.0*px.x, -7.0*px.y))*0.0044299121055113265;",
"gl_FragColor += texture2D(texture, vUv + vec2(-6.0*px.x, -6.0*px.y))*0.00895781211794;",
"gl_FragColor += texture2D(texture, vUv + vec2(-5.0*px.x, -5.0*px.y))*0.0215963866053;",
"gl_FragColor += texture2D(texture, vUv + vec2(-4.0*px.x, -4.0*px.y))*0.0443683338718;",
"gl_FragColor += texture2D(texture, vUv + vec2(-3.0*px.x, -3.0*px.y))*0.0776744219933;",
"gl_FragColor += texture2D(texture, vUv + vec2(-2.0*px.x, -2.0*px.y))*0.115876621105;",
"gl_FragColor += texture2D(texture, vUv + vec2(-1.0*px.x, -1.0*px.y))*0.147308056121;",
"gl_FragColor += texture2D(texture, vUv )*0.159576912161;",
"gl_FragColor += texture2D(texture, vUv + vec2( 1.0*px.x, 1.0*px.y))*0.147308056121;",
"gl_FragColor += texture2D(texture, vUv + vec2( 2.0*px.x, 2.0*px.y))*0.115876621105;",
"gl_FragColor += texture2D(texture, vUv + vec2( 3.0*px.x, 3.0*px.y))*0.0776744219933;",
"gl_FragColor += texture2D(texture, vUv + vec2( 4.0*px.x, 4.0*px.y))*0.0443683338718;",
"gl_FragColor += texture2D(texture, vUv + vec2( 5.0*px.x, 5.0*px.y))*0.0215963866053;",
"gl_FragColor += texture2D(texture, vUv + vec2( 6.0*px.x, 6.0*px.y))*0.00895781211794;",
"gl_FragColor += texture2D(texture, vUv + vec2( 7.0*px.x, 7.0*px.y))*0.0044299121055113265;",
"}"
].join("\n");
_filter.pixelate = function(size2) {
const blurSizeX = size2 / _width; const blurSizeX = size2 / _width;
const blurSizeY = size2 / _height; const blurSizeY = size2 / _height;
const program = _compileShader(_filter.pixelate.SHADER); const program = _compileShader(pixelate);
gl.uniform2f(program.uniform.size, blurSizeX, blurSizeY); gl.uniform2f(program == null ? void 0 : program.uniform["size"], blurSizeX, blurSizeY);
_draw(); _draw();
}
}; };
_filter.pixelate.SHADER = [
"precision highp float;",
"varying vec2 vUv;",
"uniform vec2 size;",
"uniform sampler2D texture;",
"vec2 pixelate(vec2 coord, vec2 size) {",
"return floor( coord / size ) * size;",
"}",
"void main(void) {",
"gl_FragColor = vec4(0.0);",
"vec2 coord = pixelate(vUv, size);",
"gl_FragColor += texture2D(texture, coord);",
"}"
].join("\n");
} }
// src/util/env.ts // src/util/env.ts
@ -1189,7 +1162,7 @@ function process2(input, config3, getTensor = true) {
fx.addFilter("polaroid"); fx.addFilter("polaroid");
if (config3.filter.pixelate !== 0) if (config3.filter.pixelate !== 0)
fx.addFilter("pixelate", config3.filter.pixelate); fx.addFilter("pixelate", config3.filter.pixelate);
fx.apply(inCanvas); outCanvas = fx.apply(inCanvas);
} else { } else {
copy(inCanvas, outCanvas); copy(inCanvas, outCanvas);
if (fx) if (fx)
@ -1198,6 +1171,8 @@ function process2(input, config3, getTensor = true) {
} }
if (!getTensor) if (!getTensor)
return { tensor: null, canvas: outCanvas }; return { tensor: null, canvas: outCanvas };
if (!outCanvas)
throw new Error("cannot create output canvas");
let pixels; let pixels;
let depth = 3; let depth = 3;
if (typeof ImageData !== "undefined" && input instanceof ImageData || input["data"] && input["width"] && input["height"]) { if (typeof ImageData !== "undefined" && input instanceof ImageData || input["data"] && input["width"] && input["height"]) {

443
dist/human.node.js vendored
View File

@ -260,42 +260,147 @@ var tf22 = __toModule(require_tfjs_esm());
// src/image/image.ts // src/image/image.ts
var tf2 = __toModule(require_tfjs_esm()); var tf2 = __toModule(require_tfjs_esm());
// src/image/imagefxshaders.ts
var vertexIdentity = `
precision highp float;
attribute vec2 pos;
attribute vec2 uv;
varying vec2 vUv;
uniform float flipY;
void main(void) {
vUv = uv;
gl_Position = vec4(pos.x, pos.y*flipY, 0.0, 1.);
}
`;
var colorMatrixWithAlpha = `
precision highp float;
varying vec2 vUv;
uniform sampler2D texture;
uniform float m[20];
void main(void) {
vec4 c = texture2D(texture, vUv);
gl_FragColor.r = m[0] * c.r + m[1] * c.g + m[2] * c.b + m[3] * c.a + m[4];
gl_FragColor.g = m[5] * c.r + m[6] * c.g + m[7] * c.b + m[8] * c.a + m[9];
gl_FragColor.b = m[10] * c.r + m[11] * c.g + m[12] * c.b + m[13] * c.a + m[14];
gl_FragColor.a = m[15] * c.r + m[16] * c.g + m[17] * c.b + m[18] * c.a + m[19];
}
`;
var colorMatrixWithoutAlpha = `
precision highp float;
varying vec2 vUv;
uniform sampler2D texture;
uniform float m[20];
void main(void) {
vec4 c = texture2D(texture, vUv);
gl_FragColor.r = m[0] * c.r + m[1] * c.g + m[2] * c.b + m[4];
gl_FragColor.g = m[5] * c.r + m[6] * c.g + m[7] * c.b + m[9];
gl_FragColor.b = m[10] * c.r + m[11] * c.g + m[12] * c.b + m[14];
gl_FragColor.a = c.a;
}
`;
var pixelate = `
precision highp float;
varying vec2 vUv;
uniform vec2 size;
uniform sampler2D texture;
vec2 pixelate(vec2 coord, vec2 size) {
return floor( coord / size ) * size;
}
void main(void) {
gl_FragColor = vec4(0.0);
vec2 coord = pixelate(vUv, size);
gl_FragColor += texture2D(texture, coord);
}
`;
var blur = `
precision highp float;
varying vec2 vUv;
uniform sampler2D texture;
uniform vec2 px;
void main(void) {
gl_FragColor = vec4(0.0);
gl_FragColor += texture2D(texture, vUv + vec2(-7.0*px.x, -7.0*px.y))*0.0044299121055113265;
gl_FragColor += texture2D(texture, vUv + vec2(-6.0*px.x, -6.0*px.y))*0.00895781211794;
gl_FragColor += texture2D(texture, vUv + vec2(-5.0*px.x, -5.0*px.y))*0.0215963866053;
gl_FragColor += texture2D(texture, vUv + vec2(-4.0*px.x, -4.0*px.y))*0.0443683338718;
gl_FragColor += texture2D(texture, vUv + vec2(-3.0*px.x, -3.0*px.y))*0.0776744219933;
gl_FragColor += texture2D(texture, vUv + vec2(-2.0*px.x, -2.0*px.y))*0.115876621105;
gl_FragColor += texture2D(texture, vUv + vec2(-1.0*px.x, -1.0*px.y))*0.147308056121;
gl_FragColor += texture2D(texture, vUv )*0.159576912161;
gl_FragColor += texture2D(texture, vUv + vec2( 1.0*px.x, 1.0*px.y))*0.147308056121;
gl_FragColor += texture2D(texture, vUv + vec2( 2.0*px.x, 2.0*px.y))*0.115876621105;
gl_FragColor += texture2D(texture, vUv + vec2( 3.0*px.x, 3.0*px.y))*0.0776744219933;
gl_FragColor += texture2D(texture, vUv + vec2( 4.0*px.x, 4.0*px.y))*0.0443683338718;
gl_FragColor += texture2D(texture, vUv + vec2( 5.0*px.x, 5.0*px.y))*0.0215963866053;
gl_FragColor += texture2D(texture, vUv + vec2( 6.0*px.x, 6.0*px.y))*0.00895781211794;
gl_FragColor += texture2D(texture, vUv + vec2( 7.0*px.x, 7.0*px.y))*0.0044299121055113265;
}
`;
var convolution = `
precision highp float;
varying vec2 vUv;
uniform sampler2D texture;
uniform vec2 px;
uniform float m[9];
void main(void) {
vec4 c11 = texture2D(texture, vUv - px); // top left
vec4 c12 = texture2D(texture, vec2(vUv.x, vUv.y - px.y)); // top center
vec4 c13 = texture2D(texture, vec2(vUv.x + px.x, vUv.y - px.y)); // top right
vec4 c21 = texture2D(texture, vec2(vUv.x - px.x, vUv.y) ); // mid left
vec4 c22 = texture2D(texture, vUv); // mid center
vec4 c23 = texture2D(texture, vec2(vUv.x + px.x, vUv.y) ); // mid right
vec4 c31 = texture2D(texture, vec2(vUv.x - px.x, vUv.y + px.y) ); // bottom left
vec4 c32 = texture2D(texture, vec2(vUv.x, vUv.y + px.y) ); // bottom center
vec4 c33 = texture2D(texture, vUv + px ); // bottom right
gl_FragColor =
c11 * m[0] + c12 * m[1] + c22 * m[2] +
c21 * m[3] + c22 * m[4] + c23 * m[5] +
c31 * m[6] + c32 * m[7] + c33 * m[8];
gl_FragColor.a = c22.a;
}
`;
// src/image/imagefx.ts // src/image/imagefx.ts
function GLProgram(gl, vertexSource, fragmentSource) { var GLProgram = class {
const _collect = function(source, prefix, collection) { constructor(gl, vertexSource, fragmentSource) {
__publicField(this, "uniform", {});
__publicField(this, "attribute", {});
__publicField(this, "gl");
__publicField(this, "id");
__publicField(this, "collect", (source, prefix, collection) => {
const r = new RegExp("\\b" + prefix + " \\w+ (\\w+)", "ig"); const r = new RegExp("\\b" + prefix + " \\w+ (\\w+)", "ig");
source.replace(r, (match4, name) => { source.replace(r, (match4, name) => {
collection[name] = 0; collection[name] = 0;
return match4; return match4;
}); });
}; });
const _compile = function(source, type) { __publicField(this, "compile", (source, type) => {
const shader = gl.createShader(type); const shader = this.gl.createShader(type);
gl.shaderSource(shader, source); this.gl.shaderSource(shader, source);
gl.compileShader(shader); this.gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) if (!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS))
throw new Error("filter: gl compile failed", gl.getShaderInfoLog(shader)); throw new Error(`filter: gl compile failed: ${this.gl.getShaderInfoLog(shader)}`);
return shader; return shader;
}; });
this.uniform = {}; this.gl = gl;
this.attribute = {}; const _vsh = this.compile(vertexSource, this.gl.VERTEX_SHADER);
const _vsh = _compile(vertexSource, gl.VERTEX_SHADER); const _fsh = this.compile(fragmentSource, this.gl.FRAGMENT_SHADER);
const _fsh = _compile(fragmentSource, gl.FRAGMENT_SHADER); this.id = this.gl.createProgram();
this.id = gl.createProgram(); this.gl.attachShader(this.id, _vsh);
gl.attachShader(this.id, _vsh); this.gl.attachShader(this.id, _fsh);
gl.attachShader(this.id, _fsh); this.gl.linkProgram(this.id);
gl.linkProgram(this.id); if (!this.gl.getProgramParameter(this.id, this.gl.LINK_STATUS))
if (!gl.getProgramParameter(this.id, gl.LINK_STATUS)) throw new Error(`filter: gl link failed: ${this.gl.getProgramInfoLog(this.id)}`);
throw new Error("filter: gl link failed", gl.getProgramInfoLog(this.id)); this.gl.useProgram(this.id);
gl.useProgram(this.id); this.collect(vertexSource, "attribute", this.attribute);
_collect(vertexSource, "attribute", this.attribute);
for (const a in this.attribute) for (const a in this.attribute)
this.attribute[a] = gl.getAttribLocation(this.id, a); this.attribute[a] = this.gl.getAttribLocation(this.id, a);
_collect(vertexSource, "uniform", this.uniform); this.collect(vertexSource, "uniform", this.uniform);
_collect(fragmentSource, "uniform", this.uniform); this.collect(fragmentSource, "uniform", this.uniform);
for (const u in this.uniform) for (const u in this.uniform)
this.uniform[u] = gl.getUniformLocation(this.id, u); this.uniform[u] = this.gl.getUniformLocation(this.id, u);
} }
};
function GLImageFilter(params) { function GLImageFilter(params) {
if (!params) if (!params)
params = {}; params = {};
@ -309,13 +414,12 @@ function GLImageFilter(params) {
let _height = -1; let _height = -1;
let _vertexBuffer = null; let _vertexBuffer = null;
let _currentProgram = null; let _currentProgram = null;
const _filter = {}; const _canvas = params.canvas || typeof OffscreenCanvas !== "undefined" ? new OffscreenCanvas(100, 100) : document.createElement("canvas");
const _canvas = params.canvas || document.createElement("canvas");
const _shaderProgramCache = {}; const _shaderProgramCache = {};
const DRAW = { INTERMEDIATE: 1 }; const DRAW = { INTERMEDIATE: 1 };
const gl = _canvas.getContext("webgl"); const gl = _canvas.getContext("webgl");
if (!gl) if (!gl)
throw new Error("filter: context failed"); throw new Error("filter: cannot get webgl context");
this.addFilter = function(name) { this.addFilter = function(name) {
const args = Array.prototype.slice.call(arguments, 1); const args = Array.prototype.slice.call(arguments, 1);
const filter = _filter[name]; const filter = _filter[name];
@ -325,40 +429,14 @@ function GLImageFilter(params) {
_filterChain = []; _filterChain = [];
}; };
const _resize = function(width, height) { const _resize = function(width, height) {
if (width === _width && height === _height) { if (width === _width && height === _height)
return; return;
}
_canvas.width = width; _canvas.width = width;
_width = width; _width = width;
_canvas.height = height; _canvas.height = height;
_height = height; _height = height;
if (!_vertexBuffer) { if (!_vertexBuffer) {
const vertices = new Float32Array([ const vertices = new Float32Array([-1, -1, 0, 1, 1, -1, 1, 1, -1, 1, 0, 0, -1, 1, 0, 0, 1, -1, 1, 1, 1, 1, 1, 0]);
-1,
-1,
0,
1,
1,
-1,
1,
1,
-1,
1,
0,
0,
-1,
1,
0,
0,
1,
-1,
1,
1,
1,
1,
1,
0
]);
_vertexBuffer = gl.createBuffer(), gl.bindBuffer(gl.ARRAY_BUFFER, _vertexBuffer); _vertexBuffer = gl.createBuffer(), gl.bindBuffer(gl.ARRAY_BUFFER, _vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW); gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true); gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
@ -387,16 +465,17 @@ function GLImageFilter(params) {
_tempFramebuffers[index] = _tempFramebuffers[index] || _createFramebufferTexture(_width, _height); _tempFramebuffers[index] = _tempFramebuffers[index] || _createFramebufferTexture(_width, _height);
return _tempFramebuffers[index]; return _tempFramebuffers[index];
}; };
const _draw = function(flags = null) { const _draw = function(flags = 0) {
var _a, _b; var _a, _b;
if (!_currentProgram)
return;
let source = null; let source = null;
let target = null; let target = null;
let flipY = false; let flipY = false;
if (_drawCount === 0) { if (_drawCount === 0)
source = _sourceTexture; source = _sourceTexture;
} else { else
source = (_a = _getTempFramebuffer(_currentFramebufferIndex)) == null ? void 0 : _a.texture; source = (_a = _getTempFramebuffer(_currentFramebufferIndex)) == null ? void 0 : _a.texture;
}
_drawCount++; _drawCount++;
if (_lastInChain && !(flags & DRAW.INTERMEDIATE)) { if (_lastInChain && !(flags & DRAW.INTERMEDIATE)) {
target = null; target = null;
@ -407,7 +486,7 @@ function GLImageFilter(params) {
} }
gl.bindTexture(gl.TEXTURE_2D, source); gl.bindTexture(gl.TEXTURE_2D, source);
gl.bindFramebuffer(gl.FRAMEBUFFER, target); gl.bindFramebuffer(gl.FRAMEBUFFER, target);
gl.uniform1f(_currentProgram.uniform.flipY, flipY ? -1 : 1); gl.uniform1f(_currentProgram.uniform["flipY"], flipY ? -1 : 1);
gl.drawArrays(gl.TRIANGLES, 0, 6); gl.drawArrays(gl.TRIANGLES, 0, 6);
}; };
this.apply = function(image24) { this.apply = function(image24) {
@ -423,90 +502,44 @@ function GLImageFilter(params) {
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image24); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image24);
if (_filterChain.length === 0) { if (_filterChain.length === 0) {
_draw(); _draw();
return _canvas; } else {
}
for (let i = 0; i < _filterChain.length; i++) { for (let i = 0; i < _filterChain.length; i++) {
_lastInChain = i === _filterChain.length - 1; _lastInChain = i === _filterChain.length - 1;
const f = _filterChain[i]; const f = _filterChain[i];
f.func.apply(this, f.args || []); f.func.apply(this, f.args || []);
} }
}
return _canvas; return _canvas;
}; };
const _compileShader = function(fragmentSource) { const _compileShader = function(fragmentSource) {
if (_shaderProgramCache[fragmentSource]) { if (_shaderProgramCache[fragmentSource]) {
_currentProgram = _shaderProgramCache[fragmentSource]; _currentProgram = _shaderProgramCache[fragmentSource];
gl.useProgram(_currentProgram.id); gl.useProgram(_currentProgram == null ? void 0 : _currentProgram.id);
return _currentProgram; return _currentProgram;
} }
const SHADER = {}; _currentProgram = new GLProgram(gl, vertexIdentity, fragmentSource);
SHADER.VERTEX_IDENTITY = [
"precision highp float;",
"attribute vec2 pos;",
"attribute vec2 uv;",
"varying vec2 vUv;",
"uniform float flipY;",
"void main(void) {",
"vUv = uv;",
"gl_Position = vec4(pos.x, pos.y*flipY, 0.0, 1.);",
"}"
].join("\n");
SHADER.FRAGMENT_IDENTITY = [
"precision highp float;",
"varying vec2 vUv;",
"uniform sampler2D texture;",
"void main(void) {",
"gl_FragColor = texture2D(texture, vUv);",
"}"
].join("\n");
_currentProgram = new GLProgram(gl, SHADER.VERTEX_IDENTITY, fragmentSource);
const floatSize = Float32Array.BYTES_PER_ELEMENT; const floatSize = Float32Array.BYTES_PER_ELEMENT;
const vertSize = 4 * floatSize; const vertSize = 4 * floatSize;
gl.enableVertexAttribArray(_currentProgram.attribute.pos); gl.enableVertexAttribArray(_currentProgram.attribute["pos"]);
gl.vertexAttribPointer(_currentProgram.attribute.pos, 2, gl.FLOAT, false, vertSize, 0 * floatSize); gl.vertexAttribPointer(_currentProgram.attribute["pos"], 2, gl.FLOAT, false, vertSize, 0 * floatSize);
gl.enableVertexAttribArray(_currentProgram.attribute.uv); gl.enableVertexAttribArray(_currentProgram.attribute.uv);
gl.vertexAttribPointer(_currentProgram.attribute.uv, 2, gl.FLOAT, false, vertSize, 2 * floatSize); gl.vertexAttribPointer(_currentProgram.attribute["uv"], 2, gl.FLOAT, false, vertSize, 2 * floatSize);
_shaderProgramCache[fragmentSource] = _currentProgram; _shaderProgramCache[fragmentSource] = _currentProgram;
return _currentProgram; return _currentProgram;
}; };
_filter.colorMatrix = function(matrix) { const _filter = {
colorMatrix: (matrix) => {
const m = new Float32Array(matrix); const m = new Float32Array(matrix);
m[4] /= 255; m[4] /= 255;
m[9] /= 255; m[9] /= 255;
m[14] /= 255; m[14] /= 255;
m[19] /= 255; m[19] /= 255;
const shader = m[18] === 1 && m[3] === 0 && m[8] === 0 && m[13] === 0 && m[15] === 0 && m[16] === 0 && m[17] === 0 && m[19] === 0 ? _filter.colorMatrix.SHADER.WITHOUT_ALPHA : _filter.colorMatrix.SHADER.WITH_ALPHA; const shader = m[18] === 1 && m[3] === 0 && m[8] === 0 && m[13] === 0 && m[15] === 0 && m[16] === 0 && m[17] === 0 && m[19] === 0 ? colorMatrixWithoutAlpha : colorMatrixWithAlpha;
const program = _compileShader(shader); const program = _compileShader(shader);
gl.uniform1fv(program.uniform.m, m); gl.uniform1fv(program == null ? void 0 : program.uniform["m"], m);
_draw(); _draw();
}; },
_filter.colorMatrix.SHADER = {}; brightness: (brightness) => {
_filter.colorMatrix.SHADER.WITH_ALPHA = [
"precision highp float;",
"varying vec2 vUv;",
"uniform sampler2D texture;",
"uniform float m[20];",
"void main(void) {",
"vec4 c = texture2D(texture, vUv);",
"gl_FragColor.r = m[0] * c.r + m[1] * c.g + m[2] * c.b + m[3] * c.a + m[4];",
"gl_FragColor.g = m[5] * c.r + m[6] * c.g + m[7] * c.b + m[8] * c.a + m[9];",
"gl_FragColor.b = m[10] * c.r + m[11] * c.g + m[12] * c.b + m[13] * c.a + m[14];",
"gl_FragColor.a = m[15] * c.r + m[16] * c.g + m[17] * c.b + m[18] * c.a + m[19];",
"}"
].join("\n");
_filter.colorMatrix.SHADER.WITHOUT_ALPHA = [
"precision highp float;",
"varying vec2 vUv;",
"uniform sampler2D texture;",
"uniform float m[20];",
"void main(void) {",
"vec4 c = texture2D(texture, vUv);",
"gl_FragColor.r = m[0] * c.r + m[1] * c.g + m[2] * c.b + m[4];",
"gl_FragColor.g = m[5] * c.r + m[6] * c.g + m[7] * c.b + m[9];",
"gl_FragColor.b = m[10] * c.r + m[11] * c.g + m[12] * c.b + m[14];",
"gl_FragColor.a = c.a;",
"}"
].join("\n");
_filter.brightness = function(brightness) {
const b = (brightness || 0) + 1; const b = (brightness || 0) + 1;
_filter.colorMatrix([ _filter.colorMatrix([
b, b,
@ -530,8 +563,8 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.saturation = function(amount) { saturation: (amount) => {
const x = (amount || 0) * 2 / 3 + 1; const x = (amount || 0) * 2 / 3 + 1;
const y = (x - 1) * -0.5; const y = (x - 1) * -0.5;
_filter.colorMatrix([ _filter.colorMatrix([
@ -556,11 +589,11 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.desaturate = function() { desaturate: () => {
_filter.saturation(-1); _filter.saturation(-1);
}; },
_filter.contrast = function(amount) { contrast: (amount) => {
const v = (amount || 0) + 1; const v = (amount || 0) + 1;
const o = -128 * (v - 1); const o = -128 * (v - 1);
_filter.colorMatrix([ _filter.colorMatrix([
@ -585,11 +618,11 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.negative = function() { negative: () => {
_filter.contrast(-2); _filter.contrast(-2);
}; },
_filter.hue = function(rotation) { hue: (rotation) => {
rotation = (rotation || 0) / 180 * Math.PI; rotation = (rotation || 0) / 180 * Math.PI;
const cos = Math.cos(rotation); const cos = Math.cos(rotation);
const sin = Math.sin(rotation); const sin = Math.sin(rotation);
@ -618,8 +651,8 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.desaturateLuminance = function() { desaturateLuminance: () => {
_filter.colorMatrix([ _filter.colorMatrix([
0.2764723, 0.2764723,
0.929708, 0.929708,
@ -642,8 +675,8 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.sepia = function() { sepia: () => {
_filter.colorMatrix([ _filter.colorMatrix([
0.393, 0.393,
0.7689999, 0.7689999,
@ -666,8 +699,8 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.brownie = function() { brownie: () => {
_filter.colorMatrix([ _filter.colorMatrix([
0.5997023498159715, 0.5997023498159715,
0.34553243048391263, 0.34553243048391263,
@ -690,8 +723,8 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.vintagePinhole = function() { vintagePinhole: () => {
_filter.colorMatrix([ _filter.colorMatrix([
0.6279345635605994, 0.6279345635605994,
0.3202183420819367, 0.3202183420819367,
@ -714,8 +747,8 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.kodachrome = function() { kodachrome: () => {
_filter.colorMatrix([ _filter.colorMatrix([
1.1285582396593525, 1.1285582396593525,
-0.3967382283601348, -0.3967382283601348,
@ -738,8 +771,8 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.technicolor = function() { technicolor: () => {
_filter.colorMatrix([ _filter.colorMatrix([
1.9125277891456083, 1.9125277891456083,
-0.8545344976951645, -0.8545344976951645,
@ -762,8 +795,8 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.polaroid = function() { polaroid: () => {
_filter.colorMatrix([ _filter.colorMatrix([
1.438, 1.438,
-0.062, -0.062,
@ -786,8 +819,8 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.shiftToBGR = function() { shiftToBGR: () => {
_filter.colorMatrix([ _filter.colorMatrix([
0, 0,
0, 0,
@ -810,40 +843,17 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.convolution = function(matrix) { convolution: (matrix) => {
const m = new Float32Array(matrix); const m = new Float32Array(matrix);
const pixelSizeX = 1 / _width; const pixelSizeX = 1 / _width;
const pixelSizeY = 1 / _height; const pixelSizeY = 1 / _height;
const program = _compileShader(_filter.convolution.SHADER); const program = _compileShader(convolution);
gl.uniform1fv(program.uniform.m, m); gl.uniform1fv(program == null ? void 0 : program.uniform["m"], m);
gl.uniform2f(program.uniform.px, pixelSizeX, pixelSizeY); gl.uniform2f(program == null ? void 0 : program.uniform["px"], pixelSizeX, pixelSizeY);
_draw(); _draw();
}; },
_filter.convolution.SHADER = [ detectEdges: () => {
"precision highp float;",
"varying vec2 vUv;",
"uniform sampler2D texture;",
"uniform vec2 px;",
"uniform float m[9];",
"void main(void) {",
"vec4 c11 = texture2D(texture, vUv - px);",
"vec4 c12 = texture2D(texture, vec2(vUv.x, vUv.y - px.y));",
"vec4 c13 = texture2D(texture, vec2(vUv.x + px.x, vUv.y - px.y));",
"vec4 c21 = texture2D(texture, vec2(vUv.x - px.x, vUv.y) );",
"vec4 c22 = texture2D(texture, vUv);",
"vec4 c23 = texture2D(texture, vec2(vUv.x + px.x, vUv.y) );",
"vec4 c31 = texture2D(texture, vec2(vUv.x - px.x, vUv.y + px.y) );",
"vec4 c32 = texture2D(texture, vec2(vUv.x, vUv.y + px.y) );",
"vec4 c33 = texture2D(texture, vUv + px );",
"gl_FragColor = ",
"c11 * m[0] + c12 * m[1] + c22 * m[2] +",
"c21 * m[3] + c22 * m[4] + c23 * m[5] +",
"c31 * m[6] + c32 * m[7] + c33 * m[8];",
"gl_FragColor.a = c22.a;",
"}"
].join("\n");
_filter.detectEdges = function() {
_filter.convolution.call(this, [ _filter.convolution.call(this, [
0, 0,
1, 1,
@ -855,8 +865,8 @@ function GLImageFilter(params) {
1, 1,
0 0
]); ]);
}; },
_filter.sobelX = function() { sobelX: () => {
_filter.convolution.call(this, [ _filter.convolution.call(this, [
-1, -1,
0, 0,
@ -868,8 +878,8 @@ function GLImageFilter(params) {
0, 0,
1 1
]); ]);
}; },
_filter.sobelY = function() { sobelY: () => {
_filter.convolution.call(this, [ _filter.convolution.call(this, [
-1, -1,
-2, -2,
@ -881,8 +891,8 @@ function GLImageFilter(params) {
2, 2,
1 1
]); ]);
}; },
_filter.sharpen = function(amount) { sharpen: (amount) => {
const a = amount || 1; const a = amount || 1;
_filter.convolution.call(this, [ _filter.convolution.call(this, [
0, 0,
@ -895,8 +905,8 @@ function GLImageFilter(params) {
-1 * a, -1 * a,
0 0
]); ]);
}; },
_filter.emboss = function(size2) { emboss: (size2) => {
const s = size2 || 1; const s = size2 || 1;
_filter.convolution.call(this, [ _filter.convolution.call(this, [
-2 * s, -2 * s,
@ -909,61 +919,24 @@ function GLImageFilter(params) {
1 * s, 1 * s,
2 * s 2 * s
]); ]);
}; },
_filter.blur = function(size2) { blur: (size2) => {
const blurSizeX = size2 / 7 / _width; const blurSizeX = size2 / 7 / _width;
const blurSizeY = size2 / 7 / _height; const blurSizeY = size2 / 7 / _height;
const program = _compileShader(_filter.blur.SHADER); const program = _compileShader(blur);
gl.uniform2f(program.uniform.px, 0, blurSizeY); gl.uniform2f(program == null ? void 0 : program.uniform["px"], 0, blurSizeY);
_draw(DRAW.INTERMEDIATE); _draw(DRAW.INTERMEDIATE);
gl.uniform2f(program.uniform.px, blurSizeX, 0); gl.uniform2f(program == null ? void 0 : program.uniform["px"], blurSizeX, 0);
_draw(); _draw();
}; },
_filter.blur.SHADER = [ pixelate: (size2) => {
"precision highp float;",
"varying vec2 vUv;",
"uniform sampler2D texture;",
"uniform vec2 px;",
"void main(void) {",
"gl_FragColor = vec4(0.0);",
"gl_FragColor += texture2D(texture, vUv + vec2(-7.0*px.x, -7.0*px.y))*0.0044299121055113265;",
"gl_FragColor += texture2D(texture, vUv + vec2(-6.0*px.x, -6.0*px.y))*0.00895781211794;",
"gl_FragColor += texture2D(texture, vUv + vec2(-5.0*px.x, -5.0*px.y))*0.0215963866053;",
"gl_FragColor += texture2D(texture, vUv + vec2(-4.0*px.x, -4.0*px.y))*0.0443683338718;",
"gl_FragColor += texture2D(texture, vUv + vec2(-3.0*px.x, -3.0*px.y))*0.0776744219933;",
"gl_FragColor += texture2D(texture, vUv + vec2(-2.0*px.x, -2.0*px.y))*0.115876621105;",
"gl_FragColor += texture2D(texture, vUv + vec2(-1.0*px.x, -1.0*px.y))*0.147308056121;",
"gl_FragColor += texture2D(texture, vUv )*0.159576912161;",
"gl_FragColor += texture2D(texture, vUv + vec2( 1.0*px.x, 1.0*px.y))*0.147308056121;",
"gl_FragColor += texture2D(texture, vUv + vec2( 2.0*px.x, 2.0*px.y))*0.115876621105;",
"gl_FragColor += texture2D(texture, vUv + vec2( 3.0*px.x, 3.0*px.y))*0.0776744219933;",
"gl_FragColor += texture2D(texture, vUv + vec2( 4.0*px.x, 4.0*px.y))*0.0443683338718;",
"gl_FragColor += texture2D(texture, vUv + vec2( 5.0*px.x, 5.0*px.y))*0.0215963866053;",
"gl_FragColor += texture2D(texture, vUv + vec2( 6.0*px.x, 6.0*px.y))*0.00895781211794;",
"gl_FragColor += texture2D(texture, vUv + vec2( 7.0*px.x, 7.0*px.y))*0.0044299121055113265;",
"}"
].join("\n");
_filter.pixelate = function(size2) {
const blurSizeX = size2 / _width; const blurSizeX = size2 / _width;
const blurSizeY = size2 / _height; const blurSizeY = size2 / _height;
const program = _compileShader(_filter.pixelate.SHADER); const program = _compileShader(pixelate);
gl.uniform2f(program.uniform.size, blurSizeX, blurSizeY); gl.uniform2f(program == null ? void 0 : program.uniform["size"], blurSizeX, blurSizeY);
_draw(); _draw();
}
}; };
_filter.pixelate.SHADER = [
"precision highp float;",
"varying vec2 vUv;",
"uniform vec2 size;",
"uniform sampler2D texture;",
"vec2 pixelate(vec2 coord, vec2 size) {",
"return floor( coord / size ) * size;",
"}",
"void main(void) {",
"gl_FragColor = vec4(0.0);",
"vec2 coord = pixelate(vUv, size);",
"gl_FragColor += texture2D(texture, coord);",
"}"
].join("\n");
} }
// src/util/env.ts // src/util/env.ts
@ -1188,7 +1161,7 @@ function process2(input, config3, getTensor = true) {
fx.addFilter("polaroid"); fx.addFilter("polaroid");
if (config3.filter.pixelate !== 0) if (config3.filter.pixelate !== 0)
fx.addFilter("pixelate", config3.filter.pixelate); fx.addFilter("pixelate", config3.filter.pixelate);
fx.apply(inCanvas); outCanvas = fx.apply(inCanvas);
} else { } else {
copy(inCanvas, outCanvas); copy(inCanvas, outCanvas);
if (fx) if (fx)
@ -1197,6 +1170,8 @@ function process2(input, config3, getTensor = true) {
} }
if (!getTensor) if (!getTensor)
return { tensor: null, canvas: outCanvas }; return { tensor: null, canvas: outCanvas };
if (!outCanvas)
throw new Error("cannot create output canvas");
let pixels; let pixels;
let depth = 3; let depth = 3;
if (typeof ImageData !== "undefined" && input instanceof ImageData || input["data"] && input["width"] && input["height"]) { if (typeof ImageData !== "undefined" && input instanceof ImageData || input["data"] && input["width"] && input["height"]) {

View File

@ -148,7 +148,7 @@ export function process(input: Input, config: Config, getTensor: boolean = true)
if (config.filter.technicolor) fx.addFilter('technicolor'); if (config.filter.technicolor) fx.addFilter('technicolor');
if (config.filter.polaroid) fx.addFilter('polaroid'); if (config.filter.polaroid) fx.addFilter('polaroid');
if (config.filter.pixelate !== 0) fx.addFilter('pixelate', config.filter.pixelate); if (config.filter.pixelate !== 0) fx.addFilter('pixelate', config.filter.pixelate);
fx.apply(inCanvas); outCanvas = fx.apply(inCanvas);
} else { } else {
copy(inCanvas, outCanvas); // if no filters applied, output canvas is input canvas copy(inCanvas, outCanvas); // if no filters applied, output canvas is input canvas
if (fx) fx = null; if (fx) fx = null;
@ -156,6 +156,7 @@ export function process(input: Input, config: Config, getTensor: boolean = true)
} }
if (!getTensor) return { tensor: null, canvas: outCanvas }; // just canvas was requested if (!getTensor) return { tensor: null, canvas: outCanvas }; // just canvas was requested
if (!outCanvas) throw new Error('cannot create output canvas');
// create tensor from image unless input was a tensor already // create tensor from image unless input was a tensor already
let pixels; let pixels;

View File

@ -1,15 +1,34 @@
/** /**
* Image Filters in WebGL algoritm implementation * Image Filters in WebGL algoritm implementation
*
* Based on: [WebGLImageFilter](https://github.com/phoboslab/WebGLImageFilter) * Based on: [WebGLImageFilter](https://github.com/phoboslab/WebGLImageFilter)
*
* This module is written in ES5 JS and does not conform to code and style standards * This module is written in ES5 JS and does not conform to code and style standards
*/ */
// @ts-nocheck import * as shaders from './imagefxshaders';
function GLProgram(gl, vertexSource, fragmentSource) { class GLProgram {
const _collect = function (source, prefix, collection) { uniform = {};
attribute = {};
gl: WebGLRenderingContext;
id: WebGLProgram;
constructor(gl, vertexSource, fragmentSource) {
this.gl = gl;
const _vsh = this.compile(vertexSource, this.gl.VERTEX_SHADER);
const _fsh = this.compile(fragmentSource, this.gl.FRAGMENT_SHADER);
this.id = this.gl.createProgram() as WebGLProgram;
this.gl.attachShader(this.id, _vsh);
this.gl.attachShader(this.id, _fsh);
this.gl.linkProgram(this.id);
if (!this.gl.getProgramParameter(this.id, this.gl.LINK_STATUS)) throw new Error(`filter: gl link failed: ${this.gl.getProgramInfoLog(this.id)}`);
this.gl.useProgram(this.id);
this.collect(vertexSource, 'attribute', this.attribute); // Collect attributes
for (const a in this.attribute) this.attribute[a] = this.gl.getAttribLocation(this.id, a);
this.collect(vertexSource, 'uniform', this.uniform); // Collect uniforms
this.collect(fragmentSource, 'uniform', this.uniform);
for (const u in this.uniform) this.uniform[u] = this.gl.getUniformLocation(this.id, u);
}
collect = (source, prefix, collection) => {
const r = new RegExp('\\b' + prefix + ' \\w+ (\\w+)', 'ig'); const r = new RegExp('\\b' + prefix + ' \\w+ (\\w+)', 'ig');
source.replace(r, (match, name) => { source.replace(r, (match, name) => {
collection[name] = 0; collection[name] = 0;
@ -17,55 +36,32 @@ function GLProgram(gl, vertexSource, fragmentSource) {
}); });
}; };
const _compile = function (source, type) { compile = (source, type): WebGLShader => {
const shader = gl.createShader(type); const shader = this.gl.createShader(type) as WebGLShader;
gl.shaderSource(shader, source); this.gl.shaderSource(shader, source);
gl.compileShader(shader); this.gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) throw new Error('filter: gl compile failed', gl.getShaderInfoLog(shader)); if (!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS)) throw new Error(`filter: gl compile failed: ${this.gl.getShaderInfoLog(shader)}`);
return shader; return shader;
}; };
this.uniform = {};
this.attribute = {};
const _vsh = _compile(vertexSource, gl.VERTEX_SHADER);
const _fsh = _compile(fragmentSource, gl.FRAGMENT_SHADER);
this.id = gl.createProgram();
gl.attachShader(this.id, _vsh);
gl.attachShader(this.id, _fsh);
gl.linkProgram(this.id);
if (!gl.getProgramParameter(this.id, gl.LINK_STATUS)) throw new Error('filter: gl link failed', gl.getProgramInfoLog(this.id));
gl.useProgram(this.id);
// Collect attributes
_collect(vertexSource, 'attribute', this.attribute);
for (const a in this.attribute) this.attribute[a] = gl.getAttribLocation(this.id, a);
// Collect uniforms
_collect(vertexSource, 'uniform', this.uniform);
_collect(fragmentSource, 'uniform', this.uniform);
for (const u in this.uniform) this.uniform[u] = gl.getUniformLocation(this.id, u);
} }
// export const GLImageFilter = function (params) {
export function GLImageFilter(params) { export function GLImageFilter(params) {
if (!params) params = { }; if (!params) params = { };
let _drawCount = 0; let _drawCount = 0;
let _sourceTexture = null; let _sourceTexture = null;
let _lastInChain = false; let _lastInChain = false;
let _currentFramebufferIndex = -1; let _currentFramebufferIndex = -1;
let _tempFramebuffers = [null, null]; let _tempFramebuffers: [null, null] | [{ fbo: any, texture: any }] = [null, null];
let _filterChain = []; let _filterChain: Record<string, unknown>[] = [];
let _width = -1; let _width = -1;
let _height = -1; let _height = -1;
let _vertexBuffer = null; let _vertexBuffer = null;
let _currentProgram = null; let _currentProgram: GLProgram | null = null;
const _filter = {}; const _canvas = params.canvas || typeof OffscreenCanvas !== 'undefined' ? new OffscreenCanvas(100, 100) : document.createElement('canvas');
const _canvas = params.canvas || document.createElement('canvas'); const _shaderProgramCache = { }; // key is the shader program source, value is the compiled program
// key is the shader program source, value is the compiled program
const _shaderProgramCache = { };
const DRAW = { INTERMEDIATE: 1 }; const DRAW = { INTERMEDIATE: 1 };
const gl = _canvas.getContext('webgl'); const gl = _canvas.getContext('webgl');
if (!gl) throw new Error('filter: context failed'); if (!gl) throw new Error('filter: cannot get webgl context');
this.addFilter = function (name) { this.addFilter = function (name) {
// eslint-disable-next-line prefer-rest-params // eslint-disable-next-line prefer-rest-params
@ -79,27 +75,20 @@ export function GLImageFilter(params) {
}; };
const _resize = function (width, height) { const _resize = function (width, height) {
// Same width/height? Nothing to do here if (width === _width && height === _height) return; // Same width/height? Nothing to do here
if (width === _width && height === _height) { return; }
_canvas.width = width; _canvas.width = width;
_width = width; _width = width;
_canvas.height = height; _canvas.height = height;
_height = height; _height = height;
// Create the context if we don't have it yet if (!_vertexBuffer) { // Create the context if we don't have it yet
if (!_vertexBuffer) { const vertices = new Float32Array([-1, -1, 0, 1, 1, -1, 1, 1, -1, 1, 0, 0, -1, 1, 0, 0, 1, -1, 1, 1, 1, 1, 1, 0]); // Create the vertex buffer for the two triangles [x, y, u, v] * 6
// Create the vertex buffer for the two triangles [x, y, u, v] * 6
const vertices = new Float32Array([
-1, -1, 0, 1, 1, -1, 1, 1, -1, 1, 0, 0,
-1, 1, 0, 0, 1, -1, 1, 1, 1, 1, 1, 0,
]);
// eslint-disable-next-line no-unused-expressions // eslint-disable-next-line no-unused-expressions
(_vertexBuffer = gl.createBuffer(), gl.bindBuffer(gl.ARRAY_BUFFER, _vertexBuffer)); (_vertexBuffer = gl.createBuffer(), gl.bindBuffer(gl.ARRAY_BUFFER, _vertexBuffer));
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW); gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true); gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
} }
gl.viewport(0, 0, _width, _height); gl.viewport(0, 0, _width, _height);
// Delete old temp framebuffers _tempFramebuffers = [null, null]; // Delete old temp framebuffers
_tempFramebuffers = [null, null];
}; };
const _createFramebufferTexture = function (width, height) { const _createFramebufferTexture = function (width, height) {
@ -125,146 +114,83 @@ export function GLImageFilter(params) {
return _tempFramebuffers[index]; return _tempFramebuffers[index];
}; };
const _draw = function (flags = null) { const _draw = function (flags = 0) {
if (!_currentProgram) return;
let source = null; let source = null;
let target = null; let target = null;
let flipY = false; let flipY = false;
// Set up the source if (_drawCount === 0) source = _sourceTexture; // First draw call - use the source texture
if (_drawCount === 0) { else source = _getTempFramebuffer(_currentFramebufferIndex)?.texture; // All following draw calls use the temp buffer last drawn to
// First draw call - use the source texture
source = _sourceTexture;
} else {
// All following draw calls use the temp buffer last drawn to
source = _getTempFramebuffer(_currentFramebufferIndex)?.texture;
}
_drawCount++; _drawCount++;
// Set up the target if (_lastInChain && !(flags & DRAW.INTERMEDIATE)) { // Last filter in our chain - draw directly to the WebGL Canvas. We may also have to flip the image vertically now
if (_lastInChain && !(flags & DRAW.INTERMEDIATE)) {
// Last filter in our chain - draw directly to the WebGL Canvas. We may
// also have to flip the image vertically now
target = null; target = null;
flipY = _drawCount % 2 === 0; flipY = _drawCount % 2 === 0;
} else { } else {
// Intermediate draw call - get a temp buffer to draw to
_currentFramebufferIndex = (_currentFramebufferIndex + 1) % 2; _currentFramebufferIndex = (_currentFramebufferIndex + 1) % 2;
target = _getTempFramebuffer(_currentFramebufferIndex)?.fbo; target = _getTempFramebuffer(_currentFramebufferIndex)?.fbo; // Intermediate draw call - get a temp buffer to draw to
} }
// Bind the source and target and draw the two triangles gl.bindTexture(gl.TEXTURE_2D, source); // Bind the source and target and draw the two triangles
gl.bindTexture(gl.TEXTURE_2D, source);
gl.bindFramebuffer(gl.FRAMEBUFFER, target); gl.bindFramebuffer(gl.FRAMEBUFFER, target);
gl.uniform1f(_currentProgram.uniform.flipY, (flipY ? -1 : 1)); gl.uniform1f(_currentProgram.uniform['flipY'], (flipY ? -1 : 1));
gl.drawArrays(gl.TRIANGLES, 0, 6); gl.drawArrays(gl.TRIANGLES, 0, 6);
}; };
this.apply = function (image) { this.apply = function (image) {
_resize(image.width, image.height); _resize(image.width, image.height);
_drawCount = 0; _drawCount = 0;
// Create the texture for the input image if we haven't yet if (!_sourceTexture) _sourceTexture = gl.createTexture(); // Create the texture for the input image if we haven't yet
if (!_sourceTexture) _sourceTexture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, _sourceTexture); gl.bindTexture(gl.TEXTURE_2D, _sourceTexture);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
// No filters? Just draw if (_filterChain.length === 0) { // draw when done with filters
if (_filterChain.length === 0) {
// const program = _compileShader(SHADER.FRAGMENT_IDENTITY);
_draw(); _draw();
return _canvas; } else { // apply filters one-by-one recursively
}
for (let i = 0; i < _filterChain.length; i++) { for (let i = 0; i < _filterChain.length; i++) {
_lastInChain = (i === _filterChain.length - 1); _lastInChain = (i === _filterChain.length - 1);
const f = _filterChain[i]; const f = _filterChain[i];
f.func.apply(this, f.args || []); f.func.apply(this, f.args || []);
} }
}
return _canvas; return _canvas;
}; };
const _compileShader = function (fragmentSource) { const _compileShader = function (fragmentSource) {
if (_shaderProgramCache[fragmentSource]) { if (_shaderProgramCache[fragmentSource]) {
_currentProgram = _shaderProgramCache[fragmentSource]; _currentProgram = _shaderProgramCache[fragmentSource];
gl.useProgram(_currentProgram.id); gl.useProgram(_currentProgram?.id);
return _currentProgram; return _currentProgram;
} }
// Compile shaders _currentProgram = new GLProgram(gl, shaders.vertexIdentity, fragmentSource);
const SHADER = {};
SHADER.VERTEX_IDENTITY = [
'precision highp float;',
'attribute vec2 pos;',
'attribute vec2 uv;',
'varying vec2 vUv;',
'uniform float flipY;',
'void main(void) {',
'vUv = uv;',
'gl_Position = vec4(pos.x, pos.y*flipY, 0.0, 1.);',
'}',
].join('\n');
SHADER.FRAGMENT_IDENTITY = [
'precision highp float;',
'varying vec2 vUv;',
'uniform sampler2D texture;',
'void main(void) {',
'gl_FragColor = texture2D(texture, vUv);',
'}',
].join('\n');
_currentProgram = new GLProgram(gl, SHADER.VERTEX_IDENTITY, fragmentSource);
const floatSize = Float32Array.BYTES_PER_ELEMENT; const floatSize = Float32Array.BYTES_PER_ELEMENT;
const vertSize = 4 * floatSize; const vertSize = 4 * floatSize;
gl.enableVertexAttribArray(_currentProgram.attribute.pos); gl.enableVertexAttribArray(_currentProgram.attribute['pos']);
gl.vertexAttribPointer(_currentProgram.attribute.pos, 2, gl.FLOAT, false, vertSize, 0 * floatSize); gl.vertexAttribPointer(_currentProgram.attribute['pos'], 2, gl.FLOAT, false, vertSize, 0 * floatSize);
gl.enableVertexAttribArray(_currentProgram.attribute.uv); gl.enableVertexAttribArray(_currentProgram.attribute.uv);
gl.vertexAttribPointer(_currentProgram.attribute.uv, 2, gl.FLOAT, false, vertSize, 2 * floatSize); gl.vertexAttribPointer(_currentProgram.attribute['uv'], 2, gl.FLOAT, false, vertSize, 2 * floatSize);
_shaderProgramCache[fragmentSource] = _currentProgram; _shaderProgramCache[fragmentSource] = _currentProgram;
return _currentProgram; return _currentProgram;
}; };
// ------------------------------------------------------------------------- // Color Matrix Filter: Used by most color filters
// Color Matrix Filter const _filter = {
_filter.colorMatrix = function (matrix) { colorMatrix: (matrix) => {
// Create a Float32 Array and normalize the offset component to 0-1 const m = new Float32Array(matrix); // Create a Float32 Array and normalize the offset component to 0-1
const m = new Float32Array(matrix);
m[4] /= 255; m[4] /= 255;
m[9] /= 255; m[9] /= 255;
m[14] /= 255; m[14] /= 255;
m[19] /= 255; m[19] /= 255;
// Can we ignore the alpha value? Makes things a bit faster. const shader = (m[18] === 1 && m[3] === 0 && m[8] === 0 && m[13] === 0 && m[15] === 0 && m[16] === 0 && m[17] === 0 && m[19] === 0) // Can we ignore the alpha value? Makes things a bit faster.
const shader = (m[18] === 1 && m[3] === 0 && m[8] === 0 && m[13] === 0 && m[15] === 0 && m[16] === 0 && m[17] === 0 && m[19] === 0) ? shaders.colorMatrixWithoutAlpha
? _filter.colorMatrix.SHADER.WITHOUT_ALPHA : shaders.colorMatrixWithAlpha;
: _filter.colorMatrix.SHADER.WITH_ALPHA;
const program = _compileShader(shader); const program = _compileShader(shader);
gl.uniform1fv(program.uniform.m, m); gl.uniform1fv(program?.uniform['m'], m);
_draw(); _draw();
}; },
_filter.colorMatrix.SHADER = {};
_filter.colorMatrix.SHADER.WITH_ALPHA = [
'precision highp float;',
'varying vec2 vUv;',
'uniform sampler2D texture;',
'uniform float m[20];',
'void main(void) {',
'vec4 c = texture2D(texture, vUv);',
'gl_FragColor.r = m[0] * c.r + m[1] * c.g + m[2] * c.b + m[3] * c.a + m[4];',
'gl_FragColor.g = m[5] * c.r + m[6] * c.g + m[7] * c.b + m[8] * c.a + m[9];',
'gl_FragColor.b = m[10] * c.r + m[11] * c.g + m[12] * c.b + m[13] * c.a + m[14];',
'gl_FragColor.a = m[15] * c.r + m[16] * c.g + m[17] * c.b + m[18] * c.a + m[19];',
'}',
].join('\n');
_filter.colorMatrix.SHADER.WITHOUT_ALPHA = [
'precision highp float;',
'varying vec2 vUv;',
'uniform sampler2D texture;',
'uniform float m[20];',
'void main(void) {',
'vec4 c = texture2D(texture, vUv);',
'gl_FragColor.r = m[0] * c.r + m[1] * c.g + m[2] * c.b + m[4];',
'gl_FragColor.g = m[5] * c.r + m[6] * c.g + m[7] * c.b + m[9];',
'gl_FragColor.b = m[10] * c.r + m[11] * c.g + m[12] * c.b + m[14];',
'gl_FragColor.a = c.a;',
'}',
].join('\n');
_filter.brightness = function (brightness) { brightness: (brightness) => {
const b = (brightness || 0) + 1; const b = (brightness || 0) + 1;
_filter.colorMatrix([ _filter.colorMatrix([
b, 0, 0, 0, 0, b, 0, 0, 0, 0,
@ -272,9 +198,9 @@ export function GLImageFilter(params) {
0, 0, b, 0, 0, 0, 0, b, 0, 0,
0, 0, 0, 1, 0, 0, 0, 0, 1, 0,
]); ]);
}; },
_filter.saturation = function (amount) { saturation: (amount) => {
const x = (amount || 0) * 2 / 3 + 1; const x = (amount || 0) * 2 / 3 + 1;
const y = ((x - 1) * -0.5); const y = ((x - 1) * -0.5);
_filter.colorMatrix([ _filter.colorMatrix([
@ -283,256 +209,187 @@ export function GLImageFilter(params) {
y, y, x, 0, 0, y, y, x, 0, 0,
0, 0, 0, 1, 0, 0, 0, 0, 1, 0,
]); ]);
}; },
_filter.desaturate = function () { desaturate: () => {
_filter.saturation(-1); _filter.saturation(-1);
}; },
_filter.contrast = function (amount) { contrast: (amount) => {
const v = (amount || 0) + 1; const v = (amount || 0) + 1;
const o = -128 * (v - 1); const o = -128 * (v - 1);
_filter.colorMatrix([ _filter.colorMatrix([
v, 0, 0, 0, o, v, 0, 0, 0, o,
0, v, 0, 0, o, 0, v, 0, 0, o,
0, 0, v, 0, o, 0, 0, v, 0, o,
0, 0, 0, 1, 0, 0, 0, 0, 1, 0,
]); ]);
}; },
_filter.negative = function () { negative: () => {
_filter.contrast(-2); _filter.contrast(-2);
}; },
_filter.hue = function (rotation) { hue: (rotation) => {
rotation = (rotation || 0) / 180 * Math.PI; rotation = (rotation || 0) / 180 * Math.PI;
const cos = Math.cos(rotation); const cos = Math.cos(rotation);
const sin = Math.sin(rotation); const sin = Math.sin(rotation);
const lumR = 0.213; const lumR = 0.213;
const lumG = 0.715; const lumG = 0.715;
const lumB = 0.072; const lumB = 0.072;
_filter.colorMatrix([ _filter.colorMatrix([
lumR + cos * (1 - lumR) + sin * (-lumR), lumG + cos * (-lumG) + sin * (-lumG), lumB + cos * (-lumB) + sin * (1 - lumB), 0, 0, lumR + cos * (1 - lumR) + sin * (-lumR), lumG + cos * (-lumG) + sin * (-lumG), lumB + cos * (-lumB) + sin * (1 - lumB), 0, 0,
lumR + cos * (-lumR) + sin * (0.143), lumG + cos * (1 - lumG) + sin * (0.140), lumB + cos * (-lumB) + sin * (-0.283), 0, 0, lumR + cos * (-lumR) + sin * (0.143), lumG + cos * (1 - lumG) + sin * (0.140), lumB + cos * (-lumB) + sin * (-0.283), 0, 0,
lumR + cos * (-lumR) + sin * (-(1 - lumR)), lumG + cos * (-lumG) + sin * (lumG), lumB + cos * (1 - lumB) + sin * (lumB), 0, 0, lumR + cos * (-lumR) + sin * (-(1 - lumR)), lumG + cos * (-lumG) + sin * (lumG), lumB + cos * (1 - lumB) + sin * (lumB), 0, 0,
0, 0, 0, 1, 0, 0, 0, 0, 1, 0,
]); ]);
}; },
_filter.desaturateLuminance = function () { desaturateLuminance: () => {
_filter.colorMatrix([ _filter.colorMatrix([
0.2764723, 0.9297080, 0.0938197, 0, -37.1, 0.2764723, 0.9297080, 0.0938197, 0, -37.1,
0.2764723, 0.9297080, 0.0938197, 0, -37.1, 0.2764723, 0.9297080, 0.0938197, 0, -37.1,
0.2764723, 0.9297080, 0.0938197, 0, -37.1, 0.2764723, 0.9297080, 0.0938197, 0, -37.1,
0, 0, 0, 1, 0, 0, 0, 0, 1, 0,
]); ]);
}; },
_filter.sepia = function () { sepia: () => {
_filter.colorMatrix([ _filter.colorMatrix([
0.393, 0.7689999, 0.18899999, 0, 0, 0.393, 0.7689999, 0.18899999, 0, 0,
0.349, 0.6859999, 0.16799999, 0, 0, 0.349, 0.6859999, 0.16799999, 0, 0,
0.272, 0.5339999, 0.13099999, 0, 0, 0.272, 0.5339999, 0.13099999, 0, 0,
0, 0, 0, 1, 0, 0, 0, 0, 1, 0,
]); ]);
}; },
_filter.brownie = function () { brownie: () => {
_filter.colorMatrix([ _filter.colorMatrix([
0.5997023498159715, 0.34553243048391263, -0.2708298674538042, 0, 47.43192855600873, 0.5997023498159715, 0.34553243048391263, -0.2708298674538042, 0, 47.43192855600873,
-0.037703249837783157, 0.8609577587992641, 0.15059552388459913, 0, -36.96841498319127, -0.037703249837783157, 0.8609577587992641, 0.15059552388459913, 0, -36.96841498319127,
0.24113635128153335, -0.07441037908422492, 0.44972182064877153, 0, -7.562075277591283, 0.24113635128153335, -0.07441037908422492, 0.44972182064877153, 0, -7.562075277591283,
0, 0, 0, 1, 0, 0, 0, 0, 1, 0,
]); ]);
}; },
_filter.vintagePinhole = function () { vintagePinhole: () => {
_filter.colorMatrix([ _filter.colorMatrix([
0.6279345635605994, 0.3202183420819367, -0.03965408211312453, 0, 9.651285835294123, 0.6279345635605994, 0.3202183420819367, -0.03965408211312453, 0, 9.651285835294123,
0.02578397704808868, 0.6441188644374771, 0.03259127616149294, 0, 7.462829176470591, 0.02578397704808868, 0.6441188644374771, 0.03259127616149294, 0, 7.462829176470591,
0.0466055556782719, -0.0851232987247891, 0.5241648018700465, 0, 5.159190588235296, 0.0466055556782719, -0.0851232987247891, 0.5241648018700465, 0, 5.159190588235296,
0, 0, 0, 1, 0, 0, 0, 0, 1, 0,
]); ]);
}; },
_filter.kodachrome = function () { kodachrome: () => {
_filter.colorMatrix([ _filter.colorMatrix([
1.1285582396593525, -0.3967382283601348, -0.03992559172921793, 0, 63.72958762196502, 1.1285582396593525, -0.3967382283601348, -0.03992559172921793, 0, 63.72958762196502,
-0.16404339962244616, 1.0835251566291304, -0.05498805115633132, 0, 24.732407896706203, -0.16404339962244616, 1.0835251566291304, -0.05498805115633132, 0, 24.732407896706203,
-0.16786010706155763, -0.5603416277695248, 1.6014850761964943, 0, 35.62982807460946, -0.16786010706155763, -0.5603416277695248, 1.6014850761964943, 0, 35.62982807460946,
0, 0, 0, 1, 0, 0, 0, 0, 1, 0,
]); ]);
}; },
_filter.technicolor = function () { technicolor: () => {
_filter.colorMatrix([ _filter.colorMatrix([
1.9125277891456083, -0.8545344976951645, -0.09155508482755585, 0, 11.793603434377337, 1.9125277891456083, -0.8545344976951645, -0.09155508482755585, 0, 11.793603434377337,
-0.3087833385928097, 1.7658908555458428, -0.10601743074722245, 0, -70.35205161461398, -0.3087833385928097, 1.7658908555458428, -0.10601743074722245, 0, -70.35205161461398,
-0.231103377548616, -0.7501899197440212, 1.847597816108189, 0, 30.950940869491138, -0.231103377548616, -0.7501899197440212, 1.847597816108189, 0, 30.950940869491138,
0, 0, 0, 1, 0, 0, 0, 0, 1, 0,
]); ]);
}; },
_filter.polaroid = function () { polaroid: () => {
_filter.colorMatrix([ _filter.colorMatrix([
1.438, -0.062, -0.062, 0, 0, 1.438, -0.062, -0.062, 0, 0,
-0.122, 1.378, -0.122, 0, 0, -0.122, 1.378, -0.122, 0, 0,
-0.016, -0.016, 1.483, 0, 0, -0.016, -0.016, 1.483, 0, 0,
0, 0, 0, 1, 0, 0, 0, 0, 1, 0,
]); ]);
}; },
_filter.shiftToBGR = function () { shiftToBGR: () => {
_filter.colorMatrix([ _filter.colorMatrix([
0, 0, 1, 0, 0, 0, 0, 1, 0, 0,
0, 1, 0, 0, 0, 0, 1, 0, 0, 0,
1, 0, 0, 0, 0, 1, 0, 0, 0, 0,
0, 0, 0, 1, 0, 0, 0, 0, 1, 0,
]); ]);
}; },
// -------------------------------------------------------------------------
// Convolution Filter // Convolution Filter
_filter.convolution = function (matrix) { convolution: (matrix) => {
const m = new Float32Array(matrix); const m = new Float32Array(matrix);
const pixelSizeX = 1 / _width; const pixelSizeX = 1 / _width;
const pixelSizeY = 1 / _height; const pixelSizeY = 1 / _height;
const program = _compileShader(_filter.convolution.SHADER); const program = _compileShader(shaders.convolution);
gl.uniform1fv(program.uniform.m, m); gl.uniform1fv(program?.uniform['m'], m);
gl.uniform2f(program.uniform.px, pixelSizeX, pixelSizeY); gl.uniform2f(program?.uniform['px'], pixelSizeX, pixelSizeY);
_draw(); _draw();
}; },
_filter.convolution.SHADER = [ detectEdges: () => {
'precision highp float;',
'varying vec2 vUv;',
'uniform sampler2D texture;',
'uniform vec2 px;',
'uniform float m[9];',
'void main(void) {',
'vec4 c11 = texture2D(texture, vUv - px);', // top left
'vec4 c12 = texture2D(texture, vec2(vUv.x, vUv.y - px.y));', // top center
'vec4 c13 = texture2D(texture, vec2(vUv.x + px.x, vUv.y - px.y));', // top right
'vec4 c21 = texture2D(texture, vec2(vUv.x - px.x, vUv.y) );', // mid left
'vec4 c22 = texture2D(texture, vUv);', // mid center
'vec4 c23 = texture2D(texture, vec2(vUv.x + px.x, vUv.y) );', // mid right
'vec4 c31 = texture2D(texture, vec2(vUv.x - px.x, vUv.y + px.y) );', // bottom left
'vec4 c32 = texture2D(texture, vec2(vUv.x, vUv.y + px.y) );', // bottom center
'vec4 c33 = texture2D(texture, vUv + px );', // bottom right
'gl_FragColor = ',
'c11 * m[0] + c12 * m[1] + c22 * m[2] +',
'c21 * m[3] + c22 * m[4] + c23 * m[5] +',
'c31 * m[6] + c32 * m[7] + c33 * m[8];',
'gl_FragColor.a = c22.a;',
'}',
].join('\n');
_filter.detectEdges = function () {
_filter.convolution.call(this, [ _filter.convolution.call(this, [
0, 1, 0, 0, 1, 0,
1, -4, 1, 1, -4, 1,
0, 1, 0, 0, 1, 0,
]); ]);
}; },
_filter.sobelX = function () { sobelX: () => {
_filter.convolution.call(this, [ _filter.convolution.call(this, [
-1, 0, 1, -1, 0, 1,
-2, 0, 2, -2, 0, 2,
-1, 0, 1, -1, 0, 1,
]); ]);
}; },
_filter.sobelY = function () { sobelY: () => {
_filter.convolution.call(this, [ _filter.convolution.call(this, [
-1, -2, -1, -1, -2, -1,
0, 0, 0, 0, 0, 0,
1, 2, 1, 1, 2, 1,
]); ]);
}; },
_filter.sharpen = function (amount) { sharpen: (amount) => {
const a = amount || 1; const a = amount || 1;
_filter.convolution.call(this, [ _filter.convolution.call(this, [
0, -1 * a, 0, 0, -1 * a, 0,
-1 * a, 1 + 4 * a, -1 * a, -1 * a, 1 + 4 * a, -1 * a,
0, -1 * a, 0, 0, -1 * a, 0,
]); ]);
}; },
_filter.emboss = function (size) { emboss: (size) => {
const s = size || 1; const s = size || 1;
_filter.convolution.call(this, [ _filter.convolution.call(this, [
-2 * s, -1 * s, 0, -2 * s, -1 * s, 0,
-1 * s, 1, 1 * s, -1 * s, 1, 1 * s,
0, 1 * s, 2 * s, 0, 1 * s, 2 * s,
]); ]);
}; },
// -------------------------------------------------------------------------
// Blur Filter // Blur Filter
_filter.blur = function (size) { blur: (size) => {
const blurSizeX = (size / 7) / _width; const blurSizeX = (size / 7) / _width;
const blurSizeY = (size / 7) / _height; const blurSizeY = (size / 7) / _height;
const program = _compileShader(_filter.blur.SHADER); const program = _compileShader(shaders.blur);
// Vertical // Vertical
gl.uniform2f(program.uniform.px, 0, blurSizeY); gl.uniform2f(program?.uniform['px'], 0, blurSizeY);
_draw(DRAW.INTERMEDIATE); _draw(DRAW.INTERMEDIATE);
// Horizontal // Horizontal
gl.uniform2f(program.uniform.px, blurSizeX, 0); gl.uniform2f(program?.uniform['px'], blurSizeX, 0);
_draw(); _draw();
}; },
_filter.blur.SHADER = [
'precision highp float;',
'varying vec2 vUv;',
'uniform sampler2D texture;',
'uniform vec2 px;',
'void main(void) {',
'gl_FragColor = vec4(0.0);',
'gl_FragColor += texture2D(texture, vUv + vec2(-7.0*px.x, -7.0*px.y))*0.0044299121055113265;',
'gl_FragColor += texture2D(texture, vUv + vec2(-6.0*px.x, -6.0*px.y))*0.00895781211794;',
'gl_FragColor += texture2D(texture, vUv + vec2(-5.0*px.x, -5.0*px.y))*0.0215963866053;',
'gl_FragColor += texture2D(texture, vUv + vec2(-4.0*px.x, -4.0*px.y))*0.0443683338718;',
'gl_FragColor += texture2D(texture, vUv + vec2(-3.0*px.x, -3.0*px.y))*0.0776744219933;',
'gl_FragColor += texture2D(texture, vUv + vec2(-2.0*px.x, -2.0*px.y))*0.115876621105;',
'gl_FragColor += texture2D(texture, vUv + vec2(-1.0*px.x, -1.0*px.y))*0.147308056121;',
'gl_FragColor += texture2D(texture, vUv )*0.159576912161;',
'gl_FragColor += texture2D(texture, vUv + vec2( 1.0*px.x, 1.0*px.y))*0.147308056121;',
'gl_FragColor += texture2D(texture, vUv + vec2( 2.0*px.x, 2.0*px.y))*0.115876621105;',
'gl_FragColor += texture2D(texture, vUv + vec2( 3.0*px.x, 3.0*px.y))*0.0776744219933;',
'gl_FragColor += texture2D(texture, vUv + vec2( 4.0*px.x, 4.0*px.y))*0.0443683338718;',
'gl_FragColor += texture2D(texture, vUv + vec2( 5.0*px.x, 5.0*px.y))*0.0215963866053;',
'gl_FragColor += texture2D(texture, vUv + vec2( 6.0*px.x, 6.0*px.y))*0.00895781211794;',
'gl_FragColor += texture2D(texture, vUv + vec2( 7.0*px.x, 7.0*px.y))*0.0044299121055113265;',
'}',
].join('\n');
// -------------------------------------------------------------------------
// Pixelate Filter // Pixelate Filter
_filter.pixelate = function (size) { pixelate: (size) => {
const blurSizeX = (size) / _width; const blurSizeX = (size) / _width;
const blurSizeY = (size) / _height; const blurSizeY = (size) / _height;
const program = _compileShader(_filter.pixelate.SHADER); const program = _compileShader(shaders.pixelate);
// Horizontal gl.uniform2f(program?.uniform['size'], blurSizeX, blurSizeY);
gl.uniform2f(program.uniform.size, blurSizeX, blurSizeY);
_draw(); _draw();
},
}; };
_filter.pixelate.SHADER = [
'precision highp float;',
'varying vec2 vUv;',
'uniform vec2 size;',
'uniform sampler2D texture;',
'vec2 pixelate(vec2 coord, vec2 size) {',
'return floor( coord / size ) * size;',
'}',
'void main(void) {',
'gl_FragColor = vec4(0.0);',
'vec2 coord = pixelate(vUv, size);',
'gl_FragColor += texture2D(texture, coord);',
'}',
].join('\n');
} }

112
src/image/imagefxshaders.ts Normal file
View File

@ -0,0 +1,112 @@
export const vertexIdentity = `
precision highp float;
attribute vec2 pos;
attribute vec2 uv;
varying vec2 vUv;
uniform float flipY;
void main(void) {
vUv = uv;
gl_Position = vec4(pos.x, pos.y*flipY, 0.0, 1.);
}
`;
export const fragmentIdentity = `
precision highp float;
varying vec2 vUv;
uniform sampler2D texture;
void main(void) {
gl_FragColor = texture2D(texture, vUv);
}
`;
export const colorMatrixWithAlpha = `
precision highp float;
varying vec2 vUv;
uniform sampler2D texture;
uniform float m[20];
void main(void) {
vec4 c = texture2D(texture, vUv);
gl_FragColor.r = m[0] * c.r + m[1] * c.g + m[2] * c.b + m[3] * c.a + m[4];
gl_FragColor.g = m[5] * c.r + m[6] * c.g + m[7] * c.b + m[8] * c.a + m[9];
gl_FragColor.b = m[10] * c.r + m[11] * c.g + m[12] * c.b + m[13] * c.a + m[14];
gl_FragColor.a = m[15] * c.r + m[16] * c.g + m[17] * c.b + m[18] * c.a + m[19];
}
`;
export const colorMatrixWithoutAlpha = `
precision highp float;
varying vec2 vUv;
uniform sampler2D texture;
uniform float m[20];
void main(void) {
vec4 c = texture2D(texture, vUv);
gl_FragColor.r = m[0] * c.r + m[1] * c.g + m[2] * c.b + m[4];
gl_FragColor.g = m[5] * c.r + m[6] * c.g + m[7] * c.b + m[9];
gl_FragColor.b = m[10] * c.r + m[11] * c.g + m[12] * c.b + m[14];
gl_FragColor.a = c.a;
}
`;
export const pixelate = `
precision highp float;
varying vec2 vUv;
uniform vec2 size;
uniform sampler2D texture;
vec2 pixelate(vec2 coord, vec2 size) {
return floor( coord / size ) * size;
}
void main(void) {
gl_FragColor = vec4(0.0);
vec2 coord = pixelate(vUv, size);
gl_FragColor += texture2D(texture, coord);
}
`;
export const blur = `
precision highp float;
varying vec2 vUv;
uniform sampler2D texture;
uniform vec2 px;
void main(void) {
gl_FragColor = vec4(0.0);
gl_FragColor += texture2D(texture, vUv + vec2(-7.0*px.x, -7.0*px.y))*0.0044299121055113265;
gl_FragColor += texture2D(texture, vUv + vec2(-6.0*px.x, -6.0*px.y))*0.00895781211794;
gl_FragColor += texture2D(texture, vUv + vec2(-5.0*px.x, -5.0*px.y))*0.0215963866053;
gl_FragColor += texture2D(texture, vUv + vec2(-4.0*px.x, -4.0*px.y))*0.0443683338718;
gl_FragColor += texture2D(texture, vUv + vec2(-3.0*px.x, -3.0*px.y))*0.0776744219933;
gl_FragColor += texture2D(texture, vUv + vec2(-2.0*px.x, -2.0*px.y))*0.115876621105;
gl_FragColor += texture2D(texture, vUv + vec2(-1.0*px.x, -1.0*px.y))*0.147308056121;
gl_FragColor += texture2D(texture, vUv )*0.159576912161;
gl_FragColor += texture2D(texture, vUv + vec2( 1.0*px.x, 1.0*px.y))*0.147308056121;
gl_FragColor += texture2D(texture, vUv + vec2( 2.0*px.x, 2.0*px.y))*0.115876621105;
gl_FragColor += texture2D(texture, vUv + vec2( 3.0*px.x, 3.0*px.y))*0.0776744219933;
gl_FragColor += texture2D(texture, vUv + vec2( 4.0*px.x, 4.0*px.y))*0.0443683338718;
gl_FragColor += texture2D(texture, vUv + vec2( 5.0*px.x, 5.0*px.y))*0.0215963866053;
gl_FragColor += texture2D(texture, vUv + vec2( 6.0*px.x, 6.0*px.y))*0.00895781211794;
gl_FragColor += texture2D(texture, vUv + vec2( 7.0*px.x, 7.0*px.y))*0.0044299121055113265;
}
`;
export const convolution = `
precision highp float;
varying vec2 vUv;
uniform sampler2D texture;
uniform vec2 px;
uniform float m[9];
void main(void) {
vec4 c11 = texture2D(texture, vUv - px); // top left
vec4 c12 = texture2D(texture, vec2(vUv.x, vUv.y - px.y)); // top center
vec4 c13 = texture2D(texture, vec2(vUv.x + px.x, vUv.y - px.y)); // top right
vec4 c21 = texture2D(texture, vec2(vUv.x - px.x, vUv.y) ); // mid left
vec4 c22 = texture2D(texture, vUv); // mid center
vec4 c23 = texture2D(texture, vec2(vUv.x + px.x, vUv.y) ); // mid right
vec4 c31 = texture2D(texture, vec2(vUv.x - px.x, vUv.y + px.y) ); // bottom left
vec4 c32 = texture2D(texture, vec2(vUv.x, vUv.y + px.y) ); // bottom center
vec4 c33 = texture2D(texture, vUv + px ); // bottom right
gl_FragColor =
c11 * m[0] + c12 * m[1] + c22 * m[2] +
c21 * m[3] + c22 * m[4] + c23 * m[5] +
c31 * m[6] + c32 * m[7] + c33 * m[8];
gl_FragColor.a = c22.a;
}
`;

File diff suppressed because it is too large Load Diff