Skip to content

Commit c36ef82

Browse files
authored
feat(fabric.filters) Added vibrance filter (for increasing saturation of muted colors) (fabricjs#7189)
1 parent 1344dc6 commit c36ef82

File tree

3 files changed

+132
-1
lines changed

3 files changed

+132
-1
lines changed

build.js

+1
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,7 @@ var filesToInclude = [
216216
ifSpecifiedInclude('image_filters', 'src/filters/resize_filter.class.js'),
217217
ifSpecifiedInclude('image_filters', 'src/filters/contrast_filter.class.js'),
218218
ifSpecifiedInclude('image_filters', 'src/filters/saturate_filter.class.js'),
219+
ifSpecifiedInclude('image_filters', 'src/filters/vibrance_filter.class.js'),
219220
ifSpecifiedInclude('image_filters', 'src/filters/blur_filter.class.js'),
220221
ifSpecifiedInclude('image_filters', 'src/filters/gamma_filter.class.js'),
221222
ifSpecifiedInclude('image_filters', 'src/filters/composed_filter.class.js'),

src/filters/saturate_filter.class.js

+9-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
* @see {@link http://fabricjs.com/image-filters|ImageFilters demo}
1616
* @example
1717
* var filter = new fabric.Image.filters.Saturation({
18-
* saturation: 100
18+
* saturation: 1
1919
* });
2020
* object.filters.push(filter);
2121
* object.applyFilters();
@@ -43,6 +43,14 @@
4343
'gl_FragColor = color;\n' +
4444
'}',
4545

46+
/**
47+
* Saturation value, from -1 to 1.
48+
* Increases/decreases the color saturation.
49+
* A value of 0 has no effect.
50+
*
51+
* @param {Number} saturation
52+
* @default
53+
*/
4654
saturation: 0,
4755

4856
mainParameter: 'saturation',

src/filters/vibrance_filter.class.js

+122
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
(function(global) {
2+
3+
'use strict';
4+
5+
var fabric = global.fabric || (global.fabric = { }),
6+
filters = fabric.Image.filters,
7+
createClass = fabric.util.createClass;
8+
9+
/**
10+
* Vibrance filter class
11+
* @class fabric.Image.filters.Vibrance
12+
* @memberOf fabric.Image.filters
13+
* @extends fabric.Image.filters.BaseFilter
14+
* @see {@link fabric.Image.filters.Vibrance#initialize} for constructor definition
15+
* @see {@link http://fabricjs.com/image-filters|ImageFilters demo}
16+
* @example
17+
* var filter = new fabric.Image.filters.Vibrance({
18+
* vibrance: 1
19+
* });
20+
* object.filters.push(filter);
21+
* object.applyFilters();
22+
*/
23+
filters.Vibrance = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Vibrance.prototype */ {
24+
25+
/**
26+
* Filter type
27+
* @param {String} type
28+
* @default
29+
*/
30+
type: 'Vibrance',
31+
32+
fragmentSource: 'precision highp float;\n' +
33+
'uniform sampler2D uTexture;\n' +
34+
'uniform float uVibrance;\n' +
35+
'varying vec2 vTexCoord;\n' +
36+
'void main() {\n' +
37+
'vec4 color = texture2D(uTexture, vTexCoord);\n' +
38+
'float max = max(color.r, max(color.g, color.b));\n' +
39+
'float avg = (color.r + color.g + color.b) / 3.0;\n' +
40+
'float amt = (abs(max - avg) * 2.0) * uVibrance;\n' +
41+
'color.r += max != color.r ? (max - color.r) * amt : 0.00;\n' +
42+
'color.g += max != color.g ? (max - color.g) * amt : 0.00;\n' +
43+
'color.b += max != color.b ? (max - color.b) * amt : 0.00;\n' +
44+
'gl_FragColor = color;\n' +
45+
'}',
46+
47+
/**
48+
* Vibrance value, from -1 to 1.
49+
* Increases/decreases the saturation of more muted colors with less effect on saturated colors.
50+
* A value of 0 has no effect.
51+
*
52+
* @param {Number} vibrance
53+
* @default
54+
*/
55+
vibrance: 0,
56+
57+
mainParameter: 'vibrance',
58+
59+
/**
60+
* Constructor
61+
* @memberOf fabric.Image.filters.Vibrance.prototype
62+
* @param {Object} [options] Options object
63+
* @param {Number} [options.vibrance=0] Vibrance value for the image (between -1 and 1)
64+
*/
65+
66+
/**
67+
* Apply the Vibrance operation to a Uint8ClampedArray representing the pixels of an image.
68+
*
69+
* @param {Object} options
70+
* @param {ImageData} options.imageData The Uint8ClampedArray to be filtered.
71+
*/
72+
applyTo2d: function(options) {
73+
if (this.vibrance === 0) {
74+
return;
75+
}
76+
var imageData = options.imageData,
77+
data = imageData.data, len = data.length,
78+
adjust = -this.vibrance, i, max, avg, amt;
79+
80+
for (i = 0; i < len; i += 4) {
81+
max = Math.max(data[i], data[i + 1], data[i + 2]);
82+
avg = (data[i] + data[i + 1] + data[i + 2]) / 3;
83+
amt = ((Math.abs(max - avg) * 2 / 255) * adjust);
84+
data[i] += max !== data[i] ? (max - data[i]) * amt : 0;
85+
data[i + 1] += max !== data[i + 1] ? (max - data[i + 1]) * amt : 0;
86+
data[i + 2] += max !== data[i + 2] ? (max - data[i + 2]) * amt : 0;
87+
}
88+
},
89+
90+
/**
91+
* Return WebGL uniform locations for this filter's shader.
92+
*
93+
* @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.
94+
* @param {WebGLShaderProgram} program This filter's compiled shader program.
95+
*/
96+
getUniformLocations: function(gl, program) {
97+
return {
98+
uVibrance: gl.getUniformLocation(program, 'uVibrance'),
99+
};
100+
},
101+
102+
/**
103+
* Send data from this filter to its shader program's uniforms.
104+
*
105+
* @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.
106+
* @param {Object} uniformLocations A map of string uniform names to WebGLUniformLocation objects
107+
*/
108+
sendUniformData: function(gl, uniformLocations) {
109+
gl.uniform1f(uniformLocations.uVibrance, -this.vibrance);
110+
},
111+
});
112+
113+
/**
114+
* Returns filter instance from an object representation
115+
* @static
116+
* @param {Object} object Object to create an instance from
117+
* @param {Function} [callback] to be invoked after filter creation
118+
* @return {fabric.Image.filters.Vibrance} Instance of fabric.Image.filters.Vibrance
119+
*/
120+
fabric.Image.filters.Vibrance.fromObject = fabric.Image.filters.BaseFilter.fromObject;
121+
122+
})(typeof exports !== 'undefined' ? exports : this);

0 commit comments

Comments
 (0)