Reputation: 1787
I can't seem to get the tint filter feature of fabric.js to work, or find any example of it being used. I have tried:
img.filters[0] = new f.Tint({
color:'green'
});
I've also tried #00ff00
instead of green
, but both of them just turn the image black.
I have a number of png's that are just only black and transparent (e.g. basic shapes), and I want to be able to change the colour of them, I don't know if this is possible or not, but I figured tint sounded promising, I just can't get it to work.
I've also tried it on photos, just turns black, and I've used other filters (like invert) in the same place in the code and it worked fine.
Any help would be appreciated.
UPDATE: Full JS used, picture three just appears as a black box.
var canvas = new fabric.Canvas('c');
var f = fabric.Image.filters;
fabric.Image.fromURL('img/picture3.jpg', function(img) {
img.set({
left: 100,
top: 120,
angle: 0
});
img.filters[0] = new f.Tint({
color:'00FF00'
});
img.applyFilters(canvas.renderAll.bind(canvas));
canvas.add(img);
});
Upvotes: 4
Views: 5411
Reputation: 3144
One thing I noticed when doing something similar, is that the filter would not work until the image itself was added to the canvas.
Upvotes: 0
Reputation: 494
I was having the same problem. It turned out to be the version of fabric js I was using. Without grabbing the latest, in fear of breaking other things, I grabbed only what I needed and used it as a custom filter overriding the current tint implementation.
Here's what I used:
/**
* Tint filter class
* Adapted from <a href="https://github.com/mezzoblue/PaintbrushJS">https://github.com/mezzoblue/PaintbrushJS</a>
* @class fabric.Image.filters.Tint
* @memberOf fabric.Image.filters
* @extends fabric.Image.filters.BaseFilter
* @see {@link fabric.Image.filters.Tint#initialize} for constructor definition
* @see {@link http://fabricjs.com/image-filters/|ImageFilters demo}
* @example <caption>Tint filter with hex color and opacity</caption>
* var filter = new fabric.Image.filters.Tint({
* color: '#3513B0',
* opacity: 0.5
* });
* object.filters.push(filter);
* object.applyFilters(canvas.renderAll.bind(canvas));
* @example <caption>Tint filter with rgba color</caption>
* var filter = new fabric.Image.filters.Tint({
* color: 'rgba(53, 21, 176, 0.5)'
* });
* object.filters.push(filter);
* object.applyFilters(canvas.renderAll.bind(canvas));
*/
fabric.Image.filters.Tint = fabric.util.createClass(fabric.Image.filters.BaseFilter, /** @lends fabric.Image.filters.Tint.prototype */ {
/**
* Filter type
* @param {String} type
* @default
*/
type: 'Tint',
/**
* Constructor
* @memberOf fabric.Image.filters.Tint.prototype
* @param {Object} [options] Options object
* @param {String} [options.color=#000000] Color to tint the image with
* @param {Number} [options.opacity] Opacity value that controls the tint effect's transparency (0..1)
*/
initialize: function(options) {
options = options || { };
this.color = options.color || '#000000';
this.opacity = typeof options.opacity !== 'undefined'
? options.opacity
: new fabric.Color(this.color).getAlpha();
console.log(this.color + " " + this.opacity);
},
/**
* Applies filter to canvas element
* @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,
iLen = data.length, i,
tintR, tintG, tintB,
r, g, b, alpha1,
source;
source = new fabric.Color(this.color).getSource();
tintR = source[0] * this.opacity;
tintG = source[1] * this.opacity;
tintB = source[2] * this.opacity;
alpha1 = 1 - this.opacity;
for (i = 0; i < iLen; i+=4) {
r = data[i];
g = data[i + 1];
b = data[i + 2];
// alpha compositing
data[i] = tintR + r * alpha1;
data[i + 1] = tintG + g * alpha1;
data[i + 2] = tintB + b * alpha1;
}
context.putImageData(imageData, 0, 0);
},
/**
* Returns object representation of an instance
* @return {Object} Object representation of an instance
*/
toObject: function() {
return extend(this.callSuper('toObject'), {
color: this.color,
opacity: this.opacity
});
}
});
Upvotes: 0
Reputation: 681
I had the same problem with either a JPEG image or PNG image (with transparent background).
I found out that the Tint Class wasn't working properly for that matter so I slightly changed it. You can find the thread on Google Groups : https://groups.google.com/forum/#!msg/fabricjs/DPN0WuRtc-o/ZGgIQK5F9xAJ
Here's my workaround class (which works by using a full hexadecimal value, but you could easily adapt it to your needs) :
fabric.Image.filters.Tint = fabric.util.createClass({
type: 'Tint',
/**
* Constructor
* @memberOf fabric.Image.filters.Tint.prototype
* @param {Object} [options] Options object
*/
//That's Different : HexColor
initialize: function(HexColor) {
this.color = HexColor;
},
/**
* Applies filter to canvas element
* @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;
//That's different : computation of values
var rUser = ((this.color).toString ()).substr(0,2);
var gUser = ((this.color).toString ()).substr(2,2);
var bUser = ((this.color).toString ()).substr(4,2);
for (var i = 0, len = data.length; i < len; i += 4) {
r = data[i];
g = data[i + 1];
b = data[i + 2];
data[i] = parseInt ((r * parseInt (rUser, 16))/255);
data[i + 1] = parseInt ((g * parseInt (gUser, 16))/255);
data[i + 2] = parseInt ((b * parseInt (bUser, 16))/255);
}
context.putImageData(imageData, 0, 0);
},
/**
* Returns json representation of filter
* @return {Object} json representation of filter
*/
toJSON: function() {
return {
type: this.type,
color: this.color
};
}
})`
I use it this way tho :
//$oCanvas is my fabric Canvas object
//data.color could be 'ff0000' but not 'f00' not anything else like fabric.Color
$img.filters[0] = new fabric.Image.filters.Tint(data.color);
$img.applyFilters($oCanvas.renderAll.bind($oCanvas));
Hope that helps someone.
L.
EDIT
Some changes have been done inside the Tint Filter Class (Github : https://github.com/kangax/fabric.js/pull/862).
I tested it again with still no luck so I slightly changed it again. You can find source code + explanation on Google Groups (https://groups.google.com/forum/#!topic/fabricjs/DPN0WuRtc-o)
EDIT #2
Ok so Kienz made a JSFiddle (http://jsfiddle.net/Kienz/4wGzk/) that uses the Tint Filter Class with the bugfix and he got it working. I'd recommend to implement it the way he did.
Upvotes: 1
Reputation: 387
I analysed the original class for Tint filter and I have found that this line
var rgb = parseInt(this.color, 10).toString(16);
should be adjusted like this
var rgb = this.color;
to make it work as expected. Of course, then rgb variable is useless and you can change it to this.color directly, but I personally prefer single line changes.
I'm not sure what was the original purpose of converting hex to integer and then to string as it makes no sense to me.
You would propably not want to modify the fabric.js source, so I suggest you to create custom filter class as mentioned in this tutorial under Filters section: http://fabricjs.com/fabric-intro-part-2/
Upvotes: 3
Reputation: 863
I wrote that filter and I'm using it heavily in one of our projects and it worked good so far. But what I'm missing there is the call to applyFilters - maybe you could post a little more code?
Also I think I always applied the colors like:
img.filters[0] = new f.Tint({
color:'FF0000'
});
Means no color names, no hash in front. I know that the parser for the colors should be a little more robust there. Also be sure that this filter will only work for images that have an alpha channel - means semi transparent png files.
Upvotes: 4