2012-03-02 12 views
29

Estoy usando la función clip() en un lienzo.Cómo alise los bordes del clip() en el lienzo html5 en Windows Chrome?

Resultados: using canvas clip in various browsers

como se puede ver la versión de cromo tiene el efecto de escalón horribles/aliasing a lo largo de los bordes. ¿Cómo puedo solucionar esto?

Código para reproducir:

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> 
+0

Me encontré con este problema también. Lo que hice fue dibujar un círculo en el mismo lugar que la imagen, detrás de él, con 1 o 2 px de radio más grande. Mantenga el color similar y listo, clip de imagen "anti aliased". – Automatico

Respuesta

2

partir de las respuestas de Can I turn off antialiasing on an HTML <canvas> element? parece que es específico del navegador. Incluso es un bug report activo en el proyecto Chrome Code de Google. Lo siento, pero parece que no tienes suerte por ahora.

+1

Ahora, la corrección de errores está en estado de desarrollo en [panel de control de Chrome] (https://www.chromestatus.com/features/4871530282483712). Como está escrito en [Problemas] (https://code.google.com/p/chromium/issues/detail?id=422984), otros navegadores (IE, Firefox, Safari) 'clip()' tienen antialias. – sapics

-1

Usar svg clip. Funciona como un amuleto, pero no es tan conveniente de usar.

5

Me encontré con el mismo problema con Chrome y clip().

En mi circunstancia logré una mejor compatibilidad del navegador configurando el lienzo globalCompositeOperation.

context.globalCompositeOperation = 'source-atop'; 

Así que dibuje su forma, un círculo en este caso. Luego cambia a 'fuente-encima' y dibuja tu imagen gatita.

Tenga en cuenta que esta es una solución rápida para el dibujo básico y supone un lienzo en blanco. El lienzo anterior afectará su clip.

+0

Esta solución funciona muy bien, gracias. Un arco para el clip y un arco para el trazo. Sencillo. Creo que la solución de lienzo scratch es demasiado complicada y lenta para este problema, a menos que tengas algún problema con que NO quieras el trazo. – mattdlockyer

+0

Pude aplicar esto, más la técnica de "lienzo posterior", para reducir un borde irregular desagradable cuando estaba ejecutando un video a través del lienzo: http://codepen.io/paceaux/pen/egLOeR Gracias por compartiendo. – paceaux

12

Mi solución para esto es dibujar un trazo blanco delgado (2px) en el mismo radio después de dibujar la imagen. Cubre muy bien el alias y se ve bien en todos los navegadores.

+0

¡Qué gran idea! ¡¡Gracias!! – Keith

+0

He estado luchando con esto hoy por más de una hora, una solución tan simple y sorprendente :) – trueicecold

+0

¡SÍ, ESTO, INTELIGENTE, <3! –

22

Si está haciendo un dibujo complejo en capas, puede usar globalCompositeOperation para emular el recorte en un segundo lienzo de rayado. A continuación, puede usar drawImage para copiar el lienzo scratch en el lienzo original. No puedo garantizar el rendimiento de este enfoque, pero es la única forma que conozco de obtener lo que desea.

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

La razón por la que hacemos esto en un lienzo de cero es ese destino-in es una operación bastante destructiva. Si ya había dibujado algunas cosas en el lienzo principal (quizás dejó un degradado agradable en el fondo) y luego quería dibujar una imagen recortada, el círculo de recortes también recortaría todo lo que ya había dibujado. Por supuesto, si su situación particular es más simple (tal vez TODO lo que desea dibujar es una imagen recortada), puede renunciar al lienzo de rayado.

Puede jugar con los diferentes modos de recorte en my demo page. La fila inferior (con los degradados) no es demasiado útil para usted, pero la fila superior (con el círculo y el cuadrado) es mucho más relevante.

edición

chillidos, accidentalmente forked your JSFiddle para demostrar la técnica.

+0

¡Señor, salvó mi día! – enyce12

+0

gracias hombre! ¡¡¡Funciona!!! –