drawImage() on canvas saturates colors and messes up alpha

帆布与元素

EDIT : D'OH! The body of this question is mostly irrelevant because I discovered my stupid error, which was that my canvas was getting redrawn on a timer and I was not clearing the canvas between draws. This had the effect of darkening any semi-transparent areas to full opacity.

Now doing:

mainContext.clearRect ( 0 , 0 , 320 , 480 );

before each frame draw.

A small mystery that still remains is the question of why drawing an object over itself lots of times would also darken/saturate areas of the image that were fully opaque to start with.


EDIT : I've added a picture. The bottom area shows the image loaded into an element (which looks just how the image looks in my paint program). (The img can be downloaded here. I did resize it for the purpose of making the screen shot below fit better, but I get the same result with the original downloaded image unchanged.) The top framed box is the canvas, with a drawImage() from that same element. I'm not sure if "reduced color depth" is the right description now. It seems like it's changing the colors -- you can see that in the canvas the colors are more saturated. Also also it's not handling the alpha properly. What I described before as "banding" I now realize was mostly happening in the areas with a higher level of transparency in the original image.


EDIT : progress has been made.

I see that if I draw a fully opaque background image into the canvas, when I then draw images with transparency on top of that, it gets the alpha right.

I tried drawing a rectangle filled with a color as the background, but that still had the transparency problem when images were drawn over it. Seems to be necessary to draw that opaque image underneath.

Does this sound familiar?

I also still don't understand why image colors are more saturated inside the canvas. Maybe that's a gamma correction thing akin to the color differences between Mac and PC?


I have a very simple page with a single canvas element. I load a 32-bit .png file. I load the file two ways, once by creating a new Image() object and settings its src, and once by creating an element with the same source.

That element on the page shows my image with the correct colors, nicely alpha-rounded corners, and so on.

But when I draw the image onto the canvas, it seems to lose color depth. In particular it seems to be reduced from a 32 bpp image to an 8 bpp image (using some default palette). I see strong banding on gradient areas, and the alpha channel is lost, as seen in the blocky pixelation of the corners that were smooth in the original image.

I get the same results in both Chrome and Firefox (both recent versions).

I get the image onto the canvas with

context.drawImage( theImage, 0, 0 );

For theImage in the code above, I've tried both the Image() object and the <img> element (the one that's already showing the good version of the image elsewhere on the page). In both cases, I get the same result -- the image appears to have been reduced to 8 bpp.

My canvas is set up as:

<canvas class="MainCanvas" width="320" height="480"></canvas>

As I say, my images are loaded one using the Image() class:

    var image = new Image();
    image.src = "images/myimage.png";

and one as an element:

    <img class="OtherImage" src="images/myimage.png" />

And that's pretty much the whole thing.

The fact that the image shows nicely in the <img> element seems to indicate that the problem is not with the image or the loading of the image, but with the drawImage() call, or the canvas itself.

I'm wondering if somehow my canvas or its context could have gotten set to this reduced color depth mode, but I couldn't find anything about such a setting.

(I did discover that to keep the canvas from doing confusing auto-scaling on the image it's necessary to set the canvas size using the "width" and "height" attributes as above, and not in the css. I'm hoping that the fix to this color depth problem is a similar gotcha that I just haven't been able to find...)


Here's more data for you...

I was not able to reproduce you color problems in Win7 + ( IE10 | FF21 | Chrome27 )

在这里输入图像描述

A Note on html canvas:

The natural background of canvas is transparent. Therefore when you draw a semi-transparent image on canvas there must be an attempt at color-mixing in the semi-transparent areas against whatever is underneath (the body background?).

When you drew the opaque image + semi-transparent image, you would be saturating the semi-transparent pixels and also adding the pixel-color from the background of the opaque image. I would think this would cause color distortion rather than fixing it. Curious?

Filling the canvas with an opaque (white?) rectangle prior to drawing your semi-transparent image would help control the background that your image is color-mixed against.

Anyway, hope this helps in discovering what's ailing your images! :)

Here is code and a Fiddle: http://jsfiddle.net/m1erickson/KpAyq/

<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>

<style>
    body{ background-color: white; padding:10px; }
    canvas{border:1px solid red;}
    img{border:1px solid blue;}
</style>

<script>
$(function(){

    var canvas=document.getElementById("canvas");
    var ctx=canvas.getContext("2d");

    var image=document.createElement("img");
    image.onload=function(){
    ctx.drawImage(image,0,0);
    }
    image.src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/molecule1.png";

}); // end $(function(){});
</script>

</head>

<body>
    <p>Left==canvas,  Right==img</p>
    <canvas id="canvas" width=256 height=275></canvas>
    <img src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/molecule1.png" width=256 height=275>
</body>
</html>
链接地址: http://www.djcxy.com/p/50322.html

上一篇: Canvas toDataURI()在chrome安全问题上

下一篇: 画布上的drawImage()使颜色饱和并使阿尔法变得混乱