Im looking for a way to kill banding on gradients in KineticJs. Looks horrible on low contrast black and white gradients. Thanks for any suggestion.
Asked
Active
Viewed 250 times
1 Answers
2
You can diffuse gradient banding by adding Perlin Noise to the image
BTW, this is also one way you would do anti-banding in Photoshop.
After your canvas with gradient is complete, add a layer of Perlin Noise using a low alpha so it doesn’t overwelm the original image.
// generate noise
var noise=perlinNoise();
// reduce the alpha
context.globalAlpha=.35;
// draw the noise layer over the original canvas
context.drawImage(noise,0,0,canvas.width,canvas.height);
This is what random Perlin noise layer looks like:
And this is the original image with the noise layer applied:
A few notes:
- You can tweak both the context.globalAlpha and the alpha in RandomNoise(alpha) to your taste.
- You can create and reuse 1 noise layer or create a new noise layer each time.
- Adding noise will "soften" the original gradient.
- Alternatively, you could apply a slight Kinetic blur filter.
- If you need targeted noise, you can apply the noise using a clipping region (clipFunc).
Here’s code and a Fiddle: http://jsfiddle.net/m1erickson/p4Vaf/
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Noise</title>
<style>
#canvas{border:1px solid red;}
body(background-color:blue;}
</style>
</head>
<body>
<canvas id="canvas" width=300 height=300></canvas><br>
<canvas id="noisecanvas" width=300 height=300></canvas>
<script>
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext('2d');
var noiseCanvas=document.getElementById("noisecanvas");
var img=new Image();
img.onload=function(){
canvas.width=img.width;
canvas.height=img.height;
noiseCanvas.width=img.width;
noiseCanvas.height=img.height;
ctx.drawImage(this,0,0,canvas.width,canvas.height);
var noise=perlinNoise();
ctx.globalAlpha=.35;
ctx.drawImage(noise,0,0,canvas.width,canvas.height);
}
img.src="gradient.png";
function randomNoise(alpha) {
var x = 0;
var y = 0;
var width = canvas.width;
var height = canvas.height;
var g = noiseCanvas.getContext("2d");
var imageData = g.getImageData(x, y, width, height);
var random = Math.random;
var pixels = imageData.data;
var n = pixels.length;
var i = 0;
while (i < n) {
pixels[i++] = pixels[i++] = pixels[i++] = (random() * 256) | 0;
pixels[i++] = alpha;
}
g.putImageData(imageData, x, y);
return noiseCanvas;
}
function perlinNoise() {
var noise = randomNoise(45);
var g = noiseCanvas.getContext("2d");
g.save();
/* Scale random iterations onto the canvas to generate Perlin noise. */
for (var size = 4; size <= noise.width; size *= 2) {
var x = (Math.random() * (noise.width - size)) | 0,
y = (Math.random() * (noise.height - size)) | 0;
g.globalAlpha = 4 / size;
g.drawImage(noise, x, y, size, size, 0, 0, noiseCanvas.width, noiseCanvas.height);
}
g.restore();
return noiseCanvas;
}
</script>
</body>
</html>

markE
- 102,905
- 11
- 164
- 176
-
Great answer! but the noise seems to be too ruff for my goal. I'll give it a try anyway. I like the Idea of bluring it a little bit. You seems like a pro maybe you can help me with my rotation problem I need it really badly. Please take a look if you got the time: [link](http://stackoverflow.com/questions/17338153/kineticjs-rotate-to-mouseposition) or kineticjs rotate to mouseposition – koyotee Jun 30 '13 at 21:40