HTML5 Canvas no tiene ningún método para configurar explícitamente un solo píxel.
Es posible establecer un píxel con una línea muy corta, pero luego la intercalación y los límites de línea pueden interferir.
Otra forma podría ser crear un ImageData
objeto pequeño y usar:
context.putImageData(data, x, y)
para ponerlo en su lugar.
¿Alguien puede describir una manera eficiente y confiable de hacer esto?
fillRect()
recientemente se volvió casi 10 veces más rápido que los 1x1 putimagedata en Chromev24. Entonces ... si la velocidad es crítica y conoce a su público objetivo, no tome la palabra de una respuesta desactualizada (incluso la mía). En cambio: prueba!Un método que no se ha mencionado es usar getImageData y luego putImageData.
Este método es bueno para cuando quieres dibujar mucho de una vez, rápido.
http://next.plnkr.co/edit/mfNyalsAR2MWkccr
fuente
No lo había considerado
fillRect()
, pero las respuestas me impulsaron a compararloputImage()
.Colocar 100,000 píxeles de colores aleatorios en ubicaciones aleatorias, con Chrome 9.0.597.84 en una (antigua) MacBook Pro, requiere menos de 100 ms
putImage()
, pero casi 900 ms de usofillRect()
. (Código de referencia en http://pastebin.com/4ijVKJcC ).Si, en cambio, elijo un solo color fuera de los bucles y simplemente trazo ese color en ubicaciones aleatorias,
putImage()
toma 59 ms frente a 102 msfillRect()
.Parece que la sobrecarga de generar y analizar una especificación de color CSS en
rgb(...)
sintaxis es responsable de la mayor parte de la diferencia.Por otro lado, poner valores RGB sin procesar directamente en un
ImageData
bloque no requiere manejo ni análisis de cadenas.fuente
fuente
putImageData()
después de esa función o el contexto se actualizará por referencia?Dado que los diferentes navegadores parecen preferir métodos diferentes, ¿quizás tenga sentido hacer una prueba más pequeña con los tres métodos como parte del proceso de carga para averiguar cuál es el mejor para usar y luego usarlo en toda la aplicación?
fuente
Parece extraño, pero no obstante HTML5 admite líneas de dibujo, círculos, rectángulos y muchas otras formas básicas, no tiene nada adecuado para dibujar el punto básico. La única forma de hacerlo es simulando el punto con lo que tenga.
Básicamente, hay 3 soluciones posibles:
Cada uno de ellos tiene sus inconvenientes.
Línea
Tenga en cuenta que estamos dibujando en dirección sureste, y si este es el borde, puede haber un problema. Pero también puedes dibujar en cualquier otra dirección.
Rectángulo
o de una manera más rápida usando fillRect porque el motor de renderizado solo llenará un píxel.
Circulo
Uno de los problemas con los círculos es que es más difícil que un motor los procese
la misma idea que con el rectángulo que puedes lograr con el relleno.
Problemas con todas estas soluciones:
Si se pregunta "¿Cuál es la mejor manera de dibujar un punto? ", Iría con un rectángulo lleno. Puedes ver mi jsperf aquí con pruebas de comparación .
fuente
¿Qué tal un rectángulo? Eso tiene que ser más eficiente que crear un
ImageData
objeto.fuente
putImageData
, es 10 veces más rápido quefillRect
en Chrome. (Vea mi respuesta para más información)¡Dibuja un rectángulo como dijo sdleihssirhc!
^ - debería dibujar un rectángulo 1x1 en x: 10, y: 10
fuente
Hmm, también podrías hacer una línea de 1 píxel de ancho con una longitud de 1 píxel y hacer que su dirección se mueva a lo largo de un solo eje.
fuente
Para completar la respuesta muy completa de Phrogz, hay una diferencia crítica entre
fillRect()
yputImageData()
.El primer contexto usos para dibujar sobre por la adición de un rectángulo (no un pixel), utilizando el fillStyle valor alfa y el contexto globalAlpha y la matriz de transformación , tapas de línea etc ..
La segunda sustituye a un entero conjunto de píxeles (tal vez uno, pero ¿por qué ?)
El resultado es diferente como se puede ver en jsperf .
Nadie quiere establecer un píxel a la vez (es decir, dibujarlo en la pantalla). Es por eso que no hay una API específica para hacerlo (y con razón).
En cuanto al rendimiento, si el objetivo es generar una imagen (por ejemplo, un software de trazado de rayos), siempre desea utilizar una matriz obtenida por medio de
getImageData()
un Uint8Array optimizado. Luego llamasputImageData()
UNA VEZ o unas pocas veces por segundo usandosetTimeout/seTInterval
.fuente
fillRect
fue doloroso porque la aceleración h / w de Chrome no puede hacer frente a las llamadas individuales a la GPU que requeriría. Terminé teniendo que usar datos de píxeles a 1: 1 y luego usar la escala CSS para obtener la salida deseada. Es feo :(get/putImageData
, pero 194,893 parafillRect
.1x1 image data
es 125,102 Ops / seg. EntoncesfillRect
gana con diferencia en Firefox. Así que las cosas cambiaron mucho entre 2012 y hoy. Como siempre, nunca confíe en los viejos resultados de referencia.Código de demostración HTML rápido: según lo que sé sobre la biblioteca de gráficos SFML C ++:
Guarde esto como un archivo HTML con codificación UTF-8 y ejecútelo. Siéntase libre de refactorizar, simplemente me gusta usar variables japonesas porque son concisas y no ocupan mucho espacio
Rara vez querrá establecer UN píxel arbitrario y mostrarlo en la pantalla. Entonces usa el
Método para dibujar numerosos píxeles arbitrarios en un búfer de respaldo. (llamadas baratas)
Luego, cuando esté listo para mostrar, llame al
Método para mostrar los cambios. (llamada costosa)
Código de archivo .HTML completo a continuación:
fuente
Si le preocupa la velocidad, también podría considerar WebGL.
fuente
HANDY y propuesta de la función put pixel (pp) (ES6) (lea el píxel aquí ):
Mostrar fragmento de código
Esta función utiliza
putImageData
y tiene una parte de inicialización (primera línea larga). Al principio, ens='.myCanvas'
su lugar, use su selector CSS en su lienzo.I ¿Quieres para normalizar los parámetros de valor entre 0-1 que debe cambiar el valor por defecto
a=255
dea=1
y de acuerdo con:id.data.set([r,g,b,a]),ctx.putImageData(id, x, y)
aid.data.set([r*255,g*255,b*255,a*255]),ctx.putImageData(id, x*c.width, y*c.height)
El práctico código anterior es bueno para los algoritmos gráficos de prueba ad-hoc o para hacer una prueba de concepto, pero no es bueno usarlo en producción donde el código debe ser legible y claro.
fuente
putImageData
es probablemente más rápido quefillRect
forma nativa. Creo que esto se debe a que el quinto parámetro puede tener diferentes formas de ser asignado (el color del rectángulo), utilizando una cadena que debe ser interpretada.Supongamos que estás haciendo eso:
Entonces, la línea
Es el más pesado entre todos. El quinto argumento en la
fillRect
llamada es una cadena un poco más larga.fuente
context.fillStyle = ...
en su lugar. developer.mozilla.org/en-US/docs/Web/API/…