Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

rgba fillStyle with alpha does not get fully opaque if applied multiple times

I stubled upon a weird problem. The following code results in making the image fade away because it's overdrawn by a semi-opaque rect over and over again.

But at least at the 10th iteration of draw(); the image should be completely overdrawn, because the rect should be fully opaque by then, right? But it actually never disappears completely.

This effect is worse on Chrome than it is on Firefox. But beware: bad screens may hide this faulty behaviour =)

I also made a demo on jsFiddle.

$(function () {
var canvas = $("#mycanvas"),
    ctx = canvas[0].getContext("2d"),
    imgUrl = "http://it-runde.de/dateien/2009/august/14/25.png";


var image = new Image();  
image.src = imgUrl ;  
$(image).load(function() {
    ctx.drawImage(image, 0, 0, canvas.width(), canvas.height());
    draw();
});

function draw() {        
    ctx.fillStyle = "rgba(255, 255, 255, 0.1)";
    ctx.fillRect(0, 0, canvas.width(), canvas.height());
    setTimeout(draw, 100);
    
}    
});

The effect one may want to achieve is that, say an object is moving all over the canvas, and the already drawn positions get overdrawn only slightly so after-glow of after-fade effect. But this result is just fugly.

So is there any solution to this?

like image 681
owzim Avatar asked Oct 25 '11 20:10

owzim


People also ask

How do I change transparency in canvas?

On the toolbar above the editor, click on Transparency. Click and drag the slider to adjust.

What is fillStyle in canvas?

fillStyle property of the Canvas 2D API specifies the color, gradient, or pattern to use inside shapes. The default style is #000 (black).

How do I fill a rectangle with canvas color?

The fillRect() method is used to fill the rectangle using the given color. The default color of the fillRect() method is black. Parameters: This method accepts four parameters as mentioned above and described below: x: It stores the x-coordinate of top-left corner of rectangle.


1 Answers

I know this is old but I don't think the previously accepted answer is correct. I think this is happening as a result of pixel values being truncated from float to byte. In Windows 7 running Chrome version 39.0.2171.95m, after running your fiddle for a while, the image is still visible but only lightly, and doesn't appear to be changing any more. If I take a screenshot I see the following pixel values on the image:

(246, 246, 246)

When you draw a rectangle over it with rgba of:

(255, 255, 255, 0.1)

and apply alpha blending using the default compositing mode of source-over, before converting to a byte you get:

(255 * 0.1 + 246 * 0.9) = 246.9

So you can see that, assuming the browser simply truncates the floating point value to a byte, it will write out a value of 246, and every time you repeat the drawing operation you'll always end up with the same value.

There is a big discussion on the issue at this blog post here.

As a workaround you could continually clear the canvas and redraw the image with a decreasing globalAlpha value. For example:

    // Clear the canvas
    ctx.globalAlpha = 1.0;
    ctx.fillStyle = "rgb(255, 255, 255)";
    ctx.fillRect(0,0,canvas.width(),canvas.height());

    // Decrement the alpha and draw the image
    alpha -= 0.1;
    if (alpha < 0) alpha = 0;
    ctx.globalAlpha = alpha;
    console.log(alpha);
    ctx.drawImage(image, 0, 0, 256, 256);
    setTimeout(draw, 100);

Fiddle is here.

like image 161
Sam Avatar answered Sep 28 '22 06:09

Sam