各种语言对图片的处理算法实现 图片模糊实现代码

podc9bw2的头像 podc9bw2 0 2016-03-02 12:51 0

 基本信息

× 1   

浏览数: 8824

分享时间: 1 年 前

1

收集各种语言:C C++ Java C# JS 等等语言对图片的处理实现代码;包括高斯模糊、堆栈模糊、盒子模糊等等。

所有代码均开源;可拷贝使用。

项目地址

ImageCode

FastBlur.js

/*

Superfast Blur - a fast Box Blur For Canvas

Version: 	0.5
Author:		Mario Klingemann
Contact: 	mario@quasimondo.com
Website:	http://www.quasimondo.com/BoxBlurForCanvas
Twitter:	@quasimondo

In case you find this class useful - especially in commercial projects -
I am not totally unhappy for a small donation to my PayPal account
mario@quasimondo.de

Or support me on flattr:
https://flattr.com/thing/140066/Superfast-Blur-a-pretty-fast-Box-Blur-Effect-for-CanvasJavascript

Copyright (c) 2011 Mario Klingemann

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/
var mul_table = [ 1,57,41,21,203,34,97,73,227,91,149,62,105,45,39,137,241,107,3,173,39,71,65,238,219,101,187,87,81,151,141,133,249,117,221,209,197,187,177,169,5,153,73,139,133,127,243,233,223,107,103,99,191,23,177,171,165,159,77,149,9,139,135,131,253,245,119,231,224,109,211,103,25,195,189,23,45,175,171,83,81,79,155,151,147,9,141,137,67,131,129,251,123,30,235,115,113,221,217,53,13,51,50,49,193,189,185,91,179,175,43,169,83,163,5,79,155,19,75,147,145,143,35,69,17,67,33,65,255,251,247,243,239,59,29,229,113,111,219,27,213,105,207,51,201,199,49,193,191,47,93,183,181,179,11,87,43,85,167,165,163,161,159,157,155,77,19,75,37,73,145,143,141,35,138,137,135,67,33,131,129,255,63,250,247,61,121,239,237,117,29,229,227,225,111,55,109,216,213,211,209,207,205,203,201,199,197,195,193,48,190,47,93,185,183,181,179,178,176,175,173,171,85,21,167,165,41,163,161,5,79,157,78,154,153,19,75,149,74,147,73,144,143,71,141,140,139,137,17,135,134,133,66,131,65,129,1];
        
   
var shg_table = [0,9,10,10,14,12,14,14,16,15,16,15,16,15,15,17,18,17,12,18,16,17,17,19,19,18,19,18,18,19,19,19,20,19,20,20,20,20,20,20,15,20,19,20,20,20,21,21,21,20,20,20,21,18,21,21,21,21,20,21,17,21,21,21,22,22,21,22,22,21,22,21,19,22,22,19,20,22,22,21,21,21,22,22,22,18,22,22,21,22,22,23,22,20,23,22,22,23,23,21,19,21,21,21,23,23,23,22,23,23,21,23,22,23,18,22,23,20,22,23,23,23,21,22,20,22,21,22,24,24,24,24,24,22,21,24,23,23,24,21,24,23,24,22,24,24,22,24,24,22,23,24,24,24,20,23,22,23,24,24,24,24,24,24,24,23,21,23,22,23,24,24,24,22,24,24,24,23,22,24,24,25,23,25,25,23,24,25,25,24,22,25,25,25,24,23,24,25,25,25,25,25,25,25,25,25,25,25,25,23,25,23,24,25,25,25,25,25,25,25,25,25,24,22,25,25,23,25,25,20,24,25,24,25,25,22,24,25,24,25,24,25,25,24,25,25,25,25,22,25,25,25,24,25,24,25,18];

		
function boxBlurImage( imageID, canvasID, radius, blurAlphaChannel, iterations ){
			
 	var img = document.getElementById( imageID );
	var w = img.naturalWidth;
    var h = img.naturalHeight;
       
	var canvas = document.getElementById( canvasID );
      
    canvas.style.width  = w + "px";
    canvas.style.height = h + "px";
    canvas.width = w;
    canvas.height = h;
    
    var context = canvas.getContext("2d");
    context.clearRect( 0, 0, w, h );
    context.drawImage( img, 0, 0 );

	if ( isNaN(radius) || radius < 1 ) return;
	
	if ( blurAlphaChannel )
	{
		boxBlurCanvasRGBA( canvasID, 0, 0, w, h, radius, iterations );
	} else {
		boxBlurCanvasRGB( canvasID, 0, 0, w, h, radius, iterations );
	}
	
}


function boxBlurCanvasRGBA( id, top_x, top_y, width, height, radius, iterations ){
	if ( isNaN(radius) || radius < 1 ) return;
	
	radius |= 0;
	
	if ( isNaN(iterations) ) iterations = 1;
	iterations |= 0;
	if ( iterations > 3 ) iterations = 3;
	if ( iterations < 1 ) iterations = 1;
	
	var canvas  = document.getElementById( id );
	var context = canvas.getContext("2d");
	var imageData;
	
	try {
	  try {
		imageData = context.getImageData( top_x, top_y, width, height );
	  } catch(e) {
	  
		// NOTE: this part is supposedly only needed if you want to work with local files
		// so it might be okay to remove the whole try/catch block and just use
		// imageData = context.getImageData( top_x, top_y, width, height );
		try {
			netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
			imageData = context.getImageData( top_x, top_y, width, height );
		} catch(e) {
			alert("Cannot access local image");
			throw new Error("unable to access local image data: " + e);
			return;
		}
	  }
	} catch(e) {
	  alert("Cannot access image");
	  throw new Error("unable to access image data: " + e);
	  return;
	}
			
	var pixels = imageData.data;
		
	var rsum,gsum,bsum,asum,x,y,i,p,p1,p2,yp,yi,yw,idx,pa;		
	var wm = width - 1;
  	var hm = height - 1;
    var wh = width * height;
	var rad1 = radius + 1;
    
	var mul_sum = mul_table[radius];
	var shg_sum = shg_table[radius];

	var r = [];
    var g = [];
    var b = [];
	var a = [];
	
	var vmin = [];
	var vmax = [];
  
	while ( iterations-- > 0 ){
		yw = yi = 0;
	 
		for ( y=0; y < height; y++ ){
			rsum = pixels[yw]   * rad1;
			gsum = pixels[yw+1] * rad1;
			bsum = pixels[yw+2] * rad1;
			asum = pixels[yw+3] * rad1;
			
			
			for( i = 1; i <= radius; i++ ){
				p = yw + (((i > wm ? wm : i )) << 2 );
				rsum += pixels[p++];
				gsum += pixels[p++];
				bsum += pixels[p++];
				asum += pixels[p]
			}
			
			for ( x = 0; x < width; x++ ) {
				r[yi] = rsum;
				g[yi] = gsum;
				b[yi] = bsum;
				a[yi] = asum;

				if( y==0) {
					vmin[x] = ( ( p = x + rad1) < wm ? p : wm ) << 2;
					vmax[x] = ( ( p = x - radius) > 0 ? p << 2 : 0 );
				} 
				
				p1 = yw + vmin[x];
				p2 = yw + vmax[x];
				  
				rsum += pixels[p1++] - pixels[p2++];
				gsum += pixels[p1++] - pixels[p2++];
				bsum += pixels[p1++] - pixels[p2++];
				asum += pixels[p1]   - pixels[p2];
					 
				yi++;
			}
			yw += ( width << 2 );
		}
	  
		for ( x = 0; x < width; x++ ) {
			yp = x;
			rsum = r[yp] * rad1;
			gsum = g[yp] * rad1;
			bsum = b[yp] * rad1;
			asum = a[yp] * rad1;
			
			for( i = 1; i <= radius; i++ ) {
			  yp += ( i > hm ? 0 : width );
			  rsum += r[yp];
			  gsum += g[yp];
			  bsum += b[yp];
			  asum += a[yp];
			}
			
			yi = x << 2;
			for ( y = 0; y < height; y++) {
				
				pixels[yi+3] = pa = (asum * mul_sum) >>> shg_sum;
				if ( pa > 0 )
				{
					pa = 255 / pa;
					pixels[yi]   = ((rsum * mul_sum) >>> shg_sum) * pa;
					pixels[yi+1] = ((gsum * mul_sum) >>> shg_sum) * pa;
					pixels[yi+2] = ((bsum * mul_sum) >>> shg_sum) * pa;
				} else {
					pixels[yi] = pixels[yi+1] = pixels[yi+2] = 0;
				}				
				if( x == 0 ) {
					vmin[y] = ( ( p = y + rad1) < hm ? p : hm ) * width;
					vmax[y] = ( ( p = y - radius) > 0 ? p * width : 0 );
				} 
			  
				p1 = x + vmin[y];
				p2 = x + vmax[y];

				rsum += r[p1] - r[p2];
				gsum += g[p1] - g[p2];
				bsum += b[p1] - b[p2];
				asum += a[p1] - a[p2];

				yi += width << 2;
			}
		}
	}
	
	context.putImageData( imageData, top_x, top_y );
	
}

function boxBlurCanvasRGB( id, top_x, top_y, width, height, radius, iterations ){
	if ( isNaN(radius) || radius < 1 ) return;
	
	radius |= 0;
	
	if ( isNaN(iterations) ) iterations = 1;
	iterations |= 0;
	if ( iterations > 3 ) iterations = 3;
	if ( iterations < 1 ) iterations = 1;
	
	var canvas  = document.getElementById( id );
	var context = canvas.getContext("2d");
	var imageData;
	
	try {
	  try {
		imageData = context.getImageData( top_x, top_y, width, height );
	  } catch(e) {
	  
		// NOTE: this part is supposedly only needed if you want to work with local files
		// so it might be okay to remove the whole try/catch block and just use
		// imageData = context.getImageData( top_x, top_y, width, height );
		try {
			netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
			imageData = context.getImageData( top_x, top_y, width, height );
		} catch(e) {
			alert("Cannot access local image");
			throw new Error("unable to access local image data: " + e);
			return;
		}
	  }
	} catch(e) {
	  alert("Cannot access image");
	  throw new Error("unable to access image data: " + e);
	  return;
	}
			
	var pixels = imageData.data;
		
	var rsum,gsum,bsum,asum,x,y,i,p,p1,p2,yp,yi,yw,idx;		
	var wm = width - 1;
  	var hm = height - 1;
    var wh = width * height;
	var rad1 = radius + 1;
   
	var r = [];
    var g = [];
    var b = [];
	
	var mul_sum = mul_table[radius];
	var shg_sum = shg_table[radius];
	
	var vmin = [];
	var vmax = [];
  
	while ( iterations-- > 0 ){
		yw = yi = 0;
	 
		for ( y=0; y < height; y++ ){
			rsum = pixels[yw]   * rad1;
			gsum = pixels[yw+1] * rad1;
			bsum = pixels[yw+2] * rad1;
			
			for( i = 1; i <= radius; i++ ){
				p = yw + (((i > wm ? wm : i )) << 2 );
				rsum += pixels[p++];
				gsum += pixels[p++];
				bsum += pixels[p++];
			}
			
			for ( x = 0; x < width; x++ ){
				r[yi] = rsum;
				g[yi] = gsum;
				b[yi] = bsum;
				
				if( y==0) {
					vmin[x] = ( ( p = x + rad1) < wm ? p : wm ) << 2;
					vmax[x] = ( ( p = x - radius) > 0 ? p << 2 : 0 );
				} 
				
				p1 = yw + vmin[x];
				p2 = yw + vmax[x];
				  
				rsum += pixels[p1++] - pixels[p2++];
				gsum += pixels[p1++] - pixels[p2++];
				bsum += pixels[p1++] - pixels[p2++];
				 
				yi++;
			}
			yw += ( width << 2 );
		}
	  
		for ( x = 0; x < width; x++ ){
			yp = x;
			rsum = r[yp] * rad1;
			gsum = g[yp] * rad1;
			bsum = b[yp] * rad1;
				
			for( i = 1; i <= radius; i++ ){
			  yp += ( i > hm ? 0 : width );
			  rsum += r[yp];
			  gsum += g[yp];
			  bsum += b[yp];
			}
			
			yi = x << 2;
			for ( y = 0; y < height; y++){
				pixels[yi]   = (rsum * mul_sum) >>> shg_sum;
				pixels[yi+1] = (gsum * mul_sum) >>> shg_sum;
				pixels[yi+2] = (bsum * mul_sum) >>> shg_sum;
		   
				if( x == 0 ) {
					vmin[y] = ( ( p = y + rad1) < hm ? p : hm ) * width;
					vmax[y] = ( ( p = y - radius) > 0 ? p * width : 0 );
				} 
				  
				p1 = x + vmin[y];
				p2 = x + vmax[y];

				rsum += r[p1] - r[p2];
				gsum += g[p1] - g[p2];
				bsum += b[p1] - b[p2];
				  
				yi += width << 2;
			}
		}
	}
	context.putImageData( imageData, top_x, top_y );
	
}

IntegralImage.js

/*

Integral Image

Version: 	0.4
Author:		Mario Klingemann
Contact: 	mario@quasimondo.com
Website:	http://www.quasimondo.com/IntegralImageForCanvas
Twitter:	@quasimondo

In case you find this class useful - especially in commercial projects -
I am not totally unhappy for a small donation to my PayPal account
mario@quasimondo.de


Copyright (c) 2011 Mario Klingemann

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/

function integralBlurImage( imageID, canvasID, radius, blurAlphaChannel, iterations )
{
	
	var img = document.getElementById( imageID );
	var w = img.naturalWidth;
    var h = img.naturalHeight;
       
	var canvas = document.getElementById( canvasID );
      
    canvas.style.width  = w + "px";
    canvas.style.height = h + "px";
    canvas.width = w;
    canvas.height = h;
    
    var context = canvas.getContext("2d");
    context.clearRect( 0, 0, w, h );
    context.drawImage( img, 0, 0 );

	if ( isNaN(radius) || radius < 1 ) return;
	
	if ( blurAlphaChannel )
	{
		integralBlurCanvasRGBA( canvasID, 0, 0, w, h, radius, iterations );
	} else {
		integralBlurCanvasRGB( canvasID, 0, 0, w, h, radius, iterations );
	}
}

function integralBlurCanvasRGB( id, top_x, top_y, width, height, radius, iterations )
{
	
	var ii = integralImageFromCanvasRGB( id, 0, 0, width, height );
	if ( ii == null ) return;
	var imageData = ii.imageData;
	var pixels    = imageData.pixels;
	var context   = ii.context;
	blurIntegralImageRGB( ii, radius );
	
	while ( --iterations > 0 )
	{
		ii = calculateIntegralImageRGB( pixels, width, height );
		ii.imageData = imageData;
		ii.context = context;
		blurIntegralImageRGB( ii, radius );
	}
	
	context.putImageData( imageData, top_x, top_y );
		
}


function integralBlurCanvasRGBA( id, top_x, top_y, width, height, radius, iterations )
{
	
	var ii = integralImageFromCanvasRGBA( id, 0, 0, width, height );
	if ( ii == null ) return;
	var imageData = ii.imageData;
	var pixels    = ii.pixels;
	var context   = ii.context;
	blurIntegralImageRGBA( ii, radius );
	
	while ( --iterations > 0 )
	{
		ii = calculateIntegralImageRGBA( pixels, width, height );
		ii.imageData = imageData;
		ii.context = context;
		blurIntegralImageRGBA( ii, radius );
	}
	
	context.putImageData( imageData, top_x, top_y );
		
}

function updateCanvas( integralImage )
{
	integralImage.context.putImageData( integralImage.imageData, 0, 0 );
}

function blurIntegralImageRGBA( integralImage, radius )
{
	var dx1,dx2,dy1,dy2,dy,idx1,idx2,idx3,idx4,area;

	var ii = integralImage;
	var width = ii.width;
	var height = ii.height;
	var pixels = ii.pixels;
	var i1 = 0;
	var i2 = 0;
	var r = ii.r;
	var g = ii.g;
	var b = ii.b;
	var a = ii.a;
	var pa;
	var iw = width + 1;
	
	for ( var y = 0; y < height; y++ )
	{
		dy1 = ( y < radius ? -y : -radius );
		dy2 = ( y >= height - radius ? height - y : radius );
		dy = dy2 - dy1;
		dy1 *= iw;
		dy2 *= iw;
		for ( var x = 0; x < width; x++ )
		{
			dx1 = ( x < radius ? -x : -radius );
			dx2 = ( x >= width - radius ? width - x : radius );
			area = 1 / ((dx2 - dx1) * dy);
			
			dx1 += i1;
			dx2 += i1;
			
			idx1 = dx1+dy1;
			idx2 = dx2+dy2;
			idx3 = dx1+dy2;
			idx4 = dx2+dy1;
			
			pa = (( a[idx1] + a[idx2] - a[idx3] - a[idx4] ) * area ) | 0;
			if ( pa > 0 )
			{
				pa = 255 / pa;
				pixels[i2++] = (( r[idx1] + r[idx2] - r[idx3] - r[idx4] ) * area * pa) | 0;
				pixels[i2++] = (( g[idx1] + g[idx2] - g[idx3] - g[idx4] ) * area * pa) | 0;
				pixels[i2++] = (( b[idx1] + b[idx2] - b[idx3] - b[idx4] ) * area * pa) | 0;
				pixels[i2++] = pa;
			} else {
				pixels[i2++] = pixels[i2++] = pixels[i2++] = pixels[i2++] = 0;
			}
			i1++;
		}
		i1++;
	}
}


	
function blurIntegralImageRGB( integralImage, radius )
{
	var dx1,dx2,dy1,dy2,dy,idx1,idx2,idx3,idx4,area;

	var ii = integralImage;
	var width = ii.width;
	var height = ii.height;
	var pixels = ii.pixels;
	var i1 = 0;
	var i2 = 0;
	var r = ii.r;
	var g = ii.g;
	var b = ii.b;
	var iw = width + 1;
	
	for ( var y = 0; y < height; y++ ) {
		dy1 = ( y < radius ? -y : -radius );
		dy2 = ( y >= height - radius ? height - y -1 : radius );
		dy = dy2 - dy1;
		dy1 *= iw;
		dy2 *= iw;
		
		for ( var x = 0; x < width; x++ ) {
			dx1 = ( x < radius ? -x : -radius );
			dx2 = ( x >= width - radius ? width - x - 1: radius );
			
			area = 1 / ((dx2 - dx1) * dy);
			
			dx1 += i1;
			dx2 += i1;
			
			idx1 = dx1+dy1;
			idx2 = dx2+dy2;
			idx3 = dx1+dy2;
			idx4 = dx2+dy1;
			
			pixels[i2++] = (( r[idx1] + r[idx2] - r[idx3] - r[idx4] ) * area ) | 0;
			pixels[i2++] = (( g[idx1] + g[idx2] - g[idx3] - g[idx4] ) * area ) | 0;
			pixels[i2++] = (( b[idx1] + b[idx2] - b[idx3] - b[idx4] ) * area ) | 0;
			i2++
			i1++;
		}
		i1++;
	}
	
}

function integralImageFromImage( imageID, canvasID, includeAlphaChannel )
{
			
 	var img = document.getElementById( imageID );
	var w = img.naturalWidth;
    var h = img.naturalHeight;
       
	var canvas = document.getElementById( canvasID );
      
    canvas.style.width  = w + "px";
    canvas.style.height = h + "px";
    canvas.width = w;
    canvas.height = h;
    
    var context = canvas.getContext("2d");
    context.clearRect( 0, 0, w, h );
    context.drawImage( img, 0, 0 );

	if ( includeAlphaChannel )
	{
		return integralImageFromCanvasRGBA( canvasID, 0, 0, w, h );
	} else {
		return integralImageFromCanvasRGB( canvasID, 0, 0, w, h );
	}
}

function integralImageFromCanvasRGB( id, top_x, top_y, width, height )
{
	var pixelData = getCanvasPixels( id, top_x, top_y, width, height );
	if ( pixelData == null ) return;
	
	var ii = calculateIntegralImageRGB( pixelData.pixels, width, height );
	ii.context = pixelData.context;
	ii.imageData = pixelData.imageData;
	return ii;
}

function integralImageFromCanvasRGBA( id, top_x, top_y, width, height )
{
	var pixelData = getCanvasPixels( id, top_x, top_y, width, height );
	if ( pixelData == null ) return;
	
	var ii = calculateIntegralImageRGBA( pixelData.pixels, width, height );
	ii.context = pixelData.context;
	ii.imageData = pixelData.imageData;
	return ii;
}

function getCanvasPixels( canvasID, top_x, top_y, width, height ) 
{
	var result = { id:canvasID, top_x:top_x, top_y:top_y, width:width, height:height };
	result.canvas  = document.getElementById( canvasID );
	result.context = result.canvas.getContext("2d");
	
	try {
	  result.imageData = result.context.getImageData( top_x, top_y, width, height );
	} catch(e) {
	  //throw new Error("unable to access image data: " + e);
	  return null;
	}
	result.pixels = result.imageData.data;
	return result;
}

function calculateIntegralImageRGB( pixels, width, height )
{
	var r = [];
    var g = [];
    var b = [];
	
	var i = 0;
	var j = 0;
	for ( y=0; y < height; y++ )
	{
		rsum = pixels[i++];
		gsum = pixels[i++];
		bsum = pixels[i++];
		i++;
		for ( x = 0; x < width; x++ )
		{
			r[j]   = rsum;
			g[j]   = gsum;
			b[j++] = bsum;
			
			rsum += pixels[i++];
			gsum += pixels[i++];
			bsum += pixels[i++];
			i++;
		}
		
		r[j]   = rsum;
		g[j]   = gsum;
		b[j++] = bsum;
		i-=4;
	}
	
	var j1 =  width + 1;
	var w1 = j1;
	var k = j1 * ( height + 1 );
	var j2 = j1 - w1;
	while ( j1 < k )
	{
		r[j1] += r[j2];
		g[j1] += g[j2];
		b[j1] += b[j2];
		j1++,j2++;
	}
	
	return { r:r, g:g, b:b, width:width, height:height, pixels:pixels };
	
}

function calculateIntegralImageRGBA( pixels, width, height )
{	
	
	var r = [];
    var g = [];
    var b = [];
	var a = [];
	var i = 0;
	var j = 0;
	
	for ( y=0; y < height; y++ )
	{
		rsum = pixels[i++];
		gsum = pixels[i++];
		bsum = pixels[i++];
		asum = pixels[i++];
			
		for ( x = 0; x < width; x++ )
		{
			r[j]   = rsum;
			g[j]   = gsum;
			b[j]   = bsum;
			a[j++] = asum;

			rsum += pixels[i++];
			gsum += pixels[i++];
			bsum += pixels[i++];
			asum += pixels[i++];
		}
		
		r[j]   = rsum;
		g[j]   = gsum;
		b[j]   = bsum;
		a[j++] = asum;
		i-=4;
	}
	
	var j1 = width + 1;
	var w1 = j1;
	var k = j1 * ( height + 1 );
	var j2 = j1 - w1;
	while ( j1 < k )
	{
		r[j1] += r[j2];
		g[j1] += g[j2];
		b[j1] += b[j2];
		a[j1] += a[j2];
		j1++, j2++;
	}
	
	return { r:r, g:g, b:b, a:a, width:width, height:height, pixels:pixels };
}

stackblur.cpp

// The Stack Blur Algorithm was invented by Mario Klingemann, 
// mario@quasimondo.com and described here:
// http://incubator.quasimondo.com/processing/fast_blur_deluxe.php

// This is C++ RGBA (32 bit color) multi-threaded version 
// by Victor Laskin (victor.laskin@gmail.com)
// More details: http://vitiy.info/stackblur-algorithm-multi-threaded-blur-for-cpp

// This code is using MVThread class from my cross-platform framework 
// You can exchange it with any thread implementation you like


// -------------------------------------- stackblur ----------------------------------------->

static unsigned short const stackblur_mul[255] =
{
		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
};

static unsigned char const stackblur_shr[255] =
{
		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
};

/// Stackblur algorithm body
void stackblurJob(unsigned char* src,				///< input image data
	   			  unsigned int w,					///< image width
				  unsigned int h,					///< image height
				  unsigned int radius,				///< blur intensity (should be in 2..254 range)
				  int cores,						///< total number of working threads
				  int core,							///< current thread number
				  int step,							///< step of processing (1,2)
				  unsigned char* stack				///< stack buffer
				  )
{
	unsigned int x, y, xp, yp, i;
	unsigned int sp;
	unsigned int stack_start;
	unsigned char* stack_ptr;

	unsigned char* src_ptr;
	unsigned char* dst_ptr;

	unsigned long sum_r;
	unsigned long sum_g;
	unsigned long sum_b;
	unsigned long sum_a;
	unsigned long sum_in_r;
	unsigned long sum_in_g;
	unsigned long sum_in_b;
	unsigned long sum_in_a;
	unsigned long sum_out_r;
	unsigned long sum_out_g;
	unsigned long sum_out_b;
	unsigned long sum_out_a;

	unsigned int wm = w - 1;
	unsigned int hm = h - 1;
	unsigned int w4 = w * 4;
	unsigned int div = (radius * 2) + 1;
	unsigned int mul_sum = stackblur_mul[radius];
	unsigned char shr_sum = stackblur_shr[radius];


	if (step == 1)
	{
		int minY = core * h / cores;
		int maxY = (core + 1) * h / cores;

		for(y = minY; y < maxY; y++)
		{
			sum_r = sum_g = sum_b = sum_a =
			sum_in_r = sum_in_g = sum_in_b = sum_in_a =
			sum_out_r = sum_out_g = sum_out_b = sum_out_a = 0;

			src_ptr = src + w4 * y; // start of line (0,y)

			for(i = 0; i <= radius; i++)
			{
				stack_ptr    = &stack[ 4 * i ];
				stack_ptr[0] = src_ptr[0];
				stack_ptr[1] = src_ptr[1];
				stack_ptr[2] = src_ptr[2];
				stack_ptr[3] = src_ptr[3];
				sum_r += src_ptr[0] * (i + 1);
				sum_g += src_ptr[1] * (i + 1);
				sum_b += src_ptr[2] * (i + 1);
				sum_a += src_ptr[3] * (i + 1);
				sum_out_r += src_ptr[0];
				sum_out_g += src_ptr[1];
				sum_out_b += src_ptr[2];
				sum_out_a += src_ptr[3];
			}


			for(i = 1; i <= radius; i++)
			{
				if (i <= wm) src_ptr += 4;
				stack_ptr = &stack[ 4 * (i + radius) ];
				stack_ptr[0] = src_ptr[0];
				stack_ptr[1] = src_ptr[1];
				stack_ptr[2] = src_ptr[2];
				stack_ptr[3] = src_ptr[3];
				sum_r += src_ptr[0] * (radius + 1 - i);
				sum_g += src_ptr[1] * (radius + 1 - i);
				sum_b += src_ptr[2] * (radius + 1 - i);
				sum_a += src_ptr[3] * (radius + 1 - i);
				sum_in_r += src_ptr[0];
				sum_in_g += src_ptr[1];
				sum_in_b += src_ptr[2];
				sum_in_a += src_ptr[3];
			}


			sp = radius;
			xp = radius;
			if (xp > wm) xp = wm;
			src_ptr = src + 4 * (xp + y * w); //   img.pix_ptr(xp, y);
			dst_ptr = src + y * w4; // img.pix_ptr(0, y);
			for(x = 0; x < w; x++)
			{
				dst_ptr[0] = (sum_r * mul_sum) >> shr_sum;
				dst_ptr[1] = (sum_g * mul_sum) >> shr_sum;
				dst_ptr[2] = (sum_b * mul_sum) >> shr_sum;
				dst_ptr[3] = (sum_a * mul_sum) >> shr_sum;
				dst_ptr += 4;

				sum_r -= sum_out_r;
				sum_g -= sum_out_g;
				sum_b -= sum_out_b;
				sum_a -= sum_out_a;

				stack_start = sp + div - radius;
				if (stack_start >= div) stack_start -= div;
				stack_ptr = &stack[4 * stack_start];

				sum_out_r -= stack_ptr[0];
				sum_out_g -= stack_ptr[1];
				sum_out_b -= stack_ptr[2];
				sum_out_a -= stack_ptr[3];

				if(xp < wm)
				{
					src_ptr += 4;
					++xp;
				}

				stack_ptr[0] = src_ptr[0];
				stack_ptr[1] = src_ptr[1];
				stack_ptr[2] = src_ptr[2];
				stack_ptr[3] = src_ptr[3];

				sum_in_r += src_ptr[0];
				sum_in_g += src_ptr[1];
				sum_in_b += src_ptr[2];
				sum_in_a += src_ptr[3];
				sum_r    += sum_in_r;
				sum_g    += sum_in_g;
				sum_b    += sum_in_b;
				sum_a    += sum_in_a;

				++sp;
				if (sp >= div) sp = 0;
				stack_ptr = &stack[sp*4];

				sum_out_r += stack_ptr[0];
				sum_out_g += stack_ptr[1];
				sum_out_b += stack_ptr[2];
				sum_out_a += stack_ptr[3];
				sum_in_r  -= stack_ptr[0];
				sum_in_g  -= stack_ptr[1];
				sum_in_b  -= stack_ptr[2];
				sum_in_a  -= stack_ptr[3];


			}

		}
	}

	// step 2
	if (step == 2)
	{
		int minX = core * w / cores;
		int maxX = (core + 1) * w / cores;

		for(x = minX; x < maxX; x++)
		{
			sum_r =	sum_g =	sum_b =	sum_a =
			sum_in_r = sum_in_g = sum_in_b = sum_in_a =
			sum_out_r = sum_out_g = sum_out_b = sum_out_a = 0;

			src_ptr = src + 4 * x; // x,0
			for(i = 0; i <= radius; i++)
			{
				stack_ptr    = &stack[i * 4];
				stack_ptr[0] = src_ptr[0];
				stack_ptr[1] = src_ptr[1];
				stack_ptr[2] = src_ptr[2];
				stack_ptr[3] = src_ptr[3];
				sum_r           += src_ptr[0] * (i + 1);
				sum_g           += src_ptr[1] * (i + 1);
				sum_b           += src_ptr[2] * (i + 1);
				sum_a           += src_ptr[3] * (i + 1);
				sum_out_r       += src_ptr[0];
				sum_out_g       += src_ptr[1];
				sum_out_b       += src_ptr[2];
				sum_out_a       += src_ptr[3];
			}
			for(i = 1; i <= radius; i++)
			{
				if(i <= hm) src_ptr += w4; // +stride

				stack_ptr = &stack[4 * (i + radius)];
				stack_ptr[0] = src_ptr[0];
				stack_ptr[1] = src_ptr[1];
				stack_ptr[2] = src_ptr[2];
				stack_ptr[3] = src_ptr[3];
				sum_r += src_ptr[0] * (radius + 1 - i);
				sum_g += src_ptr[1] * (radius + 1 - i);
				sum_b += src_ptr[2] * (radius + 1 - i);
				sum_a += src_ptr[3] * (radius + 1 - i);
				sum_in_r += src_ptr[0];
				sum_in_g += src_ptr[1];
				sum_in_b += src_ptr[2];
				sum_in_a += src_ptr[3];
			}

			sp = radius;
			yp = radius;
			if (yp > hm) yp = hm;
			src_ptr = src + 4 * (x + yp * w); // img.pix_ptr(x, yp);
			dst_ptr = src + 4 * x; 			  // img.pix_ptr(x, 0);
			for(y = 0; y < h; y++)
			{
				dst_ptr[0] = (sum_r * mul_sum) >> shr_sum;
				dst_ptr[1] = (sum_g * mul_sum) >> shr_sum;
				dst_ptr[2] = (sum_b * mul_sum) >> shr_sum;
				dst_ptr[3] = (sum_a * mul_sum) >> shr_sum;
				dst_ptr += w4;

				sum_r -= sum_out_r;
				sum_g -= sum_out_g;
				sum_b -= sum_out_b;
				sum_a -= sum_out_a;

				stack_start = sp + div - radius;
				if(stack_start >= div) stack_start -= div;
				stack_ptr = &stack[4 * stack_start];

				sum_out_r -= stack_ptr[0];
				sum_out_g -= stack_ptr[1];
				sum_out_b -= stack_ptr[2];
				sum_out_a -= stack_ptr[3];

				if(yp < hm)
				{
					src_ptr += w4; // stride
					++yp;
				}

				stack_ptr[0] = src_ptr[0];
				stack_ptr[1] = src_ptr[1];
				stack_ptr[2] = src_ptr[2];
				stack_ptr[3] = src_ptr[3];

				sum_in_r += src_ptr[0];
				sum_in_g += src_ptr[1];
				sum_in_b += src_ptr[2];
				sum_in_a += src_ptr[3];
				sum_r    += sum_in_r;
				sum_g    += sum_in_g;
				sum_b    += sum_in_b;
				sum_a    += sum_in_a;

				++sp;
				if (sp >= div) sp = 0;
				stack_ptr = &stack[sp*4];

				sum_out_r += stack_ptr[0];
				sum_out_g += stack_ptr[1];
				sum_out_b += stack_ptr[2];
				sum_out_a += stack_ptr[3];
				sum_in_r  -= stack_ptr[0];
				sum_in_g  -= stack_ptr[1];
				sum_in_b  -= stack_ptr[2];
				sum_in_a  -= stack_ptr[3];
			}
		}
	}

}


class MVImageUtilsStackBlurTask : public MVThread
{
public:
	unsigned char* src;
	unsigned int w;
	unsigned int h;
	unsigned int radius;
	int cores;
	int core;
	int step;
	unsigned char* stack;

	inline MVImageUtilsStackBlurTask(unsigned char* src, unsigned int w, unsigned int h, unsigned int radius, int cores, int core, int step, unsigned char* stack)
	{
		this->src = src;
		this->w = w;
		this->h = h;
		this->radius = radius;
		this->cores = cores;
		this->core = core;
		this->step = step;
		this->stack = stack;
	}

	inline void run()
	{
		stackblurJob(src, w, h, radius, cores, core, step, stack);
	}

};


/// Stackblur algorithm by Mario Klingemann
/// Details here:
/// http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html
/// C++ implemenation base from:
/// https://gist.github.com/benjamin9999/3809142
/// http://www.antigrain.com/__code/include/agg_blur.h.html
/// This version works only with RGBA color
void 			   stackblur(unsigned char* src,				///< input image data
	   					     unsigned int w,					///< image width
							 unsigned int h,					///< image height
							 unsigned int radius,				///< blur intensity (should be in 2..254 range)
							 int cores = 1						///< number of threads (1 - normal single thread)
							 )
{
	if (radius > 254) return;
	if (radius < 2) return;

	unsigned int div = (radius * 2) + 1;
	unsigned char* stack = new unsigned char [div * 4 * cores];

	if (cores == 1)
	{
		// no multithreading
		stackblurJob(src, w, h, radius, 1, 0, 1, stack);
		stackblurJob(src, w, h, radius, 1, 0, 2, stack);
	}
	else
	{
		MVImageUtilsStackBlurTask** workers = new MVImageUtilsStackBlurTask*[cores];
		for (int i = 0; i < cores; i++)
		{
			workers[i] = new MVImageUtilsStackBlurTask(src, w, h, radius, cores, i, 1, stack + div * 4 * i);
			workers[i]->start();
		}

		for (int i = 0; i < cores; i++)
			workers[i]->wait();

		for (int i = 0; i < cores; i++)
		{
			workers[i]->step = 2;
			workers[i]->start();
		}

		for (int i = 0; i < cores; i++)
		{
			workers[i]->wait();
			delete workers[i];
		}

		delete[] workers;
	}

	delete[] stack;
}

stackblur.txt

// Stack Blur v1.0
//
// Author: Mario Klingemann <mario@quasimondo.com>
// http://incubator.quasimondo.com
// created Feburary 29, 2004


// This is a compromise between Gaussian Blur and Box blur
// It creates much better looking blurs than Box Blur, but is
// 7x faster than my Gaussian Blur implementation.
//
// I called it Stack Blur because this describes best how this
// filter works internally: it creates a kind of moving stack
// of colors whilst scanning through the image. Thereby it
// just has to add one new block of color to the right side
// of the stack and remove the leftmost color. The remaining
// colors on the topmost layer of the stack are either added on
// or reduced by one, depending on if they are on the right or
// on the left side of the stack. 
//
// If you are using this algorithm in your code please add
// the following line:
// 
// Stack Blur Algorithm by Mario Klingemann <mario@quasimondo.com>

PImage a;
PImage b;

void setup()
{
  a=loadImage("dog.jpg");
  size(a.width, a.height);
  b=new PImage(a.width, a.height);
  fill(255);
  noStroke();
  frameRate(25);
}

void draw()
{
  System.arraycopy(a.pixels,0,b.pixels,0,a.pixels.length);
  fastblur(b,mouseY/4);
  image(b, 0, 0);
}

void fastblur(PImage img,int radius){

  if (radius<1){
    return;
  }
  int[] pix=img.pixels;
  int w=img.width;
  int h=img.height;
  int wm=w-1;
  int hm=h-1;
  int wh=w*h;
  int div=radius+radius+1;

  int r[]=new int[wh];
  int g[]=new int[wh];
  int b[]=new int[wh];
  int rsum,gsum,bsum,x,y,i,p,yp,yi,yw;
  int vmin[] = new int[max(w,h)];

  int divsum=(div+1)>>1;
  divsum*=divsum;
  int dv[]=new int[256*divsum];
  for (i=0;i<256*divsum;i++){
    dv[i]=(i/divsum);
  }

  yw=yi=0;

  int[][] stack=new int[div][3];
  int stackpointer;
  int stackstart;
  int[] sir;
  int rbs;
  int r1=radius+1;
  int routsum,goutsum,boutsum;
  int rinsum,ginsum,binsum;

  for (y=0;y<h;y++){
    rinsum=ginsum=binsum=routsum=goutsum=boutsum=rsum=gsum=bsum=0;
    for(i=-radius;i<=radius;i++){
      p=pix[yi+min(wm,max(i,0))];
      sir=stack[i+radius];
      sir[0]=(p & 0xff0000)>>16;
      sir[1]=(p & 0x00ff00)>>8;
      sir[2]=(p & 0x0000ff);
      rbs=r1-abs(i);
      rsum+=sir[0]*rbs;
      gsum+=sir[1]*rbs;
      bsum+=sir[2]*rbs;
      if (i>0){
        rinsum+=sir[0];
        ginsum+=sir[1];
        binsum+=sir[2];
      } else {
        routsum+=sir[0];
        goutsum+=sir[1];
        boutsum+=sir[2];
      }
    }
    stackpointer=radius;

    for (x=0;x<w;x++){

      r[yi]=dv[rsum];
      g[yi]=dv[gsum];
      b[yi]=dv[bsum];
      
      rsum-=routsum;
      gsum-=goutsum;
      bsum-=boutsum;

      stackstart=stackpointer-radius+div;
      sir=stack[stackstart%div];
      
      routsum-=sir[0];
      goutsum-=sir[1];
      boutsum-=sir[2];
      
      if(y==0){
        vmin[x]=min(x+radius+1,wm);
      }
      p=pix[yw+vmin[x]];
      
      sir[0]=(p & 0xff0000)>>16;
      sir[1]=(p & 0x00ff00)>>8;
      sir[2]=(p & 0x0000ff);

      rinsum+=sir[0];
      ginsum+=sir[1];
      binsum+=sir[2];

      rsum+=rinsum;
      gsum+=ginsum;
      bsum+=binsum;
      
      stackpointer=(stackpointer+1)%div;
      sir=stack[(stackpointer)%div];
     
      routsum+=sir[0];
      goutsum+=sir[1];
      boutsum+=sir[2];
     
       rinsum-=sir[0];
      ginsum-=sir[1];
      binsum-=sir[2];
     
       yi++;
    }
    yw+=w;
  }
  for (x=0;x<w;x++){
    rinsum=ginsum=binsum=routsum=goutsum=boutsum=rsum=gsum=bsum=0;
    yp=-radius*w;
    for(i=-radius;i<=radius;i++){
      yi=max(0,yp)+x;
     
       sir=stack[i+radius];
      
      sir[0]=r[yi];
      sir[1]=g[yi];
      sir[2]=b[yi];
     
      rbs=r1-abs(i);
      
      rsum+=r[yi]*rbs;
      gsum+=g[yi]*rbs;
      bsum+=b[yi]*rbs;
     
      if (i>0){
        rinsum+=sir[0];
        ginsum+=sir[1];
        binsum+=sir[2];
      } else {
        routsum+=sir[0];
        goutsum+=sir[1];
        boutsum+=sir[2];
      }
      
      if(i<hm){
        yp+=w;
      }
    }
    yi=x;
    stackpointer=radius;
    for (y=0;y<h;y++){
      pix[yi]=0xff000000 | (dv[rsum]<<16) | (dv[gsum]<<8) | dv[bsum];

      rsum-=routsum;
      gsum-=goutsum;
      bsum-=boutsum;

      stackstart=stackpointer-radius+div;
      sir=stack[stackstart%div];
     
      routsum-=sir[0];
      goutsum-=sir[1];
      boutsum-=sir[2];
     
       if(x==0){
        vmin[y]=min(y+r1,hm)*w;
      }
      p=x+vmin[y];
      
      sir[0]=r[p];
      sir[1]=g[p];
      sir[2]=b[p];
      
      rinsum+=sir[0];
      ginsum+=sir[1];
      binsum+=sir[2];

      rsum+=rinsum;
      gsum+=ginsum;
      bsum+=binsum;

      stackpointer=(stackpointer+1)%div;
      sir=stack[stackpointer];
     
      routsum+=sir[0];
      goutsum+=sir[1];
      boutsum+=sir[2];
      
      rinsum-=sir[0];
      ginsum-=sir[1];
      binsum-=sir[2];

      yi+=w;
    }
  }
  
  img.updatePixels();
}

StackBoxBlur.js

/*

StackBoxBlur - a fast almost Box Blur For Canvas

Version: 	0.3
Author:		Mario Klingemann
Contact: 	mario@quasimondo.com
Website:	http://www.quasimondo.com/
Twitter:	@quasimondo

In case you find this class useful - especially in commercial projects -
I am not totally unhappy for a small donation to my PayPal account
mario@quasimondo.de

Copyright (c) 2010 Mario Klingemann

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/
/*
var mul_table = [ 1,57,41,21,203,34,97,73,227,91,149,62,105,45,39,137,241,107,3,173,39,71,65,238,219,101,187,87,81,151,141,133,249,117,221,209,197,187,177,169,5,153,73,139,133,127,243,233,223,107,103,99,191,23,177,171,165,159,77,149,9,139,135,131,253,245,119,231,224,109,211,103,25,195,189,23,45,175,171,83,81,79,155,151,147,9,141,137,67,131,129,251,123,30,235,115,113,221,217,53,13,51,50,49,193,189,185,91,179,175,43,169,83,163,5,79,155,19,75,147,145,143,35,69,17,67,33,65,255,251,247,243,239,59,29,229,113,111,219,27,213,105,207,51,201,199,49,193,191,47,93,183,181,179,11,87,43,85,167,165,163,161,159,157,155,77,19,75,37,73,145,143,141,35,138,137,135,67,33,131,129,255,63,250,247,61,121,239,237,117,29,229,227,225,111,55,109,216,213,211,209,207,205,203,201,199,197,195,193,48,190,47,93,185,183,181,179,178,176,175,173,171,85,21,167,165,41,163,161,5,79,157,78,154,153,19,75,149,74,147,73,144,143,71,141,140,139,137,17,135,134,133,66,131,65,129,1];
        
   
var shg_table = [0,9,10,10,14,12,14,14,16,15,16,15,16,15,15,17,18,17,12,18,16,17,17,19,19,18,19,18,18,19,19,19,20,19,20,20,20,20,20,20,15,20,19,20,20,20,21,21,21,20,20,20,21,18,21,21,21,21,20,21,17,21,21,21,22,22,21,22,22,21,22,21,19,22,22,19,20,22,22,21,21,21,22,22,22,18,22,22,21,22,22,23,22,20,23,22,22,23,23,21,19,21,21,21,23,23,23,22,23,23,21,23,22,23,18,22,23,20,22,23,23,23,21,22,20,22,21,22,24,24,24,24,24,22,21,24,23,23,24,21,24,23,24,22,24,24,22,24,24,22,23,24,24,24,20,23,22,23,24,24,24,24,24,24,24,23,21,23,22,23,24,24,24,22,24,24,24,23,22,24,24,25,23,25,25,23,24,25,25,24,22,25,25,25,24,23,24,25,25,25,25,25,25,25,25,25,25,25,25,23,25,23,24,25,25,25,25,25,25,25,25,25,24,22,25,25,23,25,25,20,24,25,24,25,25,22,24,25,24,25,24,25,25,24,25,25,25,25,22,25,25,25,24,25,24,25,18];
*/

var mul_table = [ 1,171,205,293,57,373,79,137,241,27,391,357,41,19,283,265,497,469,443,421,25,191,365,349,335,161,155,149,9,278,269,261,505,245,475,231,449,437,213,415,405,395,193,377,369,361,353,345,169,331,325,319,313,307,301,37,145,285,281,69,271,267,263,259,509,501,493,243,479,118,465,459,113,446,55,435,429,423,209,413,51,403,199,393,97,3,379,375,371,367,363,359,355,351,347,43,85,337,333,165,327,323,5,317,157,311,77,305,303,75,297,294,73,289,287,71,141,279,277,275,68,135,67,133,33,262,260,129,511,507,503,499,495,491,61,121,481,477,237,235,467,232,115,457,227,451,7,445,221,439,218,433,215,427,425,211,419,417,207,411,409,203,202,401,399,396,197,49,389,387,385,383,95,189,47,187,93,185,23,183,91,181,45,179,89,177,11,175,87,173,345,343,341,339,337,21,167,83,331,329,327,163,81,323,321,319,159,79,315,313,39,155,309,307,153,305,303,151,75,299,149,37,295,147,73,291,145,289,287,143,285,71,141,281,35,279,139,69,275,137,273,17,271,135,269,267,133,265,33,263,131,261,130,259,129,257,1];
        
   
var shg_table = [0,9,10,11,9,12,10,11,12,9,13,13,10,9,13,13,14,14,14,14,10,13,14,14,14,13,13,13,9,14,14,14,15,14,15,14,15,15,14,15,15,15,14,15,15,15,15,15,14,15,15,15,15,15,15,12,14,15,15,13,15,15,15,15,16,16,16,15,16,14,16,16,14,16,13,16,16,16,15,16,13,16,15,16,14,9,16,16,16,16,16,16,16,16,16,13,14,16,16,15,16,16,10,16,15,16,14,16,16,14,16,16,14,16,16,14,15,16,16,16,14,15,14,15,13,16,16,15,17,17,17,17,17,17,14,15,17,17,16,16,17,16,15,17,16,17,11,17,16,17,16,17,16,17,17,16,17,17,16,17,17,16,16,17,17,17,16,14,17,17,17,17,15,16,14,16,15,16,13,16,15,16,14,16,15,16,12,16,15,16,17,17,17,17,17,13,16,15,17,17,17,16,15,17,17,17,16,15,17,17,14,16,17,17,16,17,17,16,15,17,16,14,17,16,15,17,16,17,17,16,17,15,16,17,14,17,16,15,17,16,17,13,17,16,17,17,16,17,14,17,16,17,16,17,16,17,9
];

function stackBoxBlurImage( imageID, canvasID, radius, blurAlphaChannel, iterations )
{
			
 	var img = document.getElementById( imageID );
	var w = img.naturalWidth;
    var h = img.naturalHeight;
       
	var canvas = document.getElementById( canvasID );
      
    canvas.style.width  = w + "px";
    canvas.style.height = h + "px";
    canvas.width = w;
    canvas.height = h;
    
    var context = canvas.getContext("2d");
    context.clearRect( 0, 0, w, h );
    context.drawImage( img, 0, 0 );

	if ( isNaN(radius) || radius < 1 ) return;
	
	if ( blurAlphaChannel )
		stackBoxBlurCanvasRGBA( canvasID, 0, 0, w, h, radius, iterations );
	else 
		stackBoxBlurCanvasRGB( canvasID, 0, 0, w, h, radius, iterations );
}


function stackBoxBlurCanvasRGBA( id, top_x, top_y, width, height, radius, iterations )
{
	if ( isNaN(radius) || radius < 1 ) return;
	radius |= 0;
	
	if ( isNaN(iterations) ) iterations = 1;
	iterations |= 0;
	if ( iterations > 3 ) iterations = 3;
	if ( iterations < 1 ) iterations = 1;
	
	var canvas  = document.getElementById( id );
	var context = canvas.getContext("2d");
	var imageData;
	
	try {
	  try {
		imageData = context.getImageData( top_x, top_y, width, height );
	  } catch(e) {
	  
		// NOTE: this part is supposedly only needed if you want to work with local files
		// so it might be okay to remove the whole try/catch block and just use
		// imageData = context.getImageData( top_x, top_y, width, height );
		try {
			netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
			imageData = context.getImageData( top_x, top_y, width, height );
		} catch(e) {
			alert("Cannot access local image");
			throw new Error("unable to access local image data: " + e);
			return;
		}
	  }
	} catch(e) {
	  alert("Cannot access image");
	  throw new Error("unable to access image data: " + e);
	}
			
	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 w4 = width << 2;
	var widthMinus1  = width - 1;
	var heightMinus1 = height - 1;
	var radiusPlus1  = radius + 1;
	
	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 mul_sum = mul_table[radius];
	var shg_sum = shg_table[radius];
	while ( iterations-- > 0 ) {
		yw = yi = 0;
		for ( y = height; --y > -1; )
		{
			r_sum = radiusPlus1 * ( pr = pixels[yi] );
			g_sum = radiusPlus1 * ( pg = pixels[yi+1] );
			b_sum = radiusPlus1 * ( pb = pixels[yi+2] );
			a_sum = radiusPlus1 * ( pa = pixels[yi+3] );
			
			stack = stackStart;
			
			for( i = radiusPlus1; --i > -1; )
			{
				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 = pixels[p]);
				g_sum += ( stack.g = pixels[p+1]);
				b_sum += ( stack.b = pixels[p+2]);
				a_sum += ( stack.a = pixels[p+3]);
				
				stack = stack.next;
			}
			
			stackIn = stackStart;
			for ( x = 0; x < width; x++ )
			{
				pixels[yi++] = (r_sum * mul_sum) >>> shg_sum;
				pixels[yi++] = (g_sum * mul_sum) >>> shg_sum;
				pixels[yi++] = (b_sum * mul_sum) >>> shg_sum;
				pixels[yi++] = (a_sum * mul_sum) >>> shg_sum;
				
				p =  ( yw + ( ( p = x + radius + 1 ) < widthMinus1 ? p : widthMinus1 ) ) << 2;
				
				r_sum -= stackIn.r - ( stackIn.r = pixels[p]);
				g_sum -= stackIn.g - ( stackIn.g = pixels[p+1]);
				b_sum -= stackIn.b - ( stackIn.b = pixels[p+2]);
				a_sum -= stackIn.a - ( stackIn.a = pixels[p+3]);
				
				stackIn = stackIn.next;
				
			}
			yw += width;
		}

		
		for ( x = 0; x < width; x++ )
		{
			yi = x << 2;
			
			r_sum = radiusPlus1 * ( pr = pixels[yi]);
			g_sum = radiusPlus1 * ( pg = pixels[yi+1]);
			b_sum = radiusPlus1 * ( pb = pixels[yi+2]);
			a_sum = radiusPlus1 * ( pa = pixels[yi+3]);
			
			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 = pixels[yi]);
				g_sum += ( stack.g = pixels[yi+1]);
				b_sum += ( stack.b = pixels[yi+2]);
				a_sum += ( stack.a = pixels[yi+3]);
			   
				stack = stack.next;
			
				if( i < heightMinus1 )
				{
					yp += width;
				}
			}
			
			yi = x;
			stackIn = stackStart;
			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
				}
				
				p = ( x + (( ( p = y + radiusPlus1) < heightMinus1 ? p : heightMinus1 ) * width )) << 2;
				
				r_sum -= stackIn.r - ( stackIn.r = pixels[p]);
				g_sum -= stackIn.g - ( stackIn.g = pixels[p+1]);
				b_sum -= stackIn.b - ( stackIn.b = pixels[p+2]);
				a_sum -= stackIn.a - ( stackIn.a = pixels[p+3]);
			   
				stackIn = stackIn.next;
				
				yi += width;
			}
		}
	}
	context.putImageData( imageData, top_x, top_y );
	
}


function stackBoxBlurCanvasRGB( id, top_x, top_y, width, height, radius, iterations )
{
	if ( isNaN(radius) || radius < 1 ) return;
	radius |= 0;
	
	if ( isNaN(iterations) ) iterations = 1;
	iterations |= 0;
	if ( iterations > 3 ) iterations = 3;
	if ( iterations < 1 ) iterations = 1;
	
	var canvas  = document.getElementById( id );
	var context = canvas.getContext("2d");
	var imageData;
	
	try {
	  try {
		imageData = context.getImageData( top_x, top_y, width, height );
	  } catch(e) {
	  
		// NOTE: this part is supposedly only needed if you want to work with local files
		// so it might be okay to remove the whole try/catch block and just use
		// imageData = context.getImageData( top_x, top_y, width, height );
		try {
			netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
			imageData = context.getImageData( top_x, top_y, width, height );
		} catch(e) {
			alert("Cannot access local image");
			throw new Error("unable to access local image data: " + e);
			return;
		}
	  }
	} catch(e) {
	  alert("Cannot access image");
	  throw new Error("unable to access image data: " + e);
	}
			
	var pixels = imageData.data;
			
	var x, y, i, p, yp, yi, yw, r_sum, g_sum, b_sum,
	r_out_sum, g_out_sum, b_out_sum,
	r_in_sum, g_in_sum, b_in_sum,
	pr, pg, pb, rbs;
			
	var div = radius + radius + 1;
	var w4 = width << 2;
	var widthMinus1  = width - 1;
	var heightMinus1 = height - 1;
	var radiusPlus1  = radius + 1;
	
	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 mul_sum = mul_table[radius];
	var shg_sum = shg_table[radius];
	
	while ( iterations-- > 0 ) {
		yw = yi = 0;
		
		for ( y = height; --y >-1; )
		{
			r_sum = radiusPlus1 * ( pr = pixels[yi] );
			g_sum = radiusPlus1 * ( pg = pixels[yi+1] );
			b_sum = radiusPlus1 * ( pb = pixels[yi+2] );
			
			stack = stackStart;
			
			for( i = radiusPlus1; --i > -1; )
			{
				stack.r = pr;
				stack.g = pg;
				stack.b = pb;
				stack = stack.next;
			}
			
			for( i = 1; i < radiusPlus1; i++ )
			{
				p = yi + (( widthMinus1 < i ? widthMinus1 : i ) << 2 );
				r_sum += ( stack.r = pixels[p++]);
				g_sum += ( stack.g = pixels[p++]);
				b_sum += ( stack.b = pixels[p]);
				
				stack = stack.next;
			}
			
			stackIn = stackStart;
			for ( x = 0; x < width; x++ )
			{
				pixels[yi++] = (r_sum * mul_sum) >>> shg_sum;
				pixels[yi++] = (g_sum * mul_sum) >>> shg_sum;
				pixels[yi++] = (b_sum * mul_sum) >>> shg_sum;
				yi++;
				
				p =  ( yw + ( ( p = x + radius + 1 ) < widthMinus1 ? p : widthMinus1 ) ) << 2;
				
				r_sum -= stackIn.r - ( stackIn.r = pixels[p++]);
				g_sum -= stackIn.g - ( stackIn.g = pixels[p++]);
				b_sum -= stackIn.b - ( stackIn.b = pixels[p]);
				
				stackIn = stackIn.next;
			}
			yw += width;
		}

		
		for ( x = 0; x < width; x++ )
		{
			yi = x << 2;
			
			r_sum = radiusPlus1 * ( pr = pixels[yi++]);
			g_sum = radiusPlus1 * ( pg = pixels[yi++]);
			b_sum = radiusPlus1 * ( pb = pixels[yi]);
			
			stack = stackStart;
			
			for( i = 0; i < radiusPlus1; i++ )
			{
				stack.r = pr;
				stack.g = pg;
				stack.b = pb;
				stack = stack.next;
			}
			
			yp = width;
			
			for( i = 1; i <= radius; i++ )
			{
				yi = ( yp + x ) << 2;
				
				r_sum += ( stack.r = pixels[yi++]);
				g_sum += ( stack.g = pixels[yi++]);
				b_sum += ( stack.b = pixels[yi]);
				
				stack = stack.next;
			
				if ( i < heightMinus1 ) yp += width;
			}
			
			yi = x;
			stackIn = stackStart;
			for ( y = 0; y < height; y++ )
			{
				p = yi << 2;
				pixels[p]   = (r_sum * mul_sum) >>> shg_sum;
				pixels[p+1] = (g_sum * mul_sum) >>> shg_sum;
				pixels[p+2] = (b_sum * mul_sum) >>> shg_sum;
				
				p = ( x + (( ( p = y + radiusPlus1) < heightMinus1 ? p : heightMinus1 ) * width )) << 2;
				
				r_sum -= stackIn.r - ( stackIn.r = pixels[p]);
				g_sum -= stackIn.g - ( stackIn.g = pixels[p+1]);
				b_sum -= stackIn.b - ( stackIn.b = pixels[p+2]);
				
				stackIn = stackIn.next;
				
				yi += width;
			}
		}
	}
	context.putImageData( imageData, top_x, top_y );
	
}

function BlurStack()
{
	this.r = 0;
	this.g = 0;
	this.b = 0;
	this.a = 0;
	this.next = null;
}

相关博客

[Android] 图片JNI(C++\Java)高斯模糊 多线程

[Android]-图片JNI(C++\Java)高斯模糊的实现与比较

========================================================
作者:
qiujuer
博客:blog.csdn.net/qiujuer
网站:www.qiujuer.net
开源库:Genius-Android
转载请注明出处:http://blog.csdn.net/qiujuer/article/details/41781073
========================================================
还没有人评论,赶快来抢沙发吧!