mirror of
https://github.com/konvajs/konva.git
synced 2025-06-28 06:07:13 +08:00
refactor: change Filter input and output
This commit is contained in:
parent
583fccf249
commit
de580be9b5
49
src/Node.ts
49
src/Node.ts
@ -15,7 +15,8 @@ import { Context } from './Context';
|
|||||||
import { Shape } from './Shape';
|
import { Shape } from './Shape';
|
||||||
import { Layer } from './Layer';
|
import { Layer } from './Layer';
|
||||||
|
|
||||||
export type Filter = (this: Node, imageData: ImageData) => void;
|
export type LegalCanvas = HTMLCanvasElement | OffscreenCanvas;
|
||||||
|
export type Filter = (this: Node, canvas: LegalCanvas) => void;
|
||||||
|
|
||||||
type globalCompositeOperationType =
|
type globalCompositeOperationType =
|
||||||
| ''
|
| ''
|
||||||
@ -163,7 +164,7 @@ export abstract class Node<Config extends NodeConfig = NodeConfig> {
|
|||||||
_dragEventId: number | null = null;
|
_dragEventId: number | null = null;
|
||||||
_shouldFireChangeEvents = false;
|
_shouldFireChangeEvents = false;
|
||||||
|
|
||||||
constructor(config?: Config) {
|
constructor (config?: Config) {
|
||||||
// on initial set attrs wi don't need to fire change events
|
// on initial set attrs wi don't need to fire change events
|
||||||
// because nobody is listening to them yet
|
// because nobody is listening to them yet
|
||||||
this.setAttrs(config);
|
this.setAttrs(config);
|
||||||
@ -366,10 +367,10 @@ export abstract class Node<Config extends NodeConfig = NodeConfig> {
|
|||||||
// console.log({ x, y, width, height }, rect);
|
// console.log({ x, y, width, height }, rect);
|
||||||
|
|
||||||
var cachedSceneCanvas = new SceneCanvas({
|
var cachedSceneCanvas = new SceneCanvas({
|
||||||
pixelRatio: pixelRatio,
|
pixelRatio: pixelRatio,
|
||||||
width: width,
|
width: width,
|
||||||
height: height,
|
height: height,
|
||||||
}),
|
}),
|
||||||
cachedFilterCanvas = new SceneCanvas({
|
cachedFilterCanvas = new SceneCanvas({
|
||||||
pixelRatio: pixelRatio,
|
pixelRatio: pixelRatio,
|
||||||
width: 0,
|
width: 0,
|
||||||
@ -591,12 +592,7 @@ export abstract class Node<Config extends NodeConfig = NodeConfig> {
|
|||||||
sceneCanvas.getWidth() / ratio,
|
sceneCanvas.getWidth() / ratio,
|
||||||
sceneCanvas.getHeight() / ratio
|
sceneCanvas.getHeight() / ratio
|
||||||
);
|
);
|
||||||
imageData = filterContext.getImageData(
|
let canvas = Util.createOffScreenCanvas(filterCanvas.getWidth(), filterCanvas.getHeight());
|
||||||
0,
|
|
||||||
0,
|
|
||||||
filterCanvas.getWidth(),
|
|
||||||
filterCanvas.getHeight()
|
|
||||||
);
|
|
||||||
|
|
||||||
// apply filters to filter context
|
// apply filters to filter context
|
||||||
for (n = 0; n < len; n++) {
|
for (n = 0; n < len; n++) {
|
||||||
@ -604,19 +600,20 @@ export abstract class Node<Config extends NodeConfig = NodeConfig> {
|
|||||||
if (typeof filter !== 'function') {
|
if (typeof filter !== 'function') {
|
||||||
Util.error(
|
Util.error(
|
||||||
'Filter should be type of function, but got ' +
|
'Filter should be type of function, but got ' +
|
||||||
typeof filter +
|
typeof filter +
|
||||||
' instead. Please check correct filters'
|
' instead. Please check correct filters'
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
filter.call(this, imageData);
|
canvas = filter.call(this, canvas);
|
||||||
filterContext.putImageData(imageData, 0, 0);
|
|
||||||
}
|
}
|
||||||
|
// draw the final result on top of scene canvas
|
||||||
|
filterContext.drawImage(canvas, 0, 0);
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
Util.error(
|
Util.error(
|
||||||
'Unable to apply filter. ' +
|
'Unable to apply filter. ' +
|
||||||
e.message +
|
e.message +
|
||||||
' This post my help you https://konvajs.org/docs/posts/Tainted_Canvas.html.'
|
' This post my help you https://konvajs.org/docs/posts/Tainted_Canvas.html.'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1435,10 +1432,10 @@ export abstract class Node<Config extends NodeConfig = NodeConfig> {
|
|||||||
if (zIndex < 0 || zIndex >= this.parent.children.length) {
|
if (zIndex < 0 || zIndex >= this.parent.children.length) {
|
||||||
Util.warn(
|
Util.warn(
|
||||||
'Unexpected value ' +
|
'Unexpected value ' +
|
||||||
zIndex +
|
zIndex +
|
||||||
' for zIndex property. zIndex is just index of a node in children of its parent. Expected value is from 0 to ' +
|
' for zIndex property. zIndex is just index of a node in children of its parent. Expected value is from 0 to ' +
|
||||||
(this.parent.children.length - 1) +
|
(this.parent.children.length - 1) +
|
||||||
'.'
|
'.'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
var index = this.index;
|
var index = this.index;
|
||||||
@ -1619,8 +1616,8 @@ export abstract class Node<Config extends NodeConfig = NodeConfig> {
|
|||||||
if (!Util.isValidSelector(sel)) {
|
if (!Util.isValidSelector(sel)) {
|
||||||
Util.warn(
|
Util.warn(
|
||||||
'Selector "' +
|
'Selector "' +
|
||||||
sel +
|
sel +
|
||||||
'" is invalid. Allowed selectors examples are "#foo", ".bar" or "Group".'
|
'" is invalid. Allowed selectors examples are "#foo", ".bar" or "Group".'
|
||||||
);
|
);
|
||||||
Util.warn(
|
Util.warn(
|
||||||
'If you have a custom shape with such className, please change it to start with upper letter like "Triangle".'
|
'If you have a custom shape with such className, please change it to start with upper letter like "Triangle".'
|
||||||
@ -2714,8 +2711,8 @@ export abstract class Node<Config extends NodeConfig = NodeConfig> {
|
|||||||
if (!Konva[className]) {
|
if (!Konva[className]) {
|
||||||
Util.warn(
|
Util.warn(
|
||||||
'Can not find a node with class name "' +
|
'Can not find a node with class name "' +
|
||||||
className +
|
className +
|
||||||
'". Fallback to "Shape".'
|
'". Fallback to "Shape".'
|
||||||
);
|
);
|
||||||
className = 'Shape';
|
className = 'Shape';
|
||||||
}
|
}
|
||||||
|
15
src/Util.ts
15
src/Util.ts
@ -29,7 +29,7 @@ import { IRect, RGB, RGBA, Vector2d } from './types';
|
|||||||
export class Transform {
|
export class Transform {
|
||||||
m: Array<number>;
|
m: Array<number>;
|
||||||
dirty = false;
|
dirty = false;
|
||||||
constructor(m = [1, 0, 0, 1, 0, 0]) {
|
constructor (m = [1, 0, 0, 1, 0, 0]) {
|
||||||
this.m = (m && m.slice()) || [1, 0, 0, 1, 0, 0];
|
this.m = (m && m.slice()) || [1, 0, 0, 1, 0, 0];
|
||||||
}
|
}
|
||||||
reset() {
|
reset() {
|
||||||
@ -509,9 +509,18 @@ export const Util = {
|
|||||||
// on some environments canvas.style is readonly
|
// on some environments canvas.style is readonly
|
||||||
try {
|
try {
|
||||||
(<any>canvas).style = canvas.style || {};
|
(<any>canvas).style = canvas.style || {};
|
||||||
} catch (e) {}
|
} catch (e) { }
|
||||||
return canvas;
|
return canvas;
|
||||||
},
|
},
|
||||||
|
createOffScreenCanvas(size: { width: number; height: number }) {
|
||||||
|
if (window.OffscreenCanvas !== undefined) {
|
||||||
|
return new OffscreenCanvas(size.width, size.height);
|
||||||
|
}
|
||||||
|
const canvas = this.createCanvasElement();
|
||||||
|
canvas.width = size.width;
|
||||||
|
canvas.height = size.height;
|
||||||
|
return canvas;
|
||||||
|
}
|
||||||
createImageElement() {
|
createImageElement() {
|
||||||
return document.createElement('img');
|
return document.createElement('img');
|
||||||
},
|
},
|
||||||
@ -1005,7 +1014,7 @@ export const Util = {
|
|||||||
topRight =
|
topRight =
|
||||||
bottomLeft =
|
bottomLeft =
|
||||||
bottomRight =
|
bottomRight =
|
||||||
Math.min(cornerRadius, width / 2, height / 2);
|
Math.min(cornerRadius, width / 2, height / 2);
|
||||||
} else {
|
} else {
|
||||||
topLeft = Math.min(cornerRadius[0] || 0, width / 2, height / 2);
|
topLeft = Math.min(cornerRadius[0] || 0, width / 2, height / 2);
|
||||||
topRight = Math.min(cornerRadius[1] || 0, width / 2, height / 2);
|
topRight = Math.min(cornerRadius[1] || 0, width / 2, height / 2);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Factory } from '../Factory';
|
import { Factory } from '../Factory';
|
||||||
import { Node, Filter } from '../Node';
|
import { Node, Filter, LegalCanvas } from '../Node';
|
||||||
import { getNumberValidator } from '../Validators';
|
import { getNumberValidator } from '../Validators';
|
||||||
/*
|
/*
|
||||||
the Gauss filter
|
the Gauss filter
|
||||||
@ -154,7 +154,7 @@ function filterGaussBlurRGBA(imageData, radius) {
|
|||||||
g_sum =
|
g_sum =
|
||||||
b_sum =
|
b_sum =
|
||||||
a_sum =
|
a_sum =
|
||||||
0;
|
0;
|
||||||
|
|
||||||
r_out_sum = radiusPlus1 * (pr = pixels[yi]);
|
r_out_sum = radiusPlus1 * (pr = pixels[yi]);
|
||||||
g_out_sum = radiusPlus1 * (pg = pixels[yi + 1]);
|
g_out_sum = radiusPlus1 * (pg = pixels[yi + 1]);
|
||||||
@ -254,7 +254,7 @@ function filterGaussBlurRGBA(imageData, radius) {
|
|||||||
b_sum =
|
b_sum =
|
||||||
a_sum =
|
a_sum =
|
||||||
r_sum =
|
r_sum =
|
||||||
0;
|
0;
|
||||||
|
|
||||||
yi = x << 2;
|
yi = x << 2;
|
||||||
r_out_sum = radiusPlus1 * (pr = pixels[yi]);
|
r_out_sum = radiusPlus1 * (pr = pixels[yi]);
|
||||||
@ -358,15 +358,20 @@ function filterGaussBlurRGBA(imageData, radius) {
|
|||||||
* @function
|
* @function
|
||||||
* @name Blur
|
* @name Blur
|
||||||
* @memberof Konva.Filters
|
* @memberof Konva.Filters
|
||||||
* @param {Object} imageData
|
* * @param {LegalCanvas} canvas
|
||||||
* @example
|
* @example
|
||||||
* node.cache();
|
* node.cache();
|
||||||
* node.filters([Konva.Filters.Blur]);
|
* node.filters([Konva.Filters.Blur]);
|
||||||
* node.blurRadius(10);
|
* node.blurRadius(10);
|
||||||
*/
|
*/
|
||||||
export const Blur: Filter = function Blur(imageData) {
|
export const Blur: Filter = function Blur(canvas: LegalCanvas) {
|
||||||
var radius = Math.round(this.blurRadius());
|
var radius = Math.round(this.blurRadius());
|
||||||
|
const imageData = canvas.context.getImageData(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
canvas.width,
|
||||||
|
canvas.height
|
||||||
|
);
|
||||||
if (radius > 0) {
|
if (radius > 0) {
|
||||||
filterGaussBlurRGBA(imageData, radius);
|
filterGaussBlurRGBA(imageData, radius);
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,24 @@
|
|||||||
import { Factory } from '../Factory';
|
import { Factory } from '../Factory';
|
||||||
import { Node, Filter } from '../Node';
|
import { Node, Filter, LegalCanvas } from '../Node';
|
||||||
import { getNumberValidator } from '../Validators';
|
import { getNumberValidator } from '../Validators';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Brighten Filter.
|
* Brighten Filter.
|
||||||
* @function
|
* @function
|
||||||
* @memberof Konva.Filters
|
* @memberof Konva.Filters
|
||||||
* @param {Object} imageData
|
* * @param {LegalCanvas} canvas
|
||||||
* @example
|
* @example
|
||||||
* node.cache();
|
* node.cache();
|
||||||
* node.filters([Konva.Filters.Brighten]);
|
* node.filters([Konva.Filters.Brighten]);
|
||||||
* node.brightness(0.8);
|
* node.brightness(0.8);
|
||||||
*/
|
*/
|
||||||
export const Brighten: Filter = function (imageData) {
|
export const Brighten: Filter = function (canvas: LegalCanvas) {
|
||||||
|
const imageData = canvas.context.getImageData(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
canvas.width,
|
||||||
|
canvas.height
|
||||||
|
);
|
||||||
var brightness = this.brightness() * 255,
|
var brightness = this.brightness() * 255,
|
||||||
data = imageData.data,
|
data = imageData.data,
|
||||||
len = data.length,
|
len = data.length,
|
||||||
@ -26,6 +32,9 @@ export const Brighten: Filter = function (imageData) {
|
|||||||
// blue
|
// blue
|
||||||
data[i + 2] += brightness;
|
data[i + 2] += brightness;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
canvas.context.putImageData(imageData, 0, 0);
|
||||||
|
return canvas;
|
||||||
};
|
};
|
||||||
|
|
||||||
Factory.addGetterSetter(
|
Factory.addGetterSetter(
|
||||||
|
@ -1,18 +1,24 @@
|
|||||||
import { Factory } from '../Factory';
|
import { Factory } from '../Factory';
|
||||||
import { Node, Filter } from '../Node';
|
import { Node, Filter, LegalCanvas } from '../Node';
|
||||||
import { getNumberValidator } from '../Validators';
|
import { getNumberValidator } from '../Validators';
|
||||||
/**
|
/**
|
||||||
* Contrast Filter.
|
* Contrast Filter.
|
||||||
* @function
|
* @function
|
||||||
* @memberof Konva.Filters
|
* @memberof Konva.Filters
|
||||||
* @param {Object} imageData
|
* * @param {LegalCanvas} canvas
|
||||||
* @example
|
* @example
|
||||||
* node.cache();
|
* node.cache();
|
||||||
* node.filters([Konva.Filters.Contrast]);
|
* node.filters([Konva.Filters.Contrast]);
|
||||||
* node.contrast(10);
|
* node.contrast(10);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export const Contrast: Filter = function (imageData) {
|
export const Contrast: Filter = function (canvas: LegalCanvas) {
|
||||||
|
const imageData = canvas.context.getImageData(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
canvas.width,
|
||||||
|
canvas.height
|
||||||
|
);
|
||||||
var adjust = Math.pow((this.contrast() + 100) / 100, 2);
|
var adjust = Math.pow((this.contrast() + 100) / 100, 2);
|
||||||
|
|
||||||
var data = imageData.data,
|
var data = imageData.data,
|
||||||
@ -56,6 +62,9 @@ export const Contrast: Filter = function (imageData) {
|
|||||||
data[i + 1] = green;
|
data[i + 1] = green;
|
||||||
data[i + 2] = blue;
|
data[i + 2] = blue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
canvas.context.putImageData(imageData, 0, 0);
|
||||||
|
return canvas;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Factory } from '../Factory';
|
import { Factory } from '../Factory';
|
||||||
import { Node, Filter } from '../Node';
|
import { Node, Filter, LegalCanvas } from '../Node';
|
||||||
import { Util } from '../Util';
|
import { Util } from '../Util';
|
||||||
import { getNumberValidator } from '../Validators';
|
import { getNumberValidator } from '../Validators';
|
||||||
/**
|
/**
|
||||||
@ -9,7 +9,7 @@ import { getNumberValidator } from '../Validators';
|
|||||||
* License: [http://www.pixastic.com/lib/license.txt]
|
* License: [http://www.pixastic.com/lib/license.txt]
|
||||||
* @function
|
* @function
|
||||||
* @memberof Konva.Filters
|
* @memberof Konva.Filters
|
||||||
* @param {Object} imageData
|
* * @param {LegalCanvas} canvas
|
||||||
* @example
|
* @example
|
||||||
* node.cache();
|
* node.cache();
|
||||||
* node.filters([Konva.Filters.Emboss]);
|
* node.filters([Konva.Filters.Emboss]);
|
||||||
@ -18,11 +18,17 @@ import { getNumberValidator } from '../Validators';
|
|||||||
* node.embossDirection('right');
|
* node.embossDirection('right');
|
||||||
* node.embossBlend(true);
|
* node.embossBlend(true);
|
||||||
*/
|
*/
|
||||||
export const Emboss: Filter = function (imageData) {
|
export const Emboss: Filter = function (canvas: LegalCanvas) {
|
||||||
// pixastic strength is between 0 and 10. I want it between 0 and 1
|
// pixastic strength is between 0 and 10. I want it between 0 and 1
|
||||||
// pixastic greyLevel is between 0 and 255. I want it between 0 and 1. Also,
|
// pixastic greyLevel is between 0 and 255. I want it between 0 and 1. Also,
|
||||||
// a max value of greyLevel yields a white emboss, and the min value yields a black
|
// a max value of greyLevel yields a white emboss, and the min value yields a black
|
||||||
// emboss. Therefore, I changed greyLevel to whiteLevel
|
// emboss. Therefore, I changed greyLevel to whiteLevel
|
||||||
|
const imageData = canvas.context.getImageData(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
canvas.width,
|
||||||
|
canvas.height
|
||||||
|
);
|
||||||
var strength = this.embossStrength() * 10,
|
var strength = this.embossStrength() * 10,
|
||||||
greyLevel = this.embossWhiteLevel() * 255,
|
greyLevel = this.embossWhiteLevel() * 255,
|
||||||
direction = this.embossDirection(),
|
direction = this.embossDirection(),
|
||||||
@ -138,6 +144,9 @@ export const Emboss: Filter = function (imageData) {
|
|||||||
}
|
}
|
||||||
} while (--x);
|
} while (--x);
|
||||||
} while (--y);
|
} while (--y);
|
||||||
|
|
||||||
|
canvas.context.putImageData(imageData, 0, 0);
|
||||||
|
return canvas;
|
||||||
};
|
};
|
||||||
|
|
||||||
Factory.addGetterSetter(
|
Factory.addGetterSetter(
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Factory } from '../Factory';
|
import { Factory } from '../Factory';
|
||||||
import { Node, Filter } from '../Node';
|
import { Node, Filter, LegalCanvas } from '../Node';
|
||||||
import { getNumberValidator } from '../Validators';
|
import { getNumberValidator } from '../Validators';
|
||||||
|
|
||||||
function remap(fromValue, fromMin, fromMax, toMin, toMax) {
|
function remap(fromValue, fromMin, fromMax, toMin, toMax) {
|
||||||
@ -30,14 +30,20 @@ function remap(fromValue, fromMin, fromMax, toMin, toMax) {
|
|||||||
* @function
|
* @function
|
||||||
* @name Enhance
|
* @name Enhance
|
||||||
* @memberof Konva.Filters
|
* @memberof Konva.Filters
|
||||||
* @param {Object} imageData
|
* * @param {LegalCanvas} canvas
|
||||||
* @author ippo615
|
* @author ippo615
|
||||||
* @example
|
* @example
|
||||||
* node.cache();
|
* node.cache();
|
||||||
* node.filters([Konva.Filters.Enhance]);
|
* node.filters([Konva.Filters.Enhance]);
|
||||||
* node.enhance(0.4);
|
* node.enhance(0.4);
|
||||||
*/
|
*/
|
||||||
export const Enhance: Filter = function (imageData) {
|
export const Enhance: Filter = function (canvas: LegalCanvas) {
|
||||||
|
const imageData = canvas.context.getImageData(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
canvas.width,
|
||||||
|
canvas.height
|
||||||
|
);
|
||||||
var data = imageData.data,
|
var data = imageData.data,
|
||||||
nSubPixels = data.length,
|
nSubPixels = data.length,
|
||||||
rMin = data[0],
|
rMin = data[0],
|
||||||
@ -134,6 +140,8 @@ export const Enhance: Filter = function (imageData) {
|
|||||||
data[i + 2] = remap(data[i + 2], bMin, bMax, bGoalMin, bGoalMax);
|
data[i + 2] = remap(data[i + 2], bMin, bMax, bGoalMin, bGoalMax);
|
||||||
//data[i + 3] = remap(data[i + 3], aMin, aMax, aGoalMin, aGoalMax);
|
//data[i + 3] = remap(data[i + 3], aMin, aMax, aGoalMin, aGoalMax);
|
||||||
}
|
}
|
||||||
|
canvas.context.putImageData(imageData, 0, 0);
|
||||||
|
return canvas;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,15 +1,21 @@
|
|||||||
import { Filter } from '../Node';
|
import { Filter, LegalCanvas } from '../Node';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Grayscale Filter
|
* Grayscale Filter
|
||||||
* @function
|
* @function
|
||||||
* @memberof Konva.Filters
|
* @memberof Konva.Filters
|
||||||
* @param {Object} imageData
|
* * @param {LegalCanvas} canvas
|
||||||
* @example
|
* @example
|
||||||
* node.cache();
|
* node.cache();
|
||||||
* node.filters([Konva.Filters.Grayscale]);
|
* node.filters([Konva.Filters.Grayscale]);
|
||||||
*/
|
*/
|
||||||
export const Grayscale: Filter = function (imageData) {
|
export const Grayscale: Filter = function (canvas: LegalCanvas) {
|
||||||
|
const imageData = canvas.context.getImageData(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
canvas.width,
|
||||||
|
canvas.height
|
||||||
|
);
|
||||||
var data = imageData.data,
|
var data = imageData.data,
|
||||||
len = data.length,
|
len = data.length,
|
||||||
i,
|
i,
|
||||||
@ -24,4 +30,6 @@ export const Grayscale: Filter = function (imageData) {
|
|||||||
// blue
|
// blue
|
||||||
data[i + 2] = brightness;
|
data[i + 2] = brightness;
|
||||||
}
|
}
|
||||||
|
canvas.context.putImageData(imageData, 0, 0);
|
||||||
|
return canvas;
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Factory } from '../Factory';
|
import { Factory } from '../Factory';
|
||||||
import { Node, Filter } from '../Node';
|
import { Node, Filter, LegalCanvas } from '../Node';
|
||||||
import { getNumberValidator } from '../Validators';
|
import { getNumberValidator } from '../Validators';
|
||||||
|
|
||||||
Factory.addGetterSetter(
|
Factory.addGetterSetter(
|
||||||
@ -51,14 +51,20 @@ Factory.addGetterSetter(
|
|||||||
* HSL Filter. Adjusts the hue, saturation and luminance (or lightness)
|
* HSL Filter. Adjusts the hue, saturation and luminance (or lightness)
|
||||||
* @function
|
* @function
|
||||||
* @memberof Konva.Filters
|
* @memberof Konva.Filters
|
||||||
* @param {Object} imageData
|
* * @param {LegalCanvas} canvas
|
||||||
* @author ippo615
|
* @author ippo615
|
||||||
* @example
|
* @example
|
||||||
* image.filters([Konva.Filters.HSL]);
|
* image.filters([Konva.Filters.HSL]);
|
||||||
* image.luminance(0.2);
|
* image.luminance(0.2);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export const HSL: Filter = function (imageData) {
|
export const HSL: Filter = function (canvas: LegalCanvas) {
|
||||||
|
const imageData = canvas.context.getImageData(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
canvas.width,
|
||||||
|
canvas.height
|
||||||
|
);
|
||||||
var data = imageData.data,
|
var data = imageData.data,
|
||||||
nPixels = data.length,
|
nPixels = data.length,
|
||||||
v = 1,
|
v = 1,
|
||||||
@ -105,4 +111,6 @@ export const HSL: Filter = function (imageData) {
|
|||||||
data[i + 2] = br * r + bg * g + bb * b + l;
|
data[i + 2] = br * r + bg * g + bb * b + l;
|
||||||
data[i + 3] = a; // alpha
|
data[i + 3] = a; // alpha
|
||||||
}
|
}
|
||||||
|
canvas.context.putImageData(imageData, 0, 0);
|
||||||
|
return canvas;
|
||||||
};
|
};
|
||||||
|
@ -7,14 +7,20 @@ import { getNumberValidator } from '../Validators';
|
|||||||
* @function
|
* @function
|
||||||
* @name HSV
|
* @name HSV
|
||||||
* @memberof Konva.Filters
|
* @memberof Konva.Filters
|
||||||
* @param {Object} imageData
|
* * @param {LegalCanvas} canvas
|
||||||
* @author ippo615
|
* @author ippo615
|
||||||
* @example
|
* @example
|
||||||
* image.filters([Konva.Filters.HSV]);
|
* image.filters([Konva.Filters.HSV]);
|
||||||
* image.value(200);
|
* image.value(200);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export const HSV: Filter = function (imageData) {
|
export const HSV: Filter = function (canvas: LegalCanvas) {
|
||||||
|
const imageData = canvas.context.getImageData(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
canvas.width,
|
||||||
|
canvas.height
|
||||||
|
);
|
||||||
var data = imageData.data,
|
var data = imageData.data,
|
||||||
nPixels = data.length,
|
nPixels = data.length,
|
||||||
v = Math.pow(2, this.value()),
|
v = Math.pow(2, this.value()),
|
||||||
@ -60,6 +66,8 @@ export const HSV: Filter = function (imageData) {
|
|||||||
data[i + 2] = br * r + bg * g + bb * b;
|
data[i + 2] = br * r + bg * g + bb * b;
|
||||||
data[i + 3] = a; // alpha
|
data[i + 3] = a; // alpha
|
||||||
}
|
}
|
||||||
|
canvas.context.putImageData(imageData, 0, 0);
|
||||||
|
return canvas;
|
||||||
};
|
};
|
||||||
|
|
||||||
Factory.addGetterSetter(
|
Factory.addGetterSetter(
|
||||||
|
@ -3,12 +3,18 @@ import { Filter } from '../Node';
|
|||||||
* Invert Filter
|
* Invert Filter
|
||||||
* @function
|
* @function
|
||||||
* @memberof Konva.Filters
|
* @memberof Konva.Filters
|
||||||
* @param {Object} imageData
|
* * @param {LegalCanvas} canvas
|
||||||
* @example
|
* @example
|
||||||
* node.cache();
|
* node.cache();
|
||||||
* node.filters([Konva.Filters.Invert]);
|
* node.filters([Konva.Filters.Invert]);
|
||||||
*/
|
*/
|
||||||
export const Invert: Filter = function (imageData) {
|
export const Invert: Filter = function (canvas: LegalCanvas) {
|
||||||
|
const imageData = canvas.context.getImageData(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
canvas.width,
|
||||||
|
canvas.height
|
||||||
|
);
|
||||||
var data = imageData.data,
|
var data = imageData.data,
|
||||||
len = data.length,
|
len = data.length,
|
||||||
i;
|
i;
|
||||||
@ -21,4 +27,6 @@ export const Invert: Filter = function (imageData) {
|
|||||||
// blue
|
// blue
|
||||||
data[i + 2] = 255 - data[i + 2];
|
data[i + 2] = 255 - data[i + 2];
|
||||||
}
|
}
|
||||||
|
canvas.context.putImageData(imageData, 0, 0);
|
||||||
|
return canvas;
|
||||||
};
|
};
|
||||||
|
@ -177,7 +177,13 @@ var FromPolar = function (src, dst, opt) {
|
|||||||
* node.kaleidoscopePower(3);
|
* node.kaleidoscopePower(3);
|
||||||
* node.kaleidoscopeAngle(45);
|
* node.kaleidoscopeAngle(45);
|
||||||
*/
|
*/
|
||||||
export const Kaleidoscope: Filter = function (imageData) {
|
export const Kaleidoscope: Filter = function (canvas: LegalCanvas) {
|
||||||
|
const imageData = canvas.context.getImageData(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
canvas.width,
|
||||||
|
canvas.height
|
||||||
|
);
|
||||||
var xSize = imageData.width,
|
var xSize = imageData.width,
|
||||||
ySize = imageData.height;
|
ySize = imageData.height;
|
||||||
|
|
||||||
@ -263,6 +269,8 @@ export const Kaleidoscope: Filter = function (imageData) {
|
|||||||
|
|
||||||
// Convert back from polar coordinates
|
// Convert back from polar coordinates
|
||||||
FromPolar(scratchData, imageData, { polarRotation: 0 });
|
FromPolar(scratchData, imageData, { polarRotation: 0 });
|
||||||
|
canvas.context.putImageData(imageData, 0, 0);
|
||||||
|
return canvas;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Factory } from '../Factory';
|
import { Factory } from '../Factory';
|
||||||
import { Node, Filter } from '../Node';
|
import { Node, Filter, LegalCanvas } from '../Node';
|
||||||
import { getNumberValidator } from '../Validators';
|
import { getNumberValidator } from '../Validators';
|
||||||
|
|
||||||
function pixelAt(idata, x, y) {
|
function pixelAt(idata, x, y) {
|
||||||
@ -17,8 +17,8 @@ function pixelAt(idata, x, y) {
|
|||||||
function rgbDistance(p1, p2) {
|
function rgbDistance(p1, p2) {
|
||||||
return Math.sqrt(
|
return Math.sqrt(
|
||||||
Math.pow(p1[0] - p2[0], 2) +
|
Math.pow(p1[0] - p2[0], 2) +
|
||||||
Math.pow(p1[1] - p2[1], 2) +
|
Math.pow(p1[1] - p2[1], 2) +
|
||||||
Math.pow(p1[2] - p2[2], 2)
|
Math.pow(p1[2] - p2[2], 2)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,13 +173,19 @@ function smoothEdgeMask(mask, sw, sh) {
|
|||||||
* @function
|
* @function
|
||||||
* @name Mask
|
* @name Mask
|
||||||
* @memberof Konva.Filters
|
* @memberof Konva.Filters
|
||||||
* @param {Object} imageData
|
* * @param {LegalCanvas} canvas
|
||||||
* @example
|
* @example
|
||||||
* node.cache();
|
* node.cache();
|
||||||
* node.filters([Konva.Filters.Mask]);
|
* node.filters([Konva.Filters.Mask]);
|
||||||
* node.threshold(200);
|
* node.threshold(200);
|
||||||
*/
|
*/
|
||||||
export const Mask: Filter = function (imageData) {
|
export const Mask: Filter = function (canvas: LegalCanvas) {
|
||||||
|
const imageData = canvas.context.getImageData(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
canvas.width,
|
||||||
|
canvas.height
|
||||||
|
);
|
||||||
// Detect pixels close to the background color
|
// Detect pixels close to the background color
|
||||||
var threshold = this.threshold(),
|
var threshold = this.threshold(),
|
||||||
mask = backgroundMask(imageData, threshold);
|
mask = backgroundMask(imageData, threshold);
|
||||||
@ -197,7 +203,8 @@ export const Mask: Filter = function (imageData) {
|
|||||||
applyMask(imageData, mask);
|
applyMask(imageData, mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
return imageData;
|
canvas.context.putImageData(imageData, 0, 0);
|
||||||
|
return canvas;
|
||||||
};
|
};
|
||||||
|
|
||||||
Factory.addGetterSetter(
|
Factory.addGetterSetter(
|
||||||
|
@ -7,14 +7,20 @@ import { getNumberValidator } from '../Validators';
|
|||||||
* @function
|
* @function
|
||||||
* @name Noise
|
* @name Noise
|
||||||
* @memberof Konva.Filters
|
* @memberof Konva.Filters
|
||||||
* @param {Object} imageData
|
* * @param {LegalCanvas} canvas
|
||||||
* @author ippo615
|
* @author ippo615
|
||||||
* @example
|
* @example
|
||||||
* node.cache();
|
* node.cache();
|
||||||
* node.filters([Konva.Filters.Noise]);
|
* node.filters([Konva.Filters.Noise]);
|
||||||
* node.noise(0.8);
|
* node.noise(0.8);
|
||||||
*/
|
*/
|
||||||
export const Noise: Filter = function (imageData) {
|
export const Noise: Filter = function (canvas: LegalCanvas) {
|
||||||
|
const imageData = canvas.context.getImageData(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
canvas.width,
|
||||||
|
canvas.height
|
||||||
|
);
|
||||||
var amount = this.noise() * 255,
|
var amount = this.noise() * 255,
|
||||||
data = imageData.data,
|
data = imageData.data,
|
||||||
nPixels = data.length,
|
nPixels = data.length,
|
||||||
@ -26,6 +32,8 @@ export const Noise: Filter = function (imageData) {
|
|||||||
data[i + 1] += half - 2 * half * Math.random();
|
data[i + 1] += half - 2 * half * Math.random();
|
||||||
data[i + 2] += half - 2 * half * Math.random();
|
data[i + 2] += half - 2 * half * Math.random();
|
||||||
}
|
}
|
||||||
|
canvas.context.putImageData(imageData, 0, 0);
|
||||||
|
return canvas;
|
||||||
};
|
};
|
||||||
|
|
||||||
Factory.addGetterSetter(
|
Factory.addGetterSetter(
|
||||||
|
@ -10,7 +10,7 @@ import { getNumberValidator } from '../Validators';
|
|||||||
* @function
|
* @function
|
||||||
* @name Pixelate
|
* @name Pixelate
|
||||||
* @memberof Konva.Filters
|
* @memberof Konva.Filters
|
||||||
* @param {Object} imageData
|
* * @param {LegalCanvas} canvas
|
||||||
* @author ippo615
|
* @author ippo615
|
||||||
* @example
|
* @example
|
||||||
* node.cache();
|
* node.cache();
|
||||||
@ -18,7 +18,13 @@ import { getNumberValidator } from '../Validators';
|
|||||||
* node.pixelSize(10);
|
* node.pixelSize(10);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export const Pixelate: Filter = function (imageData) {
|
export const Pixelate: Filter = function (canvas: LegalCanvas) {
|
||||||
|
const imageData = canvas.context.getImageData(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
canvas.width,
|
||||||
|
canvas.height
|
||||||
|
);
|
||||||
var pixelSize = Math.ceil(this.pixelSize()),
|
var pixelSize = Math.ceil(this.pixelSize()),
|
||||||
width = imageData.width,
|
width = imageData.width,
|
||||||
height = imageData.height,
|
height = imageData.height,
|
||||||
@ -103,6 +109,9 @@ export const Pixelate: Filter = function (imageData) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
canvas.context.putImageData(imageData, 0, 0);
|
||||||
|
return canvas;
|
||||||
};
|
};
|
||||||
|
|
||||||
Factory.addGetterSetter(
|
Factory.addGetterSetter(
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Factory } from '../Factory';
|
import { Factory } from '../Factory';
|
||||||
import { Node, Filter } from '../Node';
|
import { Node, Filter, LegalCanvas } from '../Node';
|
||||||
import { getNumberValidator } from '../Validators';
|
import { getNumberValidator } from '../Validators';
|
||||||
/**
|
/**
|
||||||
* Posterize Filter. Adjusts the channels so that there are no more
|
* Posterize Filter. Adjusts the channels so that there are no more
|
||||||
@ -9,14 +9,20 @@ import { getNumberValidator } from '../Validators';
|
|||||||
* @name Posterize
|
* @name Posterize
|
||||||
* @author ippo615
|
* @author ippo615
|
||||||
* @memberof Konva.Filters
|
* @memberof Konva.Filters
|
||||||
* @param {Object} imageData
|
* * @param {LegalCanvas} canvas
|
||||||
* @example
|
* @example
|
||||||
* node.cache();
|
* node.cache();
|
||||||
* node.filters([Konva.Filters.Posterize]);
|
* node.filters([Konva.Filters.Posterize]);
|
||||||
* node.levels(0.8); // between 0 and 1
|
* node.levels(0.8); // between 0 and 1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export const Posterize: Filter = function (imageData) {
|
export const Posterize: Filter = function (canvas: LegalCanvas) {
|
||||||
|
const imageData = canvas.context.getImageData(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
canvas.width,
|
||||||
|
canvas.height
|
||||||
|
);
|
||||||
// level must be between 1 and 255
|
// level must be between 1 and 255
|
||||||
var levels = Math.round(this.levels() * 254) + 1,
|
var levels = Math.round(this.levels() * 254) + 1,
|
||||||
data = imageData.data,
|
data = imageData.data,
|
||||||
@ -27,6 +33,8 @@ export const Posterize: Filter = function (imageData) {
|
|||||||
for (i = 0; i < len; i += 1) {
|
for (i = 0; i < len; i += 1) {
|
||||||
data[i] = Math.floor(data[i] / scale) * scale;
|
data[i] = Math.floor(data[i] / scale) * scale;
|
||||||
}
|
}
|
||||||
|
canvas.context.putImageData(imageData, 0, 0);
|
||||||
|
return canvas;
|
||||||
};
|
};
|
||||||
|
|
||||||
Factory.addGetterSetter(
|
Factory.addGetterSetter(
|
||||||
|
@ -7,7 +7,7 @@ import { RGBComponent } from '../Validators';
|
|||||||
* @function
|
* @function
|
||||||
* @name RGB
|
* @name RGB
|
||||||
* @memberof Konva.Filters
|
* @memberof Konva.Filters
|
||||||
* @param {Object} imageData
|
* * @param {LegalCanvas} canvas
|
||||||
* @author ippo615
|
* @author ippo615
|
||||||
* @example
|
* @example
|
||||||
* node.cache();
|
* node.cache();
|
||||||
@ -16,7 +16,13 @@ import { RGBComponent } from '../Validators';
|
|||||||
* node.green(200);
|
* node.green(200);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export const RGB: Filter = function (imageData) {
|
export const RGB: Filter = function (canvas: LegalCanvas) {
|
||||||
|
const imageData = canvas.context.getImageData(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
canvas.width,
|
||||||
|
canvas.height
|
||||||
|
);
|
||||||
var data = imageData.data,
|
var data = imageData.data,
|
||||||
nPixels = data.length,
|
nPixels = data.length,
|
||||||
red = this.red(),
|
red = this.red(),
|
||||||
@ -33,6 +39,8 @@ export const RGB: Filter = function (imageData) {
|
|||||||
data[i + 2] = brightness * blue; // b
|
data[i + 2] = brightness * blue; // b
|
||||||
data[i + 3] = data[i + 3]; // alpha
|
data[i + 3] = data[i + 3]; // alpha
|
||||||
}
|
}
|
||||||
|
canvas.context.putImageData(imageData, 0, 0);
|
||||||
|
return canvas;
|
||||||
};
|
};
|
||||||
|
|
||||||
Factory.addGetterSetter(Node, 'red', 0, function (this: Node, val) {
|
Factory.addGetterSetter(Node, 'red', 0, function (this: Node, val) {
|
||||||
|
@ -7,7 +7,7 @@ import { RGBComponent } from '../Validators';
|
|||||||
* @function
|
* @function
|
||||||
* @name RGBA
|
* @name RGBA
|
||||||
* @memberof Konva.Filters
|
* @memberof Konva.Filters
|
||||||
* @param {Object} imageData
|
* * @param {LegalCanvas} canvas
|
||||||
* @author codefo
|
* @author codefo
|
||||||
* @example
|
* @example
|
||||||
* node.cache();
|
* node.cache();
|
||||||
@ -17,7 +17,13 @@ import { RGBComponent } from '../Validators';
|
|||||||
* node.alpha(0.3);
|
* node.alpha(0.3);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export const RGBA: Filter = function (imageData) {
|
export const RGBA: Filter = function (canvas: LegalCanvas) {
|
||||||
|
const imageData = canvas.context.getImageData(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
canvas.width,
|
||||||
|
canvas.height
|
||||||
|
);
|
||||||
var data = imageData.data,
|
var data = imageData.data,
|
||||||
nPixels = data.length,
|
nPixels = data.length,
|
||||||
red = this.red(),
|
red = this.red(),
|
||||||
@ -34,6 +40,8 @@ export const RGBA: Filter = function (imageData) {
|
|||||||
data[i + 1] = green * alpha + data[i + 1] * ia; // g
|
data[i + 1] = green * alpha + data[i + 1] * ia; // g
|
||||||
data[i + 2] = blue * alpha + data[i + 2] * ia; // b
|
data[i + 2] = blue * alpha + data[i + 2] * ia; // b
|
||||||
}
|
}
|
||||||
|
canvas.context.putImageData(imageData, 0, 0);
|
||||||
|
return canvas;
|
||||||
};
|
};
|
||||||
|
|
||||||
Factory.addGetterSetter(Node, 'red', 0, function (this: Node, val: number) {
|
Factory.addGetterSetter(Node, 'red', 0, function (this: Node, val: number) {
|
||||||
|
@ -6,12 +6,18 @@ import { Filter } from '../Node';
|
|||||||
* @function
|
* @function
|
||||||
* @name Sepia
|
* @name Sepia
|
||||||
* @memberof Konva.Filters
|
* @memberof Konva.Filters
|
||||||
* @param {Object} imageData
|
* * @param {LegalCanvas} canvas
|
||||||
* @example
|
* @example
|
||||||
* node.cache();
|
* node.cache();
|
||||||
* node.filters([Konva.Filters.Sepia]);
|
* node.filters([Konva.Filters.Sepia]);
|
||||||
*/
|
*/
|
||||||
export const Sepia: Filter = function (imageData) {
|
export const Sepia: Filter = function (canvas: LegalCanvas) {
|
||||||
|
const imageData = canvas.context.getImageData(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
canvas.width,
|
||||||
|
canvas.height
|
||||||
|
);
|
||||||
var data = imageData.data,
|
var data = imageData.data,
|
||||||
nPixels = data.length,
|
nPixels = data.length,
|
||||||
i,
|
i,
|
||||||
@ -28,4 +34,6 @@ export const Sepia: Filter = function (imageData) {
|
|||||||
data[i + 1] = Math.min(255, r * 0.349 + g * 0.686 + b * 0.168);
|
data[i + 1] = Math.min(255, r * 0.349 + g * 0.686 + b * 0.168);
|
||||||
data[i + 2] = Math.min(255, r * 0.272 + g * 0.534 + b * 0.131);
|
data[i + 2] = Math.min(255, r * 0.272 + g * 0.534 + b * 0.131);
|
||||||
}
|
}
|
||||||
|
canvas.context.putImageData(imageData, 0, 0);
|
||||||
|
return canvas;
|
||||||
};
|
};
|
||||||
|
@ -7,13 +7,19 @@ import { Filter } from '../Node';
|
|||||||
* @function
|
* @function
|
||||||
* @name Solarize
|
* @name Solarize
|
||||||
* @memberof Konva.Filters
|
* @memberof Konva.Filters
|
||||||
* @param {Object} imageData
|
* * @param {LegalCanvas} canvas
|
||||||
* @example
|
* @example
|
||||||
* node.cache();
|
* node.cache();
|
||||||
* node.filters([Konva.Filters.Solarize]);
|
* node.filters([Konva.Filters.Solarize]);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export const Solarize: Filter = function (imageData) {
|
export const Solarize: Filter = function (canvas: LegalCanvas) {
|
||||||
|
const imageData = canvas.context.getImageData(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
canvas.width,
|
||||||
|
canvas.height
|
||||||
|
);
|
||||||
var data = imageData.data,
|
var data = imageData.data,
|
||||||
w = imageData.width,
|
w = imageData.width,
|
||||||
h = imageData.height,
|
h = imageData.height,
|
||||||
@ -44,4 +50,6 @@ export const Solarize: Filter = function (imageData) {
|
|||||||
data[offset + 2] = b;
|
data[offset + 2] = b;
|
||||||
} while (--x);
|
} while (--x);
|
||||||
} while (--y);
|
} while (--y);
|
||||||
|
canvas.context.putImageData(imageData, 0, 0);
|
||||||
|
return canvas;
|
||||||
};
|
};
|
||||||
|
@ -8,7 +8,7 @@ import { getNumberValidator } from '../Validators';
|
|||||||
* @function
|
* @function
|
||||||
* @name Threshold
|
* @name Threshold
|
||||||
* @memberof Konva.Filters
|
* @memberof Konva.Filters
|
||||||
* @param {Object} imageData
|
* * @param {LegalCanvas} canvas
|
||||||
* @author ippo615
|
* @author ippo615
|
||||||
* @example
|
* @example
|
||||||
* node.cache();
|
* node.cache();
|
||||||
@ -16,7 +16,13 @@ import { getNumberValidator } from '../Validators';
|
|||||||
* node.threshold(0.1);
|
* node.threshold(0.1);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export const Threshold: Filter = function (imageData) {
|
export const Threshold: Filter = function (canvas: LegalCanvas) {
|
||||||
|
const imageData = canvas.context.getImageData(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
canvas.width,
|
||||||
|
canvas.height
|
||||||
|
);
|
||||||
var level = this.threshold() * 255,
|
var level = this.threshold() * 255,
|
||||||
data = imageData.data,
|
data = imageData.data,
|
||||||
len = data.length,
|
len = data.length,
|
||||||
@ -25,6 +31,8 @@ export const Threshold: Filter = function (imageData) {
|
|||||||
for (i = 0; i < len; i += 1) {
|
for (i = 0; i < len; i += 1) {
|
||||||
data[i] = data[i] < level ? 0 : 255;
|
data[i] = data[i] < level ? 0 : 255;
|
||||||
}
|
}
|
||||||
|
canvas.context.putImageData(imageData, 0, 0);
|
||||||
|
return canvas;
|
||||||
};
|
};
|
||||||
|
|
||||||
Factory.addGetterSetter(
|
Factory.addGetterSetter(
|
||||||
|
Loading…
Reference in New Issue
Block a user