Il y a deux meilleurs prétendants:
Créez des données d'image 1 × 1, définissez la couleur et putImageData
à l'emplacement:
var id = myContext.createImageData(1,1); // only do this once per page
var d = id.data; // only do this once per page
d[0] = r;
d[1] = g;
d[2] = b;
d[3] = a;
myContext.putImageData( id, x, y );
Utilisez fillRect()
pour dessiner un pixel (il ne devrait y avoir aucun problème d'alias):
ctx.fillStyle = "rgba("+r+","+g+","+b+","+(a/255)+")";
ctx.fillRect( x, y, 1, 1 );
Vous pouvez tester la vitesse de ceux-ci ici: http://jsperf.com/setting-canvas-pixel/9 ou ici https://www.measurethat.net/Benchmarks/Show/1664/1
Je recommande de tester les navigateurs qui vous intéressent pour une vitesse maximale. Depuis juillet 2017, il fillRect()
est 5 à 6 fois plus rapide sur Firefox v54 et Chrome v59 (Win7x64).
D'autres alternatives plus stupides sont:
utilisation getImageData()/putImageData()
sur toute la toile; c'est environ 100 fois plus lent que les autres options.
création d'une image personnalisée à l'aide d'une URL de données et utilisation drawImage()
pour l'afficher:
var img = new Image;
img.src = "data:image/png;base64," + myPNGEncoder(r,g,b,a);
// Writing the PNGEncoder is left as an exercise for the reader
créer une autre image ou un autre canevas rempli de tous les pixels que vous souhaitez et utiliser drawImage()
pour atténuer uniquement le pixel souhaité. Ce serait probablement très rapide, mais a la limitation dont vous avez besoin pour pré-calculer les pixels dont vous avez besoin.
Notez que mes tests n'essaient pas d'enregistrer et de restaurer le contexte du canevas fillStyle
; cela ralentirait les fillRect()
performances. Notez également que je ne commence pas avec une ardoise propre ou que je ne teste pas exactement le même ensemble de pixels pour chaque test.
fillRect()
semi-récemment est devenu presque 10 fois plus rapide que le putimagedata 1x1 sur Chromev24. Donc ... si la vitesse est essentielle et que vous connaissez votre public cible, ne vous fiez pas à une réponse dépassée (même la mienne). Au lieu de cela: testez!Une méthode qui n'a pas été mentionnée utilise getImageData, puis putImageData.
Cette méthode est idéale lorsque vous souhaitez dessiner beaucoup en une seule fois, rapidement.
http://next.plnkr.co/edit/mfNyalsAR2MWkccr
la source
Je n'avais pas envisagé
fillRect()
, mais les réponses m'ont incité à le comparerputImage()
.Mettre 100 000 pixels de couleur aléatoire dans des emplacements aléatoires, avec Chrome 9.0.597.84 sur un (ancien) MacBook Pro, prend moins de
putImage()
100 ms avec , mais près de 900 msfillRect()
. (Code de référence sur http://pastebin.com/4ijVKJcC ).Si à la place je choisis une seule couleur en dehors des boucles et que je trace simplement cette couleur à des emplacements aléatoires, cela
putImage()
prend 59 ms contre 102 msfillRect()
.Il semble que la surcharge de génération et d'analyse d'une spécification de couleur CSS dans la
rgb(...)
syntaxe soit responsable de la plupart de la différence.En
ImageData
revanche, placer les valeurs RVB brutes directement dans un bloc ne nécessite aucune gestion de chaîne ni analyse.la source
la source
putImageData()
après cette fonction ou le contexte sera mis à jour par référence?Étant donné que différents navigateurs semblent préférer des méthodes différentes, il serait peut-être judicieux de faire un test plus petit avec les trois méthodes dans le cadre du processus de chargement pour savoir laquelle est la meilleure à utiliser, puis de l'utiliser dans toute l'application?
la source
Cela semble étrange, mais néanmoins HTML5 prend en charge le dessin de lignes, de cercles, de rectangles et de nombreuses autres formes de base, il n'a rien de convenable pour dessiner le point de base. La seule façon de le faire est de simuler le point avec tout ce que vous avez.
Donc, fondamentalement, il y a 3 solutions possibles:
Chacun d'eux a ses inconvénients
Ligne
Gardez à l'esprit que nous nous dirigeons vers le sud-est, et si c'est le bord, il peut y avoir un problème. Mais vous pouvez également dessiner dans n'importe quelle autre direction.
Rectangle
ou d'une manière plus rapide en utilisant fillRect car le moteur de rendu ne remplira qu'un pixel.
Cercle
L'un des problèmes avec les cercles est qu'il est plus difficile pour un moteur de les rendre
la même idée qu'avec le rectangle que vous pouvez réaliser avec un remplissage.
Problèmes avec toutes ces solutions:
Si vous vous demandez, "Quelle est la meilleure façon de dessiner un point? ", J'irais avec un rectangle rempli. Vous pouvez voir mon jsperf ici avec des tests de comparaison .
la source
Et un rectangle? Cela doit être plus efficace que de créer un
ImageData
objet.la source
putImageData
il est 10 fois plus rapide quefillRect
dans Chrome. (Voir ma réponse pour plus.)Dessinez un rectangle comme dit sdleihssirhc!
^ - devrait dessiner un rectangle 1x1 à x: 10, y: 10
la source
Hmm, vous pouvez également simplement créer une ligne de 1 pixel de large avec une longueur de 1 pixel et faire bouger sa direction le long d'un seul axe.
la source
Pour compléter la réponse très approfondie de Phrogz, il y a une différence critique entre
fillRect()
etputImageData()
.La première utilise le contexte pour dessiner sur par l' ajout d' un rectangle (pas un pixel), en utilisant la fillStyle valeur alpha et le contexte globalAlpha et la matrice de transformation , capuchons de ligne , etc ..
Le second remplace un ensemble de jeu de pixels (peut - être un, mais pourquoi ?)
Le résultat est différent comme vous pouvez le voir sur jsperf .
Personne ne veut définir un pixel à la fois (c'est-à-dire le dessiner à l'écran). C'est pourquoi il n'y a pas d'API spécifique pour le faire (et à juste titre).
En termes de performances, si l'objectif est de générer une image (par exemple un logiciel de lancer de rayons), vous souhaitez toujours utiliser un tableau obtenu par
getImageData()
lequel est un Uint8Array optimisé. Ensuite, vous appelezputImageData()
UNE FOIS ou quelques fois par seconde en utilisantsetTimeout/seTInterval
.la source
fillRect
était douloureuse car l'accélération h / w de Chrome ne peut pas faire face aux appels individuels au GPU dont elle aurait besoin. J'ai fini par devoir utiliser des données de pixels à 1: 1, puis utiliser la mise à l'échelle CSS pour obtenir la sortie souhaitée. C'est moche :(get/putImageData
, mais 194 893 pourfillRect
.1x1 image data
est de 125 102 Ops / sec. AlorsfillRect
gagne de loin dans Firefox. Les choses ont donc beaucoup changé entre 2012 et aujourd'hui. Comme toujours, ne vous fiez jamais aux anciens résultats de référence.Code de démonstration HTML rapide: basé sur ce que je sais de la bibliothèque graphique SFML C ++:
Enregistrez-le en tant que fichier HTML avec encodage UTF-8 et exécutez-le. N'hésitez pas à refactoriser, j'aime juste utiliser des variables japonaises car elles sont concises et ne prennent pas beaucoup de place
Vous voudrez rarement définir UN pixel arbitraire et l'afficher à l'écran. Alors utilisez le
méthode pour dessiner de nombreux pixels arbitraires dans un back-buffer. (appels pas chers)
Ensuite, lorsque vous êtes prêt à montrer, appelez le
méthode pour afficher les modifications. (appel coûteux)
Code de fichier .HTML complet ci-dessous:
la source
Si vous êtes préoccupé par la vitesse, vous pouvez également envisager WebGL.
la source
HANDY et proposition de la fonction put pixel (pp) (ES6) (read-pixel ici ):
Afficher l'extrait de code
Cette fonction utilise
putImageData
et a une partie d'initialisation (première longue ligne). Au début,s='.myCanvas'
utilisez plutôt votre sélecteur CSS pour votre canevas.Je vous veux pour normaliser les paramètres à la valeur de 0 à 1 , vous devez changer la valeur par défaut
a=255
poura=1
et avec la ligne:id.data.set([r,g,b,a]),ctx.putImageData(id, x, y)
àid.data.set([r*255,g*255,b*255,a*255]),ctx.putImageData(id, x*c.width, y*c.height)
Le code pratique ci-dessus est bon pour tester des algorithmes graphiques ad hoc ou faire une preuve de concept, mais il n'est pas bon à utiliser en production où le code doit être lisible et clair.
la source
putImageData
est probablement plus rapide quefillRect
nativement. Je pense que cela parce que le cinquième paramètre peut être attribué de différentes manières (la couleur du rectangle), en utilisant une chaîne qui doit être interprétée.Supposons que vous fassiez cela:
Alors, la ligne
est le plus lourd de tous. Le cinquième argument de l'
fillRect
appel est une chaîne un peu plus longue.la source
context.fillStyle = ...
place. developer.mozilla.org/en-US/docs/Web/API/…