Last active
May 16, 2018 11:48
-
-
Save flurin/327337e1beb3db983de8 to your computer and use it in GitHub Desktop.
Doing background blur with canvas
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!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