fabric
Version:
Object model for HTML5 canvas, and SVG-to-canvas parser. Backed by jsdom and node-canvas.
1,880 lines (1,398 loc) • 50.6 kB
text/typescript
import { describe, it, expect } from 'vitest';
import { BlendColor } from '../filters/BlendColor';
import { Brightness } from '../filters/Brightness';
import { Composed } from '../filters/Composed';
import { ColorMatrix } from '../filters/ColorMatrix';
import { HueRotation } from '../filters/HueRotation';
import { Contrast } from '../filters/Contrast';
import { Saturation } from '../filters/Saturation';
import { Gamma } from '../filters/Gamma';
import { Convolute } from '../filters/Convolute';
import { Grayscale } from '../filters/Grayscale';
import { Invert } from '../filters/Invert';
import { Noise } from '../filters/Noise';
import { Pixelate } from '../filters/Pixelate';
import { RemoveColor } from '../filters/RemoveColor';
import { Sepia } from '../filters/ColorMatrixFilters';
import { Resize } from '../filters/Resize';
import { Vibrance } from '../filters/Vibrance';
import { getFabricDocument } from '../env';
import { Blur } from '../filters/Blur';
import type { T2DPipelineState } from '../filters';
const canvas = getFabricDocument().createElement('canvas');
const context = canvas.getContext('2d')!;
function _createImageData(context: CanvasRenderingContext2D) {
const imageData = context.createImageData(3, 1);
imageData.data[0] = 200;
imageData.data[1] = 100;
imageData.data[2] = 50;
imageData.data[3] = 1;
imageData.data[4] = 30;
imageData.data[5] = 255;
imageData.data[6] = 10;
imageData.data[7] = 1;
imageData.data[8] = 255;
imageData.data[9] = 255;
imageData.data[10] = 3;
imageData.data[11] = 1;
return imageData;
}
describe('Image filters', () => {
describe('Brightness', () => {
it('constructor', () => {
expect(Brightness, 'Brightness filter should exist').toBeTruthy();
const filter = new Brightness();
expect(filter, 'should inherit from Brightness').toBeInstanceOf(
Brightness,
);
});
it('properties', () => {
const filter = new Brightness();
expect(filter.type, 'type should be Brightness').toBe('Brightness');
expect(filter.brightness, 'default brightness should be 0').toBe(0);
const filter2 = new Brightness({ brightness: 0.12 });
expect(
filter2.brightness,
'brightness should match constructor value',
).toBe(0.12);
});
it('applyTo2d', () => {
const filter = new Brightness();
expect(filter.applyTo2d, 'should have applyTo2d method').toBeTypeOf(
'function',
);
});
it('applyTo2d values', () => {
const filter = new Brightness({ brightness: 0.2 });
const options = {
imageData: _createImageData(context),
} as T2DPipelineState;
filter.applyTo2d(options);
const data = options.imageData.data;
const expected = [251, 151, 101, 1, 81, 255, 61, 1, 255, 255, 54, 1];
for (let i = 0; i < 12; i++) {
expect(data[i], `data[${i}] should match expected value`).toBe(
expected[i],
);
}
});
it('toObject', () => {
const filter = new Brightness();
expect(filter.toObject, 'should have toObject method').toBeTypeOf(
'function',
);
let object = filter.toObject();
expect(
JSON.stringify(object),
'serialized object should match expected value',
).toBe('{"type":"Brightness","brightness":0}');
filter.brightness = 100;
object = filter.toObject();
expect(
JSON.stringify(object),
'serialized object with brightness 100 should match expected value',
).toBe('{"type":"Brightness","brightness":100}');
});
it('toJSON', () => {
const filter = new Brightness();
expect(filter.toJSON, 'should have toJSON method').toBeTypeOf('function');
let json = filter.toJSON();
expect(
JSON.stringify(json),
'JSON representation should match expected value',
).toBe('{"type":"Brightness","brightness":0}');
filter.brightness = 100;
json = filter.toJSON();
expect(
JSON.stringify(json),
'JSON representation with brightness 100 should match expected value',
).toBe('{"type":"Brightness","brightness":100}');
});
it('fromObject', async () => {
const filter = new Brightness();
const object = filter.toObject();
const newFilter = await Brightness.fromObject(object);
expect(newFilter, 'enlived filter should match original').toEqual(filter);
});
it('isNeutralState', () => {
const filter = new Brightness();
expect(
filter.isNeutralState(),
'should be neutral when brightness is 0',
).toBeTruthy();
filter.brightness = 0.15;
expect(
filter.isNeutralState(),
'should not be neutral when brightness changes',
).toBeFalsy();
});
});
describe('Composed', () => {
it('constructor', () => {
expect(Composed, 'Composed filter should exist').toBeTruthy();
const filter = new Composed();
expect(filter, 'should inherit from Composed').toBeInstanceOf(Composed);
});
it('properties', () => {
const filter = new Composed();
expect(filter.type, 'type should be Composed').toBe('Composed');
});
it('toObject', () => {
const filter = new Composed();
expect(filter.toObject, 'should have toObject method').toBeTypeOf(
'function',
);
const object = filter.toObject();
expect(
JSON.stringify(object),
'serialized object should match expected value',
).toBe('{"type":"Composed","subFilters":[]}');
});
it('toObject with subfilters', () => {
const filter = new Composed();
const brightness = new Brightness();
const contrast = new Contrast();
filter.subFilters.push(brightness);
filter.subFilters.push(contrast);
const contrastObj = contrast.toObject();
const brightnessObj = brightness.toObject();
const object = filter.toObject();
expect(object.subFilters.length, 'there should be 2 subfilters').toBe(2);
expect(
object.subFilters[0],
'the first subfilter should be serialized',
).toEqual(brightnessObj);
expect(
object.subFilters[1],
'the second subfilter should be serialized',
).toEqual(contrastObj);
});
it('toJSON', () => {
const filter2 = new Composed();
expect(filter2.toJSON, 'should have toJSON method').toBeTypeOf(
'function',
);
const json = filter2.toJSON();
expect(
JSON.stringify(json),
'JSON representation should match expected value',
).toBe('{"type":"Composed","subFilters":[]}');
});
it('fromObject', async () => {
const filter = new Composed();
const object = filter.toObject();
const restoredFilters = await Composed.fromObject(object);
expect(restoredFilters, 'restored filter should match original').toEqual(
filter,
);
});
it('fromObject with subfilters', async () => {
const filter = new Composed();
const brightness = new Brightness();
const contrast = new Contrast();
filter.subFilters.push(brightness);
filter.subFilters.push(contrast);
const toObject = filter.toObject();
const newFilter = await Composed.fromObject(toObject);
expect(newFilter, 'should inherit from Composed').toBeInstanceOf(
Composed,
);
expect(
newFilter.subFilters[0],
'should inherit from Brightness',
).toBeInstanceOf(Brightness);
expect(
newFilter.subFilters[1],
'should inherit from Contrast',
).toBeInstanceOf(Contrast);
});
it('isNeutralState', () => {
const filter = new Composed();
const brightness = new Brightness();
const contrast = new Contrast();
filter.subFilters.push(brightness);
filter.subFilters.push(contrast);
expect(
filter.isNeutralState(),
'should be neutral when all filters are neutral',
).toBeTruthy();
(filter.subFilters[0] as Brightness).brightness = 0.15;
expect(
filter.isNeutralState(),
'should not be neutral when one subfilter changes',
).toBeFalsy();
});
});
describe('ColorMatrix', () => {
it('constructor', () => {
expect(ColorMatrix, 'ColorMatrix filter should exist').toBeTruthy();
const filter = new ColorMatrix();
expect(filter, 'should inherit from ColorMatrix').toBeInstanceOf(
ColorMatrix,
);
});
it('properties', () => {
const filter = new ColorMatrix();
expect(filter.type, 'type should be ColorMatrix').toBe('ColorMatrix');
expect(
filter.matrix,
'default matrix should match expected values',
).toEqual([1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0]);
const filter2 = new ColorMatrix({
matrix: [
0, 1, 0, 0, 0.2, 0, 0, 1, 0, 0.1, 1, 0, 0, 0, 0.3, 0, 0, 0, 1, 0,
],
});
expect(filter2.matrix, 'matrix should match constructor value').toEqual([
0, 1, 0, 0, 0.2, 0, 0, 1, 0, 0.1, 1, 0, 0, 0, 0.3, 0, 0, 0, 1, 0,
]);
});
it('applyTo2d', () => {
const filter = new ColorMatrix();
expect(filter.applyTo2d, 'should have applyTo2d method').toBeTypeOf(
'function',
);
});
it('applyTo2d values', () => {
const filter = new ColorMatrix({
matrix: [
0, 1, 0, 0, 0.2, 0, 0, 1, 0, 0.1, 1, 0, 0, 0, 0.3, 0, 0, 0, 1, 0,
],
});
const options = {
imageData: _createImageData(context),
} as T2DPipelineState;
filter.applyTo2d(options);
const data = options.imageData.data;
const expected = [151, 76, 255, 1, 255, 36, 106, 1, 255, 28, 255, 1];
for (let i = 0; i < 12; i++) {
expect(data[i], `data[${i}] should match expected value`).toBe(
expected[i],
);
}
});
it('toObject', () => {
const filter = new ColorMatrix();
expect(filter.toObject, 'should have toObject method').toBeTypeOf(
'function',
);
let object = filter.toObject();
expect(
JSON.stringify(object),
'serialized object should match expected value',
).toBe(
'{"type":"ColorMatrix","matrix":[1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0],"colorsOnly":true}',
);
filter.matrix = [
0, 1, 0, 0, 0.2, 0, 0, 1, 0, 0.1, 1, 0, 0, 0, 0.3, 0, 0, 0, 1, 0,
];
object = filter.toObject();
expect(
JSON.stringify(object),
'serialized object with custom matrix should match expected value',
).toBe(
'{"type":"ColorMatrix","matrix":[0,1,0,0,0.2,0,0,1,0,0.1,1,0,0,0,0.3,0,0,0,1,0],"colorsOnly":true}',
);
});
it('toJSON', () => {
const filter = new ColorMatrix();
expect(filter.toJSON, 'should have toJSON method').toBeTypeOf('function');
let json = filter.toJSON();
expect(
JSON.stringify(json),
'JSON representation should match expected value',
).toBe(
'{"type":"ColorMatrix","matrix":[1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0],"colorsOnly":true}',
);
filter.matrix = [
0, 1, 0, 0, 0.2, 0, 0, 1, 0, 0.1, 1, 0, 0, 0, 0.3, 0, 0, 0, 1, 0,
];
filter.colorsOnly = false;
json = filter.toJSON();
expect(
JSON.stringify(json),
'JSON representation with custom matrix should match expected value',
).toBe(
'{"type":"ColorMatrix","matrix":[0,1,0,0,0.2,0,0,1,0,0.1,1,0,0,0,0.3,0,0,0,1,0],"colorsOnly":false}',
);
});
it('fromObject', async () => {
const filter = new ColorMatrix();
const object = filter.toObject();
const restoredFilter = await ColorMatrix.fromObject(object);
expect(restoredFilter, 'restored filter should match original').toEqual(
filter,
);
});
});
describe('HueRotation', () => {
it('constructor', () => {
expect(HueRotation, 'HueRotation filter should exist').toBeTruthy();
const filter = new HueRotation();
expect(filter, 'should inherit from ColorMatrix').toBeInstanceOf(
ColorMatrix,
);
expect(filter, 'should inherit from HueRotation').toBeInstanceOf(
HueRotation,
);
});
it('properties', () => {
const filter = new HueRotation();
expect(filter.type, 'type should be HueRotation').toBe('HueRotation');
expect(filter.rotation, 'default rotation should be 0').toBe(0);
const filter2 = new HueRotation({ rotation: 0.5 });
expect(filter2.rotation, 'rotation should match constructor value').toBe(
0.5,
);
});
it('applyTo2d', () => {
const filter = new HueRotation();
expect(filter.applyTo2d, 'should have applyTo2d method').toBeTypeOf(
'function',
);
});
it('applyTo2d values', () => {
const filter = new HueRotation({ rotation: 0.5 });
const options = {
imageData: _createImageData(context),
} as T2DPipelineState;
filter.calculateMatrix();
filter.applyTo2d(options);
const data = options.imageData.data;
const expected = [88, 203, 59, 1, 0, 110, 228, 1, 26, 255, 171, 1];
for (let i = 0; i < 12; i++) {
expect(data[i], `data[${i}] should match expected value`).toBe(
expected[i],
);
}
});
it('toObject', () => {
const filter = new HueRotation();
expect(filter.toObject, 'should have toObject method').toBeTypeOf(
'function',
);
let object = filter.toObject();
expect(
JSON.stringify(object),
'serialized object should match expected value',
).toBe('{"type":"HueRotation","rotation":0}');
filter.rotation = 0.6;
object = filter.toObject();
expect(
JSON.stringify(object),
'serialized object with rotation 0.6 should match expected value',
).toBe('{"type":"HueRotation","rotation":0.6}');
});
it('toJSON', () => {
const filter = new HueRotation();
expect(filter.toJSON, 'should have toJSON method').toBeTypeOf('function');
let json = filter.toJSON();
expect(
JSON.stringify(json),
'JSON representation should match expected value',
).toBe('{"type":"HueRotation","rotation":0}');
filter.rotation = 0.3;
json = filter.toJSON();
expect(
JSON.stringify(json),
'JSON representation with rotation 0.3 should match expected value',
).toBe('{"type":"HueRotation","rotation":0.3}');
});
it('fromObject', async () => {
const filter = new HueRotation();
const object = filter.toObject();
const restoredFilter = await HueRotation.fromObject(object);
expect(restoredFilter, 'restored filter should match original').toEqual(
filter,
);
});
it('isNeutralState', () => {
const filter = new HueRotation();
expect(
filter.isNeutralState(),
'should be neutral when rotation is 0',
).toBeTruthy();
filter.rotation = 0.6;
expect(
filter.isNeutralState(),
'should not be neutral when rotation changes',
).toBeFalsy();
});
});
describe('Contrast', () => {
it('constructor', () => {
expect(Contrast, 'Contrast filter should exist').toBeTruthy();
const filter = new Contrast();
expect(filter, 'should inherit from Contrast').toBeInstanceOf(Contrast);
});
it('properties', () => {
const filter = new Contrast();
expect(filter.type, 'type should be Contrast').toBe('Contrast');
expect(filter.contrast, 'default contrast should be 0').toBe(0);
const filter2 = new Contrast({ contrast: 0.12 });
expect(filter2.contrast, 'contrast should match constructor value').toBe(
0.12,
);
});
it('applyTo2d', () => {
const filter = new Contrast();
expect(filter.applyTo2d, 'should have applyTo2d method').toBeTypeOf(
'function',
);
});
it('applyTo2d values', () => {
const filter = new Contrast({ contrast: 0.2 });
const options = {
imageData: _createImageData(context),
} as T2DPipelineState;
filter.applyTo2d(options);
const data = options.imageData.data;
const expected = [236, 86, 11, 1, 0, 255, 0, 1, 255, 255, 0, 1];
for (let i = 0; i < 12; i++) {
expect(data[i], `data[${i}] should match expected value`).toBe(
expected[i],
);
}
});
it('toObject', () => {
const filter = new Contrast();
expect(filter.toObject, 'should have toObject method').toBeTypeOf(
'function',
);
let object = filter.toObject();
expect(
JSON.stringify(object),
'serialized object should match expected value',
).toBe('{"type":"Contrast","contrast":0}');
filter.contrast = 100;
object = filter.toObject();
expect(
JSON.stringify(object),
'serialized object with contrast 100 should match expected value',
).toBe('{"type":"Contrast","contrast":100}');
});
it('toJSON', () => {
const filter = new Contrast();
expect(filter.toJSON, 'should have toJSON method').toBeTypeOf('function');
let json = filter.toJSON();
expect(
JSON.stringify(json),
'JSON representation should match expected value',
).toBe('{"type":"Contrast","contrast":0}');
filter.contrast = 100;
json = filter.toJSON();
expect(
JSON.stringify(json),
'JSON representation with contrast 100 should match expected value',
).toBe('{"type":"Contrast","contrast":100}');
});
it('fromObject', async () => {
const filter = new Contrast();
const object = filter.toObject();
const restoredFilter = await Contrast.fromObject(object);
expect(restoredFilter, 'restored filter should match original').toEqual(
filter,
);
});
it('isNeutralState', () => {
const filter = new Contrast();
expect(
filter.isNeutralState(),
'should be neutral when contrast is 0',
).toBeTruthy();
filter.contrast = 0.6;
expect(
filter.isNeutralState(),
'should not be neutral when contrast changes',
).toBeFalsy();
});
});
describe('Saturation', () => {
it('constructor', () => {
expect(Saturation, 'Saturation filter should exist').toBeTruthy();
const filter = new Saturation();
expect(filter, 'should inherit from Saturation').toBeInstanceOf(
Saturation,
);
});
it('properties', () => {
const filter = new Saturation();
expect(filter.type, 'type should be Saturation').toBe('Saturation');
expect(filter.saturation, 'default saturation should be 0').toBe(0);
const filter2 = new Saturation({ saturation: 0.12 });
expect(
filter2.saturation,
'saturation should match constructor value',
).toBe(0.12);
});
it('applyTo2d', () => {
const filter = new Saturation();
expect(filter.applyTo2d, 'should have applyTo2d method').toBeTypeOf(
'function',
);
});
it('applyTo2d values Saturation', () => {
const filter = new Saturation({ saturation: 0.2 });
const options = {
imageData: _createImageData(context),
} as T2DPipelineState;
filter.applyTo2d(options);
const data = options.imageData.data;
const expected = [200, 80, 20, 1, 0, 255, 0, 1, 255, 255, 0, 1];
for (let i = 0; i < 12; i++) {
expect(data[i], `data[${i}] should match expected value`).toBe(
expected[i],
);
}
});
it('toObject', () => {
const filter = new Saturation();
expect(filter.toObject, 'should have toObject method').toBeTypeOf(
'function',
);
let object = filter.toObject();
expect(
JSON.stringify(object),
'serialized object should match expected value',
).toBe('{"type":"Saturation","saturation":0}');
filter.saturation = 100;
object = filter.toObject();
expect(
JSON.stringify(object),
'serialized object with saturation 100 should match expected value',
).toBe('{"type":"Saturation","saturation":100}');
});
it('toJSON', () => {
const filter = new Saturation();
expect(filter.toJSON, 'should have toJSON method').toBeTypeOf('function');
let json = filter.toJSON();
expect(
JSON.stringify(json),
'JSON representation should match expected value',
).toBe('{"type":"Saturation","saturation":0}');
filter.saturation = 100;
json = filter.toJSON();
expect(
JSON.stringify(json),
'JSON representation with saturation 100 should match expected value',
).toBe('{"type":"Saturation","saturation":100}');
});
it('fromObject', async () => {
const filter = new Saturation();
const object = filter.toObject();
const restoredFilter = await Saturation.fromObject(object);
expect(restoredFilter, 'restored filter should match original').toEqual(
filter,
);
});
it('isNeutralState', () => {
const filter = new Saturation();
expect(
filter.isNeutralState(),
'should be neutral when saturation is 0',
).toBeTruthy();
filter.saturation = 0.6;
expect(
filter.isNeutralState(),
'should not be neutral when saturation changes',
).toBeFalsy();
});
});
describe('Gamma', () => {
it('constructor', () => {
expect(Gamma, 'Gamma filter should exist').toBeTruthy();
const filter = new Gamma();
expect(filter, 'should inherit from Gamma').toBeInstanceOf(Gamma);
});
it('properties', () => {
const filter = new Gamma();
expect(filter.type, 'type should be Gamma').toBe('Gamma');
expect(
filter.gamma,
'default gamma should match expected values',
).toEqual([1, 1, 1]);
const filter2 = new Gamma({ gamma: [0.1, 0.5, 1.3] });
expect(filter2.gamma, 'gamma should match constructor value').toEqual([
0.1, 0.5, 1.3,
]);
});
it('applyTo2d', () => {
const filter = new Gamma();
expect(filter.applyTo2d, 'should have applyTo2d method').toBeTypeOf(
'function',
);
});
it('applyTo2d values', () => {
const filter = new Gamma({ gamma: [0.1, 0.5, 1.3] });
const options = {
imageData: _createImageData(context),
} as T2DPipelineState;
filter.applyTo2d(options);
const data = options.imageData.data;
const expected = [22, 39, 72, 1, 0, 255, 21, 1, 255, 255, 8, 1];
for (let i = 0; i < 12; i++) {
expect(data[i], `data[${i}] should match expected value`).toBe(
expected[i],
);
}
});
it('toObject', () => {
const filter = new Gamma();
expect(filter.toObject, 'should have toObject method').toBeTypeOf(
'function',
);
let object = filter.toObject();
expect(
JSON.stringify(object),
'serialized object should match expected value',
).toBe('{"type":"Gamma","gamma":[1,1,1]}');
filter.gamma = [0.1, 0.5, 1.3];
object = filter.toObject();
expect(
JSON.stringify(object),
'serialized object with custom gamma should match expected value',
).toBe('{"type":"Gamma","gamma":[0.1,0.5,1.3]}');
});
it('toJSON', () => {
const filter = new Gamma();
expect(filter.toJSON, 'should have toJSON method').toBeTypeOf('function');
let json = filter.toJSON();
expect(
JSON.stringify(json),
'JSON representation should match expected value',
).toBe('{"type":"Gamma","gamma":[1,1,1]}');
filter.gamma = [1.5, 1.5, 1.5];
json = filter.toJSON();
expect(
JSON.stringify(json),
'JSON representation with gamma [1.5, 1.5, 1.5] should match expected value',
).toBe('{"type":"Gamma","gamma":[1.5,1.5,1.5]}');
});
it('fromObject', async () => {
const filter = new Gamma();
const object = filter.toObject();
const restoredFilter = await Gamma.fromObject(object);
expect(restoredFilter, 'restored filter should match original').toEqual(
filter,
);
});
it('isNeutralState', () => {
const filter = new Gamma();
expect(
filter.isNeutralState(),
'should be neutral when gamma is [1,1,1]',
).toBeTruthy();
filter.gamma = [1.5, 1.5, 1.5];
expect(
filter.isNeutralState(),
'should not be neutral when gamma changes',
).toBeFalsy();
});
});
describe('Convolute', () => {
it('constructor', () => {
expect(Convolute, 'Convolute filter should exist').toBeTruthy();
const filter = new Convolute();
expect(filter, 'should inherit from Convolute').toBeInstanceOf(Convolute);
});
it('properties', () => {
const filter = new Convolute();
expect(filter.type, 'type should be Convolute').toBe('Convolute');
expect(filter.opaque, 'default opaque should be false').toBe(false);
expect(
filter.matrix,
'default matrix should match expected values',
).toEqual([0, 0, 0, 0, 1, 0, 0, 0, 0]);
const filter2 = new Convolute({
// @ts-expect-error -- TODO -- check this why 1 is passed instead of boolean
opaque: 0.5,
matrix: [1, -1, 1, 0, 1, 0, 0, 0, 0],
});
expect(filter2.opaque, 'opaque should match constructor value').toBe(0.5);
expect(filter2.matrix, 'matrix should match constructor value').toEqual([
1, -1, 1, 0, 1, 0, 0, 0, 0,
]);
});
it('applyTo2d', () => {
const filter = new Convolute();
expect(filter.applyTo2d, 'should have applyTo2d method').toBeTypeOf(
'function',
);
});
it('toObject', () => {
const filter = new Convolute({ opaque: true });
expect(filter.toObject, 'should have toObject method').toBeTypeOf(
'function',
);
const object = filter.toObject();
expect(
JSON.stringify(object),
'serialized object should match expected value',
).toBe('{"type":"Convolute","opaque":true,"matrix":[0,0,0,0,1,0,0,0,0]}');
});
it('toJSON', () => {
const filter = new Convolute({ opaque: true });
expect(filter.toJSON, 'should have toJSON method').toBeTypeOf('function');
const json = filter.toJSON();
expect(
JSON.stringify(json),
'JSON representation should match expected value',
).toBe('{"type":"Convolute","opaque":true,"matrix":[0,0,0,0,1,0,0,0,0]}');
});
it('fromObject', async () => {
const filter = new Convolute();
const object = filter.toObject();
const restoredFilter = await Convolute.fromObject(object);
expect(restoredFilter, 'restored filter should match original').toEqual(
filter,
);
});
it('isNeutralState', () => {
const filter = new Convolute();
expect(filter.isNeutralState(), 'should never be neutral').toBeFalsy();
});
});
describe('Grayscale', () => {
it('constructor', () => {
expect(Grayscale, 'Grayscale filter should exist').toBeTruthy();
const filter = new Grayscale();
expect(filter, 'should inherit from Grayscale').toBeInstanceOf(Grayscale);
});
it('properties', () => {
const filter = new Grayscale();
expect(filter.type, 'type should be Grayscale').toBe('Grayscale');
});
it('applyTo2d', () => {
const filter = new Grayscale();
expect(filter.applyTo2d, 'should have applyTo2d method').toBeTypeOf(
'function',
);
});
it('applyTo2d values Grayscale average', () => {
const filter = new Grayscale({ mode: 'average' });
const options = {
imageData: _createImageData(context),
} as T2DPipelineState;
filter.applyTo2d(options);
const data = options.imageData.data;
const expected = [117, 117, 117, 1, 98, 98, 98, 1, 171, 171, 171, 1];
for (let i = 0; i < 12; i++) {
expect(data[i], `data[${i}] should match expected value`).toBe(
expected[i],
);
}
});
it('applyTo2d values Grayscale lightness', () => {
const filter = new Grayscale({ mode: 'lightness' });
const options = {
imageData: _createImageData(context),
} as T2DPipelineState;
filter.applyTo2d(options);
const data = options.imageData.data;
const expected = [125, 125, 125, 1, 132, 132, 132, 1, 129, 129, 129, 1];
for (let i = 0; i < 12; i++) {
expect(data[i], `data[${i}] should match expected value`).toBe(
expected[i],
);
}
});
it('applyTo2d values Grayscale luminosity', () => {
const filter = new Grayscale({ mode: 'luminosity' });
const options = {
imageData: _createImageData(context),
} as T2DPipelineState;
filter.applyTo2d(options);
const data = options.imageData.data;
const expected = [118, 118, 118, 1, 191, 191, 191, 1, 237, 237, 237, 1];
for (let i = 0; i < 12; i++) {
expect(data[i], `data[${i}] should match expected value`).toBe(
expected[i],
);
}
});
it('toObject', () => {
const filter = new Grayscale({ mode: 'lightness' });
expect(filter.toObject, 'should have toObject method').toBeTypeOf(
'function',
);
const object = filter.toObject();
expect(
JSON.stringify(object),
'serialized object should match expected value',
).toBe('{"type":"Grayscale","mode":"lightness"}');
});
it('toJSON', () => {
const filter = new Grayscale();
expect(filter.toJSON, 'should have toJSON method').toBeTypeOf('function');
const json = filter.toJSON();
expect(
JSON.stringify(json),
'JSON representation should match expected value',
).toBe('{"type":"Grayscale","mode":"average"}');
});
it('fromObject', async () => {
const filter = new Grayscale();
const object = filter.toObject();
const restoredFilter = await Grayscale.fromObject(object);
expect(restoredFilter, 'restored filter should match original').toEqual(
filter,
);
});
it('isNeutralState', () => {
const filter = new Grayscale();
expect(filter.isNeutralState(), 'should never be neutral').toBeFalsy();
});
});
describe('Invert', () => {
it('constructor', () => {
expect(Invert, 'Invert filter should exist').toBeTruthy();
const filter = new Invert();
expect(filter, 'should inherit from Invert').toBeInstanceOf(Invert);
});
it('properties', () => {
const filter = new Invert();
expect(filter.type, 'type should be Invert').toBe('Invert');
});
it('applyTo2d', () => {
const filter = new Invert();
expect(filter.applyTo2d, 'should have applyTo2d method').toBeTypeOf(
'function',
);
});
it('applyTo2d values Invert', () => {
const filter = new Invert();
const options = {
imageData: _createImageData(context),
} as T2DPipelineState;
filter.applyTo2d(options);
const data = options.imageData.data;
const expected = [55, 155, 205, 1, 225, 0, 245, 1, 0, 0, 252, 1];
for (let i = 0; i < 12; i++) {
expect(data[i], `data[${i}] should match expected value`).toBe(
expected[i],
);
}
});
it('toObject', () => {
const filter = new Invert();
expect(filter.toObject, 'should have toObject method').toBeTypeOf(
'function',
);
const object = filter.toObject();
expect(
JSON.stringify(object),
'serialized object should match expected value',
).toBe('{"type":"Invert","alpha":false,"invert":true}');
});
it('toJSON', () => {
const filter = new Invert({ alpha: true });
expect(filter.toJSON, 'should have toJSON method').toBeTypeOf('function');
const json = filter.toJSON();
expect(
JSON.stringify(json),
'JSON representation should match expected value',
).toBe('{"type":"Invert","alpha":true,"invert":true}');
});
it('fromObject', async () => {
const filter = new Invert();
const object = filter.toObject();
const restoredFilter = await Invert.fromObject(object);
expect(restoredFilter, 'restored filter should match original').toEqual(
filter,
);
});
it('isNeutralState', () => {
const filter = new Invert();
expect(
filter.isNeutralState(),
'should not be neutral when default',
).toBeFalsy();
filter.invert = false;
expect(
filter.isNeutralState(),
'should be neutral when invert is false',
).toBeTruthy();
});
});
describe('Noise', () => {
it('constructor', () => {
expect(Noise, 'Noise filter should exist').toBeTruthy();
const filter = new Noise();
expect(filter, 'should inherit from Noise').toBeInstanceOf(Noise);
});
it('properties', () => {
const filter = new Noise();
expect(filter.type, 'type should be Noise').toBe('Noise');
expect(filter.noise, 'default noise should be 0').toBe(0);
const filter2 = new Noise({ noise: 200 });
expect(filter2.noise, 'noise should match constructor value').toBe(200);
});
it('applyTo2d', () => {
const filter = new Noise();
expect(filter.applyTo2d, 'should have applyTo2d method').toBeTypeOf(
'function',
);
});
it('toObject', () => {
const filter = new Noise();
expect(filter.toObject, 'should have toObject method').toBeTypeOf(
'function',
);
let object = filter.toObject();
expect(
JSON.stringify(object),
'serialized object should match expected value',
).toBe('{"type":"Noise","noise":0}');
filter.noise = 100;
object = filter.toObject();
expect(
JSON.stringify(object),
'serialized object with noise 100 should match expected value',
).toBe('{"type":"Noise","noise":100}');
});
it('toJSON', () => {
const filter = new Noise();
expect(filter.toJSON, 'should have toJSON method').toBeTypeOf('function');
let json = filter.toJSON();
expect(
JSON.stringify(json),
'JSON representation should match expected value',
).toBe('{"type":"Noise","noise":0}');
filter.noise = 100;
json = filter.toJSON();
expect(
JSON.stringify(json),
'JSON representation with noise 100 should match expected value',
).toBe('{"type":"Noise","noise":100}');
});
it('fromObject', async () => {
const filter = new Noise();
const object = filter.toObject();
const restoredFilter = await Noise.fromObject(object);
expect(restoredFilter, 'restored filter should match original').toEqual(
filter,
);
});
it('isNeutralState', () => {
const filter = new Noise();
expect(
filter.isNeutralState(),
'should be neutral when noise is 0',
).toBeTruthy();
filter.noise = 1;
expect(
filter.isNeutralState(),
'should not be neutral when noise changes',
).toBeFalsy();
});
});
describe('Pixelate', () => {
it('constructor', () => {
expect(Pixelate, 'Pixelate filter should exist').toBeTruthy();
const filter = new Pixelate();
expect(filter, 'should inherit from Pixelate').toBeInstanceOf(Pixelate);
});
it('properties', () => {
const filter = new Pixelate();
expect(filter.type, 'type should be Pixelate').toBe('Pixelate');
expect(filter.blocksize, 'default blocksize should be 4').toBe(4);
const filter2 = new Pixelate({ blocksize: 8 });
expect(
filter2.blocksize,
'blocksize should match constructor value',
).toBe(8);
});
it('applyTo2d', () => {
const filter = new Pixelate();
expect(filter.applyTo2d, 'should have applyTo2d method').toBeTypeOf(
'function',
);
});
it('applyTo2d values Pixelate', () => {
const filter = new Pixelate({ blocksize: 2 });
const options = {
imageData: _createImageData(context),
} as T2DPipelineState;
filter.applyTo2d(options);
const data = options.imageData.data;
const expected = [200, 100, 50, 1, 200, 100, 50, 1, 255, 255, 3, 1];
for (let i = 0; i < 12; i++) {
expect(data[i], `data[${i}] should match expected value`).toBe(
expected[i],
);
}
});
it('toObject', () => {
const filter = new Pixelate();
expect(filter.toObject, 'should have toObject method').toBeTypeOf(
'function',
);
const object = filter.toObject();
expect(
JSON.stringify(object),
'serialized object should match expected value',
).toBe('{"type":"Pixelate","blocksize":4}');
});
it('toJSON', () => {
const filter = new Pixelate();
expect(filter.toJSON, 'should have toJSON method').toBeTypeOf('function');
const json = filter.toJSON();
expect(
JSON.stringify(json),
'JSON representation should match expected value',
).toBe('{"type":"Pixelate","blocksize":4}');
});
it('fromObject', async () => {
const filter = new Pixelate();
const object = filter.toObject();
const restoredFilter = await Pixelate.fromObject(object);
expect(restoredFilter, 'restored filter should match original').toEqual(
filter,
);
});
it('isNeutralState', () => {
const filter = new Pixelate();
filter.blocksize = 1;
expect(
filter.isNeutralState(),
'should be neutral when blockSize is 1',
).toBeTruthy();
filter.blocksize = 4;
expect(
filter.isNeutralState(),
'should not be neutral when blockSize changes',
).toBeFalsy();
});
});
describe('RemoveColor', () => {
it('constructor', () => {
expect(RemoveColor, 'RemoveColor filter should exist').toBeTruthy();
const filter = new RemoveColor();
expect(filter, 'should inherit from RemoveColor').toBeInstanceOf(
RemoveColor,
);
});
it('properties', () => {
const filter = new RemoveColor();
expect(filter.type, 'type should be RemoveColor').toBe('RemoveColor');
expect(filter.distance, 'default distance should be 0.02').toBe(0.02);
expect(filter.color, 'default color should be #FFFFFF').toBe('#FFFFFF');
const filter2 = new RemoveColor({
distance: 0.6,
color: '#FF0000',
});
expect(filter2.distance, 'distance should match constructor value').toBe(
0.6,
);
expect(filter2.color, 'color should match constructor value').toBe(
'#FF0000',
);
});
it('applyTo2d', () => {
const filter = new RemoveColor();
expect(filter.applyTo2d, 'should have applyTo2d method').toBeTypeOf(
'function',
);
});
it('applyTo2d with color', () => {
const filter = new RemoveColor({ color: '#C86432' });
expect(filter.applyTo2d, 'should have applyTo2d method').toBeTypeOf(
'function',
);
const options = {
imageData: _createImageData(context),
} as T2DPipelineState;
filter.applyTo2d(options);
const data = options.imageData.data;
const expected = [200, 100, 50, 0, 30, 255, 10, 1, 255, 255, 3, 1];
for (let i = 0; i < 12; i++) {
expect(data[i], `data[${i}] should match expected value`).toBe(
expected[i],
);
}
});
it('toObject', () => {
const filter = new RemoveColor();
expect(filter.toObject, 'should have toObject method').toBeTypeOf(
'function',
);
const object = filter.toObject();
expect(
JSON.stringify(object),
'serialized object should match expected value',
).toBe(
'{"type":"RemoveColor","color":"#FFFFFF","distance":0.02,"useAlpha":false}',
);
});
it('toJSON', () => {
const filter = new RemoveColor({
color: 'blue',
useAlpha: true,
});
expect(filter.toJSON, 'should have toJSON method').toBeTypeOf('function');
const json = filter.toJSON();
expect(
JSON.stringify(json),
'JSON representation should match expected value',
).toBe(
'{"type":"RemoveColor","color":"blue","distance":0.02,"useAlpha":true}',
);
});
it('fromObject', async () => {
const filter = new RemoveColor();
const object = filter.toObject();
const restoredFilter = await RemoveColor.fromObject(object);
expect(restoredFilter, 'restored filter should match original').toEqual(
filter,
);
});
it('isNeutralState', () => {
const filter = new RemoveColor();
expect(filter.isNeutralState(), 'should never be neutral').toBeFalsy();
});
});
describe('Sepia', () => {
it('constructor', () => {
expect(Sepia, 'Sepia filter should exist').toBeTruthy();
const filter = new Sepia();
expect(filter, 'should inherit from Sepia').toBeInstanceOf(Sepia);
expect(filter, 'should inherit from ColorMatrix').toBeInstanceOf(
ColorMatrix,
);
});
it('properties', () => {
const filter = new Sepia();
expect(filter.type, 'type should be Sepia').toBe('Sepia');
});
it('applyTo2d', () => {
const filter = new Sepia();
expect(filter.applyTo2d, 'should have applyTo2d method').toBeTypeOf(
'function',
);
});
it('toObject', () => {
const filter = new Sepia();
expect(filter.toObject, 'should have toObject method').toBeTypeOf(
'function',
);
const object = filter.toObject();
expect(
JSON.stringify(object),
'serialized object should match expected value',
).toBe('{"type":"Sepia","colorsOnly":false}');
});
it('toJSON', () => {
const filter = new Sepia();
expect(filter.toJSON, 'should have toJSON method').toBeTypeOf('function');
const json = filter.toJSON();
expect(
JSON.stringify(json),
'JSON representation should match expected value',
).toBe('{"type":"Sepia","colorsOnly":false}');
});
it('fromObject', async () => {
const filter = new Sepia();
const object = filter.toObject();
const restoredFilter = await Sepia.fromObject(object);
expect(restoredFilter, 'restored filter should match original').toEqual(
filter,
);
});
it('isNeutralState', () => {
const filter = new Sepia();
expect(filter.isNeutralState(), 'should never be neutral').toBeFalsy();
});
});
describe('Resize', () => {
it('constructor', () => {
expect(Resize, 'Resize filter should exist').toBeTruthy();
const filter = new Resize();
expect(filter, 'should inherit from Resize').toBeInstanceOf(Resize);
});
it('properties', () => {
const filter = new Resize();
expect(filter.type, 'type should be Resize').toBe('Resize');
expect(filter.resizeType, 'default resizeType should be hermite').toBe(
'hermite',
);
expect(filter.lanczosLobes, 'default lanczosLobes should be 3').toBe(3);
expect(filter.scaleX, 'default scaleX should be 1').toBe(1);
expect(filter.scaleY, 'default scaleY should be 1').toBe(1);
const filter2 = new Resize({
resizeType: 'bilinear',
scaleX: 0.3,
scaleY: 0.3,
});
expect(
filter2.resizeType,
'resizeType should match constructor value',
).toBe('bilinear');
expect(filter2.scaleX, 'scaleX should match constructor value').toBe(0.3);
expect(filter2.scaleY, 'scaleY should match constructor value').toBe(0.3);
});
it('applyTo2d', () => {
const filter = new Resize();
expect(filter.applyTo2d, 'should have applyTo2d method').toBeTypeOf(
'function',
);
});
it('toObject', () => {
const filter = new Resize();
expect(filter.toObject, 'should have toObject method').toBeTypeOf(
'function',
);
let object = filter.toObject();
expect(
JSON.stringify(object),
'serialized object should match expected value',
).toBe(
'{"type":"Resize","resizeType":"hermite","scaleX":1,"scaleY":1,"lanczosLobes":3}',
);
filter.resizeType = 'bilinear';
object = filter.toObject();
expect(
JSON.stringify(object),
'serialized object with resizeType bilinear should match expected value',
).toBe(
'{"type":"Resize","resizeType":"bilinear","scaleX":1,"scaleY":1,"lanczosLobes":3}',
);
});
it('fromObject', async () => {
const filter = new Resize();
const object = filter.toObject();
const restoredFilter = await Resize.fromObject(object);
expect(restoredFilter, 'should inherit from Resize').toBeInstanceOf(
Resize,
);
expect(restoredFilter, 'restored filter should match original').toEqual(
filter,
);
filter.resizeType = 'bilinear';
filter.scaleX = 0.8;
filter.scaleY = 0.8;
const object2 = filter.toObject();
const restoredFilter2 = await Resize.fromObject(object2);
expect(
restoredFilter2,
'restored filter with custom values should match original',
).toEqual(filter);
});
it('isNeutralState', () => {
const filter = new Resize();
expect(
filter.isNeutralState(),
'should be neutral when scale is 1',
).toBeTruthy();
filter.scaleX = 1.4;
expect(
filter.isNeutralState(),
'should not be neutral when scale changes',
).toBeFalsy();
});
});
describe('Blur', () => {
it('isNeutralState', () => {
const filter = new Blur();
expect(
filter.isNeutralState(),
'should be neutral when blur is 0',
).toBeTruthy();
filter.blur = 0.3;
expect(
filter.isNeutralState(),
'should not be neutral when blur changes',
).toBeFalsy();
});
});
describe('Vibrance', () => {
it('constructor', () => {
expect(Vibrance, 'Vibrance filter should exist').toBeTruthy();
const filter = new Vibrance({
vibrance: 0.6,
});
expect(filter, 'should inherit from Vibrance').toBeInstanceOf(Vibrance);
expect(filter.vibrance, 'parameters should be initialized').toBe(0.6);
expect(filter.type, 'type should be Vibrance').toBe('Vibrance');
});
it('applyTo2d', () => {
const filter = new Vibrance();
expect(filter.applyTo2d, 'should have applyTo2d method').toBeTypeOf(
'function',
);
});
it('toObject', () => {
const filter = new Vibrance();
expect(filter.toObject, 'should have toObject method').toBeTypeOf(
'function',
);
const object = filter.toObject();
expect(
JSON.stringify(object),
'serialized object should match expected value',
).toBe('{"type":"Vibrance","vibrance":0}');
});
it('toJSON', () => {
const filter = new Vibrance();
expect(filter.toJSON, 'should have toJSON method').toBeTypeOf('function');
const json = filter.toJSON();
expect(
JSON.stringify(json),
'JSON representation should match expected value',
).toBe('{"type":"Vibrance","vibrance":0}');
});
it('fromObject', async () => {
const filter = new Vibrance({ vibrance: 0.3 });
const object = filter.toObject();
const restoredFilter = await Vibrance.fromObject(object);
expect(restoredFilter, 'restored filter should match original').toEqual(
filter,
);
});
it('isNeutralState', () => {
const filter = new Vibrance();
filter.vibrance = 0;
expect(
filter.isNeutralState(),
'0 vibrance should be neutral',
).toBeTruthy();
filter.vibrance = 0.5;
expect(
filter.isNeutralState(),
'0.5 vibrance should not be neutral',
).toBeFalsy();
});
});
describe('BlendColor', () => {
it('constructor', () => {
expect(BlendColor, 'BlendColor filter should exist').toBeTruthy();
const filter = new BlendColor({
color: 'red',
});
expect(filter, 'should inherit from BlendColor').toBeInstanceOf(
BlendColor,
);
expect(filter.color, 'parameters should be initialized').toBe('red');
expect(filter.type, 'type should be BlendColor').toBe('BlendColor');
});
it('applyTo2d', () => {
const filter = new BlendColor();
expect(filter.applyTo2d, 'should have applyTo2d method').toBeTypeOf(
'function',
);
});
it('toObject', () => {
const filter = new BlendColor();
expect(filter.toObject, 'should have toObject method').toBeTypeOf(
'function',
);
const object = filter.toObject();
const expected = {
type: 'BlendColor',
color: '#F95C63',
alpha: 1,
mode: 'multiply',
};
expect(object, 'serialized object should match expected value').toEqual(
expected,
);
c