Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
361 views
in Technique[技术] by (71.8m points)

html - How to anti-alias clip() edges in html5 canvas under Chrome Windows?

I'm using the clip() function on a canvas.

Results: using canvas clip in various browsers

As you can see the chrome version has horrible jaggies / aliasing along the edges. How do I fix this?

Code to reproduce:

http://jsfiddle.net/ZRA76/ :

<canvas id="test" width="300" height="300"></canvas>?

<script type="text/javascript">
    cv = document.getElementById("test");
    ctx = cv.getContext("2d");

    var im = new Image();
    im.onload = function () {
        ctx.beginPath();
        ctx.arc(110, 110, 100, 0, 2*Math.PI, true);
        ctx.clip();
        ctx.drawImage(im, 0, 0);
    }
    im.src = "http://placekitten.com/300/300";
</script>
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

If you're doing complex, layered drawing, you can use globalCompositeOperation to emulate clipping in a second, scratch canvas. You can then use drawImage to copy the scratch canvas back into the original canvas. I can't guarantee the performance of this approach, but it's the only way I know to get what you want.

//set-up - probably only needs to be done once
var scratchCanvas = document.createElement('canvas');
scratchCanvas.width = 100;
scratchCanvas.height = 100;
var scratchCtx = scratchCanvas.getContext('2d');


//drawing code
scratchCtx.clearRect(0, 0, scratchCanvas.width, scratchCanvas.height);

scratchCtx.globalCompositeOperation = 'source-over'; //default

//Do whatever drawing you want. In your case, draw your image.
scratchCtx.drawImage(imageToCrop, ...);


//As long as we can represent our clipping region as a single path, 
//we can perform our clipping by using a non-default composite operation.
//You can think of destination-in as "write alpha". It will not touch
//the color channel of the canvas, but will replace the alpha channel.
//(Actually, it will multiply the already drawn alpha with the alpha
//currently being drawn - meaning that things look good where two anti-
//aliased pixels overlap.)
//
//If you can't represent the clipping region as a single path, you can
//always draw your clip shape into yet another scratch canvas.

scratchCtx.fillStyle = '#fff'; //color doesn't matter, but we want full opacity
scratchCtx.globalCompositeOperation = 'destination-in';
scratchCtx.beginPath();
scratchCtx.arc(50, 50, 50, 0, 2 * Math.PI, true);
scratchCtx.closePath();
scratchCtx.fill();


//Now that we have a nice, cropped image, we can draw it in our
//actual canvas. We can even draw it over top existing pixels, and
//everything will look great!

ctx.drawImage(scratchCanvas, ...);

The reason that we do this in a scratch canvas is that destination-in is a pretty destructive operation. If you had already drawn some things into the main canvas (perhaps you put down a nice gradient in the background), and then wanted to draw a clipped image, the clipping circle would also clip out everything you had already drawn. Of course, if your particular situation is simpler (maybe ALL you want to draw is a clipped image), then you can forego the scratch canvas.

You can play around with the different clipping modes on my demo page. The bottom row (with the gradients) is not too useful to you, but the top row (with the circle and square) is much more relevant.

edit

Whoops, I accidentally forked your JSFiddle to demonstrate the technique.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...