Reputation: 1626
Version
1.7.3
Test Case
http://jsfiddle.net/human_a/uhe70ju7/
/**
* Stack blur filter for fabricjs
* Example:
* obj.filters.push(new fabric.Image.filters.StackBlur(6));
* obj.applyFilters(canvas.renderAll.bind(canvas));
*
* Heavily inspired by:
* https://gist.github.com/pierrickouw/2ab679159beee9d80ca6
* http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html
* uses stackBlurCanvasRGBA function but could be swapped be stackBlurCanvasRGB
* @see: http://www.quasimondo.com/StackBlurForCanvas/StackBlur.js
*/
var fabric = window.fabric,
extend = fabric.util.object.extend;
var mul_table = [
512,512,456,512,328,456,335,512,405,328,271,456,388,335,292,512,
454,405,364,328,298,271,496,456,420,388,360,335,312,292,273,512,
482,454,428,405,383,364,345,328,312,298,284,271,259,496,475,456,
437,420,404,388,374,360,347,335,323,312,302,292,282,273,265,512,
497,482,468,454,441,428,417,405,394,383,373,364,354,345,337,328,
320,312,305,298,291,284,278,271,265,259,507,496,485,475,465,456,
446,437,428,420,412,404,396,388,381,374,367,360,354,347,341,335,
329,323,318,312,307,302,297,292,287,282,278,273,269,265,261,512,
505,497,489,482,475,468,461,454,447,441,435,428,422,417,411,405,
399,394,389,383,378,373,368,364,359,354,350,345,341,337,332,328,
324,320,316,312,309,305,301,298,294,291,287,284,281,278,274,271,
268,265,262,259,257,507,501,496,491,485,480,475,470,465,460,456,
451,446,442,437,433,428,424,420,416,412,408,404,400,396,392,388,
385,381,377,374,370,367,363,360,357,354,350,347,344,341,338,335,
332,329,326,323,320,318,315,312,310,307,304,302,299,297,294,292,
289,287,285,282,280,278,275,273,271,269,267,265,263,261,259
];
var shg_table = [
9, 11, 12, 13, 13, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 17,
17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23,
23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24
];
function BlurStack() {
this.r = 0;
this.g = 0;
this.b = 0;
this.a = 0;
this.next = null;
}
fabric.Image.filters.StackBlur = fabric.util.createClass(fabric.Image.filters.BaseFilter, {
/**
* Filter type
*/
type: 'StackBlur',
/**
* Constructor
*/
initialize: function(options) { //radius of the blur
options = options || {};
this.radius = options.radius || 0;
},
/**
* Applies blur to canvas element
*/
applyTo: function(canvasEl) {
// Don't apply blur if it's zero
if (!this.radius) return;
var radius = this.radius;
var width = canvasEl.width;
var height = canvasEl.height;
var context = canvasEl.getContext("2d");
var imageData;
imageData = context.getImageData( 0, 0, width, height );
var pixels = imageData.data;
var x, y, i, p, yp, yi, yw, r_sum, g_sum, b_sum, a_sum,
r_out_sum, g_out_sum, b_out_sum, a_out_sum,
r_in_sum, g_in_sum, b_in_sum, a_in_sum,
pr, pg, pb, pa, rbs;
var div = radius + radius + 1;
var widthMinus1 = width - 1;
var heightMinus1 = height - 1;
var radiusPlus1 = radius + 1;
var sumFactor = radiusPlus1 * ( radiusPlus1 + 1 ) / 2;
var stackStart = new BlurStack();
var stack = stackStart;
for ( i = 1; i < div; i++ ) {
stack = stack.next = new BlurStack();
if ( i === radiusPlus1 ) var stackEnd = stack;
}
stack.next = stackStart;
var stackIn = null;
var stackOut = null;
yw = yi = 0;
var mul_sum = mul_table[radius];
var shg_sum = shg_table[radius];
for ( y = 0; y < height; y++ ) {
r_in_sum = g_in_sum = b_in_sum = a_in_sum = r_sum = g_sum = b_sum = a_sum = 0;
r_out_sum = radiusPlus1 * ( pr = pixels[yi] );
g_out_sum = radiusPlus1 * ( pg = pixels[yi+1] );
b_out_sum = radiusPlus1 * ( pb = pixels[yi+2] );
a_out_sum = radiusPlus1 * ( pa = pixels[yi+3] );
r_sum += sumFactor * pr;
g_sum += sumFactor * pg;
b_sum += sumFactor * pb;
a_sum += sumFactor * pa;
stack = stackStart;
for( i = 0; i < radiusPlus1; i++ ) {
stack.r = pr;
stack.g = pg;
stack.b = pb;
stack.a = pa;
stack = stack.next;
}
for( i = 1; i < radiusPlus1; i++ ) {
p = yi + (( widthMinus1 < i ? widthMinus1 : i ) << 2 );
r_sum += ( stack.r = ( pr = pixels[p])) * ( rbs = radiusPlus1 - i );
g_sum += ( stack.g = ( pg = pixels[p+1])) * rbs;
b_sum += ( stack.b = ( pb = pixels[p+2])) * rbs;
a_sum += ( stack.a = ( pa = pixels[p+3])) * rbs;
r_in_sum += pr;
g_in_sum += pg;
b_in_sum += pb;
a_in_sum += pa;
stack = stack.next;
}
stackIn = stackStart;
stackOut = stackEnd;
for ( x = 0; x < width; x++ ) {
pixels[yi+3] = pa = (a_sum * mul_sum) >> shg_sum;
if ( pa !== 0 )
{
pa = 255 / pa;
pixels[yi] = ((r_sum * mul_sum) >> shg_sum) * pa;
pixels[yi+1] = ((g_sum * mul_sum) >> shg_sum) * pa;
pixels[yi+2] = ((b_sum * mul_sum) >> shg_sum) * pa;
} else {
pixels[yi] = pixels[yi+1] = pixels[yi+2] = 0;
}
r_sum -= r_out_sum;
g_sum -= g_out_sum;
b_sum -= b_out_sum;
a_sum -= a_out_sum;
r_out_sum -= stackIn.r;
g_out_sum -= stackIn.g;
b_out_sum -= stackIn.b;
a_out_sum -= stackIn.a;
// eslint-disable-next-line
p = ( yw + ( ( p = x + radius + 1 ) < widthMinus1 ? p : widthMinus1 ) ) << 2;
r_in_sum += ( stackIn.r = pixels[p]);
g_in_sum += ( stackIn.g = pixels[p+1]);
b_in_sum += ( stackIn.b = pixels[p+2]);
a_in_sum += ( stackIn.a = pixels[p+3]);
r_sum += r_in_sum;
g_sum += g_in_sum;
b_sum += b_in_sum;
a_sum += a_in_sum;
stackIn = stackIn.next;
r_out_sum += ( pr = stackOut.r );
g_out_sum += ( pg = stackOut.g );
b_out_sum += ( pb = stackOut.b );
a_out_sum += ( pa = stackOut.a );
r_in_sum -= pr;
g_in_sum -= pg;
b_in_sum -= pb;
a_in_sum -= pa;
stackOut = stackOut.next;
yi += 4;
}
yw += width;
}
for ( x = 0; x < width; x++ ) {
g_in_sum = b_in_sum = a_in_sum = r_in_sum = g_sum = b_sum = a_sum = r_sum = 0;
yi = x << 2;
r_out_sum = radiusPlus1 * ( pr = pixels[yi]);
g_out_sum = radiusPlus1 * ( pg = pixels[yi+1]);
b_out_sum = radiusPlus1 * ( pb = pixels[yi+2]);
a_out_sum = radiusPlus1 * ( pa = pixels[yi+3]);
r_sum += sumFactor * pr;
g_sum += sumFactor * pg;
b_sum += sumFactor * pb;
a_sum += sumFactor * pa;
stack = stackStart;
for( i = 0; i < radiusPlus1; i++ )
{
stack.r = pr;
stack.g = pg;
stack.b = pb;
stack.a = pa;
stack = stack.next;
}
yp = width;
for( i = 1; i <= radius; i++ )
{
yi = ( yp + x ) << 2;
r_sum += ( stack.r = ( pr = pixels[yi])) * ( rbs = radiusPlus1 - i );
g_sum += ( stack.g = ( pg = pixels[yi+1])) * rbs;
b_sum += ( stack.b = ( pb = pixels[yi+2])) * rbs;
a_sum += ( stack.a = ( pa = pixels[yi+3])) * rbs;
r_in_sum += pr;
g_in_sum += pg;
b_in_sum += pb;
a_in_sum += pa;
stack = stack.next;
if( i < heightMinus1 )
{
yp += width;
}
}
yi = x;
stackIn = stackStart;
stackOut = stackEnd;
for ( y = 0; y < height; y++ )
{
p = yi << 2;
pixels[p+3] = pa = (a_sum * mul_sum) >> shg_sum;
if ( pa > 0 )
{
pa = 255 / pa;
pixels[p] = ((r_sum * mul_sum) >> shg_sum ) * pa;
pixels[p+1] = ((g_sum * mul_sum) >> shg_sum ) * pa;
pixels[p+2] = ((b_sum * mul_sum) >> shg_sum ) * pa;
} else {
pixels[p] = pixels[p+1] = pixels[p+2] = 0;
}
r_sum -= r_out_sum;
g_sum -= g_out_sum;
b_sum -= b_out_sum;
a_sum -= a_out_sum;
r_out_sum -= stackIn.r;
g_out_sum -= stackIn.g;
b_out_sum -= stackIn.b;
a_out_sum -= stackIn.a;
// eslint-disable-next-line
p = ( x + (( ( p = y + radiusPlus1) < heightMinus1 ? p : heightMinus1 ) * width )) << 2;
r_sum += ( r_in_sum += ( stackIn.r = pixels[p]));
g_sum += ( g_in_sum += ( stackIn.g = pixels[p+1]));
b_sum += ( b_in_sum += ( stackIn.b = pixels[p+2]));
a_sum += ( a_in_sum += ( stackIn.a = pixels[p+3]));
stackIn = stackIn.next;
r_out_sum += ( pr = stackOut.r );
g_out_sum += ( pg = stackOut.g );
b_out_sum += ( pb = stackOut.b );
a_out_sum += ( pa = stackOut.a );
r_in_sum -= pr;
g_in_sum -= pg;
b_in_sum -= pb;
a_in_sum -= pa;
stackOut = stackOut.next;
yi += width;
}
}
context.putImageData( imageData, 0, 0 );
},
/**
* Returns object representation of an instance
*/
toObject: function() {
return extend(this.callSuper('toObject'), {
radius: this.radius
});
}
});
fabric.Image.filters.StackBlur.fromObject = function() {
return new fabric.Image.filters.StackBlur()
};
/* END OF STACK BLUR FILTER PLUGIN */
/* Start loading the canvas */
const canvas = new fabric.Canvas();
const el = document.getElementById('my-canvas');
const button1 = document.getElementById('load-canvas1');
const button2 = document.getElementById('load-canvas2');
const addBlur = document.getElementById('add-blur');
const json1 = {"background":"rgba(255, 255, 255, 1)","height":480,"objects":[{"alignX":"none","alignY":"none","angle":0,"backgroundColor":"","crossOrigin":"Anonymous","evented":true,"fill":"rgb(0,0,0)","fillRule":"nonzero","filters":[{"radius":21,"type":"StackBlur"}],"flipX":false,"flipY":false,"globalCompositeOperation":"source-over","height":720,"itemThumb":"https://images.unsplash.com/photo-1485239269752-c4fb2b79e7bd?ixlib=rb-0.3.5…crop=entropy&cs=tinysrgb&w=1080&fit=max&s=4f605a4cfd9130ff74b49f5b61d44436","itemTitle":"Image layer","left":360,"lockMovementX":false,"lockMovementY":false,"lockRotation":false,"lockScalingX":false,"lockScalingY":false,"lockUniScaling":true,"meetOrSlice":"meet","objType":"item","opacity":1,"originX":"center","originY":"center","scaleX":1,"scaleY":1,"selectable":true,"skewX":0,"skewY":0,"src":"https://images.unsplash.com/photo-1485239269752-c4fb2b79e7bd?ixlib=rb-0.3.5…crop=entropy&cs=tinysrgb&w=1080&fit=max&s=4f605a4cfd9130ff74b49f5b61d44436","stroke":"","strokeLineCap":"butt","strokeLineJoin":"miter","strokeMiterLimit":10,"strokeWidth":0,"timestamp":1485254754,"top":241,"type":"image","uuid":"e19bcfb3-4993-4709-bca3-ccf5be20c62f","visible":true,"width":1080}],"width":720}
const json2 = {"background":"rgba(255, 255, 255, 1)","height":480,"hoverCursor":"move","id":"mainCanvas","lastModified":1485254765,"objects":[{"alignX":"none","alignY":"none","angle":0,"backgroundColor":"","crossOrigin":"Anonymous","evented":true,"fill":"rgb(0,0,0)","fillRule":"nonzero","filters":[],"flipX":false,"flipY":false,"globalCompositeOperation":"source-over","height":720,"itemThumb":"https://images.unsplash.com/photo-1485239269752-c4fb2b79e7bd?ixlib=rb-0.3.5…crop=entropy&cs=tinysrgb&w=1080&fit=max&s=4f605a4cfd9130ff74b49f5b61d44436","itemTitle":"Image layer","left":360,"lockMovementX":false,"lockMovementY":false,"lockRotation":false,"lockScalingX":false,"lockScalingY":false,"lockUniScaling":true,"meetOrSlice":"meet","objType":"item","opacity":1,"originX":"center","originY":"center","scaleX":1,"scaleY":1,"selectable":true,"skewX":0,"skewY":0,"src":"https://images.unsplash.com/photo-1485239269752-c4fb2b79e7bd?ixlib=rb-0.3.5…crop=entropy&cs=tinysrgb&w=1080&fit=max&s=4f605a4cfd9130ff74b49f5b61d44436","stroke":"","strokeLineCap":"butt","strokeLineJoin":"miter","strokeMiterLimit":10,"strokeWidth":0,"timestamp":1485254754,"top":241,"type":"image","uuid":"e19bcfb3-4993-4709-bca3-ccf5be20c62f","visible":true,"width":1080}],"projectDesc":"","projectName":"Untitled Project","projectPublished":false,"projectTags":"","publicDemo":false,"textTemplate":false,"timestamp":1485254742,"width":720}
// Load canvas that contains an image with blur
const loadCanvas1 = function() {
canvas.initialize(el, {
backgroundColor: '#FFFFFF',
enableRetinaScaling: true,
preserveObjectStacking: true,
controlsAboveOverlay: false,
selectionCompatibility: true,
stopContextMenu: true,
fireRightClick: true,
width: 720,
height: 480,
});
canvas.loadFromJSON( JSON.stringify(json1), canvas.renderAll.bind(canvas) );
};
button1.addEventListener( 'click', loadCanvas1 );
// Load canvas WITHOUT blur
const loadCanvas2 = function() {
canvas.initialize(el, {
backgroundColor: '#FFFFFF',
enableRetinaScaling: true,
preserveObjectStacking: true,
controlsAboveOverlay: false,
selectionCompatibility: true,
stopContextMenu: true,
fireRightClick: true,
width: 720,
height: 480,
});
canvas.loadFromJSON( JSON.stringify(json2), ()=>{
canvas.renderAll.bind(canvas)
canvas.setActiveObject(canvas.getObjects()[0])
} );
};
button2.addEventListener( 'click', loadCanvas2 );
// Add blur event
const addBlurFunc = function() {
if(canvas.getActiveObject()) {
canvas.getActiveObject().filters.push(new fabric.Image.filters.StackBlur({radius: 30}));
canvas.getActiveObject().applyFilters(canvas.renderAll.bind(canvas));
canvas.renderAll();
}
}
addBlur.addEventListener( 'click', addBlurFunc );
button {
border: 0 none;
background: #fff;
border-radius: 5px;
cursor: pointer;
color: #333;
box-shadow: 0 4px 6px rgba(50, 50, 93, 0.11), 0 1px 3px rgba(0, 0, 0, 0.08);
padding: 11px 22px;
font-weight: 600;
font-size: 13px;
letter-spacing: 1px;
margin: 10px auto;
outline: 0 none;
}
button.blue {
background: #1877FF;
color: #fff;
}
button.red {
background: #C35A2D;
color: #fff;
}
button.green {
background: #65C879;
color: #fff;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.3/fabric.min.js"></script>
<canvas id="my-canvas"></canvas>
<div>
<button id="load-canvas2" class="green">LOAD CANVAS</button>
<button id="add-blur" class="blue">ADD BLUR</button>
</div>
<button id="load-canvas1" class="red">LOAD WITH BLUR</button>
Steps to reproduce
Click on the green button to load a canvas via JSON (const json2) and then click on the blue button to add StackBlur to the image inside the project. You can see that the StackBlur filter works fine.
Now click on the red button, it tries to load the other JSON (const json1) which contains an image with StackBlur filter assigned to it. But this time it fails to load the project completely, no errors shown.
Expected Behavior
If the StackBlur filter works when assigning it to the image, it should also work when loading a saved project via JSON.
Actual Behavior
It fails to load a canvas if it contains any elements with StackBlur filter assigned to them.
PS
I created this StackBlur filter plugin based on the following projects: https://gist.github.com/pierrickouw/2ab679159beee9d80ca6 http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html
You can see my gist here: https://gist.github.com/human-a/25b7f58565b89de4e999ef2f4de1982c
Upvotes: 0
Views: 684
Reputation: 1626
This question is answered here: https://github.com/kangax/fabric.js/issues/3645
The corrected version of the plugin could be found here: https://gist.github.com/human-a/25b7f58565b89de4e999ef2f4de1982c
/**
* Stack blur filter for fabricjs
* Example:
* obj.filters.push(new fabric.Image.filters.StackBlur(6));
* obj.applyFilters(canvas.renderAll.bind(canvas));
*
* Heavily inspired by:
* https://gist.github.com/pierrickouw/2ab679159beee9d80ca6
* http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html
* uses stackBlurCanvasRGBA function but could be swapped be stackBlurCanvasRGB
* @see: http://www.quasimondo.com/StackBlurForCanvas/StackBlur.js
*/
var fabric = window.fabric,
extend = fabric.util.object.extend;
var mul_table = [
512,512,456,512,328,456,335,512,405,328,271,456,388,335,292,512,
454,405,364,328,298,271,496,456,420,388,360,335,312,292,273,512,
482,454,428,405,383,364,345,328,312,298,284,271,259,496,475,456,
437,420,404,388,374,360,347,335,323,312,302,292,282,273,265,512,
497,482,468,454,441,428,417,405,394,383,373,364,354,345,337,328,
320,312,305,298,291,284,278,271,265,259,507,496,485,475,465,456,
446,437,428,420,412,404,396,388,381,374,367,360,354,347,341,335,
329,323,318,312,307,302,297,292,287,282,278,273,269,265,261,512,
505,497,489,482,475,468,461,454,447,441,435,428,422,417,411,405,
399,394,389,383,378,373,368,364,359,354,350,345,341,337,332,328,
324,320,316,312,309,305,301,298,294,291,287,284,281,278,274,271,
268,265,262,259,257,507,501,496,491,485,480,475,470,465,460,456,
451,446,442,437,433,428,424,420,416,412,408,404,400,396,392,388,
385,381,377,374,370,367,363,360,357,354,350,347,344,341,338,335,
332,329,326,323,320,318,315,312,310,307,304,302,299,297,294,292,
289,287,285,282,280,278,275,273,271,269,267,265,263,261,259
];
var shg_table = [
9, 11, 12, 13, 13, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 17,
17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23,
23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24
];
function BlurStack() {
this.r = 0;
this.g = 0;
this.b = 0;
this.a = 0;
this.next = null;
}
fabric.Image.filters.StackBlur = fabric.util.createClass(fabric.Image.filters.BaseFilter, {
/**
* Filter type
*/
type: 'StackBlur',
/**
* Constructor
*/
initialize: function(options) { //radius of the blur
options = options || {};
this.radius = options.radius || 0;
},
/**
* Applies blur to canvas element
*/
applyTo: function(canvasEl) {
// Don't apply blur if it's zero
if (!this.radius) return;
var radius = this.radius;
var width = canvasEl.width;
var height = canvasEl.height;
var context = canvasEl.getContext("2d");
var imageData;
imageData = context.getImageData( 0, 0, width, height );
var pixels = imageData.data;
var x, y, i, p, yp, yi, yw, r_sum, g_sum, b_sum, a_sum,
r_out_sum, g_out_sum, b_out_sum, a_out_sum,
r_in_sum, g_in_sum, b_in_sum, a_in_sum,
pr, pg, pb, pa, rbs;
var div = radius + radius + 1;
var widthMinus1 = width - 1;
var heightMinus1 = height - 1;
var radiusPlus1 = radius + 1;
var sumFactor = radiusPlus1 * ( radiusPlus1 + 1 ) / 2;
var stackStart = new BlurStack();
var stack = stackStart;
for ( i = 1; i < div; i++ ) {
stack = stack.next = new BlurStack();
if ( i === radiusPlus1 ) var stackEnd = stack;
}
stack.next = stackStart;
var stackIn = null;
var stackOut = null;
yw = yi = 0;
var mul_sum = mul_table[radius];
var shg_sum = shg_table[radius];
for ( y = 0; y < height; y++ ) {
r_in_sum = g_in_sum = b_in_sum = a_in_sum = r_sum = g_sum = b_sum = a_sum = 0;
r_out_sum = radiusPlus1 * ( pr = pixels[yi] );
g_out_sum = radiusPlus1 * ( pg = pixels[yi+1] );
b_out_sum = radiusPlus1 * ( pb = pixels[yi+2] );
a_out_sum = radiusPlus1 * ( pa = pixels[yi+3] );
r_sum += sumFactor * pr;
g_sum += sumFactor * pg;
b_sum += sumFactor * pb;
a_sum += sumFactor * pa;
stack = stackStart;
for( i = 0; i < radiusPlus1; i++ ) {
stack.r = pr;
stack.g = pg;
stack.b = pb;
stack.a = pa;
stack = stack.next;
}
for( i = 1; i < radiusPlus1; i++ ) {
p = yi + (( widthMinus1 < i ? widthMinus1 : i ) << 2 );
r_sum += ( stack.r = ( pr = pixels[p])) * ( rbs = radiusPlus1 - i );
g_sum += ( stack.g = ( pg = pixels[p+1])) * rbs;
b_sum += ( stack.b = ( pb = pixels[p+2])) * rbs;
a_sum += ( stack.a = ( pa = pixels[p+3])) * rbs;
r_in_sum += pr;
g_in_sum += pg;
b_in_sum += pb;
a_in_sum += pa;
stack = stack.next;
}
stackIn = stackStart;
stackOut = stackEnd;
for ( x = 0; x < width; x++ ) {
pixels[yi+3] = pa = (a_sum * mul_sum) >> shg_sum;
if ( pa !== 0 )
{
pa = 255 / pa;
pixels[yi] = ((r_sum * mul_sum) >> shg_sum) * pa;
pixels[yi+1] = ((g_sum * mul_sum) >> shg_sum) * pa;
pixels[yi+2] = ((b_sum * mul_sum) >> shg_sum) * pa;
} else {
pixels[yi] = pixels[yi+1] = pixels[yi+2] = 0;
}
r_sum -= r_out_sum;
g_sum -= g_out_sum;
b_sum -= b_out_sum;
a_sum -= a_out_sum;
r_out_sum -= stackIn.r;
g_out_sum -= stackIn.g;
b_out_sum -= stackIn.b;
a_out_sum -= stackIn.a;
// eslint-disable-next-line
p = ( yw + ( ( p = x + radius + 1 ) < widthMinus1 ? p : widthMinus1 ) ) << 2;
r_in_sum += ( stackIn.r = pixels[p]);
g_in_sum += ( stackIn.g = pixels[p+1]);
b_in_sum += ( stackIn.b = pixels[p+2]);
a_in_sum += ( stackIn.a = pixels[p+3]);
r_sum += r_in_sum;
g_sum += g_in_sum;
b_sum += b_in_sum;
a_sum += a_in_sum;
stackIn = stackIn.next;
r_out_sum += ( pr = stackOut.r );
g_out_sum += ( pg = stackOut.g );
b_out_sum += ( pb = stackOut.b );
a_out_sum += ( pa = stackOut.a );
r_in_sum -= pr;
g_in_sum -= pg;
b_in_sum -= pb;
a_in_sum -= pa;
stackOut = stackOut.next;
yi += 4;
}
yw += width;
}
for ( x = 0; x < width; x++ ) {
g_in_sum = b_in_sum = a_in_sum = r_in_sum = g_sum = b_sum = a_sum = r_sum = 0;
yi = x << 2;
r_out_sum = radiusPlus1 * ( pr = pixels[yi]);
g_out_sum = radiusPlus1 * ( pg = pixels[yi+1]);
b_out_sum = radiusPlus1 * ( pb = pixels[yi+2]);
a_out_sum = radiusPlus1 * ( pa = pixels[yi+3]);
r_sum += sumFactor * pr;
g_sum += sumFactor * pg;
b_sum += sumFactor * pb;
a_sum += sumFactor * pa;
stack = stackStart;
for( i = 0; i < radiusPlus1; i++ )
{
stack.r = pr;
stack.g = pg;
stack.b = pb;
stack.a = pa;
stack = stack.next;
}
yp = width;
for( i = 1; i <= radius; i++ )
{
yi = ( yp + x ) << 2;
r_sum += ( stack.r = ( pr = pixels[yi])) * ( rbs = radiusPlus1 - i );
g_sum += ( stack.g = ( pg = pixels[yi+1])) * rbs;
b_sum += ( stack.b = ( pb = pixels[yi+2])) * rbs;
a_sum += ( stack.a = ( pa = pixels[yi+3])) * rbs;
r_in_sum += pr;
g_in_sum += pg;
b_in_sum += pb;
a_in_sum += pa;
stack = stack.next;
if( i < heightMinus1 )
{
yp += width;
}
}
yi = x;
stackIn = stackStart;
stackOut = stackEnd;
for ( y = 0; y < height; y++ )
{
p = yi << 2;
pixels[p+3] = pa = (a_sum * mul_sum) >> shg_sum;
if ( pa > 0 )
{
pa = 255 / pa;
pixels[p] = ((r_sum * mul_sum) >> shg_sum ) * pa;
pixels[p+1] = ((g_sum * mul_sum) >> shg_sum ) * pa;
pixels[p+2] = ((b_sum * mul_sum) >> shg_sum ) * pa;
} else {
pixels[p] = pixels[p+1] = pixels[p+2] = 0;
}
r_sum -= r_out_sum;
g_sum -= g_out_sum;
b_sum -= b_out_sum;
a_sum -= a_out_sum;
r_out_sum -= stackIn.r;
g_out_sum -= stackIn.g;
b_out_sum -= stackIn.b;
a_out_sum -= stackIn.a;
// eslint-disable-next-line
p = ( x + (( ( p = y + radiusPlus1) < heightMinus1 ? p : heightMinus1 ) * width )) << 2;
r_sum += ( r_in_sum += ( stackIn.r = pixels[p]));
g_sum += ( g_in_sum += ( stackIn.g = pixels[p+1]));
b_sum += ( b_in_sum += ( stackIn.b = pixels[p+2]));
a_sum += ( a_in_sum += ( stackIn.a = pixels[p+3]));
stackIn = stackIn.next;
r_out_sum += ( pr = stackOut.r );
g_out_sum += ( pg = stackOut.g );
b_out_sum += ( pb = stackOut.b );
a_out_sum += ( pa = stackOut.a );
r_in_sum -= pr;
g_in_sum -= pg;
b_in_sum -= pb;
a_in_sum -= pa;
stackOut = stackOut.next;
yi += width;
}
}
context.putImageData( imageData, 0, 0 );
},
/**
* Returns object representation of an instance
*/
toObject: function() {
return extend(this.callSuper('toObject'), {
radius: this.radius
});
}
});
fabric.Image.filters.StackBlur.fromObject = fabric.Image.filters.BaseFilter.fromObject
/* END OF STACK BLUR FILTER PLUGIN */
/* Start loading the canvas */
const canvas = new fabric.Canvas();
const el = document.getElementById('my-canvas');
const button1 = document.getElementById('load-canvas1');
const button2 = document.getElementById('load-canvas2');
const addBlur = document.getElementById('add-blur');
const json1 = {"background":"rgba(255, 255, 255, 1)","height":480,"objects":[{"alignX":"none","alignY":"none","angle":0,"backgroundColor":"","crossOrigin":"Anonymous","evented":true,"fill":"rgb(0,0,0)","fillRule":"nonzero","filters":[{"radius":21,"type":"StackBlur"}],"flipX":false,"flipY":false,"globalCompositeOperation":"source-over","height":720,"itemThumb":"https://images.unsplash.com/photo-1485239269752-c4fb2b79e7bd?ixlib=rb-0.3.5…crop=entropy&cs=tinysrgb&w=1080&fit=max&s=4f605a4cfd9130ff74b49f5b61d44436","itemTitle":"Image layer","left":360,"lockMovementX":false,"lockMovementY":false,"lockRotation":false,"lockScalingX":false,"lockScalingY":false,"lockUniScaling":true,"meetOrSlice":"meet","objType":"item","opacity":1,"originX":"center","originY":"center","scaleX":1,"scaleY":1,"selectable":true,"skewX":0,"skewY":0,"src":"https://images.unsplash.com/photo-1485239269752-c4fb2b79e7bd?ixlib=rb-0.3.5…crop=entropy&cs=tinysrgb&w=1080&fit=max&s=4f605a4cfd9130ff74b49f5b61d44436","stroke":"","strokeLineCap":"butt","strokeLineJoin":"miter","strokeMiterLimit":10,"strokeWidth":0,"timestamp":1485254754,"top":241,"type":"image","uuid":"e19bcfb3-4993-4709-bca3-ccf5be20c62f","visible":true,"width":1080}],"width":720}
const json2 = {"background":"rgba(255, 255, 255, 1)","height":480,"hoverCursor":"move","id":"mainCanvas","lastModified":1485254765,"objects":[{"alignX":"none","alignY":"none","angle":0,"backgroundColor":"","crossOrigin":"Anonymous","evented":true,"fill":"rgb(0,0,0)","fillRule":"nonzero","filters":[],"flipX":false,"flipY":false,"globalCompositeOperation":"source-over","height":720,"itemThumb":"https://images.unsplash.com/photo-1485239269752-c4fb2b79e7bd?ixlib=rb-0.3.5…crop=entropy&cs=tinysrgb&w=1080&fit=max&s=4f605a4cfd9130ff74b49f5b61d44436","itemTitle":"Image layer","left":360,"lockMovementX":false,"lockMovementY":false,"lockRotation":false,"lockScalingX":false,"lockScalingY":false,"lockUniScaling":true,"meetOrSlice":"meet","objType":"item","opacity":1,"originX":"center","originY":"center","scaleX":1,"scaleY":1,"selectable":true,"skewX":0,"skewY":0,"src":"https://images.unsplash.com/photo-1485239269752-c4fb2b79e7bd?ixlib=rb-0.3.5…crop=entropy&cs=tinysrgb&w=1080&fit=max&s=4f605a4cfd9130ff74b49f5b61d44436","stroke":"","strokeLineCap":"butt","strokeLineJoin":"miter","strokeMiterLimit":10,"strokeWidth":0,"timestamp":1485254754,"top":241,"type":"image","uuid":"e19bcfb3-4993-4709-bca3-ccf5be20c62f","visible":true,"width":1080}],"projectDesc":"","projectName":"Untitled Project","projectPublished":false,"projectTags":"","publicDemo":false,"textTemplate":false,"timestamp":1485254742,"width":720}
// Load canvas that contains an image with blur
const loadCanvas1 = function() {
canvas.initialize(el, {
backgroundColor: '#FFFFFF',
enableRetinaScaling: true,
preserveObjectStacking: true,
controlsAboveOverlay: false,
selectionCompatibility: true,
stopContextMenu: true,
fireRightClick: true,
width: 720,
height: 480,
});
canvas.loadFromJSON( JSON.stringify(json1), canvas.renderAll.bind(canvas) );
};
button1.addEventListener( 'click', loadCanvas1 );
// Load canvas WITHOUT blur
const loadCanvas2 = function() {
canvas.initialize(el, {
backgroundColor: '#FFFFFF',
enableRetinaScaling: true,
preserveObjectStacking: true,
controlsAboveOverlay: false,
selectionCompatibility: true,
stopContextMenu: true,
fireRightClick: true,
width: 720,
height: 480,
});
canvas.loadFromJSON( JSON.stringify(json2), ()=>{
canvas.renderAll.bind(canvas)
canvas.setActiveObject(canvas.getObjects()[0])
} );
};
button2.addEventListener( 'click', loadCanvas2 );
// Add blur event
const addBlurFunc = function() {
if(canvas.getActiveObject()) {
canvas.getActiveObject().filters.push(new fabric.Image.filters.StackBlur({radius: 30}));
canvas.getActiveObject().applyFilters(canvas.renderAll.bind(canvas));
canvas.renderAll();
}
}
addBlur.addEventListener( 'click', addBlurFunc );
button {
border: 0 none;
background: #fff;
border-radius: 5px;
cursor: pointer;
color: #333;
box-shadow: 0 4px 6px rgba(50, 50, 93, 0.11), 0 1px 3px rgba(0, 0, 0, 0.08);
padding: 11px 22px;
font-weight: 600;
font-size: 13px;
letter-spacing: 1px;
margin: 10px auto;
outline: 0 none;
}
button.blue {
background: #1877FF;
color: #fff;
}
button.red {
background: #C35A2D;
color: #fff;
}
button.green {
background: #65C879;
color: #fff;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.3/fabric.min.js"></script>
<canvas id="my-canvas"></canvas>
<div>
<button id="load-canvas2" class="green">LOAD CANVAS</button>
<button id="add-blur" class="blue">ADD BLUR</button>
</div>
<button id="load-canvas1" class="red">LOAD WITH BLUR</button>
Upvotes: 1