NOTA : Esto tiene que ver con cómo se representan los elementos de lienzo existentes cuando se amplía , no con cómo se representan las líneas o gráficos en una superficie de lienzo . En otras palabras, esto tiene todo que ver con la interpolación de elementos escalados , y nada que ver con antialiasing de gráficos dibujados en un lienzo. No me preocupa cómo el navegador dibuja líneas; Me importa cómo el navegador representa el elemento del lienzo en sí mismo cuando se amplía.
¿Existe una propiedad de lienzo o una configuración del navegador que pueda cambiar mediante programación para deshabilitar la interpolación al escalar <canvas>
elementos? Una solución de navegador cruzado es ideal pero no esencial; Los navegadores basados en webkit son mi objetivo principal. El rendimiento es muy importante.
Esta pregunta es muy similar pero no ilustra suficientemente el problema. Por lo que vale, he tratado image-rendering: -webkit-optimize-contrast
en vano.
La aplicación será un juego de estilo "retro" de 8 bits escrito en HTML5 + JS para dejar en claro lo que necesito.
Para ilustrar, aquí hay un ejemplo. ( versión en vivo )
Supongamos que tengo un lienzo de 21x21 ...
<canvas id='b' width='21' height='21'></canvas>
... que tiene CSS que hace que el elemento sea 5 veces más grande (105x105):
canvas { border: 5px solid #ddd; }
canvas#b { width: 105px; height: 105px; } /* 5 * 21 = 105 */
Dibujo una simple 'X' en el lienzo así:
$('canvas').each(function () {
var ctx = this.getContext("2d");
ctx.moveTo(0,0);
ctx.lineTo(21,21);
ctx.moveTo(0,21);
ctx.lineTo(21,0);
ctx.stroke();
});
La imagen de la izquierda es lo que representa Chromium (14.0). La imagen de la derecha es lo que quiero (dibujado a mano con fines ilustrativos).
fuente
Respuestas:
Última actualización: 2014-09-12
La respuesta es quizás algún día . Por ahora, tendrás que recurrir a hackear para obtener lo que quieres.
image-rendering
El borrador de trabajo de CSS3 describe una nueva propiedad,
image-rendering
que debería hacer lo que quiero:La especificación describe tres valores aceptados:
auto
,crisp-edges
, ypixelated
.¿Estándar? Cross-browser?
Dado que esto es simplemente un borrador de trabajo , no hay garantía de que se convierta en estándar. El soporte del navegador es actualmente irregular, en el mejor de los casos.
La red de desarrolladores de Mozilla tiene una página bastante completa dedicada al estado actual de la técnica que recomiendo leer.
Los desarrolladores de Webkit inicialmente eligieron implementar esto tentativamente como
-webkit-optimize-contrast
, pero Chromium / Chrome no parecen estar usando una versión de Webkit que implemente esto.Actualización: 2014-09-12
¡Chrome 38 ahora es compatible
image-rendering: pixelated
!Firefox tiene un informe de error abierto para
image-rendering: pixelated
implementarse, pero-moz-crisp-edges
funciona por ahora.¿Solución?
La solución más multiplataforma, solo CSS hasta ahora es así:
Lamentablemente, esto todavía no funcionará en todas las plataformas HTML5 principales (Chrome, en particular).
Por supuesto, uno podría escalar manualmente las imágenes usando la interpolación del vecino más cercano en superficies de lienzo de alta resolución en javascript, o incluso preescalar imágenes del lado del servidor, pero en mi caso esto será increíblemente costoso, por lo que no es una opción viable.
ImpactJS utiliza una técnica de preescalado de textura para sortear todo este FUD. El desarrollador de Impact, Dominic Szablewski, escribió un artículo muy profundo sobre esto (incluso terminó citando esta pregunta en su investigación).
Vea la respuesta de Simon para una solución basada en lienzo que se basa en la
imageSmoothingEnabled
propiedad (no disponible en navegadores más antiguos, pero más simple que el preescalado y con un soporte bastante amplio).Demo en vivo
Si desea probar las propiedades CSS discutidas en el artículo de MDN sobre
canvas
elementos, he creado este violín que debería mostrar algo así, borroso o no, dependiendo de su navegador:fuente
Nueva respuesta 31/07/2012
¡Esto finalmente está en las especificaciones del lienzo!
La especificación ha agregado recientemente una propiedad llamada
imageSmoothingEnabled
, que por defectotrue
determina y determina si las imágenes dibujadas en coordenadas no enteras o dibujadas a escala utilizarán un algoritmo más uniforme. Si se establece en elfalse
vecino más cercano, se usa, produciendo una imagen menos uniforme y, en su lugar, creando píxeles más grandes.El suavizado de imágenes se ha agregado recientemente a la especificación del lienzo y no es compatible con todos los navegadores, pero algunos navegadores han implementado versiones prefijadas por el proveedor de esta propiedad. En el contexto, existe
mozImageSmoothingEnabled
en Firefox ywebkitImageSmoothingEnabled
en Chrome y Safari, y establecerlos en falso detendrá el suavizado. Desafortunadamente, al momento de escribir este artículo, IE9 y Opera no han implementado esta propiedad, con el prefijo del proveedor o de otra manera.Vista previa: JSFiddle
Resultado:
fuente
Editar 31/07/2012 - ¡Esta funcionalidad ahora está en la especificación del lienzo! Ver respuesta por separado aquí:
https://stackoverflow.com/a/11751817/154112
La respuesta anterior está abajo para la posteridad.
Dependiendo de su efecto deseado, tiene esto como una opción:
http://jsfiddle.net/wa95p/
Lo que crea esto:
Probablemente no sea lo que quieres. Pero si simplemente estaba buscando tener cero desenfoque, ese sería el boleto, así que lo ofreceré por si acaso.
Una opción más difícil es utilizar la manipulación de píxeles y escribir un algoritmo usted mismo para el trabajo. Cada píxel de la primera imagen se convierte en un bloque de píxeles de 5x5 en la nueva imagen. No sería demasiado difícil hacer con imagedata.
Pero Canvas y CSS por sí solos no lo ayudarán aquí para escalar uno al otro con el efecto exacto que desea.
fuente
image-rendering: -webkit-optimize-contrast
debería hacer el truco pero no parece hacer nada. Puedo considerar rodar una función para escalar el contenido de un lienzo utilizando la interpolación del vecino más cercano.En google chrome, los patrones de imágenes de lienzo no se interpolan.
Aquí hay un ejemplo de trabajo editado de la respuesta namuol http://jsfiddle.net/pGs4f/
fuente
La solución alternativa de Saviski explicada aquí es prometedora, porque funciona en:
Pero no funciona de la siguiente manera, pero se puede lograr el mismo efecto usando la representación de imágenes CSS:
Los problemáticos son estos, porque ctx.XXXImageSmoothingEnabled no funciona y el procesamiento de imágenes no funciona:
fuente