清华大佬耗费三个月吐血整理的几百G的资源,免费分享!....>>>
收集各种语言:C C++ Java C# JS 等等语言对图片的处理实现代码;包括高斯模糊、堆栈模糊、盒子模糊等等。
所有代码均开源;可拷贝使用。
项目地址
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
========================================================