mirror of https://github.com/vladmandic/human
optimize image preprocessing
parent
c7dbca2856
commit
750c10b309
|
@ -31,9 +31,9 @@ import jsonView from './helpers/jsonview.js';
|
|||
let human;
|
||||
|
||||
let userConfig = {
|
||||
face: { enabled: false },
|
||||
body: { enabled: false },
|
||||
hand: { enabled: false },
|
||||
// face: { enabled: false },
|
||||
// body: { enabled: false },
|
||||
// hand: { enabled: false },
|
||||
/*
|
||||
warmup: 'none',
|
||||
backend: 'humangl',
|
||||
|
@ -41,10 +41,7 @@ let userConfig = {
|
|||
wasmPath: 'https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-backend-wasm@3.9.0/dist/',
|
||||
async: false,
|
||||
cacheSensitivity: 0.75,
|
||||
filter: {
|
||||
enabled: false,
|
||||
flip: false,
|
||||
},
|
||||
filter: { enabled: false, flip: false },
|
||||
face: { enabled: false,
|
||||
detector: { return: false, rotation: true },
|
||||
mesh: { enabled: false },
|
||||
|
@ -54,11 +51,9 @@ let userConfig = {
|
|||
},
|
||||
object: { enabled: false },
|
||||
gesture: { enabled: true },
|
||||
// hand: { enabled: false },
|
||||
hand: { enabled: true, maxDetected: 1, minConfidence: 0.5, detector: { modelPath: 'handtrack.json' } },
|
||||
body: { enabled: false },
|
||||
// body: { enabled: true, modelPath: 'movenet-multipose.json' },
|
||||
// body: { enabled: true, modelPath: 'posenet.json' },
|
||||
segmentation: { enabled: false },
|
||||
*/
|
||||
};
|
||||
|
@ -94,7 +89,7 @@ const ui = {
|
|||
autoPlay: false, // start webcam & detection on load
|
||||
|
||||
// internal variables
|
||||
exceptionHandler: false, // should capture all unhandled exceptions
|
||||
exceptionHandler: true, // should capture all unhandled exceptions
|
||||
busy: false, // internal camera busy flag
|
||||
menuWidth: 0, // internal
|
||||
menuHeight: 0, // internal
|
||||
|
|
|
@ -363,11 +363,11 @@ var GLProgram = class {
|
|||
return shader;
|
||||
});
|
||||
this.gl = gl;
|
||||
const _vsh = this.compile(vertexSource, this.gl.VERTEX_SHADER);
|
||||
const _fsh = this.compile(fragmentSource, this.gl.FRAGMENT_SHADER);
|
||||
const vertexShader = this.compile(vertexSource, this.gl.VERTEX_SHADER);
|
||||
const fragmentShader = this.compile(fragmentSource, this.gl.FRAGMENT_SHADER);
|
||||
this.id = this.gl.createProgram();
|
||||
this.gl.attachShader(this.id, _vsh);
|
||||
this.gl.attachShader(this.id, _fsh);
|
||||
this.gl.attachShader(this.id, vertexShader);
|
||||
this.gl.attachShader(this.id, fragmentShader);
|
||||
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)}`);
|
||||
|
@ -381,50 +381,37 @@ var GLProgram = class {
|
|||
this.uniform[u] = this.gl.getUniformLocation(this.id, u);
|
||||
}
|
||||
};
|
||||
function GLImageFilter(params) {
|
||||
if (!params)
|
||||
params = {};
|
||||
let _drawCount = 0;
|
||||
let _sourceTexture = null;
|
||||
let _lastInChain = false;
|
||||
let _currentFramebufferIndex = -1;
|
||||
let _tempFramebuffers = [null, null];
|
||||
let _filterChain = [];
|
||||
let _width = -1;
|
||||
let _height = -1;
|
||||
let _vertexBuffer = null;
|
||||
let _currentProgram = null;
|
||||
const _canvas = params.canvas || typeof OffscreenCanvas !== "undefined" ? new OffscreenCanvas(100, 100) : document.createElement("canvas");
|
||||
const _shaderProgramCache = {};
|
||||
function GLImageFilter(params = {}) {
|
||||
let drawCount = 0;
|
||||
let sourceTexture = null;
|
||||
let lastInChain = false;
|
||||
let currentFramebufferIndex = -1;
|
||||
let tempFramebuffers = [null, null];
|
||||
let filterChain = [];
|
||||
let vertexBuffer = null;
|
||||
let currentProgram = null;
|
||||
const canvas3 = params["canvas"] || typeof OffscreenCanvas !== "undefined" ? new OffscreenCanvas(100, 100) : document.createElement("canvas");
|
||||
const shaderProgramCache = {};
|
||||
const DRAW = { INTERMEDIATE: 1 };
|
||||
const gl = _canvas.getContext("webgl");
|
||||
const gl = canvas3.getContext("webgl");
|
||||
if (!gl)
|
||||
throw new Error("filter: cannot get webgl context");
|
||||
this.addFilter = function(name) {
|
||||
const args = Array.prototype.slice.call(arguments, 1);
|
||||
const filter = _filter[name];
|
||||
_filterChain.push({ func: filter, args });
|
||||
};
|
||||
this.reset = function() {
|
||||
_filterChain = [];
|
||||
};
|
||||
const _resize = function(width, height) {
|
||||
if (width === _width && height === _height)
|
||||
function resize(width, height) {
|
||||
if (width === canvas3.width && height === canvas3.height)
|
||||
return;
|
||||
_canvas.width = width;
|
||||
_width = width;
|
||||
_canvas.height = height;
|
||||
_height = height;
|
||||
if (!_vertexBuffer) {
|
||||
canvas3.width = width;
|
||||
canvas3.height = height;
|
||||
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]);
|
||||
_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.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
|
||||
}
|
||||
gl.viewport(0, 0, _width, _height);
|
||||
_tempFramebuffers = [null, null];
|
||||
};
|
||||
const _createFramebufferTexture = function(width, height) {
|
||||
gl.viewport(0, 0, canvas3.width, canvas3.height);
|
||||
tempFramebuffers = [null, null];
|
||||
}
|
||||
function createFramebufferTexture(width, height) {
|
||||
const fbo = gl.createFramebuffer();
|
||||
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
|
||||
const renderbuffer = gl.createRenderbuffer();
|
||||
|
@ -440,74 +427,52 @@ function GLImageFilter(params) {
|
|||
gl.bindTexture(gl.TEXTURE_2D, null);
|
||||
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
||||
return { fbo, texture };
|
||||
};
|
||||
const _getTempFramebuffer = function(index) {
|
||||
_tempFramebuffers[index] = _tempFramebuffers[index] || _createFramebufferTexture(_width, _height);
|
||||
return _tempFramebuffers[index];
|
||||
};
|
||||
const _draw = function(flags = 0) {
|
||||
}
|
||||
function getTempFramebuffer(index) {
|
||||
tempFramebuffers[index] = tempFramebuffers[index] || createFramebufferTexture(canvas3.width, canvas3.height);
|
||||
return tempFramebuffers[index];
|
||||
}
|
||||
function draw2(flags = 0) {
|
||||
var _a, _b;
|
||||
if (!_currentProgram)
|
||||
if (!currentProgram)
|
||||
return;
|
||||
let source = null;
|
||||
let target = null;
|
||||
let flipY = false;
|
||||
if (_drawCount === 0)
|
||||
source = _sourceTexture;
|
||||
if (drawCount === 0)
|
||||
source = sourceTexture;
|
||||
else
|
||||
source = (_a = _getTempFramebuffer(_currentFramebufferIndex)) == null ? void 0 : _a.texture;
|
||||
_drawCount++;
|
||||
if (_lastInChain && !(flags & DRAW.INTERMEDIATE)) {
|
||||
source = ((_a = getTempFramebuffer(currentFramebufferIndex)) == null ? void 0 : _a.texture) || null;
|
||||
drawCount++;
|
||||
if (lastInChain && !(flags & DRAW.INTERMEDIATE)) {
|
||||
target = null;
|
||||
flipY = _drawCount % 2 === 0;
|
||||
flipY = drawCount % 2 === 0;
|
||||
} else {
|
||||
_currentFramebufferIndex = (_currentFramebufferIndex + 1) % 2;
|
||||
target = (_b = _getTempFramebuffer(_currentFramebufferIndex)) == null ? void 0 : _b.fbo;
|
||||
currentFramebufferIndex = (currentFramebufferIndex + 1) % 2;
|
||||
target = ((_b = getTempFramebuffer(currentFramebufferIndex)) == null ? void 0 : _b.fbo) || null;
|
||||
}
|
||||
gl.bindTexture(gl.TEXTURE_2D, source);
|
||||
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);
|
||||
};
|
||||
this.apply = function(image24) {
|
||||
_resize(image24.width, image24.height);
|
||||
_drawCount = 0;
|
||||
if (!_sourceTexture)
|
||||
_sourceTexture = gl.createTexture();
|
||||
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_T, gl.CLAMP_TO_EDGE);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_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, image24);
|
||||
if (_filterChain.length === 0) {
|
||||
_draw();
|
||||
} else {
|
||||
for (let i = 0; i < _filterChain.length; i++) {
|
||||
_lastInChain = i === _filterChain.length - 1;
|
||||
const f = _filterChain[i];
|
||||
f.func.apply(this, f.args || []);
|
||||
}
|
||||
}
|
||||
function compileShader(fragmentSource) {
|
||||
if (shaderProgramCache[fragmentSource]) {
|
||||
currentProgram = shaderProgramCache[fragmentSource];
|
||||
gl.useProgram((currentProgram == null ? void 0 : currentProgram.id) || null);
|
||||
return currentProgram;
|
||||
}
|
||||
return _canvas;
|
||||
};
|
||||
const _compileShader = function(fragmentSource) {
|
||||
if (_shaderProgramCache[fragmentSource]) {
|
||||
_currentProgram = _shaderProgramCache[fragmentSource];
|
||||
gl.useProgram(_currentProgram == null ? void 0 : _currentProgram.id);
|
||||
return _currentProgram;
|
||||
}
|
||||
_currentProgram = new GLProgram(gl, vertexIdentity, fragmentSource);
|
||||
currentProgram = new GLProgram(gl, vertexIdentity, fragmentSource);
|
||||
const floatSize = Float32Array.BYTES_PER_ELEMENT;
|
||||
const vertSize = 4 * floatSize;
|
||||
gl.enableVertexAttribArray(_currentProgram.attribute["pos"]);
|
||||
gl.vertexAttribPointer(_currentProgram.attribute["pos"], 2, gl.FLOAT, false, vertSize, 0 * floatSize);
|
||||
gl.enableVertexAttribArray(_currentProgram.attribute.uv);
|
||||
gl.vertexAttribPointer(_currentProgram.attribute["uv"], 2, gl.FLOAT, false, vertSize, 2 * floatSize);
|
||||
_shaderProgramCache[fragmentSource] = _currentProgram;
|
||||
return _currentProgram;
|
||||
};
|
||||
const _filter = {
|
||||
gl.enableVertexAttribArray(currentProgram.attribute["pos"]);
|
||||
gl.vertexAttribPointer(currentProgram.attribute["pos"], 2, gl.FLOAT, false, vertSize, 0 * floatSize);
|
||||
gl.enableVertexAttribArray(currentProgram.attribute["uv"]);
|
||||
gl.vertexAttribPointer(currentProgram.attribute["uv"], 2, gl.FLOAT, false, vertSize, 2 * floatSize);
|
||||
shaderProgramCache[fragmentSource] = currentProgram;
|
||||
return currentProgram;
|
||||
}
|
||||
const filter = {
|
||||
colorMatrix: (matrix) => {
|
||||
const m = new Float32Array(matrix);
|
||||
m[4] /= 255;
|
||||
|
@ -515,13 +480,13 @@ function GLImageFilter(params) {
|
|||
m[14] /= 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 ? colorMatrixWithoutAlpha : colorMatrixWithAlpha;
|
||||
const program = _compileShader(shader);
|
||||
const program = compileShader(shader);
|
||||
gl.uniform1fv(program == null ? void 0 : program.uniform["m"], m);
|
||||
_draw();
|
||||
draw2();
|
||||
},
|
||||
brightness: (brightness) => {
|
||||
const b = (brightness || 0) + 1;
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
b,
|
||||
0,
|
||||
0,
|
||||
|
@ -547,7 +512,7 @@ function GLImageFilter(params) {
|
|||
saturation: (amount) => {
|
||||
const x = (amount || 0) * 2 / 3 + 1;
|
||||
const y = (x - 1) * -0.5;
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
x,
|
||||
y,
|
||||
y,
|
||||
|
@ -571,12 +536,12 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
desaturate: () => {
|
||||
_filter.saturation(-1);
|
||||
filter.saturation(-1);
|
||||
},
|
||||
contrast: (amount) => {
|
||||
const v = (amount || 0) + 1;
|
||||
const o = -128 * (v - 1);
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
v,
|
||||
0,
|
||||
0,
|
||||
|
@ -600,7 +565,7 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
negative: () => {
|
||||
_filter.contrast(-2);
|
||||
filter.contrast(-2);
|
||||
},
|
||||
hue: (rotation) => {
|
||||
rotation = (rotation || 0) / 180 * Math.PI;
|
||||
|
@ -609,7 +574,7 @@ function GLImageFilter(params) {
|
|||
const lumR = 0.213;
|
||||
const lumG = 0.715;
|
||||
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),
|
||||
|
@ -633,7 +598,7 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
desaturateLuminance: () => {
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
0.2764723,
|
||||
0.929708,
|
||||
0.0938197,
|
||||
|
@ -657,7 +622,7 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
sepia: () => {
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
0.393,
|
||||
0.7689999,
|
||||
0.18899999,
|
||||
|
@ -681,7 +646,7 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
brownie: () => {
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
0.5997023498159715,
|
||||
0.34553243048391263,
|
||||
-0.2708298674538042,
|
||||
|
@ -705,7 +670,7 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
vintagePinhole: () => {
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
0.6279345635605994,
|
||||
0.3202183420819367,
|
||||
-0.03965408211312453,
|
||||
|
@ -729,7 +694,7 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
kodachrome: () => {
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
1.1285582396593525,
|
||||
-0.3967382283601348,
|
||||
-0.03992559172921793,
|
||||
|
@ -753,7 +718,7 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
technicolor: () => {
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
1.9125277891456083,
|
||||
-0.8545344976951645,
|
||||
-0.09155508482755585,
|
||||
|
@ -777,7 +742,7 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
polaroid: () => {
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
1.438,
|
||||
-0.062,
|
||||
-0.062,
|
||||
|
@ -801,7 +766,7 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
shiftToBGR: () => {
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
|
@ -826,15 +791,15 @@ function GLImageFilter(params) {
|
|||
},
|
||||
convolution: (matrix) => {
|
||||
const m = new Float32Array(matrix);
|
||||
const pixelSizeX = 1 / _width;
|
||||
const pixelSizeY = 1 / _height;
|
||||
const program = _compileShader(convolution);
|
||||
const pixelSizeX = 1 / canvas3.width;
|
||||
const pixelSizeY = 1 / canvas3.height;
|
||||
const program = compileShader(convolution);
|
||||
gl.uniform1fv(program == null ? void 0 : program.uniform["m"], m);
|
||||
gl.uniform2f(program == null ? void 0 : program.uniform["px"], pixelSizeX, pixelSizeY);
|
||||
_draw();
|
||||
draw2();
|
||||
},
|
||||
detectEdges: () => {
|
||||
_filter.convolution.call(this, [
|
||||
filter.convolution.call(this, [
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
|
@ -847,7 +812,7 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
sobelX: () => {
|
||||
_filter.convolution.call(this, [
|
||||
filter.convolution.call(this, [
|
||||
-1,
|
||||
0,
|
||||
1,
|
||||
|
@ -860,7 +825,7 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
sobelY: () => {
|
||||
_filter.convolution.call(this, [
|
||||
filter.convolution.call(this, [
|
||||
-1,
|
||||
-2,
|
||||
-1,
|
||||
|
@ -874,7 +839,7 @@ function GLImageFilter(params) {
|
|||
},
|
||||
sharpen: (amount) => {
|
||||
const a = amount || 1;
|
||||
_filter.convolution.call(this, [
|
||||
filter.convolution.call(this, [
|
||||
0,
|
||||
-1 * a,
|
||||
0,
|
||||
|
@ -888,7 +853,7 @@ function GLImageFilter(params) {
|
|||
},
|
||||
emboss: (size2) => {
|
||||
const s = size2 || 1;
|
||||
_filter.convolution.call(this, [
|
||||
filter.convolution.call(this, [
|
||||
-2 * s,
|
||||
-1 * s,
|
||||
0,
|
||||
|
@ -901,22 +866,55 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
blur: (size2) => {
|
||||
const blurSizeX = size2 / 7 / _width;
|
||||
const blurSizeY = size2 / 7 / _height;
|
||||
const program = _compileShader(blur);
|
||||
const blurSizeX = size2 / 7 / canvas3.width;
|
||||
const blurSizeY = size2 / 7 / canvas3.height;
|
||||
const program = compileShader(blur);
|
||||
gl.uniform2f(program == null ? void 0 : program.uniform["px"], 0, blurSizeY);
|
||||
_draw(DRAW.INTERMEDIATE);
|
||||
draw2(DRAW.INTERMEDIATE);
|
||||
gl.uniform2f(program == null ? void 0 : program.uniform["px"], blurSizeX, 0);
|
||||
_draw();
|
||||
draw2();
|
||||
},
|
||||
pixelate: (size2) => {
|
||||
const blurSizeX = size2 / _width;
|
||||
const blurSizeY = size2 / _height;
|
||||
const program = _compileShader(pixelate);
|
||||
const blurSizeX = size2 / canvas3.width;
|
||||
const blurSizeY = size2 / canvas3.height;
|
||||
const program = compileShader(pixelate);
|
||||
gl.uniform2f(program == null ? void 0 : program.uniform["size"], blurSizeX, blurSizeY);
|
||||
_draw();
|
||||
draw2();
|
||||
}
|
||||
};
|
||||
this.add = function(name) {
|
||||
const args = Array.prototype.slice.call(arguments, 1);
|
||||
const func = filter[name];
|
||||
filterChain.push({ func, args });
|
||||
};
|
||||
this.reset = function() {
|
||||
filterChain = [];
|
||||
};
|
||||
this.get = function() {
|
||||
return filterChain;
|
||||
};
|
||||
this.apply = function(image24) {
|
||||
resize(image24.width, image24.height);
|
||||
drawCount = 0;
|
||||
if (!sourceTexture)
|
||||
sourceTexture = gl.createTexture();
|
||||
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_T, gl.CLAMP_TO_EDGE);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_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, image24);
|
||||
for (let i = 0; i < filterChain.length; i++) {
|
||||
lastInChain = i === filterChain.length - 1;
|
||||
const f = filterChain[i];
|
||||
f.func.apply(this, f.args || []);
|
||||
}
|
||||
return canvas3;
|
||||
};
|
||||
this.draw = function(image24) {
|
||||
this.add("brightness", 0);
|
||||
return this.apply(image24);
|
||||
};
|
||||
}
|
||||
|
||||
// src/util/env.ts
|
||||
|
@ -1113,34 +1111,38 @@ function process2(input, config3, getTensor = true) {
|
|||
if (!fx)
|
||||
return { tensor: null, canvas: inCanvas };
|
||||
fx.reset();
|
||||
fx.addFilter("brightness", config3.filter.brightness);
|
||||
if (config3.filter.brightness !== 0)
|
||||
fx.add("brightness", config3.filter.brightness);
|
||||
if (config3.filter.contrast !== 0)
|
||||
fx.addFilter("contrast", config3.filter.contrast);
|
||||
fx.add("contrast", config3.filter.contrast);
|
||||
if (config3.filter.sharpness !== 0)
|
||||
fx.addFilter("sharpen", config3.filter.sharpness);
|
||||
fx.add("sharpen", config3.filter.sharpness);
|
||||
if (config3.filter.blur !== 0)
|
||||
fx.addFilter("blur", config3.filter.blur);
|
||||
fx.add("blur", config3.filter.blur);
|
||||
if (config3.filter.saturation !== 0)
|
||||
fx.addFilter("saturation", config3.filter.saturation);
|
||||
fx.add("saturation", config3.filter.saturation);
|
||||
if (config3.filter.hue !== 0)
|
||||
fx.addFilter("hue", config3.filter.hue);
|
||||
fx.add("hue", config3.filter.hue);
|
||||
if (config3.filter.negative)
|
||||
fx.addFilter("negative");
|
||||
fx.add("negative");
|
||||
if (config3.filter.sepia)
|
||||
fx.addFilter("sepia");
|
||||
fx.add("sepia");
|
||||
if (config3.filter.vintage)
|
||||
fx.addFilter("brownie");
|
||||
fx.add("brownie");
|
||||
if (config3.filter.sepia)
|
||||
fx.addFilter("sepia");
|
||||
fx.add("sepia");
|
||||
if (config3.filter.kodachrome)
|
||||
fx.addFilter("kodachrome");
|
||||
fx.add("kodachrome");
|
||||
if (config3.filter.technicolor)
|
||||
fx.addFilter("technicolor");
|
||||
fx.add("technicolor");
|
||||
if (config3.filter.polaroid)
|
||||
fx.addFilter("polaroid");
|
||||
fx.add("polaroid");
|
||||
if (config3.filter.pixelate !== 0)
|
||||
fx.addFilter("pixelate", config3.filter.pixelate);
|
||||
outCanvas = fx.apply(inCanvas);
|
||||
fx.add("pixelate", config3.filter.pixelate);
|
||||
if (fx.get() > 0)
|
||||
outCanvas = fx.apply(inCanvas);
|
||||
else
|
||||
outCanvas = fx.draw(inCanvas);
|
||||
} else {
|
||||
copy(inCanvas, outCanvas);
|
||||
if (fx)
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -67852,11 +67852,11 @@ var GLProgram = class {
|
|||
return shader;
|
||||
});
|
||||
this.gl = gl;
|
||||
const _vsh = this.compile(vertexSource, this.gl.VERTEX_SHADER);
|
||||
const _fsh = this.compile(fragmentSource, this.gl.FRAGMENT_SHADER);
|
||||
const vertexShader = this.compile(vertexSource, this.gl.VERTEX_SHADER);
|
||||
const fragmentShader = this.compile(fragmentSource, this.gl.FRAGMENT_SHADER);
|
||||
this.id = this.gl.createProgram();
|
||||
this.gl.attachShader(this.id, _vsh);
|
||||
this.gl.attachShader(this.id, _fsh);
|
||||
this.gl.attachShader(this.id, vertexShader);
|
||||
this.gl.attachShader(this.id, fragmentShader);
|
||||
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)}`);
|
||||
|
@ -67870,50 +67870,37 @@ var GLProgram = class {
|
|||
this.uniform[u] = this.gl.getUniformLocation(this.id, u);
|
||||
}
|
||||
};
|
||||
function GLImageFilter(params) {
|
||||
if (!params)
|
||||
params = {};
|
||||
let _drawCount = 0;
|
||||
let _sourceTexture = null;
|
||||
let _lastInChain = false;
|
||||
let _currentFramebufferIndex = -1;
|
||||
let _tempFramebuffers = [null, null];
|
||||
let _filterChain = [];
|
||||
let _width = -1;
|
||||
let _height = -1;
|
||||
let _vertexBuffer = null;
|
||||
let _currentProgram = null;
|
||||
const _canvas = params.canvas || typeof OffscreenCanvas !== "undefined" ? new OffscreenCanvas(100, 100) : document.createElement("canvas");
|
||||
const _shaderProgramCache = {};
|
||||
function GLImageFilter(params = {}) {
|
||||
let drawCount = 0;
|
||||
let sourceTexture = null;
|
||||
let lastInChain = false;
|
||||
let currentFramebufferIndex = -1;
|
||||
let tempFramebuffers = [null, null];
|
||||
let filterChain = [];
|
||||
let vertexBuffer = null;
|
||||
let currentProgram = null;
|
||||
const canvas3 = params["canvas"] || typeof OffscreenCanvas !== "undefined" ? new OffscreenCanvas(100, 100) : document.createElement("canvas");
|
||||
const shaderProgramCache = {};
|
||||
const DRAW = { INTERMEDIATE: 1 };
|
||||
const gl = _canvas.getContext("webgl");
|
||||
const gl = canvas3.getContext("webgl");
|
||||
if (!gl)
|
||||
throw new Error("filter: cannot get webgl context");
|
||||
this.addFilter = function(name) {
|
||||
const args = Array.prototype.slice.call(arguments, 1);
|
||||
const filter = _filter[name];
|
||||
_filterChain.push({ func: filter, args });
|
||||
};
|
||||
this.reset = function() {
|
||||
_filterChain = [];
|
||||
};
|
||||
const _resize = function(width, height) {
|
||||
if (width === _width && height === _height)
|
||||
function resize(width, height) {
|
||||
if (width === canvas3.width && height === canvas3.height)
|
||||
return;
|
||||
_canvas.width = width;
|
||||
_width = width;
|
||||
_canvas.height = height;
|
||||
_height = height;
|
||||
if (!_vertexBuffer) {
|
||||
canvas3.width = width;
|
||||
canvas3.height = height;
|
||||
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]);
|
||||
_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.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
|
||||
}
|
||||
gl.viewport(0, 0, _width, _height);
|
||||
_tempFramebuffers = [null, null];
|
||||
};
|
||||
const _createFramebufferTexture = function(width, height) {
|
||||
gl.viewport(0, 0, canvas3.width, canvas3.height);
|
||||
tempFramebuffers = [null, null];
|
||||
}
|
||||
function createFramebufferTexture(width, height) {
|
||||
const fbo = gl.createFramebuffer();
|
||||
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
|
||||
const renderbuffer = gl.createRenderbuffer();
|
||||
|
@ -67929,74 +67916,52 @@ function GLImageFilter(params) {
|
|||
gl.bindTexture(gl.TEXTURE_2D, null);
|
||||
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
||||
return { fbo, texture };
|
||||
};
|
||||
const _getTempFramebuffer = function(index) {
|
||||
_tempFramebuffers[index] = _tempFramebuffers[index] || _createFramebufferTexture(_width, _height);
|
||||
return _tempFramebuffers[index];
|
||||
};
|
||||
const _draw = function(flags = 0) {
|
||||
}
|
||||
function getTempFramebuffer(index) {
|
||||
tempFramebuffers[index] = tempFramebuffers[index] || createFramebufferTexture(canvas3.width, canvas3.height);
|
||||
return tempFramebuffers[index];
|
||||
}
|
||||
function draw2(flags = 0) {
|
||||
var _a, _b;
|
||||
if (!_currentProgram)
|
||||
if (!currentProgram)
|
||||
return;
|
||||
let source = null;
|
||||
let target = null;
|
||||
let flipY = false;
|
||||
if (_drawCount === 0)
|
||||
source = _sourceTexture;
|
||||
if (drawCount === 0)
|
||||
source = sourceTexture;
|
||||
else
|
||||
source = (_a = _getTempFramebuffer(_currentFramebufferIndex)) == null ? void 0 : _a.texture;
|
||||
_drawCount++;
|
||||
if (_lastInChain && !(flags & DRAW.INTERMEDIATE)) {
|
||||
source = ((_a = getTempFramebuffer(currentFramebufferIndex)) == null ? void 0 : _a.texture) || null;
|
||||
drawCount++;
|
||||
if (lastInChain && !(flags & DRAW.INTERMEDIATE)) {
|
||||
target = null;
|
||||
flipY = _drawCount % 2 === 0;
|
||||
flipY = drawCount % 2 === 0;
|
||||
} else {
|
||||
_currentFramebufferIndex = (_currentFramebufferIndex + 1) % 2;
|
||||
target = (_b = _getTempFramebuffer(_currentFramebufferIndex)) == null ? void 0 : _b.fbo;
|
||||
currentFramebufferIndex = (currentFramebufferIndex + 1) % 2;
|
||||
target = ((_b = getTempFramebuffer(currentFramebufferIndex)) == null ? void 0 : _b.fbo) || null;
|
||||
}
|
||||
gl.bindTexture(gl.TEXTURE_2D, source);
|
||||
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);
|
||||
};
|
||||
this.apply = function(image7) {
|
||||
_resize(image7.width, image7.height);
|
||||
_drawCount = 0;
|
||||
if (!_sourceTexture)
|
||||
_sourceTexture = gl.createTexture();
|
||||
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_T, gl.CLAMP_TO_EDGE);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_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, image7);
|
||||
if (_filterChain.length === 0) {
|
||||
_draw();
|
||||
} else {
|
||||
for (let i = 0; i < _filterChain.length; i++) {
|
||||
_lastInChain = i === _filterChain.length - 1;
|
||||
const f = _filterChain[i];
|
||||
f.func.apply(this, f.args || []);
|
||||
}
|
||||
}
|
||||
function compileShader(fragmentSource) {
|
||||
if (shaderProgramCache[fragmentSource]) {
|
||||
currentProgram = shaderProgramCache[fragmentSource];
|
||||
gl.useProgram((currentProgram == null ? void 0 : currentProgram.id) || null);
|
||||
return currentProgram;
|
||||
}
|
||||
return _canvas;
|
||||
};
|
||||
const _compileShader = function(fragmentSource) {
|
||||
if (_shaderProgramCache[fragmentSource]) {
|
||||
_currentProgram = _shaderProgramCache[fragmentSource];
|
||||
gl.useProgram(_currentProgram == null ? void 0 : _currentProgram.id);
|
||||
return _currentProgram;
|
||||
}
|
||||
_currentProgram = new GLProgram(gl, vertexIdentity, fragmentSource);
|
||||
currentProgram = new GLProgram(gl, vertexIdentity, fragmentSource);
|
||||
const floatSize = Float32Array.BYTES_PER_ELEMENT;
|
||||
const vertSize = 4 * floatSize;
|
||||
gl.enableVertexAttribArray(_currentProgram.attribute["pos"]);
|
||||
gl.vertexAttribPointer(_currentProgram.attribute["pos"], 2, gl.FLOAT, false, vertSize, 0 * floatSize);
|
||||
gl.enableVertexAttribArray(_currentProgram.attribute.uv);
|
||||
gl.vertexAttribPointer(_currentProgram.attribute["uv"], 2, gl.FLOAT, false, vertSize, 2 * floatSize);
|
||||
_shaderProgramCache[fragmentSource] = _currentProgram;
|
||||
return _currentProgram;
|
||||
};
|
||||
const _filter = {
|
||||
gl.enableVertexAttribArray(currentProgram.attribute["pos"]);
|
||||
gl.vertexAttribPointer(currentProgram.attribute["pos"], 2, gl.FLOAT, false, vertSize, 0 * floatSize);
|
||||
gl.enableVertexAttribArray(currentProgram.attribute["uv"]);
|
||||
gl.vertexAttribPointer(currentProgram.attribute["uv"], 2, gl.FLOAT, false, vertSize, 2 * floatSize);
|
||||
shaderProgramCache[fragmentSource] = currentProgram;
|
||||
return currentProgram;
|
||||
}
|
||||
const filter = {
|
||||
colorMatrix: (matrix) => {
|
||||
const m = new Float32Array(matrix);
|
||||
m[4] /= 255;
|
||||
|
@ -68004,13 +67969,13 @@ function GLImageFilter(params) {
|
|||
m[14] /= 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 ? colorMatrixWithoutAlpha : colorMatrixWithAlpha;
|
||||
const program = _compileShader(shader);
|
||||
const program = compileShader(shader);
|
||||
gl.uniform1fv(program == null ? void 0 : program.uniform["m"], m);
|
||||
_draw();
|
||||
draw2();
|
||||
},
|
||||
brightness: (brightness) => {
|
||||
const b = (brightness || 0) + 1;
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
b,
|
||||
0,
|
||||
0,
|
||||
|
@ -68036,7 +68001,7 @@ function GLImageFilter(params) {
|
|||
saturation: (amount) => {
|
||||
const x = (amount || 0) * 2 / 3 + 1;
|
||||
const y = (x - 1) * -0.5;
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
x,
|
||||
y,
|
||||
y,
|
||||
|
@ -68060,12 +68025,12 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
desaturate: () => {
|
||||
_filter.saturation(-1);
|
||||
filter.saturation(-1);
|
||||
},
|
||||
contrast: (amount) => {
|
||||
const v = (amount || 0) + 1;
|
||||
const o = -128 * (v - 1);
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
v,
|
||||
0,
|
||||
0,
|
||||
|
@ -68089,7 +68054,7 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
negative: () => {
|
||||
_filter.contrast(-2);
|
||||
filter.contrast(-2);
|
||||
},
|
||||
hue: (rotation) => {
|
||||
rotation = (rotation || 0) / 180 * Math.PI;
|
||||
|
@ -68098,7 +68063,7 @@ function GLImageFilter(params) {
|
|||
const lumR = 0.213;
|
||||
const lumG = 0.715;
|
||||
const lumB = 0.072;
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
lumR + cos5 * (1 - lumR) + sin5 * -lumR,
|
||||
lumG + cos5 * -lumG + sin5 * -lumG,
|
||||
lumB + cos5 * -lumB + sin5 * (1 - lumB),
|
||||
|
@ -68122,7 +68087,7 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
desaturateLuminance: () => {
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
0.2764723,
|
||||
0.929708,
|
||||
0.0938197,
|
||||
|
@ -68146,7 +68111,7 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
sepia: () => {
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
0.393,
|
||||
0.7689999,
|
||||
0.18899999,
|
||||
|
@ -68170,7 +68135,7 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
brownie: () => {
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
0.5997023498159715,
|
||||
0.34553243048391263,
|
||||
-0.2708298674538042,
|
||||
|
@ -68194,7 +68159,7 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
vintagePinhole: () => {
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
0.6279345635605994,
|
||||
0.3202183420819367,
|
||||
-0.03965408211312453,
|
||||
|
@ -68218,7 +68183,7 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
kodachrome: () => {
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
1.1285582396593525,
|
||||
-0.3967382283601348,
|
||||
-0.03992559172921793,
|
||||
|
@ -68242,7 +68207,7 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
technicolor: () => {
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
1.9125277891456083,
|
||||
-0.8545344976951645,
|
||||
-0.09155508482755585,
|
||||
|
@ -68266,7 +68231,7 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
polaroid: () => {
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
1.438,
|
||||
-0.062,
|
||||
-0.062,
|
||||
|
@ -68290,7 +68255,7 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
shiftToBGR: () => {
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
|
@ -68315,15 +68280,15 @@ function GLImageFilter(params) {
|
|||
},
|
||||
convolution: (matrix) => {
|
||||
const m = new Float32Array(matrix);
|
||||
const pixelSizeX = 1 / _width;
|
||||
const pixelSizeY = 1 / _height;
|
||||
const program = _compileShader(convolution);
|
||||
const pixelSizeX = 1 / canvas3.width;
|
||||
const pixelSizeY = 1 / canvas3.height;
|
||||
const program = compileShader(convolution);
|
||||
gl.uniform1fv(program == null ? void 0 : program.uniform["m"], m);
|
||||
gl.uniform2f(program == null ? void 0 : program.uniform["px"], pixelSizeX, pixelSizeY);
|
||||
_draw();
|
||||
draw2();
|
||||
},
|
||||
detectEdges: () => {
|
||||
_filter.convolution.call(this, [
|
||||
filter.convolution.call(this, [
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
|
@ -68336,7 +68301,7 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
sobelX: () => {
|
||||
_filter.convolution.call(this, [
|
||||
filter.convolution.call(this, [
|
||||
-1,
|
||||
0,
|
||||
1,
|
||||
|
@ -68349,7 +68314,7 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
sobelY: () => {
|
||||
_filter.convolution.call(this, [
|
||||
filter.convolution.call(this, [
|
||||
-1,
|
||||
-2,
|
||||
-1,
|
||||
|
@ -68363,7 +68328,7 @@ function GLImageFilter(params) {
|
|||
},
|
||||
sharpen: (amount) => {
|
||||
const a = amount || 1;
|
||||
_filter.convolution.call(this, [
|
||||
filter.convolution.call(this, [
|
||||
0,
|
||||
-1 * a,
|
||||
0,
|
||||
|
@ -68377,7 +68342,7 @@ function GLImageFilter(params) {
|
|||
},
|
||||
emboss: (size2) => {
|
||||
const s = size2 || 1;
|
||||
_filter.convolution.call(this, [
|
||||
filter.convolution.call(this, [
|
||||
-2 * s,
|
||||
-1 * s,
|
||||
0,
|
||||
|
@ -68390,22 +68355,55 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
blur: (size2) => {
|
||||
const blurSizeX = size2 / 7 / _width;
|
||||
const blurSizeY = size2 / 7 / _height;
|
||||
const program = _compileShader(blur);
|
||||
const blurSizeX = size2 / 7 / canvas3.width;
|
||||
const blurSizeY = size2 / 7 / canvas3.height;
|
||||
const program = compileShader(blur);
|
||||
gl.uniform2f(program == null ? void 0 : program.uniform["px"], 0, blurSizeY);
|
||||
_draw(DRAW.INTERMEDIATE);
|
||||
draw2(DRAW.INTERMEDIATE);
|
||||
gl.uniform2f(program == null ? void 0 : program.uniform["px"], blurSizeX, 0);
|
||||
_draw();
|
||||
draw2();
|
||||
},
|
||||
pixelate: (size2) => {
|
||||
const blurSizeX = size2 / _width;
|
||||
const blurSizeY = size2 / _height;
|
||||
const program = _compileShader(pixelate);
|
||||
const blurSizeX = size2 / canvas3.width;
|
||||
const blurSizeY = size2 / canvas3.height;
|
||||
const program = compileShader(pixelate);
|
||||
gl.uniform2f(program == null ? void 0 : program.uniform["size"], blurSizeX, blurSizeY);
|
||||
_draw();
|
||||
draw2();
|
||||
}
|
||||
};
|
||||
this.add = function(name) {
|
||||
const args = Array.prototype.slice.call(arguments, 1);
|
||||
const func2 = filter[name];
|
||||
filterChain.push({ func: func2, args });
|
||||
};
|
||||
this.reset = function() {
|
||||
filterChain = [];
|
||||
};
|
||||
this.get = function() {
|
||||
return filterChain;
|
||||
};
|
||||
this.apply = function(image7) {
|
||||
resize(image7.width, image7.height);
|
||||
drawCount = 0;
|
||||
if (!sourceTexture)
|
||||
sourceTexture = gl.createTexture();
|
||||
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_T, gl.CLAMP_TO_EDGE);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_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, image7);
|
||||
for (let i = 0; i < filterChain.length; i++) {
|
||||
lastInChain = i === filterChain.length - 1;
|
||||
const f = filterChain[i];
|
||||
f.func.apply(this, f.args || []);
|
||||
}
|
||||
return canvas3;
|
||||
};
|
||||
this.draw = function(image7) {
|
||||
this.add("brightness", 0);
|
||||
return this.apply(image7);
|
||||
};
|
||||
}
|
||||
|
||||
// src/util/env.ts
|
||||
|
@ -68602,34 +68600,38 @@ function process2(input2, config3, getTensor2 = true) {
|
|||
if (!fx)
|
||||
return { tensor: null, canvas: inCanvas };
|
||||
fx.reset();
|
||||
fx.addFilter("brightness", config3.filter.brightness);
|
||||
if (config3.filter.brightness !== 0)
|
||||
fx.add("brightness", config3.filter.brightness);
|
||||
if (config3.filter.contrast !== 0)
|
||||
fx.addFilter("contrast", config3.filter.contrast);
|
||||
fx.add("contrast", config3.filter.contrast);
|
||||
if (config3.filter.sharpness !== 0)
|
||||
fx.addFilter("sharpen", config3.filter.sharpness);
|
||||
fx.add("sharpen", config3.filter.sharpness);
|
||||
if (config3.filter.blur !== 0)
|
||||
fx.addFilter("blur", config3.filter.blur);
|
||||
fx.add("blur", config3.filter.blur);
|
||||
if (config3.filter.saturation !== 0)
|
||||
fx.addFilter("saturation", config3.filter.saturation);
|
||||
fx.add("saturation", config3.filter.saturation);
|
||||
if (config3.filter.hue !== 0)
|
||||
fx.addFilter("hue", config3.filter.hue);
|
||||
fx.add("hue", config3.filter.hue);
|
||||
if (config3.filter.negative)
|
||||
fx.addFilter("negative");
|
||||
fx.add("negative");
|
||||
if (config3.filter.sepia)
|
||||
fx.addFilter("sepia");
|
||||
fx.add("sepia");
|
||||
if (config3.filter.vintage)
|
||||
fx.addFilter("brownie");
|
||||
fx.add("brownie");
|
||||
if (config3.filter.sepia)
|
||||
fx.addFilter("sepia");
|
||||
fx.add("sepia");
|
||||
if (config3.filter.kodachrome)
|
||||
fx.addFilter("kodachrome");
|
||||
fx.add("kodachrome");
|
||||
if (config3.filter.technicolor)
|
||||
fx.addFilter("technicolor");
|
||||
fx.add("technicolor");
|
||||
if (config3.filter.polaroid)
|
||||
fx.addFilter("polaroid");
|
||||
fx.add("polaroid");
|
||||
if (config3.filter.pixelate !== 0)
|
||||
fx.addFilter("pixelate", config3.filter.pixelate);
|
||||
outCanvas = fx.apply(inCanvas);
|
||||
fx.add("pixelate", config3.filter.pixelate);
|
||||
if (fx.get() > 0)
|
||||
outCanvas = fx.apply(inCanvas);
|
||||
else
|
||||
outCanvas = fx.draw(inCanvas);
|
||||
} else {
|
||||
copy(inCanvas, outCanvas);
|
||||
if (fx)
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -383,11 +383,11 @@ var GLProgram = class {
|
|||
return shader;
|
||||
});
|
||||
this.gl = gl;
|
||||
const _vsh = this.compile(vertexSource, this.gl.VERTEX_SHADER);
|
||||
const _fsh = this.compile(fragmentSource, this.gl.FRAGMENT_SHADER);
|
||||
const vertexShader = this.compile(vertexSource, this.gl.VERTEX_SHADER);
|
||||
const fragmentShader = this.compile(fragmentSource, this.gl.FRAGMENT_SHADER);
|
||||
this.id = this.gl.createProgram();
|
||||
this.gl.attachShader(this.id, _vsh);
|
||||
this.gl.attachShader(this.id, _fsh);
|
||||
this.gl.attachShader(this.id, vertexShader);
|
||||
this.gl.attachShader(this.id, fragmentShader);
|
||||
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)}`);
|
||||
|
@ -401,50 +401,37 @@ var GLProgram = class {
|
|||
this.uniform[u] = this.gl.getUniformLocation(this.id, u);
|
||||
}
|
||||
};
|
||||
function GLImageFilter(params) {
|
||||
if (!params)
|
||||
params = {};
|
||||
let _drawCount = 0;
|
||||
let _sourceTexture = null;
|
||||
let _lastInChain = false;
|
||||
let _currentFramebufferIndex = -1;
|
||||
let _tempFramebuffers = [null, null];
|
||||
let _filterChain = [];
|
||||
let _width = -1;
|
||||
let _height = -1;
|
||||
let _vertexBuffer = null;
|
||||
let _currentProgram = null;
|
||||
const _canvas = params.canvas || typeof OffscreenCanvas !== "undefined" ? new OffscreenCanvas(100, 100) : document.createElement("canvas");
|
||||
const _shaderProgramCache = {};
|
||||
function GLImageFilter(params = {}) {
|
||||
let drawCount = 0;
|
||||
let sourceTexture = null;
|
||||
let lastInChain = false;
|
||||
let currentFramebufferIndex = -1;
|
||||
let tempFramebuffers = [null, null];
|
||||
let filterChain = [];
|
||||
let vertexBuffer = null;
|
||||
let currentProgram = null;
|
||||
const canvas3 = params["canvas"] || typeof OffscreenCanvas !== "undefined" ? new OffscreenCanvas(100, 100) : document.createElement("canvas");
|
||||
const shaderProgramCache = {};
|
||||
const DRAW = { INTERMEDIATE: 1 };
|
||||
const gl = _canvas.getContext("webgl");
|
||||
const gl = canvas3.getContext("webgl");
|
||||
if (!gl)
|
||||
throw new Error("filter: cannot get webgl context");
|
||||
this.addFilter = function(name) {
|
||||
const args = Array.prototype.slice.call(arguments, 1);
|
||||
const filter = _filter[name];
|
||||
_filterChain.push({ func: filter, args });
|
||||
};
|
||||
this.reset = function() {
|
||||
_filterChain = [];
|
||||
};
|
||||
const _resize = function(width, height) {
|
||||
if (width === _width && height === _height)
|
||||
function resize(width, height) {
|
||||
if (width === canvas3.width && height === canvas3.height)
|
||||
return;
|
||||
_canvas.width = width;
|
||||
_width = width;
|
||||
_canvas.height = height;
|
||||
_height = height;
|
||||
if (!_vertexBuffer) {
|
||||
canvas3.width = width;
|
||||
canvas3.height = height;
|
||||
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]);
|
||||
_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.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
|
||||
}
|
||||
gl.viewport(0, 0, _width, _height);
|
||||
_tempFramebuffers = [null, null];
|
||||
};
|
||||
const _createFramebufferTexture = function(width, height) {
|
||||
gl.viewport(0, 0, canvas3.width, canvas3.height);
|
||||
tempFramebuffers = [null, null];
|
||||
}
|
||||
function createFramebufferTexture(width, height) {
|
||||
const fbo = gl.createFramebuffer();
|
||||
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
|
||||
const renderbuffer = gl.createRenderbuffer();
|
||||
|
@ -460,74 +447,52 @@ function GLImageFilter(params) {
|
|||
gl.bindTexture(gl.TEXTURE_2D, null);
|
||||
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
||||
return { fbo, texture };
|
||||
};
|
||||
const _getTempFramebuffer = function(index) {
|
||||
_tempFramebuffers[index] = _tempFramebuffers[index] || _createFramebufferTexture(_width, _height);
|
||||
return _tempFramebuffers[index];
|
||||
};
|
||||
const _draw = function(flags = 0) {
|
||||
}
|
||||
function getTempFramebuffer(index) {
|
||||
tempFramebuffers[index] = tempFramebuffers[index] || createFramebufferTexture(canvas3.width, canvas3.height);
|
||||
return tempFramebuffers[index];
|
||||
}
|
||||
function draw2(flags = 0) {
|
||||
var _a, _b;
|
||||
if (!_currentProgram)
|
||||
if (!currentProgram)
|
||||
return;
|
||||
let source = null;
|
||||
let target = null;
|
||||
let flipY = false;
|
||||
if (_drawCount === 0)
|
||||
source = _sourceTexture;
|
||||
if (drawCount === 0)
|
||||
source = sourceTexture;
|
||||
else
|
||||
source = (_a = _getTempFramebuffer(_currentFramebufferIndex)) == null ? void 0 : _a.texture;
|
||||
_drawCount++;
|
||||
if (_lastInChain && !(flags & DRAW.INTERMEDIATE)) {
|
||||
source = ((_a = getTempFramebuffer(currentFramebufferIndex)) == null ? void 0 : _a.texture) || null;
|
||||
drawCount++;
|
||||
if (lastInChain && !(flags & DRAW.INTERMEDIATE)) {
|
||||
target = null;
|
||||
flipY = _drawCount % 2 === 0;
|
||||
flipY = drawCount % 2 === 0;
|
||||
} else {
|
||||
_currentFramebufferIndex = (_currentFramebufferIndex + 1) % 2;
|
||||
target = (_b = _getTempFramebuffer(_currentFramebufferIndex)) == null ? void 0 : _b.fbo;
|
||||
currentFramebufferIndex = (currentFramebufferIndex + 1) % 2;
|
||||
target = ((_b = getTempFramebuffer(currentFramebufferIndex)) == null ? void 0 : _b.fbo) || null;
|
||||
}
|
||||
gl.bindTexture(gl.TEXTURE_2D, source);
|
||||
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);
|
||||
};
|
||||
this.apply = function(image24) {
|
||||
_resize(image24.width, image24.height);
|
||||
_drawCount = 0;
|
||||
if (!_sourceTexture)
|
||||
_sourceTexture = gl.createTexture();
|
||||
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_T, gl.CLAMP_TO_EDGE);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_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, image24);
|
||||
if (_filterChain.length === 0) {
|
||||
_draw();
|
||||
} else {
|
||||
for (let i = 0; i < _filterChain.length; i++) {
|
||||
_lastInChain = i === _filterChain.length - 1;
|
||||
const f = _filterChain[i];
|
||||
f.func.apply(this, f.args || []);
|
||||
}
|
||||
}
|
||||
function compileShader(fragmentSource) {
|
||||
if (shaderProgramCache[fragmentSource]) {
|
||||
currentProgram = shaderProgramCache[fragmentSource];
|
||||
gl.useProgram((currentProgram == null ? void 0 : currentProgram.id) || null);
|
||||
return currentProgram;
|
||||
}
|
||||
return _canvas;
|
||||
};
|
||||
const _compileShader = function(fragmentSource) {
|
||||
if (_shaderProgramCache[fragmentSource]) {
|
||||
_currentProgram = _shaderProgramCache[fragmentSource];
|
||||
gl.useProgram(_currentProgram == null ? void 0 : _currentProgram.id);
|
||||
return _currentProgram;
|
||||
}
|
||||
_currentProgram = new GLProgram(gl, vertexIdentity, fragmentSource);
|
||||
currentProgram = new GLProgram(gl, vertexIdentity, fragmentSource);
|
||||
const floatSize = Float32Array.BYTES_PER_ELEMENT;
|
||||
const vertSize = 4 * floatSize;
|
||||
gl.enableVertexAttribArray(_currentProgram.attribute["pos"]);
|
||||
gl.vertexAttribPointer(_currentProgram.attribute["pos"], 2, gl.FLOAT, false, vertSize, 0 * floatSize);
|
||||
gl.enableVertexAttribArray(_currentProgram.attribute.uv);
|
||||
gl.vertexAttribPointer(_currentProgram.attribute["uv"], 2, gl.FLOAT, false, vertSize, 2 * floatSize);
|
||||
_shaderProgramCache[fragmentSource] = _currentProgram;
|
||||
return _currentProgram;
|
||||
};
|
||||
const _filter = {
|
||||
gl.enableVertexAttribArray(currentProgram.attribute["pos"]);
|
||||
gl.vertexAttribPointer(currentProgram.attribute["pos"], 2, gl.FLOAT, false, vertSize, 0 * floatSize);
|
||||
gl.enableVertexAttribArray(currentProgram.attribute["uv"]);
|
||||
gl.vertexAttribPointer(currentProgram.attribute["uv"], 2, gl.FLOAT, false, vertSize, 2 * floatSize);
|
||||
shaderProgramCache[fragmentSource] = currentProgram;
|
||||
return currentProgram;
|
||||
}
|
||||
const filter = {
|
||||
colorMatrix: (matrix) => {
|
||||
const m = new Float32Array(matrix);
|
||||
m[4] /= 255;
|
||||
|
@ -535,13 +500,13 @@ function GLImageFilter(params) {
|
|||
m[14] /= 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 ? colorMatrixWithoutAlpha : colorMatrixWithAlpha;
|
||||
const program = _compileShader(shader);
|
||||
const program = compileShader(shader);
|
||||
gl.uniform1fv(program == null ? void 0 : program.uniform["m"], m);
|
||||
_draw();
|
||||
draw2();
|
||||
},
|
||||
brightness: (brightness) => {
|
||||
const b = (brightness || 0) + 1;
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
b,
|
||||
0,
|
||||
0,
|
||||
|
@ -567,7 +532,7 @@ function GLImageFilter(params) {
|
|||
saturation: (amount) => {
|
||||
const x = (amount || 0) * 2 / 3 + 1;
|
||||
const y = (x - 1) * -0.5;
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
x,
|
||||
y,
|
||||
y,
|
||||
|
@ -591,12 +556,12 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
desaturate: () => {
|
||||
_filter.saturation(-1);
|
||||
filter.saturation(-1);
|
||||
},
|
||||
contrast: (amount) => {
|
||||
const v = (amount || 0) + 1;
|
||||
const o = -128 * (v - 1);
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
v,
|
||||
0,
|
||||
0,
|
||||
|
@ -620,7 +585,7 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
negative: () => {
|
||||
_filter.contrast(-2);
|
||||
filter.contrast(-2);
|
||||
},
|
||||
hue: (rotation) => {
|
||||
rotation = (rotation || 0) / 180 * Math.PI;
|
||||
|
@ -629,7 +594,7 @@ function GLImageFilter(params) {
|
|||
const lumR = 0.213;
|
||||
const lumG = 0.715;
|
||||
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),
|
||||
|
@ -653,7 +618,7 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
desaturateLuminance: () => {
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
0.2764723,
|
||||
0.929708,
|
||||
0.0938197,
|
||||
|
@ -677,7 +642,7 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
sepia: () => {
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
0.393,
|
||||
0.7689999,
|
||||
0.18899999,
|
||||
|
@ -701,7 +666,7 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
brownie: () => {
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
0.5997023498159715,
|
||||
0.34553243048391263,
|
||||
-0.2708298674538042,
|
||||
|
@ -725,7 +690,7 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
vintagePinhole: () => {
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
0.6279345635605994,
|
||||
0.3202183420819367,
|
||||
-0.03965408211312453,
|
||||
|
@ -749,7 +714,7 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
kodachrome: () => {
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
1.1285582396593525,
|
||||
-0.3967382283601348,
|
||||
-0.03992559172921793,
|
||||
|
@ -773,7 +738,7 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
technicolor: () => {
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
1.9125277891456083,
|
||||
-0.8545344976951645,
|
||||
-0.09155508482755585,
|
||||
|
@ -797,7 +762,7 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
polaroid: () => {
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
1.438,
|
||||
-0.062,
|
||||
-0.062,
|
||||
|
@ -821,7 +786,7 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
shiftToBGR: () => {
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
|
@ -846,15 +811,15 @@ function GLImageFilter(params) {
|
|||
},
|
||||
convolution: (matrix) => {
|
||||
const m = new Float32Array(matrix);
|
||||
const pixelSizeX = 1 / _width;
|
||||
const pixelSizeY = 1 / _height;
|
||||
const program = _compileShader(convolution);
|
||||
const pixelSizeX = 1 / canvas3.width;
|
||||
const pixelSizeY = 1 / canvas3.height;
|
||||
const program = compileShader(convolution);
|
||||
gl.uniform1fv(program == null ? void 0 : program.uniform["m"], m);
|
||||
gl.uniform2f(program == null ? void 0 : program.uniform["px"], pixelSizeX, pixelSizeY);
|
||||
_draw();
|
||||
draw2();
|
||||
},
|
||||
detectEdges: () => {
|
||||
_filter.convolution.call(this, [
|
||||
filter.convolution.call(this, [
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
|
@ -867,7 +832,7 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
sobelX: () => {
|
||||
_filter.convolution.call(this, [
|
||||
filter.convolution.call(this, [
|
||||
-1,
|
||||
0,
|
||||
1,
|
||||
|
@ -880,7 +845,7 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
sobelY: () => {
|
||||
_filter.convolution.call(this, [
|
||||
filter.convolution.call(this, [
|
||||
-1,
|
||||
-2,
|
||||
-1,
|
||||
|
@ -894,7 +859,7 @@ function GLImageFilter(params) {
|
|||
},
|
||||
sharpen: (amount) => {
|
||||
const a = amount || 1;
|
||||
_filter.convolution.call(this, [
|
||||
filter.convolution.call(this, [
|
||||
0,
|
||||
-1 * a,
|
||||
0,
|
||||
|
@ -908,7 +873,7 @@ function GLImageFilter(params) {
|
|||
},
|
||||
emboss: (size2) => {
|
||||
const s = size2 || 1;
|
||||
_filter.convolution.call(this, [
|
||||
filter.convolution.call(this, [
|
||||
-2 * s,
|
||||
-1 * s,
|
||||
0,
|
||||
|
@ -921,22 +886,55 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
blur: (size2) => {
|
||||
const blurSizeX = size2 / 7 / _width;
|
||||
const blurSizeY = size2 / 7 / _height;
|
||||
const program = _compileShader(blur);
|
||||
const blurSizeX = size2 / 7 / canvas3.width;
|
||||
const blurSizeY = size2 / 7 / canvas3.height;
|
||||
const program = compileShader(blur);
|
||||
gl.uniform2f(program == null ? void 0 : program.uniform["px"], 0, blurSizeY);
|
||||
_draw(DRAW.INTERMEDIATE);
|
||||
draw2(DRAW.INTERMEDIATE);
|
||||
gl.uniform2f(program == null ? void 0 : program.uniform["px"], blurSizeX, 0);
|
||||
_draw();
|
||||
draw2();
|
||||
},
|
||||
pixelate: (size2) => {
|
||||
const blurSizeX = size2 / _width;
|
||||
const blurSizeY = size2 / _height;
|
||||
const program = _compileShader(pixelate);
|
||||
const blurSizeX = size2 / canvas3.width;
|
||||
const blurSizeY = size2 / canvas3.height;
|
||||
const program = compileShader(pixelate);
|
||||
gl.uniform2f(program == null ? void 0 : program.uniform["size"], blurSizeX, blurSizeY);
|
||||
_draw();
|
||||
draw2();
|
||||
}
|
||||
};
|
||||
this.add = function(name) {
|
||||
const args = Array.prototype.slice.call(arguments, 1);
|
||||
const func = filter[name];
|
||||
filterChain.push({ func, args });
|
||||
};
|
||||
this.reset = function() {
|
||||
filterChain = [];
|
||||
};
|
||||
this.get = function() {
|
||||
return filterChain;
|
||||
};
|
||||
this.apply = function(image24) {
|
||||
resize(image24.width, image24.height);
|
||||
drawCount = 0;
|
||||
if (!sourceTexture)
|
||||
sourceTexture = gl.createTexture();
|
||||
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_T, gl.CLAMP_TO_EDGE);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_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, image24);
|
||||
for (let i = 0; i < filterChain.length; i++) {
|
||||
lastInChain = i === filterChain.length - 1;
|
||||
const f = filterChain[i];
|
||||
f.func.apply(this, f.args || []);
|
||||
}
|
||||
return canvas3;
|
||||
};
|
||||
this.draw = function(image24) {
|
||||
this.add("brightness", 0);
|
||||
return this.apply(image24);
|
||||
};
|
||||
}
|
||||
|
||||
// src/util/env.ts
|
||||
|
@ -1134,34 +1132,38 @@ function process2(input, config3, getTensor = true) {
|
|||
if (!fx)
|
||||
return { tensor: null, canvas: inCanvas };
|
||||
fx.reset();
|
||||
fx.addFilter("brightness", config3.filter.brightness);
|
||||
if (config3.filter.brightness !== 0)
|
||||
fx.add("brightness", config3.filter.brightness);
|
||||
if (config3.filter.contrast !== 0)
|
||||
fx.addFilter("contrast", config3.filter.contrast);
|
||||
fx.add("contrast", config3.filter.contrast);
|
||||
if (config3.filter.sharpness !== 0)
|
||||
fx.addFilter("sharpen", config3.filter.sharpness);
|
||||
fx.add("sharpen", config3.filter.sharpness);
|
||||
if (config3.filter.blur !== 0)
|
||||
fx.addFilter("blur", config3.filter.blur);
|
||||
fx.add("blur", config3.filter.blur);
|
||||
if (config3.filter.saturation !== 0)
|
||||
fx.addFilter("saturation", config3.filter.saturation);
|
||||
fx.add("saturation", config3.filter.saturation);
|
||||
if (config3.filter.hue !== 0)
|
||||
fx.addFilter("hue", config3.filter.hue);
|
||||
fx.add("hue", config3.filter.hue);
|
||||
if (config3.filter.negative)
|
||||
fx.addFilter("negative");
|
||||
fx.add("negative");
|
||||
if (config3.filter.sepia)
|
||||
fx.addFilter("sepia");
|
||||
fx.add("sepia");
|
||||
if (config3.filter.vintage)
|
||||
fx.addFilter("brownie");
|
||||
fx.add("brownie");
|
||||
if (config3.filter.sepia)
|
||||
fx.addFilter("sepia");
|
||||
fx.add("sepia");
|
||||
if (config3.filter.kodachrome)
|
||||
fx.addFilter("kodachrome");
|
||||
fx.add("kodachrome");
|
||||
if (config3.filter.technicolor)
|
||||
fx.addFilter("technicolor");
|
||||
fx.add("technicolor");
|
||||
if (config3.filter.polaroid)
|
||||
fx.addFilter("polaroid");
|
||||
fx.add("polaroid");
|
||||
if (config3.filter.pixelate !== 0)
|
||||
fx.addFilter("pixelate", config3.filter.pixelate);
|
||||
outCanvas = fx.apply(inCanvas);
|
||||
fx.add("pixelate", config3.filter.pixelate);
|
||||
if (fx.get() > 0)
|
||||
outCanvas = fx.apply(inCanvas);
|
||||
else
|
||||
outCanvas = fx.draw(inCanvas);
|
||||
} else {
|
||||
copy(inCanvas, outCanvas);
|
||||
if (fx)
|
||||
|
|
|
@ -384,11 +384,11 @@ var GLProgram = class {
|
|||
return shader;
|
||||
});
|
||||
this.gl = gl;
|
||||
const _vsh = this.compile(vertexSource, this.gl.VERTEX_SHADER);
|
||||
const _fsh = this.compile(fragmentSource, this.gl.FRAGMENT_SHADER);
|
||||
const vertexShader = this.compile(vertexSource, this.gl.VERTEX_SHADER);
|
||||
const fragmentShader = this.compile(fragmentSource, this.gl.FRAGMENT_SHADER);
|
||||
this.id = this.gl.createProgram();
|
||||
this.gl.attachShader(this.id, _vsh);
|
||||
this.gl.attachShader(this.id, _fsh);
|
||||
this.gl.attachShader(this.id, vertexShader);
|
||||
this.gl.attachShader(this.id, fragmentShader);
|
||||
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)}`);
|
||||
|
@ -402,50 +402,37 @@ var GLProgram = class {
|
|||
this.uniform[u] = this.gl.getUniformLocation(this.id, u);
|
||||
}
|
||||
};
|
||||
function GLImageFilter(params) {
|
||||
if (!params)
|
||||
params = {};
|
||||
let _drawCount = 0;
|
||||
let _sourceTexture = null;
|
||||
let _lastInChain = false;
|
||||
let _currentFramebufferIndex = -1;
|
||||
let _tempFramebuffers = [null, null];
|
||||
let _filterChain = [];
|
||||
let _width = -1;
|
||||
let _height = -1;
|
||||
let _vertexBuffer = null;
|
||||
let _currentProgram = null;
|
||||
const _canvas = params.canvas || typeof OffscreenCanvas !== "undefined" ? new OffscreenCanvas(100, 100) : document.createElement("canvas");
|
||||
const _shaderProgramCache = {};
|
||||
function GLImageFilter(params = {}) {
|
||||
let drawCount = 0;
|
||||
let sourceTexture = null;
|
||||
let lastInChain = false;
|
||||
let currentFramebufferIndex = -1;
|
||||
let tempFramebuffers = [null, null];
|
||||
let filterChain = [];
|
||||
let vertexBuffer = null;
|
||||
let currentProgram = null;
|
||||
const canvas3 = params["canvas"] || typeof OffscreenCanvas !== "undefined" ? new OffscreenCanvas(100, 100) : document.createElement("canvas");
|
||||
const shaderProgramCache = {};
|
||||
const DRAW = { INTERMEDIATE: 1 };
|
||||
const gl = _canvas.getContext("webgl");
|
||||
const gl = canvas3.getContext("webgl");
|
||||
if (!gl)
|
||||
throw new Error("filter: cannot get webgl context");
|
||||
this.addFilter = function(name) {
|
||||
const args = Array.prototype.slice.call(arguments, 1);
|
||||
const filter = _filter[name];
|
||||
_filterChain.push({ func: filter, args });
|
||||
};
|
||||
this.reset = function() {
|
||||
_filterChain = [];
|
||||
};
|
||||
const _resize = function(width, height) {
|
||||
if (width === _width && height === _height)
|
||||
function resize(width, height) {
|
||||
if (width === canvas3.width && height === canvas3.height)
|
||||
return;
|
||||
_canvas.width = width;
|
||||
_width = width;
|
||||
_canvas.height = height;
|
||||
_height = height;
|
||||
if (!_vertexBuffer) {
|
||||
canvas3.width = width;
|
||||
canvas3.height = height;
|
||||
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]);
|
||||
_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.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
|
||||
}
|
||||
gl.viewport(0, 0, _width, _height);
|
||||
_tempFramebuffers = [null, null];
|
||||
};
|
||||
const _createFramebufferTexture = function(width, height) {
|
||||
gl.viewport(0, 0, canvas3.width, canvas3.height);
|
||||
tempFramebuffers = [null, null];
|
||||
}
|
||||
function createFramebufferTexture(width, height) {
|
||||
const fbo = gl.createFramebuffer();
|
||||
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
|
||||
const renderbuffer = gl.createRenderbuffer();
|
||||
|
@ -461,74 +448,52 @@ function GLImageFilter(params) {
|
|||
gl.bindTexture(gl.TEXTURE_2D, null);
|
||||
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
||||
return { fbo, texture };
|
||||
};
|
||||
const _getTempFramebuffer = function(index) {
|
||||
_tempFramebuffers[index] = _tempFramebuffers[index] || _createFramebufferTexture(_width, _height);
|
||||
return _tempFramebuffers[index];
|
||||
};
|
||||
const _draw = function(flags = 0) {
|
||||
}
|
||||
function getTempFramebuffer(index) {
|
||||
tempFramebuffers[index] = tempFramebuffers[index] || createFramebufferTexture(canvas3.width, canvas3.height);
|
||||
return tempFramebuffers[index];
|
||||
}
|
||||
function draw2(flags = 0) {
|
||||
var _a, _b;
|
||||
if (!_currentProgram)
|
||||
if (!currentProgram)
|
||||
return;
|
||||
let source = null;
|
||||
let target = null;
|
||||
let flipY = false;
|
||||
if (_drawCount === 0)
|
||||
source = _sourceTexture;
|
||||
if (drawCount === 0)
|
||||
source = sourceTexture;
|
||||
else
|
||||
source = (_a = _getTempFramebuffer(_currentFramebufferIndex)) == null ? void 0 : _a.texture;
|
||||
_drawCount++;
|
||||
if (_lastInChain && !(flags & DRAW.INTERMEDIATE)) {
|
||||
source = ((_a = getTempFramebuffer(currentFramebufferIndex)) == null ? void 0 : _a.texture) || null;
|
||||
drawCount++;
|
||||
if (lastInChain && !(flags & DRAW.INTERMEDIATE)) {
|
||||
target = null;
|
||||
flipY = _drawCount % 2 === 0;
|
||||
flipY = drawCount % 2 === 0;
|
||||
} else {
|
||||
_currentFramebufferIndex = (_currentFramebufferIndex + 1) % 2;
|
||||
target = (_b = _getTempFramebuffer(_currentFramebufferIndex)) == null ? void 0 : _b.fbo;
|
||||
currentFramebufferIndex = (currentFramebufferIndex + 1) % 2;
|
||||
target = ((_b = getTempFramebuffer(currentFramebufferIndex)) == null ? void 0 : _b.fbo) || null;
|
||||
}
|
||||
gl.bindTexture(gl.TEXTURE_2D, source);
|
||||
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);
|
||||
};
|
||||
this.apply = function(image24) {
|
||||
_resize(image24.width, image24.height);
|
||||
_drawCount = 0;
|
||||
if (!_sourceTexture)
|
||||
_sourceTexture = gl.createTexture();
|
||||
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_T, gl.CLAMP_TO_EDGE);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_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, image24);
|
||||
if (_filterChain.length === 0) {
|
||||
_draw();
|
||||
} else {
|
||||
for (let i = 0; i < _filterChain.length; i++) {
|
||||
_lastInChain = i === _filterChain.length - 1;
|
||||
const f = _filterChain[i];
|
||||
f.func.apply(this, f.args || []);
|
||||
}
|
||||
}
|
||||
function compileShader(fragmentSource) {
|
||||
if (shaderProgramCache[fragmentSource]) {
|
||||
currentProgram = shaderProgramCache[fragmentSource];
|
||||
gl.useProgram((currentProgram == null ? void 0 : currentProgram.id) || null);
|
||||
return currentProgram;
|
||||
}
|
||||
return _canvas;
|
||||
};
|
||||
const _compileShader = function(fragmentSource) {
|
||||
if (_shaderProgramCache[fragmentSource]) {
|
||||
_currentProgram = _shaderProgramCache[fragmentSource];
|
||||
gl.useProgram(_currentProgram == null ? void 0 : _currentProgram.id);
|
||||
return _currentProgram;
|
||||
}
|
||||
_currentProgram = new GLProgram(gl, vertexIdentity, fragmentSource);
|
||||
currentProgram = new GLProgram(gl, vertexIdentity, fragmentSource);
|
||||
const floatSize = Float32Array.BYTES_PER_ELEMENT;
|
||||
const vertSize = 4 * floatSize;
|
||||
gl.enableVertexAttribArray(_currentProgram.attribute["pos"]);
|
||||
gl.vertexAttribPointer(_currentProgram.attribute["pos"], 2, gl.FLOAT, false, vertSize, 0 * floatSize);
|
||||
gl.enableVertexAttribArray(_currentProgram.attribute.uv);
|
||||
gl.vertexAttribPointer(_currentProgram.attribute["uv"], 2, gl.FLOAT, false, vertSize, 2 * floatSize);
|
||||
_shaderProgramCache[fragmentSource] = _currentProgram;
|
||||
return _currentProgram;
|
||||
};
|
||||
const _filter = {
|
||||
gl.enableVertexAttribArray(currentProgram.attribute["pos"]);
|
||||
gl.vertexAttribPointer(currentProgram.attribute["pos"], 2, gl.FLOAT, false, vertSize, 0 * floatSize);
|
||||
gl.enableVertexAttribArray(currentProgram.attribute["uv"]);
|
||||
gl.vertexAttribPointer(currentProgram.attribute["uv"], 2, gl.FLOAT, false, vertSize, 2 * floatSize);
|
||||
shaderProgramCache[fragmentSource] = currentProgram;
|
||||
return currentProgram;
|
||||
}
|
||||
const filter = {
|
||||
colorMatrix: (matrix) => {
|
||||
const m = new Float32Array(matrix);
|
||||
m[4] /= 255;
|
||||
|
@ -536,13 +501,13 @@ function GLImageFilter(params) {
|
|||
m[14] /= 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 ? colorMatrixWithoutAlpha : colorMatrixWithAlpha;
|
||||
const program = _compileShader(shader);
|
||||
const program = compileShader(shader);
|
||||
gl.uniform1fv(program == null ? void 0 : program.uniform["m"], m);
|
||||
_draw();
|
||||
draw2();
|
||||
},
|
||||
brightness: (brightness) => {
|
||||
const b = (brightness || 0) + 1;
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
b,
|
||||
0,
|
||||
0,
|
||||
|
@ -568,7 +533,7 @@ function GLImageFilter(params) {
|
|||
saturation: (amount) => {
|
||||
const x = (amount || 0) * 2 / 3 + 1;
|
||||
const y = (x - 1) * -0.5;
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
x,
|
||||
y,
|
||||
y,
|
||||
|
@ -592,12 +557,12 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
desaturate: () => {
|
||||
_filter.saturation(-1);
|
||||
filter.saturation(-1);
|
||||
},
|
||||
contrast: (amount) => {
|
||||
const v = (amount || 0) + 1;
|
||||
const o = -128 * (v - 1);
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
v,
|
||||
0,
|
||||
0,
|
||||
|
@ -621,7 +586,7 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
negative: () => {
|
||||
_filter.contrast(-2);
|
||||
filter.contrast(-2);
|
||||
},
|
||||
hue: (rotation) => {
|
||||
rotation = (rotation || 0) / 180 * Math.PI;
|
||||
|
@ -630,7 +595,7 @@ function GLImageFilter(params) {
|
|||
const lumR = 0.213;
|
||||
const lumG = 0.715;
|
||||
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),
|
||||
|
@ -654,7 +619,7 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
desaturateLuminance: () => {
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
0.2764723,
|
||||
0.929708,
|
||||
0.0938197,
|
||||
|
@ -678,7 +643,7 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
sepia: () => {
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
0.393,
|
||||
0.7689999,
|
||||
0.18899999,
|
||||
|
@ -702,7 +667,7 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
brownie: () => {
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
0.5997023498159715,
|
||||
0.34553243048391263,
|
||||
-0.2708298674538042,
|
||||
|
@ -726,7 +691,7 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
vintagePinhole: () => {
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
0.6279345635605994,
|
||||
0.3202183420819367,
|
||||
-0.03965408211312453,
|
||||
|
@ -750,7 +715,7 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
kodachrome: () => {
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
1.1285582396593525,
|
||||
-0.3967382283601348,
|
||||
-0.03992559172921793,
|
||||
|
@ -774,7 +739,7 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
technicolor: () => {
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
1.9125277891456083,
|
||||
-0.8545344976951645,
|
||||
-0.09155508482755585,
|
||||
|
@ -798,7 +763,7 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
polaroid: () => {
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
1.438,
|
||||
-0.062,
|
||||
-0.062,
|
||||
|
@ -822,7 +787,7 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
shiftToBGR: () => {
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
|
@ -847,15 +812,15 @@ function GLImageFilter(params) {
|
|||
},
|
||||
convolution: (matrix) => {
|
||||
const m = new Float32Array(matrix);
|
||||
const pixelSizeX = 1 / _width;
|
||||
const pixelSizeY = 1 / _height;
|
||||
const program = _compileShader(convolution);
|
||||
const pixelSizeX = 1 / canvas3.width;
|
||||
const pixelSizeY = 1 / canvas3.height;
|
||||
const program = compileShader(convolution);
|
||||
gl.uniform1fv(program == null ? void 0 : program.uniform["m"], m);
|
||||
gl.uniform2f(program == null ? void 0 : program.uniform["px"], pixelSizeX, pixelSizeY);
|
||||
_draw();
|
||||
draw2();
|
||||
},
|
||||
detectEdges: () => {
|
||||
_filter.convolution.call(this, [
|
||||
filter.convolution.call(this, [
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
|
@ -868,7 +833,7 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
sobelX: () => {
|
||||
_filter.convolution.call(this, [
|
||||
filter.convolution.call(this, [
|
||||
-1,
|
||||
0,
|
||||
1,
|
||||
|
@ -881,7 +846,7 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
sobelY: () => {
|
||||
_filter.convolution.call(this, [
|
||||
filter.convolution.call(this, [
|
||||
-1,
|
||||
-2,
|
||||
-1,
|
||||
|
@ -895,7 +860,7 @@ function GLImageFilter(params) {
|
|||
},
|
||||
sharpen: (amount) => {
|
||||
const a = amount || 1;
|
||||
_filter.convolution.call(this, [
|
||||
filter.convolution.call(this, [
|
||||
0,
|
||||
-1 * a,
|
||||
0,
|
||||
|
@ -909,7 +874,7 @@ function GLImageFilter(params) {
|
|||
},
|
||||
emboss: (size2) => {
|
||||
const s = size2 || 1;
|
||||
_filter.convolution.call(this, [
|
||||
filter.convolution.call(this, [
|
||||
-2 * s,
|
||||
-1 * s,
|
||||
0,
|
||||
|
@ -922,22 +887,55 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
blur: (size2) => {
|
||||
const blurSizeX = size2 / 7 / _width;
|
||||
const blurSizeY = size2 / 7 / _height;
|
||||
const program = _compileShader(blur);
|
||||
const blurSizeX = size2 / 7 / canvas3.width;
|
||||
const blurSizeY = size2 / 7 / canvas3.height;
|
||||
const program = compileShader(blur);
|
||||
gl.uniform2f(program == null ? void 0 : program.uniform["px"], 0, blurSizeY);
|
||||
_draw(DRAW.INTERMEDIATE);
|
||||
draw2(DRAW.INTERMEDIATE);
|
||||
gl.uniform2f(program == null ? void 0 : program.uniform["px"], blurSizeX, 0);
|
||||
_draw();
|
||||
draw2();
|
||||
},
|
||||
pixelate: (size2) => {
|
||||
const blurSizeX = size2 / _width;
|
||||
const blurSizeY = size2 / _height;
|
||||
const program = _compileShader(pixelate);
|
||||
const blurSizeX = size2 / canvas3.width;
|
||||
const blurSizeY = size2 / canvas3.height;
|
||||
const program = compileShader(pixelate);
|
||||
gl.uniform2f(program == null ? void 0 : program.uniform["size"], blurSizeX, blurSizeY);
|
||||
_draw();
|
||||
draw2();
|
||||
}
|
||||
};
|
||||
this.add = function(name) {
|
||||
const args = Array.prototype.slice.call(arguments, 1);
|
||||
const func = filter[name];
|
||||
filterChain.push({ func, args });
|
||||
};
|
||||
this.reset = function() {
|
||||
filterChain = [];
|
||||
};
|
||||
this.get = function() {
|
||||
return filterChain;
|
||||
};
|
||||
this.apply = function(image24) {
|
||||
resize(image24.width, image24.height);
|
||||
drawCount = 0;
|
||||
if (!sourceTexture)
|
||||
sourceTexture = gl.createTexture();
|
||||
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_T, gl.CLAMP_TO_EDGE);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_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, image24);
|
||||
for (let i = 0; i < filterChain.length; i++) {
|
||||
lastInChain = i === filterChain.length - 1;
|
||||
const f = filterChain[i];
|
||||
f.func.apply(this, f.args || []);
|
||||
}
|
||||
return canvas3;
|
||||
};
|
||||
this.draw = function(image24) {
|
||||
this.add("brightness", 0);
|
||||
return this.apply(image24);
|
||||
};
|
||||
}
|
||||
|
||||
// src/util/env.ts
|
||||
|
@ -1135,34 +1133,38 @@ function process2(input, config3, getTensor = true) {
|
|||
if (!fx)
|
||||
return { tensor: null, canvas: inCanvas };
|
||||
fx.reset();
|
||||
fx.addFilter("brightness", config3.filter.brightness);
|
||||
if (config3.filter.brightness !== 0)
|
||||
fx.add("brightness", config3.filter.brightness);
|
||||
if (config3.filter.contrast !== 0)
|
||||
fx.addFilter("contrast", config3.filter.contrast);
|
||||
fx.add("contrast", config3.filter.contrast);
|
||||
if (config3.filter.sharpness !== 0)
|
||||
fx.addFilter("sharpen", config3.filter.sharpness);
|
||||
fx.add("sharpen", config3.filter.sharpness);
|
||||
if (config3.filter.blur !== 0)
|
||||
fx.addFilter("blur", config3.filter.blur);
|
||||
fx.add("blur", config3.filter.blur);
|
||||
if (config3.filter.saturation !== 0)
|
||||
fx.addFilter("saturation", config3.filter.saturation);
|
||||
fx.add("saturation", config3.filter.saturation);
|
||||
if (config3.filter.hue !== 0)
|
||||
fx.addFilter("hue", config3.filter.hue);
|
||||
fx.add("hue", config3.filter.hue);
|
||||
if (config3.filter.negative)
|
||||
fx.addFilter("negative");
|
||||
fx.add("negative");
|
||||
if (config3.filter.sepia)
|
||||
fx.addFilter("sepia");
|
||||
fx.add("sepia");
|
||||
if (config3.filter.vintage)
|
||||
fx.addFilter("brownie");
|
||||
fx.add("brownie");
|
||||
if (config3.filter.sepia)
|
||||
fx.addFilter("sepia");
|
||||
fx.add("sepia");
|
||||
if (config3.filter.kodachrome)
|
||||
fx.addFilter("kodachrome");
|
||||
fx.add("kodachrome");
|
||||
if (config3.filter.technicolor)
|
||||
fx.addFilter("technicolor");
|
||||
fx.add("technicolor");
|
||||
if (config3.filter.polaroid)
|
||||
fx.addFilter("polaroid");
|
||||
fx.add("polaroid");
|
||||
if (config3.filter.pixelate !== 0)
|
||||
fx.addFilter("pixelate", config3.filter.pixelate);
|
||||
outCanvas = fx.apply(inCanvas);
|
||||
fx.add("pixelate", config3.filter.pixelate);
|
||||
if (fx.get() > 0)
|
||||
outCanvas = fx.apply(inCanvas);
|
||||
else
|
||||
outCanvas = fx.draw(inCanvas);
|
||||
} else {
|
||||
copy(inCanvas, outCanvas);
|
||||
if (fx)
|
||||
|
|
|
@ -383,11 +383,11 @@ var GLProgram = class {
|
|||
return shader;
|
||||
});
|
||||
this.gl = gl;
|
||||
const _vsh = this.compile(vertexSource, this.gl.VERTEX_SHADER);
|
||||
const _fsh = this.compile(fragmentSource, this.gl.FRAGMENT_SHADER);
|
||||
const vertexShader = this.compile(vertexSource, this.gl.VERTEX_SHADER);
|
||||
const fragmentShader = this.compile(fragmentSource, this.gl.FRAGMENT_SHADER);
|
||||
this.id = this.gl.createProgram();
|
||||
this.gl.attachShader(this.id, _vsh);
|
||||
this.gl.attachShader(this.id, _fsh);
|
||||
this.gl.attachShader(this.id, vertexShader);
|
||||
this.gl.attachShader(this.id, fragmentShader);
|
||||
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)}`);
|
||||
|
@ -401,50 +401,37 @@ var GLProgram = class {
|
|||
this.uniform[u] = this.gl.getUniformLocation(this.id, u);
|
||||
}
|
||||
};
|
||||
function GLImageFilter(params) {
|
||||
if (!params)
|
||||
params = {};
|
||||
let _drawCount = 0;
|
||||
let _sourceTexture = null;
|
||||
let _lastInChain = false;
|
||||
let _currentFramebufferIndex = -1;
|
||||
let _tempFramebuffers = [null, null];
|
||||
let _filterChain = [];
|
||||
let _width = -1;
|
||||
let _height = -1;
|
||||
let _vertexBuffer = null;
|
||||
let _currentProgram = null;
|
||||
const _canvas = params.canvas || typeof OffscreenCanvas !== "undefined" ? new OffscreenCanvas(100, 100) : document.createElement("canvas");
|
||||
const _shaderProgramCache = {};
|
||||
function GLImageFilter(params = {}) {
|
||||
let drawCount = 0;
|
||||
let sourceTexture = null;
|
||||
let lastInChain = false;
|
||||
let currentFramebufferIndex = -1;
|
||||
let tempFramebuffers = [null, null];
|
||||
let filterChain = [];
|
||||
let vertexBuffer = null;
|
||||
let currentProgram = null;
|
||||
const canvas3 = params["canvas"] || typeof OffscreenCanvas !== "undefined" ? new OffscreenCanvas(100, 100) : document.createElement("canvas");
|
||||
const shaderProgramCache = {};
|
||||
const DRAW = { INTERMEDIATE: 1 };
|
||||
const gl = _canvas.getContext("webgl");
|
||||
const gl = canvas3.getContext("webgl");
|
||||
if (!gl)
|
||||
throw new Error("filter: cannot get webgl context");
|
||||
this.addFilter = function(name) {
|
||||
const args = Array.prototype.slice.call(arguments, 1);
|
||||
const filter = _filter[name];
|
||||
_filterChain.push({ func: filter, args });
|
||||
};
|
||||
this.reset = function() {
|
||||
_filterChain = [];
|
||||
};
|
||||
const _resize = function(width, height) {
|
||||
if (width === _width && height === _height)
|
||||
function resize(width, height) {
|
||||
if (width === canvas3.width && height === canvas3.height)
|
||||
return;
|
||||
_canvas.width = width;
|
||||
_width = width;
|
||||
_canvas.height = height;
|
||||
_height = height;
|
||||
if (!_vertexBuffer) {
|
||||
canvas3.width = width;
|
||||
canvas3.height = height;
|
||||
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]);
|
||||
_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.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
|
||||
}
|
||||
gl.viewport(0, 0, _width, _height);
|
||||
_tempFramebuffers = [null, null];
|
||||
};
|
||||
const _createFramebufferTexture = function(width, height) {
|
||||
gl.viewport(0, 0, canvas3.width, canvas3.height);
|
||||
tempFramebuffers = [null, null];
|
||||
}
|
||||
function createFramebufferTexture(width, height) {
|
||||
const fbo = gl.createFramebuffer();
|
||||
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
|
||||
const renderbuffer = gl.createRenderbuffer();
|
||||
|
@ -460,74 +447,52 @@ function GLImageFilter(params) {
|
|||
gl.bindTexture(gl.TEXTURE_2D, null);
|
||||
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
||||
return { fbo, texture };
|
||||
};
|
||||
const _getTempFramebuffer = function(index) {
|
||||
_tempFramebuffers[index] = _tempFramebuffers[index] || _createFramebufferTexture(_width, _height);
|
||||
return _tempFramebuffers[index];
|
||||
};
|
||||
const _draw = function(flags = 0) {
|
||||
}
|
||||
function getTempFramebuffer(index) {
|
||||
tempFramebuffers[index] = tempFramebuffers[index] || createFramebufferTexture(canvas3.width, canvas3.height);
|
||||
return tempFramebuffers[index];
|
||||
}
|
||||
function draw2(flags = 0) {
|
||||
var _a, _b;
|
||||
if (!_currentProgram)
|
||||
if (!currentProgram)
|
||||
return;
|
||||
let source = null;
|
||||
let target = null;
|
||||
let flipY = false;
|
||||
if (_drawCount === 0)
|
||||
source = _sourceTexture;
|
||||
if (drawCount === 0)
|
||||
source = sourceTexture;
|
||||
else
|
||||
source = (_a = _getTempFramebuffer(_currentFramebufferIndex)) == null ? void 0 : _a.texture;
|
||||
_drawCount++;
|
||||
if (_lastInChain && !(flags & DRAW.INTERMEDIATE)) {
|
||||
source = ((_a = getTempFramebuffer(currentFramebufferIndex)) == null ? void 0 : _a.texture) || null;
|
||||
drawCount++;
|
||||
if (lastInChain && !(flags & DRAW.INTERMEDIATE)) {
|
||||
target = null;
|
||||
flipY = _drawCount % 2 === 0;
|
||||
flipY = drawCount % 2 === 0;
|
||||
} else {
|
||||
_currentFramebufferIndex = (_currentFramebufferIndex + 1) % 2;
|
||||
target = (_b = _getTempFramebuffer(_currentFramebufferIndex)) == null ? void 0 : _b.fbo;
|
||||
currentFramebufferIndex = (currentFramebufferIndex + 1) % 2;
|
||||
target = ((_b = getTempFramebuffer(currentFramebufferIndex)) == null ? void 0 : _b.fbo) || null;
|
||||
}
|
||||
gl.bindTexture(gl.TEXTURE_2D, source);
|
||||
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);
|
||||
};
|
||||
this.apply = function(image24) {
|
||||
_resize(image24.width, image24.height);
|
||||
_drawCount = 0;
|
||||
if (!_sourceTexture)
|
||||
_sourceTexture = gl.createTexture();
|
||||
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_T, gl.CLAMP_TO_EDGE);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_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, image24);
|
||||
if (_filterChain.length === 0) {
|
||||
_draw();
|
||||
} else {
|
||||
for (let i = 0; i < _filterChain.length; i++) {
|
||||
_lastInChain = i === _filterChain.length - 1;
|
||||
const f = _filterChain[i];
|
||||
f.func.apply(this, f.args || []);
|
||||
}
|
||||
}
|
||||
function compileShader(fragmentSource) {
|
||||
if (shaderProgramCache[fragmentSource]) {
|
||||
currentProgram = shaderProgramCache[fragmentSource];
|
||||
gl.useProgram((currentProgram == null ? void 0 : currentProgram.id) || null);
|
||||
return currentProgram;
|
||||
}
|
||||
return _canvas;
|
||||
};
|
||||
const _compileShader = function(fragmentSource) {
|
||||
if (_shaderProgramCache[fragmentSource]) {
|
||||
_currentProgram = _shaderProgramCache[fragmentSource];
|
||||
gl.useProgram(_currentProgram == null ? void 0 : _currentProgram.id);
|
||||
return _currentProgram;
|
||||
}
|
||||
_currentProgram = new GLProgram(gl, vertexIdentity, fragmentSource);
|
||||
currentProgram = new GLProgram(gl, vertexIdentity, fragmentSource);
|
||||
const floatSize = Float32Array.BYTES_PER_ELEMENT;
|
||||
const vertSize = 4 * floatSize;
|
||||
gl.enableVertexAttribArray(_currentProgram.attribute["pos"]);
|
||||
gl.vertexAttribPointer(_currentProgram.attribute["pos"], 2, gl.FLOAT, false, vertSize, 0 * floatSize);
|
||||
gl.enableVertexAttribArray(_currentProgram.attribute.uv);
|
||||
gl.vertexAttribPointer(_currentProgram.attribute["uv"], 2, gl.FLOAT, false, vertSize, 2 * floatSize);
|
||||
_shaderProgramCache[fragmentSource] = _currentProgram;
|
||||
return _currentProgram;
|
||||
};
|
||||
const _filter = {
|
||||
gl.enableVertexAttribArray(currentProgram.attribute["pos"]);
|
||||
gl.vertexAttribPointer(currentProgram.attribute["pos"], 2, gl.FLOAT, false, vertSize, 0 * floatSize);
|
||||
gl.enableVertexAttribArray(currentProgram.attribute["uv"]);
|
||||
gl.vertexAttribPointer(currentProgram.attribute["uv"], 2, gl.FLOAT, false, vertSize, 2 * floatSize);
|
||||
shaderProgramCache[fragmentSource] = currentProgram;
|
||||
return currentProgram;
|
||||
}
|
||||
const filter = {
|
||||
colorMatrix: (matrix) => {
|
||||
const m = new Float32Array(matrix);
|
||||
m[4] /= 255;
|
||||
|
@ -535,13 +500,13 @@ function GLImageFilter(params) {
|
|||
m[14] /= 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 ? colorMatrixWithoutAlpha : colorMatrixWithAlpha;
|
||||
const program = _compileShader(shader);
|
||||
const program = compileShader(shader);
|
||||
gl.uniform1fv(program == null ? void 0 : program.uniform["m"], m);
|
||||
_draw();
|
||||
draw2();
|
||||
},
|
||||
brightness: (brightness) => {
|
||||
const b = (brightness || 0) + 1;
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
b,
|
||||
0,
|
||||
0,
|
||||
|
@ -567,7 +532,7 @@ function GLImageFilter(params) {
|
|||
saturation: (amount) => {
|
||||
const x = (amount || 0) * 2 / 3 + 1;
|
||||
const y = (x - 1) * -0.5;
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
x,
|
||||
y,
|
||||
y,
|
||||
|
@ -591,12 +556,12 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
desaturate: () => {
|
||||
_filter.saturation(-1);
|
||||
filter.saturation(-1);
|
||||
},
|
||||
contrast: (amount) => {
|
||||
const v = (amount || 0) + 1;
|
||||
const o = -128 * (v - 1);
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
v,
|
||||
0,
|
||||
0,
|
||||
|
@ -620,7 +585,7 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
negative: () => {
|
||||
_filter.contrast(-2);
|
||||
filter.contrast(-2);
|
||||
},
|
||||
hue: (rotation) => {
|
||||
rotation = (rotation || 0) / 180 * Math.PI;
|
||||
|
@ -629,7 +594,7 @@ function GLImageFilter(params) {
|
|||
const lumR = 0.213;
|
||||
const lumG = 0.715;
|
||||
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),
|
||||
|
@ -653,7 +618,7 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
desaturateLuminance: () => {
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
0.2764723,
|
||||
0.929708,
|
||||
0.0938197,
|
||||
|
@ -677,7 +642,7 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
sepia: () => {
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
0.393,
|
||||
0.7689999,
|
||||
0.18899999,
|
||||
|
@ -701,7 +666,7 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
brownie: () => {
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
0.5997023498159715,
|
||||
0.34553243048391263,
|
||||
-0.2708298674538042,
|
||||
|
@ -725,7 +690,7 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
vintagePinhole: () => {
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
0.6279345635605994,
|
||||
0.3202183420819367,
|
||||
-0.03965408211312453,
|
||||
|
@ -749,7 +714,7 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
kodachrome: () => {
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
1.1285582396593525,
|
||||
-0.3967382283601348,
|
||||
-0.03992559172921793,
|
||||
|
@ -773,7 +738,7 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
technicolor: () => {
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
1.9125277891456083,
|
||||
-0.8545344976951645,
|
||||
-0.09155508482755585,
|
||||
|
@ -797,7 +762,7 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
polaroid: () => {
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
1.438,
|
||||
-0.062,
|
||||
-0.062,
|
||||
|
@ -821,7 +786,7 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
shiftToBGR: () => {
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
|
@ -846,15 +811,15 @@ function GLImageFilter(params) {
|
|||
},
|
||||
convolution: (matrix) => {
|
||||
const m = new Float32Array(matrix);
|
||||
const pixelSizeX = 1 / _width;
|
||||
const pixelSizeY = 1 / _height;
|
||||
const program = _compileShader(convolution);
|
||||
const pixelSizeX = 1 / canvas3.width;
|
||||
const pixelSizeY = 1 / canvas3.height;
|
||||
const program = compileShader(convolution);
|
||||
gl.uniform1fv(program == null ? void 0 : program.uniform["m"], m);
|
||||
gl.uniform2f(program == null ? void 0 : program.uniform["px"], pixelSizeX, pixelSizeY);
|
||||
_draw();
|
||||
draw2();
|
||||
},
|
||||
detectEdges: () => {
|
||||
_filter.convolution.call(this, [
|
||||
filter.convolution.call(this, [
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
|
@ -867,7 +832,7 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
sobelX: () => {
|
||||
_filter.convolution.call(this, [
|
||||
filter.convolution.call(this, [
|
||||
-1,
|
||||
0,
|
||||
1,
|
||||
|
@ -880,7 +845,7 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
sobelY: () => {
|
||||
_filter.convolution.call(this, [
|
||||
filter.convolution.call(this, [
|
||||
-1,
|
||||
-2,
|
||||
-1,
|
||||
|
@ -894,7 +859,7 @@ function GLImageFilter(params) {
|
|||
},
|
||||
sharpen: (amount) => {
|
||||
const a = amount || 1;
|
||||
_filter.convolution.call(this, [
|
||||
filter.convolution.call(this, [
|
||||
0,
|
||||
-1 * a,
|
||||
0,
|
||||
|
@ -908,7 +873,7 @@ function GLImageFilter(params) {
|
|||
},
|
||||
emboss: (size2) => {
|
||||
const s = size2 || 1;
|
||||
_filter.convolution.call(this, [
|
||||
filter.convolution.call(this, [
|
||||
-2 * s,
|
||||
-1 * s,
|
||||
0,
|
||||
|
@ -921,22 +886,55 @@ function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
blur: (size2) => {
|
||||
const blurSizeX = size2 / 7 / _width;
|
||||
const blurSizeY = size2 / 7 / _height;
|
||||
const program = _compileShader(blur);
|
||||
const blurSizeX = size2 / 7 / canvas3.width;
|
||||
const blurSizeY = size2 / 7 / canvas3.height;
|
||||
const program = compileShader(blur);
|
||||
gl.uniform2f(program == null ? void 0 : program.uniform["px"], 0, blurSizeY);
|
||||
_draw(DRAW.INTERMEDIATE);
|
||||
draw2(DRAW.INTERMEDIATE);
|
||||
gl.uniform2f(program == null ? void 0 : program.uniform["px"], blurSizeX, 0);
|
||||
_draw();
|
||||
draw2();
|
||||
},
|
||||
pixelate: (size2) => {
|
||||
const blurSizeX = size2 / _width;
|
||||
const blurSizeY = size2 / _height;
|
||||
const program = _compileShader(pixelate);
|
||||
const blurSizeX = size2 / canvas3.width;
|
||||
const blurSizeY = size2 / canvas3.height;
|
||||
const program = compileShader(pixelate);
|
||||
gl.uniform2f(program == null ? void 0 : program.uniform["size"], blurSizeX, blurSizeY);
|
||||
_draw();
|
||||
draw2();
|
||||
}
|
||||
};
|
||||
this.add = function(name) {
|
||||
const args = Array.prototype.slice.call(arguments, 1);
|
||||
const func = filter[name];
|
||||
filterChain.push({ func, args });
|
||||
};
|
||||
this.reset = function() {
|
||||
filterChain = [];
|
||||
};
|
||||
this.get = function() {
|
||||
return filterChain;
|
||||
};
|
||||
this.apply = function(image24) {
|
||||
resize(image24.width, image24.height);
|
||||
drawCount = 0;
|
||||
if (!sourceTexture)
|
||||
sourceTexture = gl.createTexture();
|
||||
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_T, gl.CLAMP_TO_EDGE);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_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, image24);
|
||||
for (let i = 0; i < filterChain.length; i++) {
|
||||
lastInChain = i === filterChain.length - 1;
|
||||
const f = filterChain[i];
|
||||
f.func.apply(this, f.args || []);
|
||||
}
|
||||
return canvas3;
|
||||
};
|
||||
this.draw = function(image24) {
|
||||
this.add("brightness", 0);
|
||||
return this.apply(image24);
|
||||
};
|
||||
}
|
||||
|
||||
// src/util/env.ts
|
||||
|
@ -1134,34 +1132,38 @@ function process2(input, config3, getTensor = true) {
|
|||
if (!fx)
|
||||
return { tensor: null, canvas: inCanvas };
|
||||
fx.reset();
|
||||
fx.addFilter("brightness", config3.filter.brightness);
|
||||
if (config3.filter.brightness !== 0)
|
||||
fx.add("brightness", config3.filter.brightness);
|
||||
if (config3.filter.contrast !== 0)
|
||||
fx.addFilter("contrast", config3.filter.contrast);
|
||||
fx.add("contrast", config3.filter.contrast);
|
||||
if (config3.filter.sharpness !== 0)
|
||||
fx.addFilter("sharpen", config3.filter.sharpness);
|
||||
fx.add("sharpen", config3.filter.sharpness);
|
||||
if (config3.filter.blur !== 0)
|
||||
fx.addFilter("blur", config3.filter.blur);
|
||||
fx.add("blur", config3.filter.blur);
|
||||
if (config3.filter.saturation !== 0)
|
||||
fx.addFilter("saturation", config3.filter.saturation);
|
||||
fx.add("saturation", config3.filter.saturation);
|
||||
if (config3.filter.hue !== 0)
|
||||
fx.addFilter("hue", config3.filter.hue);
|
||||
fx.add("hue", config3.filter.hue);
|
||||
if (config3.filter.negative)
|
||||
fx.addFilter("negative");
|
||||
fx.add("negative");
|
||||
if (config3.filter.sepia)
|
||||
fx.addFilter("sepia");
|
||||
fx.add("sepia");
|
||||
if (config3.filter.vintage)
|
||||
fx.addFilter("brownie");
|
||||
fx.add("brownie");
|
||||
if (config3.filter.sepia)
|
||||
fx.addFilter("sepia");
|
||||
fx.add("sepia");
|
||||
if (config3.filter.kodachrome)
|
||||
fx.addFilter("kodachrome");
|
||||
fx.add("kodachrome");
|
||||
if (config3.filter.technicolor)
|
||||
fx.addFilter("technicolor");
|
||||
fx.add("technicolor");
|
||||
if (config3.filter.polaroid)
|
||||
fx.addFilter("polaroid");
|
||||
fx.add("polaroid");
|
||||
if (config3.filter.pixelate !== 0)
|
||||
fx.addFilter("pixelate", config3.filter.pixelate);
|
||||
outCanvas = fx.apply(inCanvas);
|
||||
fx.add("pixelate", config3.filter.pixelate);
|
||||
if (fx.get() > 0)
|
||||
outCanvas = fx.apply(inCanvas);
|
||||
else
|
||||
outCanvas = fx.draw(inCanvas);
|
||||
} else {
|
||||
copy(inCanvas, outCanvas);
|
||||
if (fx)
|
||||
|
|
|
@ -134,21 +134,22 @@ export function process(input: Input, config: Config, getTensor: boolean = true)
|
|||
env.filter = !!fx;
|
||||
if (!fx) return { tensor: null, canvas: inCanvas };
|
||||
fx.reset();
|
||||
fx.addFilter('brightness', config.filter.brightness); // must have at least one filter enabled
|
||||
if (config.filter.contrast !== 0) fx.addFilter('contrast', config.filter.contrast);
|
||||
if (config.filter.sharpness !== 0) fx.addFilter('sharpen', config.filter.sharpness);
|
||||
if (config.filter.blur !== 0) fx.addFilter('blur', config.filter.blur);
|
||||
if (config.filter.saturation !== 0) fx.addFilter('saturation', config.filter.saturation);
|
||||
if (config.filter.hue !== 0) fx.addFilter('hue', config.filter.hue);
|
||||
if (config.filter.negative) fx.addFilter('negative');
|
||||
if (config.filter.sepia) fx.addFilter('sepia');
|
||||
if (config.filter.vintage) fx.addFilter('brownie');
|
||||
if (config.filter.sepia) fx.addFilter('sepia');
|
||||
if (config.filter.kodachrome) fx.addFilter('kodachrome');
|
||||
if (config.filter.technicolor) fx.addFilter('technicolor');
|
||||
if (config.filter.polaroid) fx.addFilter('polaroid');
|
||||
if (config.filter.pixelate !== 0) fx.addFilter('pixelate', config.filter.pixelate);
|
||||
outCanvas = fx.apply(inCanvas);
|
||||
if (config.filter.brightness !== 0) fx.add('brightness', config.filter.brightness);
|
||||
if (config.filter.contrast !== 0) fx.add('contrast', config.filter.contrast);
|
||||
if (config.filter.sharpness !== 0) fx.add('sharpen', config.filter.sharpness);
|
||||
if (config.filter.blur !== 0) fx.add('blur', config.filter.blur);
|
||||
if (config.filter.saturation !== 0) fx.add('saturation', config.filter.saturation);
|
||||
if (config.filter.hue !== 0) fx.add('hue', config.filter.hue);
|
||||
if (config.filter.negative) fx.add('negative');
|
||||
if (config.filter.sepia) fx.add('sepia');
|
||||
if (config.filter.vintage) fx.add('brownie');
|
||||
if (config.filter.sepia) fx.add('sepia');
|
||||
if (config.filter.kodachrome) fx.add('kodachrome');
|
||||
if (config.filter.technicolor) fx.add('technicolor');
|
||||
if (config.filter.polaroid) fx.add('polaroid');
|
||||
if (config.filter.pixelate !== 0) fx.add('pixelate', config.filter.pixelate);
|
||||
if (fx.get() > 0) outCanvas = fx.apply(inCanvas);
|
||||
else outCanvas = fx.draw(inCanvas);
|
||||
} else {
|
||||
copy(inCanvas, outCanvas); // if no filters applied, output canvas is input canvas
|
||||
if (fx) fx = null;
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
/**
|
||||
* Image Filters in WebGL algoritm implementation
|
||||
* Based on: [WebGLImageFilter](https://github.com/phoboslab/WebGLImageFilter)
|
||||
* This module is written in ES5 JS and does not conform to code and style standards
|
||||
*/
|
||||
|
||||
import * as shaders from './imagefxshaders';
|
||||
|
@ -13,11 +12,11 @@ class GLProgram {
|
|||
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);
|
||||
const vertexShader = this.compile(vertexSource, this.gl.VERTEX_SHADER);
|
||||
const fragmentShader = 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.attachShader(this.id, vertexShader);
|
||||
this.gl.attachShader(this.id, fragmentShader);
|
||||
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);
|
||||
|
@ -45,53 +44,46 @@ class GLProgram {
|
|||
};
|
||||
}
|
||||
|
||||
export function GLImageFilter(params) {
|
||||
if (!params) params = { };
|
||||
let _drawCount = 0;
|
||||
let _sourceTexture = null;
|
||||
let _lastInChain = false;
|
||||
let _currentFramebufferIndex = -1;
|
||||
let _tempFramebuffers: [null, null] | [{ fbo: any, texture: any }] = [null, null];
|
||||
let _filterChain: Record<string, unknown>[] = [];
|
||||
let _width = -1;
|
||||
let _height = -1;
|
||||
let _vertexBuffer = null;
|
||||
let _currentProgram: GLProgram | null = null;
|
||||
const _canvas = params.canvas || typeof OffscreenCanvas !== 'undefined' ? new OffscreenCanvas(100, 100) : document.createElement('canvas');
|
||||
const _shaderProgramCache = { }; // key is the shader program source, value is the compiled program
|
||||
// function that is instantiated as class so it has private this members
|
||||
/**
|
||||
* @class GLImageFilter
|
||||
* @property {function} reset reset current filter chain
|
||||
* @property {function} add add specified filter to filter chain
|
||||
* @property {function} apply execute filter chain and draw result
|
||||
* @property {function} draw just draw input to result
|
||||
* @param {HTMLCanvasElement | OffscreenCanvas} canvas use specific canvas for all webgl bindings
|
||||
*/
|
||||
export function GLImageFilter(params = {}) {
|
||||
let drawCount = 0;
|
||||
let sourceTexture: WebGLTexture | null = null;
|
||||
let lastInChain = false;
|
||||
let currentFramebufferIndex = -1;
|
||||
let tempFramebuffers: [null, null] | [{ fbo: WebGLFramebuffer | null, texture: WebGLTexture | null }] = [null, null];
|
||||
let filterChain: Record<string, unknown>[] = [];
|
||||
let vertexBuffer: WebGLBuffer | null = null;
|
||||
let currentProgram: GLProgram | null = null;
|
||||
const canvas = params['canvas'] || typeof OffscreenCanvas !== 'undefined' ? new OffscreenCanvas(100, 100) : document.createElement('canvas');
|
||||
const shaderProgramCache = { }; // key is the shader program source, value is the compiled program
|
||||
const DRAW = { INTERMEDIATE: 1 };
|
||||
const gl = _canvas.getContext('webgl');
|
||||
const gl = canvas.getContext('webgl') as WebGLRenderingContext;
|
||||
if (!gl) throw new Error('filter: cannot get webgl context');
|
||||
|
||||
this.addFilter = function (name) {
|
||||
// eslint-disable-next-line prefer-rest-params
|
||||
const args = Array.prototype.slice.call(arguments, 1);
|
||||
const filter = _filter[name];
|
||||
_filterChain.push({ func: filter, args });
|
||||
};
|
||||
|
||||
this.reset = function () {
|
||||
_filterChain = [];
|
||||
};
|
||||
|
||||
const _resize = function (width, height) {
|
||||
if (width === _width && height === _height) return; // Same width/height? Nothing to do here
|
||||
_canvas.width = width;
|
||||
_width = width;
|
||||
_canvas.height = height;
|
||||
_height = height;
|
||||
if (!_vertexBuffer) { // Create the context if we don't have it yet
|
||||
function resize(width, height) {
|
||||
if (width === canvas.width && height === canvas.height) return; // Same width/height? Nothing to do here
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
if (!vertexBuffer) { // Create the context if we don't have it yet
|
||||
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
|
||||
// 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.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
|
||||
}
|
||||
gl.viewport(0, 0, _width, _height);
|
||||
_tempFramebuffers = [null, null]; // Delete old temp framebuffers
|
||||
};
|
||||
gl.viewport(0, 0, canvas.width, canvas.height);
|
||||
tempFramebuffers = [null, null]; // Delete old temp framebuffers
|
||||
}
|
||||
|
||||
const _createFramebufferTexture = function (width, height) {
|
||||
function createFramebufferTexture(width, height) {
|
||||
const fbo = gl.createFramebuffer();
|
||||
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
|
||||
const renderbuffer = gl.createRenderbuffer();
|
||||
|
@ -107,77 +99,54 @@ export function GLImageFilter(params) {
|
|||
gl.bindTexture(gl.TEXTURE_2D, null);
|
||||
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
||||
return { fbo, texture };
|
||||
};
|
||||
}
|
||||
|
||||
const _getTempFramebuffer = function (index) {
|
||||
_tempFramebuffers[index] = _tempFramebuffers[index] || _createFramebufferTexture(_width, _height);
|
||||
return _tempFramebuffers[index];
|
||||
};
|
||||
function getTempFramebuffer(index) {
|
||||
tempFramebuffers[index] = tempFramebuffers[index] || createFramebufferTexture(canvas.width, canvas.height);
|
||||
return tempFramebuffers[index];
|
||||
}
|
||||
|
||||
const _draw = function (flags = 0) {
|
||||
if (!_currentProgram) return;
|
||||
let source = null;
|
||||
let target = null;
|
||||
function draw(flags = 0) {
|
||||
if (!currentProgram) return;
|
||||
let source: WebGLTexture | null = null;
|
||||
let target: WebGLFramebuffer | null = null;
|
||||
let flipY = false;
|
||||
if (_drawCount === 0) source = _sourceTexture; // First draw call - use the source texture
|
||||
else source = _getTempFramebuffer(_currentFramebufferIndex)?.texture; // All following draw calls use the temp buffer last drawn to
|
||||
_drawCount++;
|
||||
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 (drawCount === 0) source = sourceTexture; // First draw call - use the source texture
|
||||
else source = getTempFramebuffer(currentFramebufferIndex)?.texture || null; // All following draw calls use the temp buffer last drawn to
|
||||
drawCount++;
|
||||
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;
|
||||
flipY = _drawCount % 2 === 0;
|
||||
flipY = drawCount % 2 === 0;
|
||||
} else {
|
||||
_currentFramebufferIndex = (_currentFramebufferIndex + 1) % 2;
|
||||
target = _getTempFramebuffer(_currentFramebufferIndex)?.fbo; // Intermediate draw call - get a temp buffer to draw to
|
||||
currentFramebufferIndex = (currentFramebufferIndex + 1) % 2;
|
||||
target = getTempFramebuffer(currentFramebufferIndex)?.fbo || null; // Intermediate draw call - get a temp buffer to draw to
|
||||
}
|
||||
gl.bindTexture(gl.TEXTURE_2D, source); // Bind the source and target and draw the two triangles
|
||||
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);
|
||||
};
|
||||
}
|
||||
|
||||
this.apply = function (image) {
|
||||
_resize(image.width, image.height);
|
||||
_drawCount = 0;
|
||||
if (!_sourceTexture) _sourceTexture = gl.createTexture(); // Create the texture for the input image if we haven't yet
|
||||
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_T, gl.CLAMP_TO_EDGE);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_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);
|
||||
if (_filterChain.length === 0) { // draw when done with filters
|
||||
_draw();
|
||||
} else { // apply filters one-by-one recursively
|
||||
for (let i = 0; i < _filterChain.length; i++) {
|
||||
_lastInChain = (i === _filterChain.length - 1);
|
||||
const f = _filterChain[i];
|
||||
f.func.apply(this, f.args || []);
|
||||
}
|
||||
function compileShader(fragmentSource) {
|
||||
if (shaderProgramCache[fragmentSource]) {
|
||||
currentProgram = shaderProgramCache[fragmentSource];
|
||||
gl.useProgram(currentProgram?.id || null);
|
||||
return currentProgram;
|
||||
}
|
||||
return _canvas;
|
||||
};
|
||||
|
||||
const _compileShader = function (fragmentSource) {
|
||||
if (_shaderProgramCache[fragmentSource]) {
|
||||
_currentProgram = _shaderProgramCache[fragmentSource];
|
||||
gl.useProgram(_currentProgram?.id);
|
||||
return _currentProgram;
|
||||
}
|
||||
_currentProgram = new GLProgram(gl, shaders.vertexIdentity, fragmentSource);
|
||||
currentProgram = new GLProgram(gl, shaders.vertexIdentity, fragmentSource);
|
||||
const floatSize = Float32Array.BYTES_PER_ELEMENT;
|
||||
const vertSize = 4 * floatSize;
|
||||
gl.enableVertexAttribArray(_currentProgram.attribute['pos']);
|
||||
gl.vertexAttribPointer(_currentProgram.attribute['pos'], 2, gl.FLOAT, false, vertSize, 0 * floatSize);
|
||||
gl.enableVertexAttribArray(_currentProgram.attribute.uv);
|
||||
gl.vertexAttribPointer(_currentProgram.attribute['uv'], 2, gl.FLOAT, false, vertSize, 2 * floatSize);
|
||||
_shaderProgramCache[fragmentSource] = _currentProgram;
|
||||
return _currentProgram;
|
||||
};
|
||||
gl.enableVertexAttribArray(currentProgram.attribute['pos']);
|
||||
gl.vertexAttribPointer(currentProgram.attribute['pos'], 2, gl.FLOAT, false, vertSize, 0 * floatSize);
|
||||
gl.enableVertexAttribArray(currentProgram.attribute['uv']);
|
||||
gl.vertexAttribPointer(currentProgram.attribute['uv'], 2, gl.FLOAT, false, vertSize, 2 * floatSize);
|
||||
shaderProgramCache[fragmentSource] = currentProgram;
|
||||
return currentProgram;
|
||||
}
|
||||
|
||||
// Color Matrix Filter: Used by most color filters
|
||||
const _filter = {
|
||||
colorMatrix: (matrix) => {
|
||||
const m = new Float32Array(matrix); // Create a Float32 Array and normalize the offset component to 0-1
|
||||
const filter = {
|
||||
colorMatrix: (matrix) => { // general color matrix filter
|
||||
const m = new Float32Array(matrix);
|
||||
m[4] /= 255;
|
||||
m[9] /= 255;
|
||||
m[14] /= 255;
|
||||
|
@ -185,14 +154,14 @@ export function GLImageFilter(params) {
|
|||
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.
|
||||
? shaders.colorMatrixWithoutAlpha
|
||||
: shaders.colorMatrixWithAlpha;
|
||||
const program = _compileShader(shader);
|
||||
const program = compileShader(shader);
|
||||
gl.uniform1fv(program?.uniform['m'], m);
|
||||
_draw();
|
||||
draw();
|
||||
},
|
||||
|
||||
brightness: (brightness) => {
|
||||
const b = (brightness || 0) + 1;
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
b, 0, 0, 0, 0,
|
||||
0, b, 0, 0, 0,
|
||||
0, 0, b, 0, 0,
|
||||
|
@ -203,7 +172,7 @@ export function GLImageFilter(params) {
|
|||
saturation: (amount) => {
|
||||
const x = (amount || 0) * 2 / 3 + 1;
|
||||
const y = ((x - 1) * -0.5);
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
x, y, y, 0, 0,
|
||||
y, x, y, 0, 0,
|
||||
y, y, x, 0, 0,
|
||||
|
@ -212,13 +181,13 @@ export function GLImageFilter(params) {
|
|||
},
|
||||
|
||||
desaturate: () => {
|
||||
_filter.saturation(-1);
|
||||
filter.saturation(-1);
|
||||
},
|
||||
|
||||
contrast: (amount) => {
|
||||
const v = (amount || 0) + 1;
|
||||
const o = -128 * (v - 1);
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
v, 0, 0, 0, o,
|
||||
0, v, 0, 0, o,
|
||||
0, 0, v, 0, o,
|
||||
|
@ -227,7 +196,7 @@ export function GLImageFilter(params) {
|
|||
},
|
||||
|
||||
negative: () => {
|
||||
_filter.contrast(-2);
|
||||
filter.contrast(-2);
|
||||
},
|
||||
|
||||
hue: (rotation) => {
|
||||
|
@ -237,7 +206,7 @@ export function GLImageFilter(params) {
|
|||
const lumR = 0.213;
|
||||
const lumG = 0.715;
|
||||
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 * (-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,
|
||||
|
@ -246,7 +215,7 @@ export function GLImageFilter(params) {
|
|||
},
|
||||
|
||||
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,
|
||||
|
@ -255,7 +224,7 @@ export function GLImageFilter(params) {
|
|||
},
|
||||
|
||||
sepia: () => {
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
0.393, 0.7689999, 0.18899999, 0, 0,
|
||||
0.349, 0.6859999, 0.16799999, 0, 0,
|
||||
0.272, 0.5339999, 0.13099999, 0, 0,
|
||||
|
@ -264,7 +233,7 @@ export function GLImageFilter(params) {
|
|||
},
|
||||
|
||||
brownie: () => {
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
0.5997023498159715, 0.34553243048391263, -0.2708298674538042, 0, 47.43192855600873,
|
||||
-0.037703249837783157, 0.8609577587992641, 0.15059552388459913, 0, -36.96841498319127,
|
||||
0.24113635128153335, -0.07441037908422492, 0.44972182064877153, 0, -7.562075277591283,
|
||||
|
@ -273,7 +242,7 @@ export function GLImageFilter(params) {
|
|||
},
|
||||
|
||||
vintagePinhole: () => {
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
0.6279345635605994, 0.3202183420819367, -0.03965408211312453, 0, 9.651285835294123,
|
||||
0.02578397704808868, 0.6441188644374771, 0.03259127616149294, 0, 7.462829176470591,
|
||||
0.0466055556782719, -0.0851232987247891, 0.5241648018700465, 0, 5.159190588235296,
|
||||
|
@ -282,7 +251,7 @@ export function GLImageFilter(params) {
|
|||
},
|
||||
|
||||
kodachrome: () => {
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
1.1285582396593525, -0.3967382283601348, -0.03992559172921793, 0, 63.72958762196502,
|
||||
-0.16404339962244616, 1.0835251566291304, -0.05498805115633132, 0, 24.732407896706203,
|
||||
-0.16786010706155763, -0.5603416277695248, 1.6014850761964943, 0, 35.62982807460946,
|
||||
|
@ -291,7 +260,7 @@ export function GLImageFilter(params) {
|
|||
},
|
||||
|
||||
technicolor: () => {
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
1.9125277891456083, -0.8545344976951645, -0.09155508482755585, 0, 11.793603434377337,
|
||||
-0.3087833385928097, 1.7658908555458428, -0.10601743074722245, 0, -70.35205161461398,
|
||||
-0.231103377548616, -0.7501899197440212, 1.847597816108189, 0, 30.950940869491138,
|
||||
|
@ -300,7 +269,7 @@ export function GLImageFilter(params) {
|
|||
},
|
||||
|
||||
polaroid: () => {
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
1.438, -0.062, -0.062, 0, 0,
|
||||
-0.122, 1.378, -0.122, 0, 0,
|
||||
-0.016, -0.016, 1.483, 0, 0,
|
||||
|
@ -309,7 +278,7 @@ export function GLImageFilter(params) {
|
|||
},
|
||||
|
||||
shiftToBGR: () => {
|
||||
_filter.colorMatrix([
|
||||
filter.colorMatrix([
|
||||
0, 0, 1, 0, 0,
|
||||
0, 1, 0, 0, 0,
|
||||
1, 0, 0, 0, 0,
|
||||
|
@ -317,19 +286,19 @@ export function GLImageFilter(params) {
|
|||
]);
|
||||
},
|
||||
|
||||
// Convolution Filter
|
||||
convolution: (matrix) => {
|
||||
convolution: (matrix) => { // general convolution Filter
|
||||
const m = new Float32Array(matrix);
|
||||
const pixelSizeX = 1 / _width;
|
||||
const pixelSizeY = 1 / _height;
|
||||
const program = _compileShader(shaders.convolution);
|
||||
const pixelSizeX = 1 / canvas.width;
|
||||
const pixelSizeY = 1 / canvas.height;
|
||||
const program = compileShader(shaders.convolution);
|
||||
gl.uniform1fv(program?.uniform['m'], m);
|
||||
gl.uniform2f(program?.uniform['px'], pixelSizeX, pixelSizeY);
|
||||
_draw();
|
||||
draw();
|
||||
},
|
||||
|
||||
detectEdges: () => {
|
||||
_filter.convolution.call(this, [
|
||||
// @ts-ignore this
|
||||
filter.convolution.call(this, [
|
||||
0, 1, 0,
|
||||
1, -4, 1,
|
||||
0, 1, 0,
|
||||
|
@ -337,7 +306,8 @@ export function GLImageFilter(params) {
|
|||
},
|
||||
|
||||
sobelX: () => {
|
||||
_filter.convolution.call(this, [
|
||||
// @ts-ignore this
|
||||
filter.convolution.call(this, [
|
||||
-1, 0, 1,
|
||||
-2, 0, 2,
|
||||
-1, 0, 1,
|
||||
|
@ -345,7 +315,8 @@ export function GLImageFilter(params) {
|
|||
},
|
||||
|
||||
sobelY: () => {
|
||||
_filter.convolution.call(this, [
|
||||
// @ts-ignore this
|
||||
filter.convolution.call(this, [
|
||||
-1, -2, -1,
|
||||
0, 0, 0,
|
||||
1, 2, 1,
|
||||
|
@ -354,7 +325,8 @@ export function GLImageFilter(params) {
|
|||
|
||||
sharpen: (amount) => {
|
||||
const a = amount || 1;
|
||||
_filter.convolution.call(this, [
|
||||
// @ts-ignore this
|
||||
filter.convolution.call(this, [
|
||||
0, -1 * a, 0,
|
||||
-1 * a, 1 + 4 * a, -1 * a,
|
||||
0, -1 * a, 0,
|
||||
|
@ -363,33 +335,76 @@ export function GLImageFilter(params) {
|
|||
|
||||
emboss: (size) => {
|
||||
const s = size || 1;
|
||||
_filter.convolution.call(this, [
|
||||
// @ts-ignore this
|
||||
filter.convolution.call(this, [
|
||||
-2 * s, -1 * s, 0,
|
||||
-1 * s, 1, 1 * s,
|
||||
0, 1 * s, 2 * s,
|
||||
]);
|
||||
},
|
||||
|
||||
// Blur Filter
|
||||
blur: (size) => {
|
||||
const blurSizeX = (size / 7) / _width;
|
||||
const blurSizeY = (size / 7) / _height;
|
||||
const program = _compileShader(shaders.blur);
|
||||
const blurSizeX = (size / 7) / canvas.width;
|
||||
const blurSizeY = (size / 7) / canvas.height;
|
||||
const program = compileShader(shaders.blur);
|
||||
// Vertical
|
||||
gl.uniform2f(program?.uniform['px'], 0, blurSizeY);
|
||||
_draw(DRAW.INTERMEDIATE);
|
||||
draw(DRAW.INTERMEDIATE);
|
||||
// Horizontal
|
||||
gl.uniform2f(program?.uniform['px'], blurSizeX, 0);
|
||||
_draw();
|
||||
draw();
|
||||
},
|
||||
|
||||
// Pixelate Filter
|
||||
pixelate: (size) => {
|
||||
const blurSizeX = (size) / _width;
|
||||
const blurSizeY = (size) / _height;
|
||||
const program = _compileShader(shaders.pixelate);
|
||||
const blurSizeX = (size) / canvas.width;
|
||||
const blurSizeY = (size) / canvas.height;
|
||||
const program = compileShader(shaders.pixelate);
|
||||
gl.uniform2f(program?.uniform['size'], blurSizeX, blurSizeY);
|
||||
_draw();
|
||||
draw();
|
||||
},
|
||||
};
|
||||
|
||||
// @ts-ignore this
|
||||
this.add = function (name) {
|
||||
// eslint-disable-next-line prefer-rest-params
|
||||
const args = Array.prototype.slice.call(arguments, 1);
|
||||
const func = filter[name];
|
||||
filterChain.push({ func, args });
|
||||
};
|
||||
|
||||
// @ts-ignore this
|
||||
this.reset = function () {
|
||||
filterChain = [];
|
||||
};
|
||||
|
||||
// @ts-ignore this
|
||||
this.get = function () {
|
||||
return filterChain;
|
||||
};
|
||||
|
||||
// @ts-ignore this
|
||||
this.apply = function (image) {
|
||||
resize(image.width, image.height);
|
||||
drawCount = 0;
|
||||
if (!sourceTexture) sourceTexture = gl.createTexture(); // Create the texture for the input image if we haven't yet
|
||||
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_T, gl.CLAMP_TO_EDGE);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_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);
|
||||
for (let i = 0; i < filterChain.length; i++) {
|
||||
lastInChain = (i === filterChain.length - 1);
|
||||
const f = filterChain[i];
|
||||
// @ts-ignore function assigment
|
||||
f.func.apply(this, f.args || []);
|
||||
}
|
||||
return canvas;
|
||||
};
|
||||
|
||||
// @ts-ignore this
|
||||
this.draw = function (image) {
|
||||
this.add('brightness', 0);
|
||||
return this.apply(image);
|
||||
};
|
||||
}
|
||||
|
|
1355
test/build.log
1355
test/build.log
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue