Skip to content

Instantly share code, notes, and snippets.

@flurin
Last active May 16, 2018 11:48
Show Gist options
  • Save flurin/327337e1beb3db983de8 to your computer and use it in GitHub Desktop.
Save flurin/327337e1beb3db983de8 to your computer and use it in GitHub Desktop.
Doing background blur with canvas
<!doctype html>
<html>
<head>
<title>Blur!</title>
</head>
<body>
<div id="box1" class="box blurred-bg tinted">
<h1>Blurred Background</h1>
<h2>By Flurin Egger, inspired by <a href="http://ariona.net">Ariona, Rian</a></h2>
<p>Drag this box to move around</p>
<p><a href="http://codepen.io/ariona/pen/geFIK">Original on codepen</a></p>
</div>
<script src="http://code.jquery.com/jquery-1.10.2.js"></script>
<script src="http://code.jquery.com/ui/1.10.4/jquery-ui.js"></script>
<!-- http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html -->
<script src="http://www.quasimondo.com/StackBlurForCanvas/StackBlur.js"></script>
<script>
var blurRadius = 5;
$(function() {
$( ".box" ).draggable();
});
// Load the image
var img = new Image();
img.onload = onImageLoaded;
img.src = "normal.jpg";
function onImageLoaded(){
var tmpCanvas = document.createElement("canvas");
var tmpCtx = tmpCanvas.getContext("2d");
// We're going to draw the image smaller for faster performance
var blurImageMaxWidth = 300, blurImageMaxHeight = 300;
var scaleFactor = Math.min(blurImageMaxWidth / img.width, blurImageMaxHeight / img.height, 1);
var blurImageWidth = Math.round(img.width * scaleFactor);
var blurImageHeight = Math.round(img.height * scaleFactor);
tmpCanvas.width = blurImageWidth;
tmpCanvas.height = blurImageHeight;
tmpCtx.drawImage(img, 0, 0, blurImageWidth, blurImageHeight);
// Apply the blur to the canvas
stackBlurCtxRGB(tmpCtx, 0, 0, blurImageWidth, blurImageHeight, blurRadius);
// $(".blurred-bg").css("background-image", 'url(' + tmpCanvas.toDataURL() + ')');
$(".blurred-bg.tinted").css("background-image", 'linear-gradient(rgba(255,255,255,0.2), rgba(255,255,255,0.2)), url(' + tmpCanvas.toDataURL() + ')')
}
// Hack to make stackblurCtxRGB work with plain Canvas Context as well.
function stackBlurCtxRGB( ctx, top_x, top_y, width, height, radius )
{
if ( isNaN(radius) || radius < 1 ) return;
radius |= 0;
var context = ctx;
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 sumFactor = radiusPlus1 * ( radiusPlus1 + 1 ) / 2;
var stackStart = new BlurStack();
var stack = stackStart;
for ( i = 1; i < div; i++ )
{
stack = stack.next = new BlurStack();
if ( i == radiusPlus1 ) var stackEnd = stack;
}
stack.next = stackStart;
var stackIn = null;
var stackOut = null;
yw = yi = 0;
var mul_sum = mul_table[radius];
var shg_sum = shg_table[radius];
for ( y = 0; y < height; y++ )
{
r_in_sum = g_in_sum = b_in_sum = r_sum = g_sum = b_sum = 0;
r_out_sum = radiusPlus1 * ( pr = pixels[yi] );
g_out_sum = radiusPlus1 * ( pg = pixels[yi+1] );
b_out_sum = radiusPlus1 * ( pb = pixels[yi+2] );
r_sum += sumFactor * pr;
g_sum += sumFactor * pg;
b_sum += sumFactor * pb;
stack = stackStart;
for( i = 0; i < radiusPlus1; i++ )
{
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 = ( pr = pixels[p])) * ( rbs = radiusPlus1 - i );
g_sum += ( stack.g = ( pg = pixels[p+1])) * rbs;
b_sum += ( stack.b = ( pb = pixels[p+2])) * rbs;
r_in_sum += pr;
g_in_sum += pg;
b_in_sum += pb;
stack = stack.next;
}
stackIn = stackStart;
stackOut = stackEnd;
for ( x = 0; x < width; x++ )
{
pixels[yi] = (r_sum * mul_sum) >> shg_sum;
pixels[yi+1] = (g_sum * mul_sum) >> shg_sum;
pixels[yi+2] = (b_sum * mul_sum) >> shg_sum;
r_sum -= r_out_sum;
g_sum -= g_out_sum;
b_sum -= b_out_sum;
r_out_sum -= stackIn.r;
g_out_sum -= stackIn.g;
b_out_sum -= stackIn.b;
p = ( yw + ( ( p = x + radius + 1 ) < widthMinus1 ? p : widthMinus1 ) ) << 2;
r_in_sum += ( stackIn.r = pixels[p]);
g_in_sum += ( stackIn.g = pixels[p+1]);
b_in_sum += ( stackIn.b = pixels[p+2]);
r_sum += r_in_sum;
g_sum += g_in_sum;
b_sum += b_in_sum;
stackIn = stackIn.next;
r_out_sum += ( pr = stackOut.r );
g_out_sum += ( pg = stackOut.g );
b_out_sum += ( pb = stackOut.b );
r_in_sum -= pr;
g_in_sum -= pg;
b_in_sum -= pb;
stackOut = stackOut.next;
yi += 4;
}
yw += width;
}
for ( x = 0; x < width; x++ )
{
g_in_sum = b_in_sum = r_in_sum = g_sum = b_sum = r_sum = 0;
yi = x << 2;
r_out_sum = radiusPlus1 * ( pr = pixels[yi]);
g_out_sum = radiusPlus1 * ( pg = pixels[yi+1]);
b_out_sum = radiusPlus1 * ( pb = pixels[yi+2]);
r_sum += sumFactor * pr;
g_sum += sumFactor * pg;
b_sum += sumFactor * pb;
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 = ( pr = pixels[yi])) * ( rbs = radiusPlus1 - i );
g_sum += ( stack.g = ( pg = pixels[yi+1])) * rbs;
b_sum += ( stack.b = ( pb = pixels[yi+2])) * rbs;
r_in_sum += pr;
g_in_sum += pg;
b_in_sum += pb;
stack = stack.next;
if( i < heightMinus1 )
{
yp += width;
}
}
yi = x;
stackIn = stackStart;
stackOut = stackEnd;
for ( y = 0; y < height; y++ )
{
p = yi << 2;
pixels[p] = (r_sum * mul_sum) >> shg_sum;
pixels[p+1] = (g_sum * mul_sum) >> shg_sum;
pixels[p+2] = (b_sum * mul_sum) >> shg_sum;
r_sum -= r_out_sum;
g_sum -= g_out_sum;
b_sum -= b_out_sum;
r_out_sum -= stackIn.r;
g_out_sum -= stackIn.g;
b_out_sum -= stackIn.b;
p = ( x + (( ( p = y + radiusPlus1) < heightMinus1 ? p : heightMinus1 ) * width )) << 2;
r_sum += ( r_in_sum += ( stackIn.r = pixels[p]));
g_sum += ( g_in_sum += ( stackIn.g = pixels[p+1]));
b_sum += ( b_in_sum += ( stackIn.b = pixels[p+2]));
stackIn = stackIn.next;
r_out_sum += ( pr = stackOut.r );
g_out_sum += ( pg = stackOut.g );
b_out_sum += ( pb = stackOut.b );
r_in_sum -= pr;
g_in_sum -= pg;
b_in_sum -= pb;
stackOut = stackOut.next;
yi += width;
}
}
context.putImageData( imageData, top_x, top_y );
}
</script>
<style>
body {
background-image: url("normal.jpg");
background-repeat: no-repeat;
background-size: cover;
background-attachment: fixed;
font-family: Raleway, Open Sans, Droid Sans, Roboto,arial, sans-serif;
}
.blurred-bg {
background-repeat: no-repeat;
-moz-background-size: cover;
-o-background-size: cover;
-webkit-background-size: cover;
background-size: cover;
background-attachment: fixed;
/* &.tinted{
@include background-image(linear-gradient(0deg, rgba(255,255,255,.2),rgba(255,255,255,.2)),url($blurred-img));
}
&.shaded{
@include background-image(linear-gradient(0deg, rgba(0,0,0,.2),rgba(0,0,0,.2)),url($blurred-img));
}*/
}
.box {
width: 500px;
height: 300px;
left: -webkit-calc( 50% - 250px );
top: 20%;
position: absolute;
border-radius: 5px;
-moz-box-shadow: 0 20px 30px rgba(0, 0, 0, 0.6);
-webkit-box-shadow: 0 20px 30px rgba(0, 0, 0, 0.6);
box-shadow: 0 20px 30px rgba(0, 0, 0, 0.6);
border: 1px solid rgba(255, 255, 255, 0.3);
padding: 20px;
text-align: center;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.4);
}
.box:active {
cursor: move;
}
h1, h2, a, p {
color: white;
font-weight: 100;
}
.tinted h1, .tinted h2, .tinted a, .tinted p {
color: black;
text-shadow: 0 1px 1px rgba(255, 255, 255, 0.2);
}
h2 {
font-size: 14px;
}
p {
margin: 20px;
}
</style>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment