I want to generate a blurred image from a normal image. I've searched on the internet and found out that people have done it by putting CSS filter property through javascript on Image to make it blur. But it can be removed by inspecting the page and I don't want that.
I want to generate a blurred version of image through javascript. I think I can do it with canvas but I never worked with canvas and any help will be highly appreciated (:
So, it depends. If you're worried about them removing it with developer tools, then the answer is probably "you can't".
The reason for this, is if you want to blur it with JavaScript, you need to send the unblurred image. And, if you send the unblurred image, they can easily scoop it out of the network tab, even if you never add it directly to the DOM. Anything you use as an input for JavaScript can be obtained by a clever enough user.
If you want the user to never be able to see the original, only the blurred, you'll have to blur it server-side.
If, for some weird reason, you're okay with that and still want to blur it in canvas, you'll need to pick and implement a blur algorithm for canvas. There are lots of different blur algorithms to choose from. Probably the most common one would be a Gaussian blur.
The algorithm isn't super insane, but it also isn't exactly super straightforward either, and I'd recommend using a library instead, such as this one: glur. I've not directly used that one, so can't vouch for it, but it has half a million downloads a week on NPM, so probably pretty solid.
Simple filters
You can apply a blur via the canvas using ctx.filter. CanvasRenderingContext2D.filter will accept a (limited set of) filters defined as strings. Eg ctx.filter = "blur(10px)";
See ctx.filter for set of filters you can use directly.
Example
Example uses CanvasRenderingContext2D.filter to blur image over time.
const img = new Image;
img.src = "https://i.stack.imgur.com/C7qq2.png?s=256&g=1";
img.addEventListener("load", () => requestAnimationFrame(uodate));
function drawImageBlur(img, blurAmount) {
const ctx = can.getContext("2d");
ctx.clearRect(0,0,128,128);
ctx.filter = "blur(" + blurAmount+ "px)";
ctx.drawImage(img, 128 - img.naturalWidth * 0.5, 128 - img.naturalHeight * 0.5);
}
var frameCount = 0;
function uodate(time) {
if (frameCount++ % 10 === 0) { // no point burning CPU cycles so only once every 10 frames
drawImageBlur(img, Math.sin(time / 1000) * 5 + 6);
}
requestAnimationFrame(uodate);
}
canvas {border: 1px solid black;}
<canvas id="can" width="256" height="256"></canvas>
There is no way to protect the image from inspection if you apply the image blur on the client (no matter what method you use). If you want to obfuscate (blur) the image it must be done on the server.
Related
Context:
I'm working on a project to render a map into a HTML Canvas, this map is based on a jittered points and voronoi diagrams. Because of this technique I need to use ctx.scale (both values, width and height are set to 8). Once the map is generated in the canvas, I read each pixel looking for a specific color set, which will then became a 3D map.
Problem:
Everything 'works' fine, except that the canvas shapes gets somehow anti-aliased, and that obviously creates a huge problem since some of the colors I read from the pixels won't match my colorset.
So far this is how my canvas setup looks like:
const dpr = window.devicePixelRatio | 1
const ctx = mapCanvas.getContext('2d')
ctx.save()
ctx.scale((mapCanvas.width / CONFIG.RESOLUTION) *dpr, (mapCanvas.Height / CONFIG.RESOLUTION) *dpr)
ctx.lineWidth = 0.5
ctx.globalCompositeOperation = 'source-over'
ctx.imageSmoothingEnabled = false
As for globalCompositeOperation I tried almost all options that made some sense, but the results still the same.
I also added on the CSS side the following:
image-rendering: pixelated;
But also tried crisp-edges.
Long story short, I read more articles / tutorial than I wished, spent 3 hours trying to get around it, but no matter what I do I can't see how am I going to fix it.
Can anybody give a little help?
Thanks in advance.
TF
Long time lurker but never made an account. Just wanted to preface that I'm by no means a dev and just tinkering and experimenting for fun, so I apologise in advance if I seem really dumb.
I'm working on a dynamic overlay for Twitch streaming and was previously using AS3 but I've switched over to HTML5 now. I'm trying to load an image onto the canvas (which will eventually be a profile picture fetched using Twitch API... but one step at a time). I'm using Adobe Animate and I have the following so far applied in Actions on the first frame of the layer:
var canvas = document.getElementById('canvas'),
context = canvas.getContext('2d');
show_image();
function show_image() {
source_image = new Image();
source_image.src = 'https://cdn.sstatic.net/stackexchange/img/logos/so/so-icon.png';
source_image.onload = function () {
context.drawImage(source_image, 100, 100);
}
}
When I hit Ctrl+Enter and see it in Chrome, the image appears for the first frame then disappears. I'm not sure how I'm supposed to get it to stay indefinitely. I need to be able to animate it later, and it'll change depending on the latest follow/donation/sub, etc.
I tried extending the frame itself in the timeline, however, this just changed long how it took to loop and didn't make the image itself stay longer. I'm probably missing something really simple!
Any help would be appreciated. Thanks!
Your code is okay if your approach is using a canvas with HTML and JS, without any libraries involved. However, this is not the case, as you are using Animate, and the way to draw graphics with it is different than using default canvas methods like drawImage().
Animate includes the CreateJS suite, which includes the EaselJS library ,and this allows you to use another tools to draw to your canvas. Two or them are the Stage object, the visual container of your animate project, and the Bitmap object, who represents an image, canvas or video. For effects of this question, only both objects are required.
Note that the code below is only for the first frame:
/* It is not necessary to declare the canvas or stage element,
as both are already declared. At this point the stage is ready to be drawn */
show_image();
function show_image() {
var source_image = new Image();
source_image.src = 'https://cdn.sstatic.net/stackexchange/img/logos/so/so-icon.png';
source_image.onload = function(event) {
/* A new Bitmap object is created using your image element */
var bmp = new createjs.Bitmap(event.currentTarget);
/* The Bitmap is added to the stage */
stage.addChild(bmp);
}
}
I've been experimenting with creating a canvas element in a few different ways and was wondering if anyone knows which of these (or some other) ways is the most efficient.
the most basic seems to be placing a canvas element in the html like this:
<canvas id="myCanvas" width="500", height="500"></canvas>
and then in the javascript:
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
there are times I need to keep all my canvas biznass in a .js file (ex when I want to dynamically change the width/height of the element) and I'll do it like this:
var canvas = document.createElement('canvas');
document.body.appendChild(canvas);
canvas.height = '500';
canvas.width = '500';
var ctx = canvas.getContext('2d');
or when I get lazy, something like this:
document.write("<canvas id='myCanvas' width='500', height='500'></canvas>");
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
Pros? Cons? Edits? Other options?
The first one is the best by far.
The first one wins on efficiency (slightly) because the second and third ones cause the page to re-layout unnecessarily. Also, if there's an error in the JavaScript that halts subsequent execution the page will look awfully weird.
Furthermore, you should always choose the first one for accessibility purposes. If someone has JavaScript disabled you will still want them to see the fallback content. Even if it is just to say "turn on JavaScript!" or "Get a modern browser!"
If you use the second or third method, the user might never know, and they will continue on merely thinking that you suck at page layouts because there's a strange space where fallback content (or a canvas for that matter) ought to be.
Even aside from all that, methods 2 and 3 break the order of things a little bit. When are you adding the canvas? after onload fires? Well by firing onload the page just said that the DOM was done doing it's dance and its all ready! And then you go and change the DOM!
...How rude!
Of course you probably won't be using any libraries that rely on the the implicit promise made in onload that you are sorta breaking by using 2 or 3, but it's an unnecessary break of convention if you can avoid it.
By the way for the start of simple apps or examples I have this fiddle bookmarked:
http://jsfiddle.net/eAVMs/
Which uses the first method. If you use canvas a lot, you should bookmark this fiddle too!
document.write("<canvas id='myCanvas' width='500', height='500'></canvas>");
Is the only method Id caution against. Using document.write is generally considered bad practice for arbitrarily creating elements.
I could just repeat why here, but this answer explains it well enough.
The other two methods are perfectly valid and fine. Its really just a matter of preference. Generally I create a canvas tag, unless I need a temp canvas to do something, in which Ill use the createElement method.
Other than that its really just a matter of preference and overall doesn't affect performance in any way.
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.
I am running firefox 3.5.6.
I want to display an image on a canvas and draw a couple lines on it. It needs to display properly in firefox and internet explorer (using excanvas).
Here is what I am getting:
The top image is what I see in IE8, the bottom is what I see in firefox.
IE seems to be a bit messed up as far as the canvas is the wrong size but firefox is going crazy! What gives with this aspect ratio? Why does the second half of my arc not appear?
Also, some times firefox just flat out doesn't show anything.
Here is my code by the way.
Aspect ratio problem
If you don't set a width on the canvas element, it defaults to 300x150. In your CSS, you set the style to 94x120, so it scales the image to that size. To fix it, you need to either set the width and height in the HTML, or with JavaScript.
In HTML:
<canvas id="c" width="94" height="120">Ugh, this just ain't gonna work</canvas>
In JavaScript (with jQuery):
$('canvas').attr('width', '94').attr('height', '120');
Internet Explorer's incorrect size
Adding the size to the canvas element should fix this problem too. Since IE is using VML instead of a canvas to render the image, the CSS rule for canvas won't apply. excanvas should see the specified size and apply it in IE.
Missing the second half of the arc
The simpleArc function doesn't work in Firefox when the amplitude is negative. The problem is that a negative amplitude results in a negative radius for the arc, which is illegal according to the canvas spec. It should actually throw an INDEX_SIZE_ERR exception, but Firefox just seems to ignore the call.
There are two possible solutions (basically; there are several ways you could accomplish either): when you pass a negative amplitude, either calculate the parameters for the arc taking into account the negative radius (with a different center point and angles, etc.), or change the sign and use transformations to rotate the arc. I implemented the second solution like this:
ctx.simpleArc = function(x,y, length, amplitude) {
var rotate = false;
// Check whether we need to rotate the image
if (amplitude < 0) {
rotate = true;
amplitude = -amplitude;
}
var radius = amplitude/2+ length*length/(8*amplitude);
var outerAngle = Math.asin((radius-amplitude)/radius);
var innerAngle = Math.PI - 2*outerAngle;
// The translate/rotate/translate steps could be combined into one matrix
// transformation, but I think this is clearer and less error-prone.
if (rotate) {
this.save(); // So we can easily undo the transformation
this.translate(x + length, y);
this.rotate(Math.PI);
this.translate(-length, -y);
}
this.arc(x+length/2, y+(radius-amplitude), radius, -(outerAngle+innerAngle), -outerAngle, false);
// Reset the transformation matrix to its original value
if (rotate) {
this.restore();
}
return this;
}
Firefox not showing anything
In your code, you create the image and set the source, but it may not be loaded before the rest of the code get's executed. The image loads asynchronously, and when you draw the image onto the canvas, it doesn't wait for it to finish. You will need to call the code that uses the image from an onload event.
var img = $('<img>');
img[0].onload = function() {
ctx.drawImage(img[0], 0, 0);
ctx.strokeStyle = "blue";
ctx.simpleStroke(function(ctx) { ctx.simpleArc(0, 70, img_w/2, 3)});
ctx.simpleStroke(function(ctx) { ctx.simpleArc(img_w / 2, 70, img_w/2, -3)});
};
// I moved this so it happens after you set the `onload` event, because I
// think IE won't call `onload` if it happens to already be loaded.
img.attr('src', 'shortcylinder.png');
You could also pre-load all the images you will need instead of creating them when you need them. You would still need to prevent the code from running until all the images are loaded.
I've recently noticed that using style to define width & height for canvas elements caused an issue like this. Taking from an earlier example
This works in FF 9.0.1 Mac
<canvas id="c" width="94" height="120">Ugh, this just ain't gonna work</canvas>
vs.
This had similar display issues as your example, in FF 9.0.1 Mac
<canvas id="c" style="width:94;height:120;">Ugh, this just ain't gonna work</canvas>
Maybe that's it?