I am trying to create a custom filter it should like accepting color code.
Here is my code.
It is working fine.
fabric.Image.fromURL('pug.jpg', function(img) {
img.filters.push(
new fabric.Image.filters.Sepia(),
new fabric.Image.filters.Brightness({ brightness: 100 }));
img.applyFilters(canvas.renderAll.bind(canvas));
canvas.add(img);
});
Now, i need to create a filter with specific color code. What i found is
fabric.Image.filters.Redify = fabric.util.createClass({
type: 'Redify',
applyTo: function(canvasEl) {
var context = canvasEl.getContext('2d'),
imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),
data = imageData.data;
for (var i = 0, len = data.length; i < len; i += 4) {
data[i + 1] = 0;
data[i + 2] = 0;
}
context.putImageData(imageData, 0, 0);
}
});
fabric.Image.filters.Redify.fromObject = function(object) {
return new fabric.Image.filters.Redify(object);
};
I need explanation what for loop does...also please explain how can i pass color code.
I am trying to create a custom filter it should like accepting color code.
Here is my code.
It is working fine.
fabric.Image.fromURL('pug.jpg', function(img) {
img.filters.push(
new fabric.Image.filters.Sepia(),
new fabric.Image.filters.Brightness({ brightness: 100 }));
img.applyFilters(canvas.renderAll.bind(canvas));
canvas.add(img);
});
Now, i need to create a filter with specific color code. What i found is
fabric.Image.filters.Redify = fabric.util.createClass({
type: 'Redify',
applyTo: function(canvasEl) {
var context = canvasEl.getContext('2d'),
imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),
data = imageData.data;
for (var i = 0, len = data.length; i < len; i += 4) {
data[i + 1] = 0;
data[i + 2] = 0;
}
context.putImageData(imageData, 0, 0);
}
});
fabric.Image.filters.Redify.fromObject = function(object) {
return new fabric.Image.filters.Redify(object);
};
I need explanation what for loop does...also please explain how can i pass color code.
Share Improve this question asked Mar 18, 2016 at 11:06 gamblergambler 672 silver badges7 bronze badges 3- You want pass color and what do you want to do with that color? – AndreaBogazzi Commented Mar 19, 2016 at 16:39
- @AndreaBogazzi, i will create a new color filter – gambler Commented Mar 21, 2016 at 3:46
- @AndreaBogazzi, i have a requirement like creating custom filter based on color code – gambler Commented Mar 21, 2016 at 5:52
2 Answers
Reset to default 5The redify filter you found is not really a colorify filter. As you can see from the code it is killing the green and blue channell and leaving you just with the reds of the image. It is not the same effect you would get applying a colorify with red.
You could create a bluify and greenify filter in the same way just changing the surviving channell:
fabric.Image.filters.Greenify= fabric.util.createClass({
type: 'greenify',
applyTo: function(canvasEl) {
var context = canvasEl.getContext('2d'),
imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),
data = imageData.data;
for (var i = 0, len = data.length; i < len; i += 4) {
//kill red
data[i] = 0;
//kill blue
data[i + 2] = 0;
}
context.putImageData(imageData, 0, 0);
}
});
To create a colorify filter, first you have to know how to do it. I personally checked how colorify filter from GIMP works:
https://docs.gimp/en/plug-in-colorify.html
1) make the image grayscale, based on luminosity
2) multiply the gray level for the color you want
This would be more or less equal to apply the existing fabricjs filters in order Grayscale and Multiply.
var canvas = new fabric.Canvas("c");
fabric.Image.filters.Luminosity = fabric.util.createClass(fabric.Image.filters.BaseFilter, /** @lends fabric.Image.filters.Luminosity.prototype */ {
/**
* Filter type
* @param {String} type
* @default
*/
type: 'Luminosity',
/**
* Applies filter to canvas element
* @memberOf fabric.Image.filters.Grayscale.prototype
* @param {Object} canvasEl Canvas element to apply filter to
*/
applyTo: function(canvasEl) {
var context = canvasEl.getContext('2d'),
imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),
data = imageData.data,
len = imageData.width * imageData.height * 4,
index = 0,
average;
while (index < len) {
//Luminosity = 0.21 × R + 0.72 × G + 0.07 × B
average = (0.21 * data[index] + 0.72 * data[index + 1] + 0.07 * data[index + 2]);
data[index] = average;
data[index + 1] = average;
data[index + 2] = average;
index += 4;
}
context.putImageData(imageData, 0, 0);
}
});
/**
* Returns filter instance from an object representation
* @static
* @return {fabric.Image.filters.Grayscale} Instance of fabric.Image.filters.Grayscale
*/
fabric.Image.filters.Grayscale.fromObject = function() {
return new fabric.Image.filters.Grayscale();
};
fabric.Image.fromURL("http://fabricjs./assets/pug.jpg", function(img) {
img.filters.push(new fabric.Image.filters.Grayscale());
img.filters.push(new fabric.Image.filters.Multiply({color: '#F0F'}));
img.scale(0.3);
img.applyFilters(function() {
canvas.add(img);
});
}, {crossOrigin: 'Anonymous'});
fabric.Image.fromURL("http://fabricjs./assets/pug.jpg", function(img) {
img.filters.push(new fabric.Image.filters.Luminosity());
img.filters.push(new fabric.Image.filters.Multiply({color: '#F0F'}));
img.applyFilters(function() {
img.scale(0.3);
img.left = img.getWidth();
canvas.add(img);
});
}, {crossOrigin: 'Anonymous'});
<script src="http://www.deltalink.it/andreab/fabric/fabric.js"></script>
<canvas width="500" height="400" id="c" ></canvas>
To pare the built in functions of fabricjs with the example from gimp, i created a Luminosity filter to use instead of grayscale filter that is based on the "Average" method. As you see the results are pretty similar but it is image dependent.
Check the Multiply Filter source code to see how a parameter in the filter is handled if you want to build your own filter.
To be able to use your filter you need to change your filter code to below according to Fabricjs filter boilerplate
(function(global) {
'use strict';
var fabric = global.fabric || (global.fabric = { }),
filters = fabric.Image.filters,
createClass = fabric.util.createClass;
/**
* Redify filter class
* @class fabric.Image.filters.Redify
* @memberOf fabric.Image.filters
* @extends fabric.Image.filters.BaseFilter
* @see {@link fabric.Image.filters.Redify#initialize} for constructor definition
* @see {@link http://fabricjs./image-filters|ImageFilters demo}
* @example
* var filter = new fabric.Image.filters.Redify({
* add here an example of how to use your filter
* });
* object.filters.push(filter);
* object.applyFilters();
*/
filters.Redify = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Redify.prototype */ {
/**
* Filter type
* @param {String} type
* @default
*/
type: 'Redify',
/**
* Fragment source for the threshold program
*/
fragmentSource: 'precision highp float;\n' +
'uniform sampler2D uTexture;\n' +
'uniform float uthreshold;\n' +
'varying vec2 vTexCoord;\n' +
'void main() {\n' +
'vec4 color = texture2D(uTexture, vTexCoord);\n' +
// add your gl code here
'gl_FragColor = color;\n' +
'}',
/**
* Redify value, from -1 to 1.
* translated to -255 to 255 for 2d
* 0.0039215686 is the part of 1 that get translated to 1 in 2d
* @param {Number} threshold
* @default
*/
threshold: 5,
/**
* Describe the property that is the filter parameter
* @param {String} m
* @default
*/
mainParameter: 'threshold',
/**
* Apply the Redify operation to a Uint8ClampedArray representing the pixels of an image.
*
* @param {Object} options
* @param {ImageData} options.imageData The Uint8ClampedArray to be filtered.
*/
applyTo2d: function(options) {
var imageData = options.imageData,
data = imageData.data, i, len = data.length,sublim = 255-this.threshold;
for (i = 0; i < len; i += 4) {
if (data[i] < sublim && data[i + 1] < sublim && data[i + 2] < sublim) {
data[i + 1] = 0;
data[i + 2] = 0;
}
}
},
/**
* Return WebGL uniform locations for this filter's shader.
*
* @param {WebGLRenderingContext} gl The GL canvas context used to pile this filter's shader.
* @param {WebGLShaderProgram} program This filter's piled shader program.
*/
getUniformLocations: function(gl, program) {
return {
uMyParameter: gl.getUniformLocation(program, 'uMyParameter'),
};
},
/**
* Send data from this filter to its shader program's uniforms.
*
* @param {WebGLRenderingContext} gl The GL canvas context used to pile this filter's shader.
* @param {Object} uniformLocations A map of string uniform names to WebGLUniformLocation objects
*/
sendUniformData: function(gl, uniformLocations) {
gl.uniform1f(uniformLocations.uMyParameter, this.threshold);
},
});
/**
* Returns filter instance from an object representation
* @static
* @param {Object} object Object to create an instance from
* @param {function} [callback] to be invoked after filter creation
* @return {fabric.Image.filters.Redify} Instance of fabric.Image.filters.Redify
*/
fabric.Image.filters.Redify.fromObject = fabric.Image.filters.BaseFilter.fromObject;
})(typeof exports !== 'undefined' ? exports : this);
Once you have done that you can simply use it as below to pass a variable
fabric.Image.fromURL('pug.jpg', function(img) {
img.filters.push(
new fabric.Image.filters.Redify({ threshold: 10 }));
img.applyFilters();
canvas.add(img);
});