I have two shaded colors like this:
I want to apply gradient colors on single image with fabric js image filter.
Basically I added two palettes for colors. What I need is when I change color from palettes that both colors apply in a single image like the above image. Is that possible?
I am designing a T-shirt like below:
I want to apply those two colors on a big grey image of the T-shirt. Currently different color images are working as separate image and separate object in fabric js and I want to apply those colors on single grey image part.
Is there any way to make this work?
Since FabricJs doesn't give natively the possibility of apply a gradient to an Image
, you can achieve your task with the ImageFilter
included in the following code snippet.
(function(global) {
'use strict';
var fabric = global.fabric || (global.fabric = {}),
extend = fabric.util.object.extend;
fabric.Image.filters.GradientEffect = fabric.util.createClass(fabric.Image.filters.BaseFilter, {
type: 'GradientEffect',
initialize: function (options) {
options = options || {};
this.gradient = options.gradient || {};
this.img = options.img;
},
applyTo: function(canvasEl) {
var gr = this.gradient;
var w = this.img._element.naturalWidth;
var h = this.img._element.naturalHeight;
var hc = document.createElement('canvas');
hc.setAttribute('width', w);
hc.setAttribute('height', h);
var fhc = new fabric.Canvas(hc);
var rect = new fabric.Rect({
fill: 'transparent',
width: w,
height: h
});
rect.setGradient('fill', gr);
fhc.add(rect);
fhc.renderAll();
var ifhcContext = fhc.getContext('2d');
var fhcImageData = ifhcContext.getImageData(0, 0, fhc.width, fhc.height);
var fhcData = fhcImageData.data;
var context = canvasEl.getContext('2d'),
imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),
data = imageData.data;
for (var i = 0, n = data.length; i < n; i += 4) {
if(data[i] != 0 && data[i+1] != 0 && data[i+2] != 0) {
data[i] += fhcData[i];
data[i + 1] += fhcData[i + 1];
data[i + 2] += fhcData[i + 2];
}
}
context.putImageData(imageData, 0, 0);
},
toObject: function() {
return extend(this.callSuper('toObject'), {
gradient: this.gradient
});
}
});
fabric.Image.filters.GradientEffect.fromObject = function(object) {
return new fabric.Image.filters.GradientEffect(object);
};
})(typeof exports !== 'undefined' ? exports : this);
var canvas = new fabric.Canvas('c');
fabric.Image.fromURL('http://i.imgur.com/bkMw5mx.png', function(img) {
var gr = {
x1: 0,
y1: 0,
x2: 0,
y2: img.height,
colorStops: {
0: "red",
1: "blue",
}
};
img.filters.push(new fabric.Image.filters.GradientEffect({
gradient: gr,
img: img,
}));
img.applyFilters(canvas.renderAll.bind(canvas));
canvas.add(img.set({
width: 150,
height: 150,
}));
}, {
crossOrigin: ''
});
.floatLeft {
display: inline-block;
border: 2px solid #ccc;
}
.placeholder {
margin-left: 10px;
}
<script src="//cdnjs.cloudflare.com/ajax/libs/fabric.js/1.5.0/fabric.min.js"></script>
<img class='image floatLeft' src='http://i.imgur.com/bkMw5mx.png' width='200' height='200'>
<div class='placeholder floatLeft'>
<canvas id='c' width='300' height='300'></canvas>
<div>
The work is done by applyTo function, I create a new Canvas
on the fly and I put a rectangle filled with the argument gradient on it, then, pixel by pixel, I apply the relative color picked from the gradient.:
applyTo: function(canvasEl) {
var gr = this.gradient;
var w = this.img._element.naturalWidth;
var h = this.img._element.naturalHeight;
var hc = document.createElement('canvas');
hc.setAttribute('width', w);
hc.setAttribute('height', h);
var fhc = new fabric.Canvas(hc);
var rect = new fabric.Rect({
fill: 'transparent',
width: w,
height: h
});
rect.setGradient('fill', gr);
fhc.add(rect);
fhc.renderAll();
var ifhcContext = fhc.getContext('2d');
var fhcImageData = ifhcContext.getImageData(0, 0, fhc.width, fhc.height);
var fhcData = fhcImageData.data;
var context = canvasEl.getContext('2d'),
imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),
data = imageData.data;
for (var i = 0, n = data.length; i < n; i += 4) {
if(data[i] != 0 && data[i+1] != 0 && data[i+2] != 0) {
data[i] += fhcData[i];
data[i + 1] += fhcData[i + 1];
data[i + 2] += fhcData[i + 2];
}
}
context.putImageData(imageData, 0, 0);
}