Added Gaussian Blur back, put QuickBlur in separate file

This commit is contained in:
ippo615 2013-12-04 19:03:20 -05:00
parent 21b0bb8574
commit a680d33c40
6 changed files with 733 additions and 231 deletions

View File

@ -39,6 +39,7 @@ module.exports = function(grunt) {
'src/filters/Brighten.js', 'src/filters/Brighten.js',
'src/filters/Invert.js', 'src/filters/Invert.js',
'src/filters/Blur.js', 'src/filters/Blur.js',
'src/filters/QuickBlur.js',
'src/filters/Mask.js', 'src/filters/Mask.js',
'src/filters/ColorPack.js', 'src/filters/ColorPack.js',
'src/filters/ConvolvePack.js', 'src/filters/ConvolvePack.js',

View File

@ -1,225 +1,375 @@
(function () { /*
the Gauss filter
/** master repo: https://github.com/pavelpower/kineticjsGaussFilter/
* BlurX Filter. Blurs the image in the X direction (horizontally). It */
* performs w*h pixel reads, and w*h pixel writes. (function() {
* @function /*
* @author ippo615
* @memberof Kinetic.Filters StackBlur - a fast almost Gaussian Blur For Canvas
* @param {ImageData} src, the source image data (what will be transformed)
* @param {ImageData} dst, the destination image data (where it will be saved) Version: 0.5
* @param {Object} opt Author: Mario Klingemann
* @param {Number} [opt.blurWidth] how many neighboring pixels to will affect the Contact: mario@quasimondo.com
* blurred pixel, default: 5 Website: http://www.quasimondo.com/StackBlurForCanvas
*/ Twitter: @quasimondo
var BlurX = function(src,dst,opt){ In case you find this class useful - especially in commercial projects -
I am not totally unhappy for a small donation to my PayPal account
var srcPixels = src.data, mario@quasimondo.de
dstPixels = dst.data,
xSize = src.width, Or support me on flattr:
ySize = src.height, https://flattr.com/thing/72791/StackBlur-a-fast-almost-Gaussian-Blur-Effect-for-CanvasJavascript
i, m, x, y, k, tmp, r=0,g=0,b=0,a=0;
Copyright (c) 2010 Mario Klingemann
// DONT USE: kSize = opt.blurWidth || 5;
// HINT: consider when (opt.blurWidth = 0) Permission is hereby granted, free of charge, to any person
var kSize = 5; obtaining a copy of this software and associated documentation
if( opt.hasOwnProperty('blurWidth') ){ files (the "Software"), to deal in the Software without
kSize = Math.round( Math.abs(opt.blurWidth) )+1; restriction, including without limitation the rights to use,
} copy, modify, merge, publish, distribute, sublicense, and/or sell
var kMid = Math.floor(kSize/2); copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
//console.info('Blur Width: '+kSize); conditions:
//console.info('Blur Middle: '+kMid);
The above copyright notice and this permission notice shall be
var xEnd = xSize - kMid; included in all copies or substantial portions of the Software.
for (y = 0; y < ySize; y += 1) { THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
r=0;g=0;b=0;a=0; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
for (x=-kMid; x<kMid; x+=1 ){ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// Add the new NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
//if( y === 0 ){ console.info('Loading pixel at: '+((x+xSize)%xSize) ); } HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
i = (y * xSize + (x+xSize)%xSize ) * 4; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
r += srcPixels[i+0]; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
g += srcPixels[i+1]; OTHER DEALINGS IN THE SOFTWARE.
b += srcPixels[i+2]; */
a += srcPixels[i+3];
} function BlurStack() {
this.r = 0;
for (x = 0; x < xSize; x += 1) { this.g = 0;
//if( y === 0 ){ console.info('Added pixel at: '+(x+kMid)); } this.b = 0;
//if( y === 0 ){ console.info('Recorded pixel at: '+x); } this.a = 0;
//if( y === 0 ){ console.info('Removed pixel at: '+((x-kMid+xSize)%xSize) ); } this.next = null;
// Add the new }
i = (y * xSize + (x+kMid)%xSize ) * 4;
r += srcPixels[i+0]; var mul_table = [
g += srcPixels[i+1]; 512,512,456,512,328,456,335,512,405,328,271,456,388,335,292,512,
b += srcPixels[i+2]; 454,405,364,328,298,271,496,456,420,388,360,335,312,292,273,512,
a += srcPixels[i+3]; 482,454,428,405,383,364,345,328,312,298,284,271,259,496,475,456,
// Store the result 437,420,404,388,374,360,347,335,323,312,302,292,282,273,265,512,
i = (y * xSize + x) * 4; 497,482,468,454,441,428,417,405,394,383,373,364,354,345,337,328,
dstPixels[i+0] = r/kSize; 320,312,305,298,291,284,278,271,265,259,507,496,485,475,465,456,
dstPixels[i+1] = g/kSize; 446,437,428,420,412,404,396,388,381,374,367,360,354,347,341,335,
dstPixels[i+2] = b/kSize; 329,323,318,312,307,302,297,292,287,282,278,273,269,265,261,512,
dstPixels[i+3] = a/kSize; 505,497,489,482,475,468,461,454,447,441,435,428,422,417,411,405,
// Subtract the old 399,394,389,383,378,373,368,364,359,354,350,345,341,337,332,328,
i = (y * xSize + (x-kMid+xSize)%xSize ) * 4; 324,320,316,312,309,305,301,298,294,291,287,284,281,278,274,271,
r -= srcPixels[i+0]; 268,265,262,259,257,507,501,496,491,485,480,475,470,465,460,456,
g -= srcPixels[i+1]; 451,446,442,437,433,428,424,420,416,412,408,404,400,396,392,388,
b -= srcPixels[i+2]; 385,381,377,374,370,367,363,360,357,354,350,347,344,341,338,335,
a -= srcPixels[i+3]; 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,
* BlurY Filter. Blurs the image in the Y direction (vertically). It 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
* performs w*h pixel reads, and w*h pixel writes. 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22,
* @function 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
* @author ippo615 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23,
* @memberof Kinetic.Filters 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
* @param {ImageData} src, the source image data (what will be transformed) 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
* @param {ImageData} dst, the destination image data (where it will be saved) 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
* @param {Object} opt 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
* @param {Number} [opt.blurHeight] how many neighboring pixels to will affect the 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
* blurred pixel, default: 5 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 ];
var BlurY = function(src,dst,opt){
function filterGaussBlurRGBA( imageData, radius) {
var srcPixels = src.data,
dstPixels = dst.data, var pixels = imageData.data,
xSize = src.width, width = imageData.width,
ySize = src.height, height = imageData.height;
i, m, x, y, k, tmp, r=0,g=0,b=0,a=0;
var x, y, i, p, yp, yi, yw, r_sum, g_sum, b_sum, a_sum,
var kSize = 5; r_out_sum, g_out_sum, b_out_sum, a_out_sum,
if( opt.hasOwnProperty('blurHeight') ){ r_in_sum, g_in_sum, b_in_sum, a_in_sum,
kSize = Math.round( Math.abs(opt.blurHeight) )+1; pr, pg, pb, pa, rbs;
}
var kMid = Math.floor(kSize/2); var div = radius + radius + 1,
widthMinus1 = width - 1,
var yEnd = ySize - kMid; heightMinus1 = height - 1,
radiusPlus1 = radius + 1,
for (x = 0; x < xSize; x += 1) { sumFactor = radiusPlus1 * ( radiusPlus1 + 1 ) / 2,
r=0;g=0;b=0;a=0; stackStart = new BlurStack(),
for (y=-kMid; y<kMid; y+=1 ){ stackEnd = null,
// Add the new stack = stackStart,
i = ((y+ySize)%ySize * xSize + x ) * 4; stackIn = null,
r += srcPixels[i+0]; stackOut = null,
g += srcPixels[i+1]; mul_sum = mul_table[radius],
b += srcPixels[i+2]; shg_sum = shg_table[radius];
a += srcPixels[i+3];
} for ( i = 1; i < div; i++ ) {
stack = stack.next = new BlurStack();
for (y = 0; y < ySize; y += 1) { if ( i == radiusPlus1 ) stackEnd = stack;
// Add the new }
i = ((y+kMid+ySize)%ySize * xSize + x ) * 4;
r += srcPixels[i+0]; stack.next = stackStart;
g += srcPixels[i+1];
b += srcPixels[i+2]; yw = yi = 0;
a += srcPixels[i+3];
// Store the result for ( y = 0; y < height; y++ )
i = (y * xSize + x) * 4; {
dstPixels[i+0] = r/kSize; r_in_sum = g_in_sum = b_in_sum = a_in_sum = r_sum = g_sum = b_sum = a_sum = 0;
dstPixels[i+1] = g/kSize;
dstPixels[i+2] = b/kSize; r_out_sum = radiusPlus1 * ( pr = pixels[yi] );
dstPixels[i+3] = a/kSize; g_out_sum = radiusPlus1 * ( pg = pixels[yi+1] );
// Subtract the old b_out_sum = radiusPlus1 * ( pb = pixels[yi+2] );
i = ((y-kMid+ySize)%ySize * xSize + x ) * 4; a_out_sum = radiusPlus1 * ( pa = pixels[yi+3] );
r -= srcPixels[i+0];
g -= srcPixels[i+1]; r_sum += sumFactor * pr;
b -= srcPixels[i+2]; g_sum += sumFactor * pg;
a -= srcPixels[i+3]; b_sum += sumFactor * pb;
} a_sum += sumFactor * pa;
} stack = stackStart;
}; for( i = 0; i < radiusPlus1; i++ )
{
Kinetic.Factory.addFilterGetterSetter(Kinetic.Image, 'blurWidth', 5); stack.r = pr;
Kinetic.Factory.addFilterGetterSetter(Kinetic.Image, 'blurHeight', 5); stack.g = pg;
stack.b = pb;
Kinetic.Filters.BlurX = function(src,dst,opt){ stack.a = pa;
if( this === Kinetic.Filters ){ stack = stack.next;
BlurX(src, dst||src, opt ); }
}else{
BlurX.call(this, src, dst||src, opt || { for( i = 1; i < radiusPlus1; i++ )
blurWidth: this.getBlurWidth() {
}); 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;
Kinetic.Filters.BlurY = function(src,dst,opt){ b_sum += ( stack.b = ( pb = pixels[p+2])) * rbs;
if( this === Kinetic.Filters ){ a_sum += ( stack.a = ( pa = pixels[p+3])) * rbs;
BlurY(src, dst||src, opt );
}else{ r_in_sum += pr;
BlurY.call(this, src, dst||src, opt || { g_in_sum += pg;
blurHeight: this.getBlurHeight() b_in_sum += pb;
}); a_in_sum += pa;
}
}; stack = stack.next;
}
/**
* get filter blur width. Returns the width of a blurred pixel. Must be
* an integer greater than 0. stackIn = stackStart;
* @name getBlurWidth stackOut = stackEnd;
* @method for ( x = 0; x < width; x++ )
* @memberof Kinetic.Image.prototype {
*/ pixels[yi+3] = pa = (a_sum * mul_sum) >> shg_sum;
if ( pa !== 0 )
/** {
* set filter blur width. pa = 255 / pa;
* @name setBlurWidth pixels[yi] = ((r_sum * mul_sum) >> shg_sum) * pa;
* @method pixels[yi+1] = ((g_sum * mul_sum) >> shg_sum) * pa;
* @memberof Kinetic.Image.prototype pixels[yi+2] = ((b_sum * mul_sum) >> shg_sum) * pa;
*/ } else {
pixels[yi] = pixels[yi+1] = pixels[yi+2] = 0;
/** }
* get filter blur height. Returns the height of a blurred pixel. Must be
* an integer greater than 0. r_sum -= r_out_sum;
* @name getBlurHeight g_sum -= g_out_sum;
* @method b_sum -= b_out_sum;
* @memberof Kinetic.Image.prototype a_sum -= a_out_sum;
*/
r_out_sum -= stackIn.r;
/** g_out_sum -= stackIn.g;
* set filter blur height. b_out_sum -= stackIn.b;
* @name setBlurHeight a_out_sum -= stackIn.a;
* @method
* @memberof Kinetic.Image.prototype p = ( yw + ( ( p = x + radius + 1 ) < widthMinus1 ? p : widthMinus1 ) ) << 2;
*/
r_in_sum += ( stackIn.r = pixels[p]);
Kinetic.Factory.addFilterGetterSetter(Kinetic.Image, 'filterRadius', 5); g_in_sum += ( stackIn.g = pixels[p+1]);
b_in_sum += ( stackIn.b = pixels[p+2]);
Kinetic.Filters.Blur = Kinetic.Util._FilterWrapSingleBuffer(function(src,dst,opt){ a_in_sum += ( stackIn.a = pixels[p+3]);
if( this === Kinetic.Filters ){
BlurX(src, src, opt ); r_sum += r_in_sum;
BlurY(src, dst||src, opt ); g_sum += g_in_sum;
}else{ b_sum += b_in_sum;
opt = opt || { a_sum += a_in_sum;
blurHeight: this.getFilterRadius(),
blurWidth: this.getFilterRadius() stackIn = stackIn.next;
};
BlurX.call(this, src, src, opt); r_out_sum += ( pr = stackOut.r );
BlurY.call(this, src, dst||src, opt); g_out_sum += ( pg = stackOut.g );
} b_out_sum += ( pb = stackOut.b );
}); a_out_sum += ( pa = stackOut.a );
/** r_in_sum -= pr;
* get filter radius. Returns the radius of a blurred pixel. The blur g_in_sum -= pg;
* is applied horzontally and vertically. b_in_sum -= pb;
* @name getFilterRadius a_in_sum -= pa;
* @method
* @memberof Kinetic.Image.prototype stackOut = stackOut.next;
*/
yi += 4;
/** }
* set filter radius. yw += width;
* @name setFilterRadius }
* @method
* @memberof Kinetic.Image.prototype
*/ 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;
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;
}
}
}
/**
* Blur Filter
* @function
* @memberof Kinetic.Filters
* @param {Object} imageData
*/
var Blur = function(src,dst,opt){
var radius = opt.filterRadius | 0;
// If a different desntination image data is supplied
// copy the source and perform the blur on the destination
var i;
if( dst !== src ){
i = src.data.length;
while( i-- ){
dst.data[i] = src.data[i];
}
}
if( radius > 0 ){
filterGaussBlurRGBA(dst,radius);
}
};
Kinetic.Filters.Blur = function(src,dst,opt){
if( this === Kinetic.Filters ){
Blur(src, dst||src, opt );
}else{
Blur.call(this, src, dst||src, opt || {
filterRadius: this.getFilterRadius()
});
}
};
Kinetic.Factory.addFilterGetterSetter(Kinetic.Image, 'filterRadius', 0);
/**
* get filter radius. Returns the radius for Gaussian blur filter.
* @name getFilterRadius
* @method
* @memberof Kinetic.Image.prototype
*/
/**
* get filter radius. Set the radius for Gaussian blur filter.
* @name setFilterRadius
* @method
* @memberof Kinetic.Image.prototype
*/
})();

198
src/filters/QuickBlur.js Normal file
View File

@ -0,0 +1,198 @@
(function () {
/**
* BlurX Filter. Blurs the image in the X direction (horizontally). It
* performs w*h pixel reads, and w*h pixel writes. It is faster than a
* Gaussian blur but does not look as nice. Use Kinetic.Filters.Blur for
* a Gaussian blur.
* @function
* @author ippo615
* @memberof Kinetic.Filters
* @param {ImageData} src, the source image data (what will be transformed)
* @param {ImageData} dst, the destination image data (where it will be saved)
* @param {Object} opt
* @param {Number} [opt.blurWidth] how many neighboring pixels to will affect the
* blurred pixel, default: 5
*/
var BlurX = function(src,dst,opt){
var srcPixels = src.data,
dstPixels = dst.data,
xSize = src.width,
ySize = src.height,
i, m, x, y, k, tmp, r=0,g=0,b=0,a=0;
// DONT USE: kSize = opt.blurWidth || 5;
// HINT: consider when (opt.blurWidth = 0)
var kSize = 5;
if( opt.hasOwnProperty('blurWidth') ){
kSize = Math.round( Math.abs(opt.blurWidth) )+1;
}
var kMid = Math.floor(kSize/2);
//console.info('Blur Width: '+kSize);
//console.info('Blur Middle: '+kMid);
var xEnd = xSize - kMid;
for (y = 0; y < ySize; y += 1) {
r=0;g=0;b=0;a=0;
for (x=-kMid; x<kMid; x+=1 ){
// Add the new
//if( y === 0 ){ console.info('Loading pixel at: '+((x+xSize)%xSize) ); }
i = (y * xSize + (x+xSize)%xSize ) * 4;
r += srcPixels[i+0];
g += srcPixels[i+1];
b += srcPixels[i+2];
a += srcPixels[i+3];
}
for (x = 0; x < xSize; x += 1) {
//if( y === 0 ){ console.info('Added pixel at: '+(x+kMid)); }
//if( y === 0 ){ console.info('Recorded pixel at: '+x); }
//if( y === 0 ){ console.info('Removed pixel at: '+((x-kMid+xSize)%xSize) ); }
// Add the new
i = (y * xSize + (x+kMid)%xSize ) * 4;
r += srcPixels[i+0];
g += srcPixels[i+1];
b += srcPixels[i+2];
a += srcPixels[i+3];
// Store the result
i = (y * xSize + x) * 4;
dstPixels[i+0] = r/kSize;
dstPixels[i+1] = g/kSize;
dstPixels[i+2] = b/kSize;
dstPixels[i+3] = a/kSize;
// Subtract the old
i = (y * xSize + (x-kMid+xSize)%xSize ) * 4;
r -= srcPixels[i+0];
g -= srcPixels[i+1];
b -= srcPixels[i+2];
a -= srcPixels[i+3];
}
}
};
/**
* BlurY Filter. Blurs the image in the Y direction (vertically). It
* performs w*h pixel reads, and w*h pixel writes. It is faster than a
* Gaussian blur but does not look as nice. Use Kinetic.Filters.Blur for
* a Gaussian blur.
* @function
* @author ippo615
* @memberof Kinetic.Filters
* @param {ImageData} src, the source image data (what will be transformed)
* @param {ImageData} dst, the destination image data (where it will be saved)
* @param {Object} opt
* @param {Number} [opt.blurHeight] how many neighboring pixels to will affect the
* blurred pixel, default: 5
*/
var BlurY = function(src,dst,opt){
var srcPixels = src.data,
dstPixels = dst.data,
xSize = src.width,
ySize = src.height,
i, m, x, y, k, tmp, r=0,g=0,b=0,a=0;
var kSize = 5;
if( opt.hasOwnProperty('blurHeight') ){
kSize = Math.round( Math.abs(opt.blurHeight) )+1;
}
var kMid = Math.floor(kSize/2);
var yEnd = ySize - kMid;
for (x = 0; x < xSize; x += 1) {
r=0;g=0;b=0;a=0;
for (y=-kMid; y<kMid; y+=1 ){
// Add the new
i = ((y+ySize)%ySize * xSize + x ) * 4;
r += srcPixels[i+0];
g += srcPixels[i+1];
b += srcPixels[i+2];
a += srcPixels[i+3];
}
for (y = 0; y < ySize; y += 1) {
// Add the new
i = ((y+kMid+ySize)%ySize * xSize + x ) * 4;
r += srcPixels[i+0];
g += srcPixels[i+1];
b += srcPixels[i+2];
a += srcPixels[i+3];
// Store the result
i = (y * xSize + x) * 4;
dstPixels[i+0] = r/kSize;
dstPixels[i+1] = g/kSize;
dstPixels[i+2] = b/kSize;
dstPixels[i+3] = a/kSize;
// Subtract the old
i = ((y-kMid+ySize)%ySize * xSize + x ) * 4;
r -= srcPixels[i+0];
g -= srcPixels[i+1];
b -= srcPixels[i+2];
a -= srcPixels[i+3];
}
}
};
Kinetic.Factory.addFilterGetterSetter(Kinetic.Image, 'blurWidth', 5);
Kinetic.Factory.addFilterGetterSetter(Kinetic.Image, 'blurHeight', 5);
Kinetic.Filters.BlurX = function(src,dst,opt){
if( this === Kinetic.Filters ){
BlurX(src, dst||src, opt );
}else{
BlurX.call(this, src, dst||src, opt || {
blurWidth: this.getBlurWidth()
});
}
};
Kinetic.Filters.BlurY = function(src,dst,opt){
if( this === Kinetic.Filters ){
BlurY(src, dst||src, opt );
}else{
BlurY.call(this, src, dst||src, opt || {
blurHeight: this.getBlurHeight()
});
}
};
/**
* get filter blur width. Returns the width of a blurred pixel. Must be
* an integer greater than 0.
* @name getBlurWidth
* @method
* @memberof Kinetic.Image.prototype
*/
/**
* set filter blur width.
* @name setBlurWidth
* @method
* @memberof Kinetic.Image.prototype
*/
/**
* get filter blur height. Returns the height of a blurred pixel. Must be
* an integer greater than 0.
* @name getBlurHeight
* @method
* @memberof Kinetic.Image.prototype
*/
/**
* set filter blur height.
* @name setBlurHeight
* @method
* @memberof Kinetic.Image.prototype
*/
})();

View File

@ -76,6 +76,7 @@
<!-- filters --> <!-- filters -->
<script src="unit/filters/Blur-test.js"></script> <script src="unit/filters/Blur-test.js"></script>
<script src="unit/filters/QuickBlur-test.js"></script>
<script src="unit/filters/Brighten-test.js"></script> <script src="unit/filters/Brighten-test.js"></script>
<script src="unit/filters/ColorPack-test.js"></script> <script src="unit/filters/ColorPack-test.js"></script>
<script src="unit/filters/Invert-test.js"></script> <script src="unit/filters/Invert-test.js"></script>

View File

@ -189,19 +189,17 @@ suite('Blur', function() {
}); });
// ====================================================== // ======================================================
test('fast blur', function (done) { test('half layer gaussian blur', function (done) {
var stage = addStage(); var stage = addStage();
var shapesLayer = new Kinetic.Layer(); var shapesLayer = new Kinetic.Layer();
// The important line! // The important line!
shapesLayer.on('draw', function () { shapesLayer.on('draw', function () {
var BLURAMOUNT = 10; var imageData = this.getContext().getImageData(0,0,this.getCanvas().width/2,this.getCanvas().height);
var imageData = this.getContext().getImageData(0,0,this.getCanvas().width,this.getCanvas().height);
var scratchData = this.getContext().createImageData(imageData); // only size copied var scratchData = this.getContext().createImageData(imageData); // only size copied
Kinetic.Filters.BlurX(imageData,scratchData,{blurWidth:BLURAMOUNT}); Kinetic.Filters.Blur(imageData,scratchData,{filterRadius:24});
Kinetic.Filters.BlurY(scratchData,imageData,{blurHeight:BLURAMOUNT}); this.getContext().putImageData(scratchData,0,0);
this.getContext().putImageData(imageData,0,0);
}); });
var triangle = new Kinetic.RegularPolygon({ var triangle = new Kinetic.RegularPolygon({

View File

@ -0,0 +1,154 @@
suite('Quick Blur', function() {
// ======================================================
test('half layer blur', function (done) {
var stage = addStage();
var shapesLayer = new Kinetic.Layer();
// The important line!
shapesLayer.on('draw', function () {
var imageData = this.getContext().getImageData(0,0,this.getCanvas().width/2,this.getCanvas().height);
var scratchData = this.getContext().createImageData(imageData); // only size copied
Kinetic.Filters.BlurX(imageData,scratchData,{blurWidth:24});
Kinetic.Filters.BlurY(scratchData,imageData,{blurHeight:24});
this.getContext().putImageData(imageData,0,0);
});
var triangle = new Kinetic.RegularPolygon({
x: stage.getWidth() / 4,
y: stage.getHeight() / 2,
sides: 3,
radius: 80,
fillRadialGradientStartPoint: 0,
fillRadialGradientStartRadius: 0,
fillRadialGradientEndPoint: 0,
fillRadialGradientEndRadius: 70,
fillRadialGradientColorStops: [0, '#881111', 0.5, '#888811', 1, '#000088'],
stroke: 'black',
strokeWidth: 4,
draggable: true
});
var circle = new Kinetic.Circle({
x: 3 * stage.getWidth() / 4,
y: stage.getHeight() / 2,
radius: 70,
fill: '#880000',
stroke: 'black',
strokeWidth: 4,
draggable: true,
id: 'myCircle'
});
for( var i=0; i<10; i+=1 ){
for( var j=0; j<10; j+=1 ){
var rect = new Kinetic.Rect({
x: i/10*stage.getWidth(),
y: j/10*stage.getHeight(),
width: stage.getWidth()/10,
height: stage.getHeight()/10,
fill: (i+j)%2===0?'#FF0000':'#FFFF00',
stroke: 'black',
strokeWidth: 4,
draggable: true
});
shapesLayer.add(rect);
}
}
shapesLayer.add(circle);
shapesLayer.add(triangle);
stage.add(shapesLayer);
done();
});
// ======================================================
test('tween x blur', function(done) {
var stage = addStage();
var imageObj = new Image();
imageObj.onload = function() {
var layer = new Kinetic.Layer();
darth = new Kinetic.Image({
x: 10,
y: 10,
image: imageObj,
draggable: true
});
layer.add(darth);
stage.add(layer);
darth.setFilter(Kinetic.Filters.BlurX);
darth.setBlurWidth(100);
layer.draw();
var tween = new Kinetic.Tween({
node: darth,
duration: 2.0,
blurWidth: 0,
easing: Kinetic.Easings.EaseInOut
});
darth.on('mouseover', function() {
tween.play();
});
darth.on('mouseout', function() {
tween.reverse();
});
done();
};
imageObj.src = 'assets/darth-vader.jpg';
});
// ======================================================
test('tween y blur', function(done) {
var stage = addStage();
var imageObj = new Image();
imageObj.onload = function() {
var layer = new Kinetic.Layer();
darth = new Kinetic.Image({
x: 10,
y: 10,
image: imageObj,
draggable: true
});
layer.add(darth);
stage.add(layer);
darth.setFilter(Kinetic.Filters.BlurY);
darth.setBlurHeight(100);
layer.draw();
var tween = new Kinetic.Tween({
node: darth,
duration: 2.0,
blurHeight: 0,
easing: Kinetic.Easings.EaseInOut
});
darth.on('mouseover', function() {
tween.play();
});
darth.on('mouseout', function() {
tween.reverse();
});
done();
};
imageObj.src = 'assets/darth-vader.jpg';
});
});