Fabricjs filter - javascript

i made the code,but I always get this error "TypeError: (intermediate value)(intermediate value).filter is not a function
at i.applyFilters "
var canvas = new fabric.Canvas('c');
fabric.Image.fromURL('https://upload.wikimedia.org/wikipedia/en/a/a9/Example.jpg', function(img) {
var oImg = img.set({
left: 50,
top: 50
});
canvas.add(oImg).renderAll();
canvas.setActiveObject(oImg);
}, {
crossOrigin: 'anonymous'
});
function applyFilter(index, filter) {
var obj = canvas.getActiveObject();
obj.filters[index] = filter;
obj.applyFilters(canvas.renderAll.bind(canvas));
}
var f = fabric.Image.filters;
document.getElementById("input").onchange = function() {
applyFilter(0, new f.Contrast({
contrast: parseInt(document.getElementById("input").value, 10)
}));
};
<canvas width=600 height=400 id="c"></canvas>
<input id="input" type="range" min="-255" max="255" value="0" />

thank you for the answer,but this does not work.the image is only changed to one color

Change this line:
obj.applyFilters(canvas.renderAll.bind(canvas));
To
obj.applyFilters();
canvas.renderAll();
Also, the Contrast filter only accepts values between -1 and 1 (see http://fabricjs.com/docs/fabric.Image.filters.Contrast.html), so change this line:
<input id="input" type="range" min="-255" max="255" value="0" />
To this:
<input id="input" type="range" min="-100" max="100" value="0" />
And then divide the value from the input by 100
parseInt(document.getElementById("input").value, 10) / 100
var canvas = new fabric.Canvas('c');
fabric.Image.fromURL('https://upload.wikimedia.org/wikipedia/en/a/a9/Example.jpg', function(img) {
var oImg = img.set({
left: 50,
top: 50
});
canvas.add(oImg).renderAll();
canvas.setActiveObject(oImg);
}, {
crossOrigin: 'anonymous'
});
function applyFilter(index, filter) {
var obj = canvas.getActiveObject();
obj.filters[index] = filter;
obj.applyFilters();
canvas.renderAll();
}
var f = fabric.Image.filters;
document.getElementById("input").onchange = function() {
applyFilter(0, new f.Contrast({
contrast: parseInt(document.getElementById("input").value, 10) / 100
}));
};
<script src="https://unpkg.com/fabric#4.4.0/dist/fabric.js"></script>
<canvas width=600 height=400 id="c"></canvas>
<input id="input" type="range" min="-100" max="100" value="0" />

Related

Fabric js - reset all actions/filters on active object

In my project I'm trying to figure out how to reset all the changes I make on the image.
Example:
If I remove two colors from my image I would like that when I click on button#remove the image returns to the previous one without changes and without filters.
My code is this:
$(function() {
var canvas = this.__canvas = new fabric.Canvas('canvas');
canvas.setHeight('300');
canvas.setWidth('800');
canvas.renderAll();
document.getElementById('file-input').addEventListener("change", function (e) {
var file = e.target.files[0];
var reader = new FileReader();
reader.onload = function (f) {
var data = f.target.result;
fabric.Image.fromURL(data, function (img) {
var oImg = img.set({left: 10, top: 10, angle: 00}).scale(0.8);
canvas.add(oImg).renderAll();
var a = canvas.setActiveObject(oImg);
var dataURL = canvas.toDataURL({ format: 'png', quality: 0.8 });
console.log("Canvas Image " + dataURL);
});
};
reader.readAsDataURL(file);
});
fabric.Object.prototype.transparentCorners = false;
fabric.Object.prototype.padding = 5;
$("#remove-color-color").change(function(){
var oImg = canvas.getActiveObject();
var filter = new fabric.Image.filters.RemoveColor({
color: $(this).val(),
threshold: 0.2,
distance: 0.5,
});
oImg.filters.push(filter);
oImg.applyFilters();
canvas.renderAll();
});
$(".removeItem").click(function(){
canvas.remove(canvas.getActiveObject());
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/4.3.1/fabric.min.js"></script>
<div id="contCanvasLogo" style="float:left;width:100%;">
<canvas id="canvas" class="resize canvasLogo" style="width:500px;height:500px;border:1px solid #ccc;"></canvas>
<input type="file" id="file-input">
<input type="color" id="remove-color-color" />
</div>
<br/>
<button class="removeItem" >Remove</button>
<button class="reset" >Reset</button>
How can i do for reset all filters on my activeObject?
To clear all filters on the object just set your filters to an empty array and then run applyFilters(), then renderAll()
obj.filters = [];
obj.applyFilters();
canvas.renderAll();
$(function() {
var canvas = this.__canvas = new fabric.Canvas('canvas');
canvas.setHeight('300');
canvas.setWidth('800');
canvas.renderAll();
document.getElementById('file-input').addEventListener("change", function(e) {
var file = e.target.files[0];
var reader = new FileReader();
reader.onload = function(f) {
var data = f.target.result;
fabric.Image.fromURL(data, function(img) {
var oImg = img.set({
left: 10,
top: 10,
angle: 00
}).scale(0.8);
canvas.add(oImg).renderAll();
var a = canvas.setActiveObject(oImg);
var dataURL = canvas.toDataURL({
format: 'png',
quality: 0.8
});
console.log("Canvas Image " + dataURL);
});
};
reader.readAsDataURL(file);
});
fabric.Object.prototype.transparentCorners = false;
fabric.Object.prototype.padding = 5;
$("#remove-color-color").change(function() {
var oImg = canvas.getActiveObject();
if(!oImg) return;
var filter = new fabric.Image.filters.RemoveColor({
color: $(this).val(),
threshold: 0.2,
distance: 0.5,
});
oImg.filters.push(filter);
oImg.applyFilters();
canvas.renderAll();
});
$(".removeItem").click(function() {
var obj = canvas.getActiveObject();
if(obj) canvas.remove(obj);
});
$(".reset").click(function() {
var obj = canvas.getActiveObject();
if(!obj) return;
obj.filters = [];
obj.applyFilters();
canvas.renderAll();
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/4.3.1/fabric.min.js"></script>
<div id="contCanvasLogo" style="float:left;width:100%;">
<canvas id="canvas" class="resize canvasLogo" style="width:500px;height:500px;border:1px solid #ccc;"></canvas>
<input type="file" id="file-input">
<input type="color" id="remove-color-color" />
</div>
<br/>
<button class="removeItem">Remove</button>
<button class="reset">Reset</button>

Getting sliders to update HTML canvas

I'm trying to make a colour selector in JavaScript, so far it works (in Firefox, not chrome) if you select a value in the slider and then refresh the page - displaying the colour in a HTML tag.
However, I want it to refresh the colour real-time, so that the canvas changes colour as you adjust the sliders. I imagine I've made a really simple error, but I just can't figure it out - I would very much appreciate any help/advice!
Example of code on my web page.
I've messed around with using .onchange etc, plus declaring "outputR.value" in the rbg() call, but none of this works. I imagine I need an update function - but I'm not sure where to even start on that.
var sliderR = document.getElementById("myRangeR");
var sliderG = document.getElementById("myRangeG");
var sliderB = document.getElementById("myRangeB");
var outputR = document.getElementById("demoR");
var outputG = document.getElementById("demoG");
var outputB = document.getElementById("demoB");
sliderR.oninput = function() {
outputR.innerHTML = this.value;
}
sliderG.oninput = function() {
outputG.innerHTML = this.value;
}
sliderB.oninput = function() {
outputB.innerHTML = this.value;
}
outputR.innerHTML = sliderR.value;
outputG.innerHTML = sliderG.value;
outputB.innerHTML = sliderB.value;
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
ctx.fillStyle = "rgb("+sliderR.value+","+sliderG.value+","+sliderB.value+")";
ctx.fillRect(0, 0, 80, 80);
<p>
<div class="slidecontainer">
<p>Red: <span id="demoR"></span>/255</p>
<input type="range" min="0" max="255" value="128" class="slider" id="myRangeR">
<p>Green: <span id="demoG"></span>/255</p>
<input type="range" min="0" max="255" value="128" class="slider" id="myRangeG">
<p>Blue: <span id="demoB"></span>/255</p>
<input type="range" min="0" max="255" value="128" class="slider" id="myRangeB">
<canvas id="myCanvas"></canvas>
</div>
</p>
<script src="js/canvastest.js"></script>
Expected: HTML canvas element changes colour when sliders are moved.
Actual: Colours only change when page is refreshed (in Firefox), or not at all (chrome).
I'm not seeing a point in which you update the canvas itself. You would want to update the canvas when the value changes such as:
ctx.fillStyle = "rgb(" + [outputR, outputG, outputB].join(', ') + ")";
then rerender with ctx.fillRect(0, 0, 80, 80);.
This would give you something like the following:
var sliderR = document.getElementById("myRangeR");
var sliderG = document.getElementById("myRangeG");
var sliderB = document.getElementById("myRangeB");
var outputR = document.getElementById("demoR");
var outputG = document.getElementById("demoG");
var outputB = document.getElementById("demoB");
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
sliderR.oninput = function() {
outputR.innerHTML = this.value;
updateRect();
}
sliderG.oninput = function() {
outputG.innerHTML = this.value;
updateRect();
}
sliderB.oninput = function() {
outputB.innerHTML = this.value;
updateRect();
}
outputR.innerHTML = sliderR.value;
outputG.innerHTML = sliderG.value;
outputB.innerHTML = sliderB.value;
function updateRect() {
ctx.fillStyle = "rgb(" + [outputR, outputG, outputB].map(i => i.innerHTML).join(', ') + ")";
ctx.fillRect(0, 0, 80, 80);
}
updateRect();
st.js
First things first, you should not enclose your div or another p inside <p> tag. It's wrong structurally.
Now coming to your question, it is not re-rendering as the script is only getting executed on page load.
Try something like this:
var sliderR = document.getElementById("myRangeR");
var sliderG = document.getElementById("myRangeG");
var sliderB = document.getElementById("myRangeB");
var outputR = document.getElementById("demoR");
var outputG = document.getElementById("demoG");
var outputB = document.getElementById("demoB");
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
myfunc = () => {
outputR.innerHTML = sliderR.value;
outputG.innerHTML = sliderG.value;
outputB.innerHTML = sliderB.value;
ctx.fillStyle = "rgb("+sliderR.value+","+sliderG.value+","+sliderB.value+")";
ctx.fillRect(0, 0, 80, 80);
}
myfunc(); // for initialising values on first load
<div>
<div class="slidecontainer">
<p>Red: <span id="demoR"></span>/255</p>
<input type="range" min="0" max="255" value="128" class="slider" id="myRangeR" oninput="myfunc()" >
<p>Green: <span id="demoG"></span>/255</p>
<input type="range" min="0" max="255" value="128" class="slider" id="myRangeG" oninput="myfunc()">
<p>Blue: <span id="demoB"></span>/255</p>
<input type="range" min="0" max="255" value="128" class="slider" id="myRangeB" oninput="myfunc()">
<canvas id="myCanvas"></canvas>
</div>
</div>
Hope it helps!

Maintain strokeWidth while scaling in fabric js

Note: I have refereed SO question, but it is not useful for my case, because
1) I am trying to maintain previous border but as of now its recalculate border while scaling.
I have added below code to stop increasing border automatically while scaling the object. Now the issue is I have added a 5px border to object but when scaling the object then it is not maintaining the border which I added earlier.
canvas.on('object:scaling', (e) => {
var o = e.target;
if (!o.strokeWidthUnscaled && o.strokeWidth) {
o.strokeWidthUnscaled = o.strokeWidth;
}
if (o.strokeWidthUnscaled) {
o.strokeWidth = o.strokeWidthUnscaled / o.scaleX;
}
});
Now what I want is to prevent increasing of border while scaling the object. Border should remain as it was earlier.
Here is snippet / Codepen
var canvas = new fabric.Canvas('canvas1');
$('.add_shape').click(function() {
var cur_value = $(this).attr('data-rel');
if (cur_value != '') {
switch (cur_value) {
case 'rectangle':
var rect = new fabric.Rect({
left: 50,
top: 50,
fill: '#aaa',
width: 50,
height: 50,
opacity: 1,
stroke: '#000',
strokeWidth: 1
});
canvas.add(rect);
canvas.setActiveObject(rect);
break;
case 'circle':
var circle = new fabric.Circle({
left: 50,
top: 50,
fill: '#aaa',
radius: 50,
opacity: 1,
stroke: '#000',
strokeWidth: 1
});
canvas.add(circle);
canvas.setActiveObject(circle);
break;
}
}
});
canvas.on('object:scaling', (e) => {
var o = e.target;
if (!o.strokeWidthUnscaled && o.strokeWidth) {
o.strokeWidthUnscaled = o.strokeWidth;
}
if (o.strokeWidthUnscaled) {
o.strokeWidth = o.strokeWidthUnscaled / o.scaleX;
}
});
/* Control the border */
$('#control_border').change(function() {
var cur_value = parseInt($(this).val());
var activeObj = canvas.getActiveObject();
if (activeObj == undefined) {
alert('Please select the Object');
return false;
}
activeObj.set({
strokeWidth: cur_value
});
canvas.renderAll();
});
button {
max-resolution: 10px;
height: 30px;
}
div {
margin: 10px
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.0.0-beta.7/fabric.js"></script>
<div>
<button class="add_shape" data-rel="circle">Add Circle</button>
<button class="add_shape" data-rel="rectangle">Add Rectangle</button>
<label class="control-label">Border</label>
<input id="control_border" type="range" min="0" max="10" step="1" value="0" />
</div>
<canvas id="canvas1" width="600" height="300" style="border:1px solid #000000;"></canvas>
Steps
1) Add Rectangle
2) Apply the border (lets say 5)
3) Scale that object
Now you can see the applied border is gone. So how to resolve that?
Update
I have tried below option but its not working, basically i am trying to maintain strokeWidth/Border for objects like rectangle, circle, triangle, line, polygon
What i have tried so far:
//1st try
canvas.on('object:scaling', (e) => {
var o = e.target;
o.strokeWidth = o.strokeWidth / ((o.scaleX + o.scaleY) / 2);
var activeObject = canvas.getActiveObject();
activeObject.set('strokeWidth',o.strokeWidth);
});
//2nd try
canvas.on('object:scaling', (e) => {
if (!o.strokeWidthUnscaled && o.strokeWidth) {
o.strokeWidthUnscaled = o.strokeWidth;
}
if (o.strokeWidthUnscaled) {
o.strokeWidth = o.strokeWidthUnscaled / o.scaleX;
}
});
//3rd try
fabric.Object.prototype._renderStroke = function(ctx) {
if (!this.stroke || this.strokeWidth === 0) {
return;
}
if (this.shadow && !this.shadow.affectStroke) {
this._removeShadow(ctx);
}
ctx.save();
ctx.scale(1 / this.scaleX, 1 / this.scaleY);
this._setLineDash(ctx, this.strokeDashArray, this._renderDashedStroke);
this._applyPatternGradientTransform(ctx, this.stroke);
ctx.stroke();
ctx.restore();
};
Questions i have refereed:
https://github.com/kangax/fabric.js/issues/66
Unable to maintain thickness of strokeWidth while resizing in case of Groups in Fabricjs
Fabricjs How to scale object but keep the border (stroke) width fixed
Resize a fabricjs rect to maintain border size
https://github.com/kangax/fabric.js/issues/2012
But not able to found solution.
This has become much easier as of Fabric.js version 2.7.0. There is now a strokeUniform property that when enabled, prevents the stroke width from being affected by the object's scale values.
obj.set('strokeUniform', true);
https://github.com/fabricjs/fabric.js/pull/5546
var canvas = new fabric.Canvas('canvas1');
$('.add_shape').click(function() {
var cur_value = $(this).attr('data-rel');
if (cur_value != '') {
switch (cur_value) {
case 'rectangle':
var rect = new fabric.Rect({
left: 50,
top: 50,
fill: '#aaa',
width: 50,
height: 50,
opacity: 1,
stroke: '#000',
strokeWidth: 1,
noScaleCache: false,
strokeUniform: true,
});
canvas.add(rect);
canvas.setActiveObject(rect);
break;
case 'circle':
var circle = new fabric.Circle({
left: 50,
top: 50,
fill: '#aaa',
radius: 50,
opacity: 1,
stroke: '#000',
strokeWidth: 1,
noScaleCache: false,
strokeUniform: true
});
canvas.add(circle);
canvas.setActiveObject(circle);
break;
}
}
});
/* Control the border */
$('#control_border').change(function() {
var cur_value = parseInt($(this).val());
var activeObj = canvas.getActiveObject();
if (activeObj == undefined) {
alert('Please select the Object');
return false;
}
activeObj.set({
strokeWidth: cur_value
});
canvas.renderAll();
});
button {
max-resolution: 10px;
height: 30px;
}
div {
margin: 10px
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.7.0/fabric.min.js"></script>
<div>
<button class="add_shape" data-rel="circle">Add Circle</button>
<button class="add_shape" data-rel="rectangle">Add Rectangle</button>
<label class="control-label">Border</label>
<input id="control_border" type="range" min="0" max="10" step="1" value="0" />
</div>
<canvas id="canvas1" width="600" height="300" style="border:1px solid #000000;"></canvas>
Set strokeWidth to strokeWidthUnscaled for first time then set # at scalling, for caching make it false only when scalling after modified change it.
object.strokeWidth = object.strokeWidthUnscaled/((object.scaleX+object.scaleY)/2);
And for selecting new stroke width, do this
var newStrokeWidth = cur_value / ((activeObj.scaleX + activeObj.scaleY) / 2)
activeObj.set({
strokeWidth: newStrokeWidth,
strokeWidthUnscaled : cur_value
});
Example
var canvas = new fabric.Canvas('canvas1');
var globalStrokeWidth = 1;
$('.add_shape').click(function() {
var cur_value = $(this).attr('data-rel');
if (cur_value != '') {
switch (cur_value) {
case 'rectangle':
var rect = new fabric.Rect({
left: 50,
top: 50,
fill: '#aaa',
width: 50,
height: 50,
opacity: 1,
stroke: '#000',
strokeWidth: globalStrokeWidth
});
canvas.add(rect);
canvas.setActiveObject(rect);
break;
case 'circle':
var circle = new fabric.Circle({
left: 50,
top: 50,
fill: '#aaa',
radius: 50,
opacity: 1,
stroke: '#000',
strokeWidth: globalStrokeWidth
});
canvas.add(circle);
canvas.setActiveObject(circle);
break;
}
}
});
canvas.on('object:scaling', (e) => {
var o = e.target;
if (!o.strokeWidthUnscaled && o.strokeWidth) {
o.strokeWidthUnscaled = o.strokeWidth;
}
if (o.strokeWidthUnscaled) {
if(o.objectCaching) o.objectCaching = false;
o.strokeWidth = o.strokeWidthUnscaled / ((o.scaleX + o.scaleY) / 2);
}
});
canvas.on('object:modified', (e) => {
var o = e.target;
if(!o.objectCaching) o.objectCaching = true;
canvas.renderAll();
});
/* Control the border */
$('#control_border').change(function() {
var cur_value = parseInt($(this).val());
globalStrokeWidth = cur_value;
var activeObj = canvas.getActiveObject();
if (activeObj == undefined) {
alert('Please select the Object');
return false;
}
var newStrokeWidth = cur_value / ((activeObj.scaleX + activeObj.scaleY) / 2)
activeObj.set({
strokeWidth: newStrokeWidth,
strokeWidthUnscaled : cur_value
});
activeObj.setCoords();
canvas.renderAll();
});
button {
max-resolution: 10px;
height: 30px;
}
div {
margin: 10px
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.0.0-beta.7/fabric.js"></script>
<div>
<button class="add_shape" data-rel="circle">Add Circle</button>
<button class="add_shape" data-rel="rectangle">Add Rectangle</button>
<label class="control-label">Border</label>
<input id="control_border" type="range" min="0" max="10" step="1" value="0" />
</div>
<canvas id="canvas1" width="600" height="300" style="border:1px solid #000000;"></canvas>
While working on this issue, I've noticed that after resizing an object value of width and height doesn't change, it only changes scaleX and scaleY.
To maintain the stroke width, you need to reset scaleX and scalyY to 1 and also update width and height with new values.
For rectangle:
var currObj = canvas.getActiveObject();
if (currObj.type === 'rect') {
var newWidth = currObj.width * currObj.scaleX,
newHeight = currObj.height * currObj.scaleY;
currObj.set({
'width': newWidth,
'height': newHeight,
scaleX: 1,
scaleY: 1
});
}
For Ellipse:
var currObj = canvas.getActiveObject();
if (currObj.type === 'ellipse') {
var newRX = currObj.rx * currObj.scaleX,
newRY = currObj.ry * currObj.scaleY;
currObj.set({
'rx': newRX,
'ry': newRY,
scaleX: 1,
scaleY: 1
});
}
Don't forget to call canvas.renderAll() later;
http://jsfiddle.net/eLoamgrq/5/
In object:scaling, I commented out the calculation based on scale. Since the unscaled was = 1 and it was divided by scaling it always resulted in the border equaling a fraction (rather than staying put).
var canvas = new fabric.Canvas('canvas1');
$('.add_shape').click(function() {
var cur_value = $(this).attr('data-rel');
if (cur_value != '') {
switch (cur_value) {
case 'rectangle':
var rect = new fabric.Rect({
left: 50,
top: 50,
fill: '#aaa',
width: 50,
height: 50,
opacity: 1,
stroke: '#000',
strokeWidth: 1
});
canvas.add(rect);
canvas.setActiveObject(rect);
break;
case 'circle':
var circle = new fabric.Circle({
left: 50,
top: 50,
fill: '#aaa',
radius: 50,
opacity: 1,
stroke: '#000',
strokeWidth: 1
});
canvas.add(circle);
canvas.setActiveObject(circle);
break;
}
}
});
canvas.on('object:scaling', (e) => {
var o = e.target;
if (!o.strokeWidthUnscaled && o.strokeWidth) {
o.strokeWidthUnscaled = o.strokeWidth;
}
if (o.strokeWidthUnscaled) {
//o.strokeWidth = o.strokeWidthUnscaled / o.scaleX;
}
});
/* Control the border */
$('#control_border').change(function() {
var cur_value = parseInt($(this).val());
var activeObj = canvas.getActiveObject();
if (activeObj == undefined) {
alert('Please select the Object');
return false;
}
activeObj.set({
strokeWidth: cur_value
});
canvas.renderAll();
});
button {
max-resolution: 10px;
height: 30px;
}
div {
margin: 10px
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.0.0-beta.7/fabric.js"></script>
<div>
<button class="add_shape" data-rel="circle">Add Circle</button>
<button class="add_shape" data-rel="rectangle">Add Rectangle</button>
<label class="control-label">Border</label>
<input id="control_border" type="range" min="0" max="10" step="1" value="0" />
</div>
<canvas id="canvas1" width="600" height="300" style="border:1px solid #000000;"></canvas>
If your object is inside a group, strokeUniform property does not work. In that case you can reduce the scaling of the inner object and update its width and height property on scaling. Example:
object.on('scaling', function() {
object.item(0).set('scaleX', 1/object.scaleX);
object.item(0).set('scaleY', 1/object.scaleY);
var newobjwidth = Math.round(object.width * object.scaleX);
var newobjheight = Math.round(object.height * object.scaleY);
object.item(0).set('width', newobjwidth);
object.item(0).set('height', newobjheight);
object.item(0).setCoords();
}
If your object is blurry delete it and add it again after scaling.

How to select a color, fill it into the selected image that is uploaded in the canvas using fabric.js?

I have this project, and one of the requirement would be customize and design an uploaded image in a canvas
. So with customizing, I will upload an image, select it, and I want to change or tint the color with the selected color. But I do not know how.
var canvas = new fabric.Canvas('canvas');
var clearEl = document.getElementById('clear');
var reset = document.getElementById('Reset');
clearEl.onclick = function ()
{
canvas.clear()
};
reset.onclick = function () {
window.location.reload();
};
document.getElementById('file').addEventListener("change", function (e) {
var file = e.target.files[0];
var reader = new FileReader();
console.log("reader " + reader);
reader.onload = function (f) {
var data = f.target.result;
fabric.Image.fromURL(data, function (img) {
var oImg = img.set({ left: 70, top: 100, width: 250, height: 200, angle: 0 }).scale(0.9);
canvas.add(oImg).renderAll();
canvas.setActiveObject(oImg);
});
};
reader.readAsDataURL(file);
});
$('#fill').change(function () {
var obj = canvas.getActiveObject();
if (obj) {
obj.setFill($(this).val());
}
canvas.renderAll();
});
$('#font').change(function () {
var obj = canvas.getActiveObject();
if (obj) {
obj.setFontFamily($(this).val());
}
canvas.renderAll();
});
function addText() {
var oText = new fabric.IText('Tap and Type', {
left: 100,
top: 100,
});
canvas.add(oText);
canvas.setActiveObject(oText);
$('#fill, #font').trigger('change');
oText.bringToFront();
}
document.querySelector('#txt').onclick = function (e) {
e.preventDefault();
canvas.deactivateAll().renderAll();
document.querySelector('#preview').src = canvas.toDataURL();
};
$("#saveImg").click(function(){
$("#canvas").get(0).toBlob(function(blob){
saveAs(blob, uuidv4());
});
});
canvas{
border:1px solid black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://rawgit.com/kangax/fabric.js/master/dist/fabric.min.js"></script>
<input type="file" id="file">
<input type="color" value="blue" id="fill" />
<input type="checkbox" id=tint />
Tint:
<input type="color" value="blue" id="fillimage" />
<select id="font">
<option>arial</option>
<option>tahoma</option>
<option>times new roman</option>
</select>
<button onclick="addText(); return false;">Add Custom Text</button>
<input type="button" value="Clear Canvas" id="clear" />
<input type="button" value="Reset" id="Reset" />
<input type="button" id="saveImg" value="Save Image"/>
<br />
<canvas id="canvas" width="600" height="400"></canvas>
<br />
Preview Image
<br />
<img id="preview" />
The following code provides a basic demo of the functionality that you're trying to implement:
var canvas = new fabric.Canvas('canvas');
var clearEl = document.getElementById('clear');
var reset = document.getElementById('Reset');
clearEl.onclick = function ()
{
canvas.clear();
};
reset.onclick = function () {
window.location.reload();
};
document.getElementById('file').addEventListener("change", function (e) {
var file = e.target.files[0];
var reader = new FileReader();
console.log("reader " + reader);
reader.onload = function (f) {
var data = f.target.result;
fabric.Image.fromURL(data, function (img) {
var oImg = img.set({ left: 70, top: 100, width: 250, height: 200, angle: 0 }).scale(0.9);
canvas.add(oImg).renderAll();
canvas.setActiveObject(oImg);
});
};
reader.readAsDataURL(file);
});
$('#fill').change(function () {
var obj = canvas.getActiveObject();
if (obj) {
obj.setFill($(this).val());
}
canvas.renderAll();
});
$('#font').change(function () {
var obj = canvas.getActiveObject();
if (obj) {
obj.setFontFamily($(this).val());
}
canvas.renderAll();
});
// Listen for changes in UI
$('#tint').change(function() {
// Get the selected colour
var tintHex = $('#fillimage').val();
if ($(this).is(':checked') === true) {
applyTint(tintHex);
} else {
removeTint();
}
});
// Apply Tint filter
function applyTint (tintHex) {
// Get active object
var object = canvas.getActiveObject();
if (!object) {
console.error('No image selected');
return false;
// Could prompt the user to select an image, or programmatically do it for them
}
// Apply the tint. Based on docs at: http://fabricjs.com/docs/fabric.Image.filters.Tint.html#initialize
var tintFilter = new fabric.Image.filters.Tint({
color: tintHex,
//opacity: 0.5 // Could also pass in an opacity value
});
object.filters.push(tintFilter);
object.applyFilters(canvas.renderAll.bind(canvas));
}
// Remove Tint filter
function removeTint () {
// Get active object
var object = canvas.getActiveObject();
if (!object) {
console.error('No image selected');
return false;
// Could prompt the user to select an image, or programmatically do it for them
}
object.filters = []; // Empty filters array
object.applyFilters(canvas.renderAll.bind(canvas));
}
function addText() {
var oText = new fabric.IText('Tap and Type', {
left: 100,
top: 100,
});
canvas.add(oText);
canvas.setActiveObject(oText);
$('#fill, #font').trigger('change');
oText.bringToFront();
}
document.querySelector('#txt').onclick = function (e) {
e.preventDefault();
canvas.deactivateAll().renderAll();
document.querySelector('#preview').src = canvas.toDataURL();
};
$("#saveImg").click(function(){
$("#canvas").get(0).toBlob(function(blob){
saveAs(blob, uuidv4());
});
});
canvas{
border:1px solid black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.6.4/fabric.min.js"></script>
<input type="file" id="file">
<input type="color" value="blue" id="fill" />
<input type="checkbox" id=tint />
Tint:
<input type="color" value="blue" id="fillimage" />
<select id="font">
<option>arial</option>
<option>tahoma</option>
<option>times new roman</option>
</select>
<button onclick="addText(); return false;">Add Custom Text</button>
<input type="button" value="Clear Canvas" id="clear" />
<input type="button" value="Reset" id="Reset" />
<input type="button" id="saveImg" value="Save Image"/>
<br />
<canvas id="canvas" width="600" height="400"></canvas>
<br />
Preview Image
<br />
<img id="preview" />
Key changes:
Using a different CDN for the Fabric JS library. The version of the Fabric JS library that you were linking to was causing an error when attempting to create a Tint filter.
Using jQuery to listen for changes to checkbox state and call the new functions to apply or remove the tint filter
N.B. Be sure to test the example with a semi-transparent PNG image to see the tint in action

Convert canvas into image with fix size in HTML5

I am using HTML5. Right now I am convert canvas into image by toDataURL. But I want to this canvas convert into different size. For example, My canvas size is 450px*450px then it should convert into 1000px*1000px.
var canvas = new fabric.Canvas('canvas');
document.getElementById('file').addEventListener("change", function (e) {
var file = e.target.files[0];
var reader = new FileReader();
reader.onload = function (f) {
var data = f.target.result;
fabric.Image.fromURL(data, function (img) {
var oImg = img.set({left: 50, top: 100,width:100, height:100, angle: 00}).scale(0.9);
canvas.add(oImg).renderAll();
var a = canvas.setActiveObject(oImg);
var dataURL = canvas.toDataURL({format: 'png', quality: 0.8, width:1000, height:10000});
console.log("aaaaaaaaaaa" + dataURL);
// console.log("Canvas Image " + dataURL);
// document.getElementById('txt').href = dataURL;
});
};
reader.readAsDataURL(file);
});
document.querySelector('#txt').onclick = function (e) {
e.preventDefault();
canvas.deactivateAll().renderAll();
document.querySelector('#preview').src = canvas.toDataURL();
}
canvas {
border: 1px solid black;
}
<script src="https://rawgit.com/kangax/fabric.js/master/dist/fabric.min.js"></script>
<input type="file" id="file">
<canvas id="canvas" width="400" height="400"></canvas>
Click Me!!
<br />
<img id="preview" />
I tried canvas.toDataUrl({format: 'png', quality: 0.8, width:1000,
height:1000}) But it is not works.
DEMO JSFIDDLE.
https://jsfiddle.net/varunPes/8gt6d7op/13/
expected Result:
Just add width:1000, height:1000 to var oImg = img.set({left: 50, top: 100, angle: 00}).scale(0.9);
Full Code:
var canvas = new fabric.Canvas('canvas');
document.getElementById('file').addEventListener("change", function (e) {
var file = e.target.files[0];
var reader = new FileReader();
reader.onload = function (f) {
var data = f.target.result;
fabric.Image.fromURL(data, function (img) {
var oImg = img.set({left: 0, top: 0, angle: 00}).scale(0.9);
canvas.add(oImg).renderAll();
var a = canvas.setActiveObject(oImg);
var dataURL = canvas.toDataURL({format: 'png', quality: 0.8});
});
};
reader.readAsDataURL(file);
});
document.querySelector('#txt').onclick = function (e) {
e.preventDefault();
canvas.deactivateAll().renderAll();
increaseImg(canvas.toDataURL(), function(dataURL) {
document.querySelector('#preview').src = dataURL;
});
}
function increaseImg(src, callback) {
var n_canvas = $('<canvas width="1800" height="2000" />')[0],
n_ctx = n_canvas.getContext('2d'),
n_img = new Image();
n_img.onload = function() {
n_ctx.drawImage(n_img, 0, 0, n_canvas.width, n_canvas.height);
callback(n_canvas.toDataURL());
}
n_img.src = src;
}
canvas{
border: 1px solid black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://rawgit.com/kangax/fabric.js/master/dist/fabric.min.js"></script>
<input type="file" id="file"><br />
<canvas id="canvas" width="450" height="450"></canvas>
Click Me!!
<br />
<img id="preview" />
Your code is fine and do not need any big change.
If you want to export image in various dimensions try this.
I created two export links, one for width 500 and one for 1000.
As you see you can export image directly instead of canvas.
var canvas = new fabric.Canvas('canvas');
document.getElementById('file').addEventListener("change", function (e) {
var file = e.target.files[0];
var reader = new FileReader();
reader.onload = function (f) {
var data = f.target.result;
fabric.Image.fromURL(data, function (img) {
var oImg = img.set({left: 50, top: 100, angle: 00}).scale(0.9);
canvas.add(oImg);
});
};
reader.readAsDataURL(file);
});
document.querySelector('#txt').onclick = function (e) {
_export(e, 500);
}
document.querySelector('#txt2').onclick = function (e) {
_export(e, 1000);
}
function _export(e, width) {
e.preventDefault();
var a = canvas.getActiveObject();
canvas.deactivateAll().renderAll();
var mult = width / a.width;
document.querySelector('#preview').src = a.toDataURL({multiplier: mult});
}
canvas {
border: 1px solid black;
}
<script src="https://rawgit.com/kangax/fabric.js/master/dist/fabric.min.js"></script>
<input type="file" id="file">
<canvas id="canvas" width="400" height="400"></canvas>
Click Me!! 500<br />
Click Me!! 1000
<br />
<img id="preview" />
See if https://jsfiddle.net/8gt6d7op/14/ works. toDataURL only works with whatever is in the canvas, so you can't specify size. Size is already in the canvas.
You can use a 2nd canvas with a size you want and use that to populate the image from.
<script src="https://rawgit.com/kangax/fabric.js/master/dist/fabric.min.js"></script>
<input type="file" id="file">
<canvas id="canvas" width="400" height="400"></canvas>
Click Me!!
<br />
<img id="preview" />
<canvas id="canvas2" width="1000" height="1000" style="display:none;"></canvas>
var canvas = new fabric.Canvas('canvas');
var canvas2 = new fabric.Canvas('canvas2');
document.getElementById('file').addEventListener("change", function (e) {
var file = e.target.files[0];
var reader = new FileReader();
reader.onload = function (f) {
var data = f.target.result;
fabric.Image.fromURL(data, function (img) {
var oImg = img.set({left: 50, top: 100, angle: 00}).scale(0.9);
canvas.add(oImg).renderAll();
canvas2.add(oImg).renderAll();
var a = canvas.setActiveObject(oImg);
var dataURL = canvas2.toDataURL({format: 'png', quality: 0.8});
console.log("aaaaaaaaaaa" + dataURL);
// console.log("Canvas Image " + dataURL);
// document.getElementById('txt').href = dataURL;
});
};
reader.readAsDataURL(file);
});
document.querySelector('#txt').onclick = function (e) {
e.preventDefault();
canvas2.deactivateAll().renderAll();
document.querySelector('#preview').src = canvas2.toDataURL();
}

Categories