31

我在画布上使用 clip() 函数。

结果: 在各种浏览器中使用画布剪辑

如您所见,镀铬版本的边缘有可怕的锯齿/锯齿。我该如何解决?

重现代码:

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>
4

5 回答 5

26

如果您正在执行复杂的分层绘图,则可以使用 globalCompositeOperation 在第二个临时画布中模拟剪辑。然后,您可以使用 drawImage 将临时画布复制回原始画布。我不能保证这种方法的性能,但这是我知道得到你想要的东西的唯一方法。

//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, ...);

我们在草稿画布中执行此操作的原因是destination-in 是一个非常具有破坏性的操作。如果你已经在主画布上画了一些东西(也许你在背景中放了一个漂亮的渐变),然后想画一个剪裁的图像,剪裁圆也会剪掉你已经画的所有东西。当然,如果您的特定情况更简单(也许您想要绘制的只是一张剪裁的图像),那么您可以放弃草稿画布。

您可以在我的演示页面上使用不同的剪辑模式。底行(带有渐变)对您来说不太有用,但顶行(带有圆形和正方形)更相关。

编辑

哎呀,我不小心分叉了你的 JSFiddle来演示这项技术。

于 2012-12-13T06:25:41.737 回答
12

我对此的解决方法是在绘制图像后在相同的半径处绘制一个细(2px)的白色笔触。它很好地掩盖了别名,并且在浏览器中看起来很好。

于 2012-09-12T20:43:59.057 回答
5

我在 Chrome 和 clip() 上遇到了同样的问题。

在我的情况下,我通过设置画布 globalCompositeOperation 实现了更好的浏览器兼容性。

context.globalCompositeOperation = 'source-atop';

所以画出你的形状,在这种情况下是一个圆圈。然后切换到“source-atop”并绘制你的小猫图像。

请注意,这是基本绘图的快速修复,并假定为空白画布。以前的画布绘图会影响您的剪辑。

于 2012-07-31T03:29:43.640 回答
2

from the answers on Can I turn off antialiasing on an HTML <canvas> element? it appears that it is browser specific. It is even an active bug report on the google code chromium project. Sorry, but it looks like you're out of luck for now.

于 2012-03-02T16:06:03.413 回答
-1

使用 svg 剪辑。像魅力一样工作,但使用起来不太方便。

于 2012-03-31T11:44:22.603 回答