Canvas blur function - no third party plug-ins - javascript

I have been searching on the internet for a simple way to blur a canvas image. I thought it would be easy to find information about how to program the gaussian blur function but every time I found something, it always included a lot of unneeded functions like animation and so on. All I want is to take an image -> draw it in canvas -> blur image-> output image to data -> apply the data to a div element -> then delete the canvas element.
I saw this one about motion blur: Better canvas motion blur Which didn't require that much code. How do I do something similar but in gaussian blur instead of motion blur?

In the example you posted, the HTML5 globalAlpha property of the target image is changed to change its opacity, and then the image is painted 10 times on a different vertical point to create the illusion of a motion blur.
For a normal Gaussian blur, you can use the regular CSS3 filter / feGaussianBlur attributes. Check here for an example:
http://css-plus.com/2012/03/gaussian-blur/
In particular, the section named "SVG blur filter applied to a SVG image element"
There are more techniques to do this, including Javascript plugins like the following:
http://blurjs.com/
http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html
However, the CSS3 filter / feGaussianBlur attributes should be the simplest to use, for your needs.

Try this:
blur = function (canvasId) {
var c = document.getElementById(canvasId);
var ctx = c.getContext("2d");
ctx.globalAlpha = 0.3;
var offset = 3;
for (var i=1; i<=8; i+=1) {
ctx.drawImage(c, offset, 0, c.width - offset, c.height, 0, 0, c.width-offset, c.height);
ctx.drawImage(c, 0, offset, c.width, c.height - offset, 0, 0,c.width, c.height-offset);
}
};
blur("myCanvas");

Related

Efficiently limit the area to render graphics to on an HTML5 canvas using JavaScript

I'm looking for a way to render graphics onto an HTML5 canvas using JavaScript, but I want to only render said graphics if they're inside a pre-defined mask.
I'm creating a GUI framework that can be used to easily and quickly create GUIs on an HTML5 canvas. I think that something that would be really nice to have is a way to render graphics inside an element, and make the element auto-crop the graphics so that they always stay inside of it. For example, I can make a rectangular element and animate a circular pulse inside of it, and as the circle extends past the outside of the element, those parts of he circle should just not render to keep it looking smooth and sharp. This is similar to what CSS does with overflow: hidden;
Now, I know that one option is to use a mask-like feature. For example, P5.js has mask(). However, this is very very slow. Masking a single element a single time using P5.js significantly reduces framerate, and I want to be doing this potentially hundreds of times per frame without frame drops. I know that CSS does this incredibly efficiently (from my own experience working with it), but I can't seem to think of any way to make it efficient on a canvas element.
I could do it pretty simply if it was just a rectangle, but I want to do this for any shape. For example, a circle, a star, a rectangle with rounded edges, or really any polygon at all.
How can this be done? I thought of potentially rendering to an off screen canvas (which is shrunken to the size of the element in question), then render the element onto that screen using one color (let's say the background color will be white, and the shape will be black), then rendering the image we want masked onto another off screen canvas that's the same width as our other OSC, then looping through one of their image data arrays and mapping one to the other based on whether said pixel is white or black on the mask canvas.
But........ I can't help but think that that's going to be incredibly slow for the computer to process. I assume that CSS somehow leverages the GPU to do this type of computation incredibly efficiently and that's why they get such an increase in performance. Is it possible for me to do the same or am I just dreaming?
Okay, so I have found two different means of doing this (huge thank you to #Kaiido). One method is to use ctx.clip() while one works with CanvasPattern.
This snippet shows both means in action:
<canvas id = "c" width = "400" height = "400"></canvas>
<canvas id = "c2" width = "400" height = "400"></canvas>
<script>
var canvas = document.getElementById("c");
var ctx = canvas.getContext("2d");
ctx.fillStyle = "yellow";
ctx.fillRect(0,0,400,400);
ctx.beginPath();
ctx.arc(200,200,100,0,6);
ctx.clip();
ctx.beginPath();// This clears our previous arc from the path so that it doesn't render in when we `fill()`
ctx.fillStyle = "rgb(255,0,0)";
for(var i = 0;i < 20;i++){
for(var j = 0;j < 40;j++){
ctx.rect(i * 20 + j % 2 * 10,j * 10,10,10);
}
}
ctx.fill();
</script>
<script>
var canvas2 = document.getElementById("c2");
var ctx2 = canvas2.getContext("2d");
ctx2.fillStyle = "orange";
ctx2.fillRect(0,0,400,400);
var osc = new OffscreenCanvas(400,400);
var oscctx = osc.getContext("2d");
oscctx.fillStyle = "rgb(255,0,0)";
for(var i = 0;i < 20;i++){
for(var j = 0;j < 40;j++){
oscctx.rect(i * 20 + j % 2 * 10,j * 10,10,10);
}
}
oscctx.fill();
var pattern = ctx2.createPattern(osc,"no-repeat");
ctx2.fillStyle = pattern;
ctx2.arc(200,200,100,0,6);
ctx2.fill();
</script>
Which one is more efficient and better to be run hundreds of times per frame?
Another edit:
I spent about an hour messing around with it on a sandbox website, and I made this small project:
https://www.khanacademy.org/computer-programming/-/6446241383661568
There I run each one every millisecond and see how quickly each one updates to see which appears more efficient. clip() is on top while CanvasPattern is on the bottom. They both appear to be incredibly fast to me, and I feel that no matter which I chose I will have almost exactly the same results. However, clip() does still appear to be a bit faster as far as I can tell.
See for yourself and let me know what you think!

Skew the drawing horizontally and vertically in html5 canvas using mouse

In my code I am loading images to canvas element. Then I need to drag, resize, rotate and skew it. I managed to implement both dragging and resizing. How can I implement skew using mouse on this code? I read a helpful article on this subject (http://www.subshell.com/en/subshell/blog/image-manipulation-html5-canvas102.html). I found fabricjs plugin, but it work only one image and without drag. For example: http://fabricjs.com/matrix-transformation/ .
If you will use the transform function:
ctx.transform(1, 0.5, -0.5, 1.2, 30, 60);
This will transform all image objects assigned to the canvas element. I would like only the selected image.
My code:
https://jsfiddle.net/sjLnqk5d/2/
Here's an updated fiddle that allows you to skew any image individually by pressing Shift when clicking one of the corner handles. You may need to tweak it a little bit to have the movements appear a bit more intuitive.
The trick is indeed in using ctx.save() and ctx.restore() around the ctx.transform() call, which makes sure that the transformation (and any other property changes) only applies between the save and restore.
Here are the key changes:
Shape.prototype.draw:
...
var skewX = this.skewX;
var skewY = this.skewY;
imgNew.onload = function(){
ctx.save();
ctx.transform(1, skewX/100, skewY/100, 1, 0, 0);
ctx.drawImage(imgNew, locx, locy, width, height);
ctx.restore();
}

Fastest algorithm to draw a crossword grid in <canvas>?

I'm rendering a grid of cells, very much like the grid you find in a crossword puzzle, but using four different colors to fill each cell (not only black or white).
The grid size is about 160x120, and I need to render it as fast as possible, as it will be used to display a Cellular automaton animation.
I have tried two different approaches to render the grid:
Render each cell using something like:
var w = x + step;
var h = y + step;
canvasContext.fillStyle=cell.color;
canvasContext.fillRect(x+1,y+1,w-1,h-1);
canvasContext.strokeRect(x,y,w,h);
Render the all of cells without the border, and then render the grid lines using:
var XSteps = Math.floor(width/step);
canvasContext.fillStyle = gridColor;
for (var i = 0, len=XSteps; i<len; i++) {
canvasContext.fillRect(i*step, 0, 1, height);
}
//Similar thing for Y coord
Both algorithms perform poorly: it is slower to draw the grid than the cells in both cases. Am I missing something? How can I optimize those algorithms? Is there another way I should try?
Note: the grid moves, as the user can displace it or zoom the view.
The general question will be: what is the fastest algorithm to draw a grid of cells on a element?
The fastest way to do something is to not do it at all.
Draw your unchanging grid once on one canvas, and draw (and clear and redraw) your cellular automata on another canvas layered above (or below) that. Let the browser (in all it's native compiled optimized glory) handle dirtying and redrawing and compositing for you.
Or (better) if you are not going to change your grid size, just create a tiny image and let CSS fill it as the background.
Demo of CSS Background image to Canvas: http://jsfiddle.net/LdmFw/3/
Based on this excellent demo, here's a background image grid created entirely through CSS; with this you could change the size as desired (in whole-pixels increments).
Demo of CSS3 Grid to Canvas: http://jsfiddle.net/LdmFw/5/
If you must draw a grid, the fastest will be to just draw lines:
function drawGrid(ctx,size){
var w = ctx.canvas.width,
h = ctx.canvas.height;
ctx.beginPath();
for (var x=0;x<=w;x+=size){
ctx.moveTo(x-0.5,0); // 0.5 offset so that 1px lines are crisp
ctx.lineTo(x-0.5,h);
}
for (var y=0;y<=h;y+=size){
ctx.moveTo(0,y-0.5);
ctx.lineTo(w,y-0.5);
}
ctx.stroke(); // Only do this once, not inside the loops
}
Demo of grid drawing: http://jsfiddle.net/QScAk/4/
For m rows and n columns this requires m+n line draws in a single pass. Contrast this with drawing m×n individual rects and you can see that the performance difference can be quite significant.
For example, a 512×512 grid of 8×8 cells would take 4,096 fillRect() calls in the naive case, but only 128 lines need to be stroked in a single stroke() call using the code above.
It's really hard to help without seeing all the code to know where the performance is going, but just off the bat:
Instead of drawing a background grid using stroke, can you draw it using one call to drawImage? That will be much faster. If its truly static then you can just set a css background-image on the canvas to an image of the grid you want.
You're using fillRect and strokeRect a lot and these can probably be replaced with several calls to rect() (the path command) and only a single call to fill at the very end. So all the filled cells are rendered at once with a single filling (or stroking or both) command.
Set the fillStyle/strokeStyle as little as possible (not inside loops if you can avoid it)
You are using fill to draw the lines; it would be faster, I think, to define a path and stroke it:
canvasContext.beginPath();
var XSteps = Math.floor(width / step);
canvasContext.fillStyle = gridColor;
var x = 0;
for (var i = 0, len = XSteps; i < len; i++) {
canvasContext.moveTo(x, 0);
canvasContext.lineTo(x, height);
x += step;
}
// similar for y
canvasContext.stroke();

Pixel perfect 2D mouse picking with Canvas

I'm writing a 2D game in html5 using Canvas which requires mouse click and hover events to be detected. There are 3 problems with this: detections must be pixel-perfect, objects are not rectangular (houses, weird-shaped UI buttons...), and it is required to be fast and responsive. (Obviously brute force is not an option)
So what I want to ask is how do I find out which object the mouse is on, and what are the possible optimizations.
P.S: I did some investigation and found a guy who used QuadTree here.
I have a (dated) tutorial that explains the concept of a ghost canvas which is decent for pixel-perfect hit detection. The tutorial is here. Ignore the warning about a newer tutorial, the newer one does not use the ghost canvas concept.
The idea is to draw the image in question to an in-memory canvas and then use getImageData to get the single pixel of the mouse click. Then you see if that single pixel is fully transparent or not.
If its not fully transparent, well, you've got your target.
If it is fully transparent, draw the next object to the in-memory canvas and repeat.
You only have to clear the in-memory canvas at the end.
getImageData is slow but it is your only option if you want pixel-perfect hit detection and aren't pre-computing anything.
Alternatively you could precompute a path or else an array of pixels with an offset. This would be a lot of work but might be faster. For instance if you have a 40x20 image with some transparency you'd compute an array[40][20] that would have true or false corresponding to transparent or not. Then you'd test that against the mouse position, with some offset, if the image is drawn at (25, 55) you'd want to subtract that from the mouse position and then test if the new position is true when you look at array[posx][posy].
That's my answer to your question. My Suggestion? Forget pixel-perfect detection if this is a game.
Seriously.
Instead make paths (not in canvas, in plain javascript code) that represent the objects but are not pixel perfect, for instance a house might be a square with a triangle on the top that is a very close approximation of the image but is used in its stead when it comes to hit testing. It is comparatively extremely fast to compute if a point is inside a path than it is to do pixel-perfect detection. Look up point in polygon winding number rule detection. That's your best bet, honestly.
The common solution in traditional game development is to build a click mask. You can re-render everything onto a separate off-screen canvas in a solid color (the rendering should be very quick). When you want to figure out what was clicked on, you simply sample the color at the x/y co-ordinate on the off-screen canvas. You end up building a color-->obj hash, akin to:
var map = {
'#000000' : obj1
, '#000001' : obj2
, ...
};
You can also optimize the rendering to the secondary canvas to only happen when the user clicks on something. And using various techniques, you can further optimize it to only draw the part of the canvas that the user has clicked on (for example, you can split you canvas into an NxN grid, e.g. a grid of 20x20 pixel squares, and flag all of the objects in that square -- you'd then only need to re-draw a small number of objects)
HTML5 Canvas is just a drawing plane, where you can set different transforms before calling each drawing API function. Objects cannot be created and there is no display list. So you have to build these features yourself or you can use different libraries available for this.
http://www.kineticjs.com/
http://easeljs.com/
A few months before I got interested in this and even wrote a library for this purpose. You can see it here : http://exsprite.com. Ended up facing a lot of performance issues, but because of lack of time I couldn't optimize it. It was really interesting, so waiting for some time to make it perfect.
I believe the comments should suffice. This is how I determine user intention in my 2d isometric scroller, currently located at http://untitled.servegame.com
var lastUp = 0;
function mouseUp(){
mousedown = false; //one of my program globals.
var timeNow = new Date().getTime();
if(mouseX == xmouse && mouseY == ymouse && timeNow > lastUp + 100){//if it was a centralized click. (mouseX = click down point, xmouse = mouse's most recent x) and is at least 1/10th of a second after the previous click.
lastUp = new Date().getTime();
var elem = document.elementFromPoint(mouseX, mouseY); //get the element under the mouse.
var url = extractUrl($(elem).css('background-image')); // function I found here: http://webdevel.blogspot.com/2009/07/jquery-quick-tip-extract-css-background.html
imgW = $("#hiddenCanvas").width(); //EVERY art file is 88px wide. thus my canvas element is set to 88px wide.
imgH = $(elem).css('height').split('p')[0]; //But they vary in height. (currently up to 200);
hiddenCanvas.clearRect(0, 0, imgW, imgH); //so only clear what is necessary.
var img = new Image();
img.src = url;
img.onload = function(){
//draw this elements image to the canvas at 0,0
hiddenCanvas.drawImage(img,0,0);
///This computes where the mouse is clicking the element.
var left = $(elem).css('left').split('p')[0]; //get this element's css absolute left.
var top = $(elem).css('top').split('p')[0];
offX = left - offsetLeft; //left minus the game rendering element's absolute left. gives us the element's position relative of document 0,0
offY = top - offsetTop;
offX = mouseX - offX; //apply the difference of the click point's x and y
offY = mouseY - offY;
var imgPixel = hiddenCanvas.getImageData(offX, offY, 1, 1); //Grab that pixel. Start at it's relative X and it's relative Y and only grab one pixel.
var opacity = imgPixel.data[3]; //get the opacity value of this pixel.
if(opacity == 0){//if that pixel is fully transparent
$(elem).hide();
var temp = document.elementFromPoint(mouseX, mouseY); //set the element right under this one
$(elem).show();
elem = temp;
}
//draw a circle on our hiddenCanvas so when it's not hidden we can see it working!
hiddenCanvas.beginPath();
hiddenCanvas.arc(offX, offY, 10, 0, Math.PI*2, true);
hiddenCanvas.closePath();
hiddenCanvas.fill();
$(elem).css("top", "+=1"); //apply something to the final element.
}
}
}
In conjunction with this:
<canvas id="hiddenCanvas" width="88" height="200"></canvas>
Set the CSS positioning absolute and x = -(width) to hide;

html canvas shape blur filter

There must be a way to do this. I have drawn a shape with the html5 canvas and I would like to blur it. As far as I know there is no native method so I assume a js library is needed. The problem is most libraries only blur images like this one for example. Is this possible?
myContext.filter = 'blur(10px)';
The CanvasRenderingContext2D.filter property of the Canvas 2D API provides filter effects like blurring or gray-scaling. It is similar to the CSS filter property and accepts the same functions. https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/filter
it's still experimental but is supported by chrome & firefox atm.
You can use CSS to blur the canvas. If it's just the shape you want to blur then the shape will need to be on its own separate layer (canvas), which you could create on the fly.
Example:
canvas.style.webkitFilter = "blur(3px)";
You can un-blur the canvas again with:
canvas.style.webkitFilter = "blur(0px)";
This is probably the fastest (and simplest) way to blur a canvas – especially for mobile devices.
For a fast blur that is almost Gaussian I'd recommend StackBlur:
http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html
Alternatively you could use this Superfast Box Blur with 2 iterations:
http://www.quasimondo.com/BoxBlurForCanvas/FastBlurDemo.html
The pixastic library example you've linked to should actually work with a canvas element as the first argument rather than an image.
By default the pixastic library will try to replace the node you pass in with the canvas element that it creates. To prevent it from doing so you can include an option to specify to leave the DOM node and include a callback to handle the returned data yourself. Something like this:
Pixastic.process(canvas, "blur", { leaveDOM: true }, function(img) {
canvas.getContext('2d').drawImage(img, 0, 0);
});
Alternatively, if you don't want to depend on a library, you can implement a blur yourself using getImageData(), manipulating the returned pixel data and using putImageData() to draw the blurred image back to the canvas.
One other thing to note is that individual pixel manipulation is slow and may not work well for large images. If that's a problem, you might try scaling the image down and scaling back up for a quickly done blur like effect. Something like this:
ctx.drawImage(canvas, 0, 0, canvas.width / 2, canvas.height / 2);
ctx.drawImage(canvas, 0, 0, canvas.width / 2, canvas.height / 2, 0, 0, canvas.width, canvas.height);
https://github.com/nodeca/glur - it implements gaussian blur via IIR filter. See demos.

Categories