tag new library examples ejemplos javascript html5 canvas

javascript - new - Deshabilite la interpolación al escalar un<canvas>



canvas tag (5)

NOTA : Esto tiene que ver con cómo se representan los elementos de lienzo existentes cuando se amplían , no con cómo se representan las líneas o los gráficos en una superficie de lienzo . En otras palabras, esto tiene mucho que ver con la interpolación de elementos escalados y nada que ver con el antialiasing de los gráficos que se dibujan en un lienzo. No me preocupa cómo el navegador dibuja líneas; Me importa cómo el navegador renderiza el elemento canvas en sí mismo cuando se amplía.

¿Existe una propiedad de lienzo o una configuración de navegador que pueda cambiar programáticamente para deshabilitar la interpolación al escalar elementos <canvas> ? 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, probé image-rendering: -webkit-optimize-contrast en vano.

La aplicación será un juego "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 */

Dibujé 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 muestra Chromium (14.0). La imagen de la derecha es lo que quiero (dibujado a mano con fines ilustrativos).


Última actualización: 2014-09-12

¿Existe una propiedad de lienzo o una configuración de navegador que pueda cambiar programáticamente para deshabilitar la interpolación al escalar elementos?

La respuesta es tal vez algún día . Por ahora, tendrás que recurrir a hack-arounds para obtener lo que quieres.

image-rendering

El borrador de trabajo de CSS3 describe una nueva propiedad, image-rendering que debe hacer lo que quiero:

La propiedad de representación de imágenes proporciona una pista al agente de usuario sobre qué aspectos de una imagen son más importantes para preservar cuando se escala la imagen, para ayudar al agente usuario en la elección de un algoritmo de escalamiento apropiado.

La especificación describe tres valores aceptados: auto , crisp-edges y pixelated .

pixelado:

Al escalar la imagen, se debe usar el "vecino más cercano" o algoritmo similar, de modo que la imagen parezca estar compuesta simplemente por píxeles muy grandes. Al reducir la escala, esto es lo mismo que automático.

¿Estándar? Cross-browser?

Como esto no es más que un borrador en funcionamiento , 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 Mozilla Developer Network tiene una página muy completa dedicada al estado del arte actual que recomiendo leer.

Los desarrolladores de Webkit inicialmente optaron por implementarlo 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 ¡ image-rendering: pixelated !

Firefox tiene un informe de errores abierto para obtener image-rendering: pixelated implementado por image-rendering: pixelated , pero -moz-crisp-edges funciona por ahora.

¿Solución?

La solución más multiplataforma y solo CSS hasta ahora es la siguiente:

canvas { image-rendering: optimizeSpeed; /* Older versions of FF */ image-rendering: -moz-crisp-edges; /* FF 6.0+ */ image-rendering: -webkit-optimize-contrast; /* Safari */ image-rendering: -o-crisp-edges; /* OS X & Windows Opera (12.02+) */ image-rendering: pixelated; /* Awesome future-browsers */ -ms-interpolation-mode: nearest-neighbor; /* IE */ }

Lamentablemente, esto no funcionará en todas las principales plataformas HTML5 hasta el momento (Chrome, en particular).

Por supuesto, uno puede escalar manualmente las imágenes utilizando la interpolación del vecino más cercano en superficies de lienzo de alta resolución en javascript, o incluso imágenes de escala previa en el servidor, pero en mi caso esto será prohibitivamente costoso por lo que no es una opción viable.

ImpactJS usa una técnica de textura previa a la incrustación para evitar 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).

Consulte la respuesta de Simon para una solución basada en lienzo que se basa en la propiedad imageSmoothingEnabled (no disponible en los navegadores más antiguos, pero más simple que la escala previa y ampliamente compatible).

Demo en vivo

Si desea probar las propiedades de CSS que se tratan en el artículo de MDN sobre los elementos canvas , he creado este violín que debería mostrar algo así, borroso o no, según su navegador:


En google chrome, los patrones de imagen del lienzo no se interpolan.

Aquí hay un ejemplo de trabajo editado a partir de la respuesta namuol http://jsfiddle.net/pGs4f/

ctx.scale(4, 4); ctx.fillStyle = ctx.createPattern(image, ''repeat''); ctx.fillRect(0, 0, 64, 64);


jsfiddle.net/saviski/pGs4f/12 explicada here es prometedora, porque funciona en:

  • Chrome 22.0.1229.79 Mac OS X 10.6.8
  • Chrome 22.0.1229.79 m Windows 7
  • Chromium 18.0.1025.168 (Desarrollador Build 134367 Linux) Ubuntu 11.10
  • Firefox 3.6.25 Windows 7

Pero no funciona en lo siguiente, pero se puede lograr el mismo efecto usando CSS-rendering:

  • Firefox 15.0.1 Mac OS X 10.6.8 (renderización de imágenes: -moz-crisp-edges funciona en jsfiddle.net/VAXrL/21 )
  • Opera 12.02 Mac OS X 10.6.8 (representación de imágenes: -o-crisp-edges funciona en jsfiddle.net/VAXrL/21 )
  • Opera 12.02 Windows 7 (renderización de imágenes: -o-crisp-edges funciona en jsfiddle.net/VAXrL/21 )

Los problemas son estos, porque ctx.XXXImageSmoothingEnabled no funciona y la representación de imágenes no funciona:

  • Safari 5.1.7 Mac OS X 10.6.8. (representación de imagen: -webkit-optimize-contrast NO funciona)
  • Safari 5.1.7 Windows 7 (representación de imágenes: -webkit-optimize-contrast NO funciona)
  • IE 9 Windows 7 (-ms-interpolation-mode: el vecino más cercano NO funciona)

Editar 31/07/2012 - ¡Esta funcionalidad ahora está en el lienzo! Vea la respuesta por separado aquí:

https://.com/a/11751817/154112

La respuesta anterior está abajo para la posteridad.

Dependiendo de su efecto deseado, tiene esto como una opción:

var can = document.getElementById(''b''); var ctx = can.getContext(''2d''); ctx.scale(5,5); $(''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(); });

http://jsfiddle.net/wa95p/

Lo que crea esto:

Probablemente no es lo que quieres. Pero si estuvieras simplemente buscando no tener ningún borrón, entonces 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 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 de hacer con imagedata.

Pero Canvas y CSS por sí solo no lo ayudarán a escalar uno con el otro con el efecto exacto que desee.


Nueva respuesta 31/07/2012

¡Esto finalmente está en el lienzo!

La especificación ha agregado recientemente una propiedad llamada imageSmoothingEnabled , que por defecto es true y determina si las imágenes dibujadas en coordenadas no enteras o dibujadas a escala usarán un algoritmo más suave. Si se configura como false , se utiliza el vecino más cercano, lo que produce una imagen menos uniforme y, en cambio, solo crea píxeles de mayor tamaño.

El alisado de imágenes se ha agregado recientemente a la especificación canvas y no es compatible con todos los navegadores, pero algunos navegadores han implementado versiones con prefijo de proveedor de esta propiedad. En el contexto, existe mozImageSmoothingEnabled en Firefox y webkitImageSmoothingEnabled en Chrome y Safari, y establecer esto en falso detendrá la aparición de anti-aliasing. Desafortunadamente, en el momento de la escritura, IE9 y Opera no han implementado esta propiedad, el prefijo del proveedor o de lo contrario.

Vista previa: JSFiddle

Resultado: