Je travaille avec une toile relativement grande où sont dessinées diverses choses (complexes). Je veux ensuite sauvegarder l'état du Canvas, afin de pouvoir le réinitialiser rapidement à l'état actuel à un moment ultérieur. Pour cela, j'utilise getImageData et je stocke les données dans une variable. Je dessine ensuite d'autres éléments sur le canevas et je remettrai plus tard le canevas dans l'état où il était lorsque j'ai sauvegardé son état, en utilisant putImageData.
Cependant, il s'avère que putImageData est très lent. En fait, il est plus lent que le simple fait de redessiner l'intégralité du Canvas à partir de zéro, ce qui implique plusieurs drawImage couvrant la majeure partie de la surface, et plus de 40 000 opérations lineTo suivies de traits et de remplissages.
Redessiner le canevas d'environ 2000 x 5000 pixels à partir de zéro prend environ 170 ms, alors que l'utilisation de putImageData prend 240 ms. Pourquoi putImageData est-il si lent par rapport au redessin du canevas, bien que le redessin du canevas implique le remplissage de presque tout le canevas avec drawImage et ensuite le remplissage d'environ 50% du canevas avec des polygones utilisant lineTo, stroke et fill. En gros, chaque pixel est touché au moins une fois lors du redessin.
Parce que drawImage semble être beaucoup plus rapide que putImageData (après tout, la partie drawImage du redessin du canevas prend moins de 30 ms). J'ai décidé d'essayer de sauvegarder l'état du canevas sans utiliser getImageData, mais en utilisant plutôt canvas.toDataURL et en créant ensuite une image à partir de l'URL des données que je collerais dans drawImage pour la dessiner sur le canevas. Il s'avère que cette procédure est beaucoup plus rapide et ne prend que 35 ms environ.
Alors pourquoi putImageData est-il tellement plus lent que les autres solutions (utilisation de getDataURL ou simple redécoupage) ? Comment pourrais-je accélérer davantage les choses ? Existe-t-il et si oui, quelle est en général la meilleure façon de stocker l'état d'un canevas ?
(Tous les chiffres sont mesurés à l'aide de Firebug depuis Firefox).
1 votes
Il serait intéressant que vous puissiez mettre en ligne quelque part une démonstration de votre problème. Dans noVNC ( github.com/kanaka/noVNC ) J'utilise putImageData pour de nombreux tableaux de données d'images de petite et moyenne taille et je ne vois pas de problème de performance avec putImageData. Peut-être que vous rencontrez un cas spécifique de performance pessimale qui devrait faire l'objet d'un bug.
0 votes
Vous pouvez jeter un coup d'œil ici danielbaulig.de/A3O Il ne fonctionnera pas à 100% si la console firebug est désactivée, assurez-vous donc de l'activer. La version vérifiée est celle qui utilise putImageData. Vous pouvez la déclencher en cliquant sur n'importe quelle "tuile". Il va rafraîchir le canevas de la mémoire tampon en utilisant putImageData et ensuite "mettre en évidence" la tuile sélectionnée. Dans a3o_oo.js il y a quelques lignes commentées, qui peuvent être utilisées pour basculer entre l'utilisation de putImageData (courant), l'utilisation de getDataURL (les deux lignes mentionnant this.boardBuffer) et le simple redessin (la ligne drawBoard) du canevas de la mémoire tampon.
0 votes
Excellente question et excellentes solutions. Mais avez-vous trouvé la vraie raison pour laquelle putImageData est si lent par rapport à drawImage ?
1 votes
@cherouvim Non, pas vraiment. Mon hypothèse est que la raison principale est que la structure ImageData n'est plus gérée dans les structures graphiques accélérées par le matériel et donc l'appel à getImageData/putImageData devra être traduit vers/depuis ces objets, ce qui est lent, implique la copie de beaucoup de données, l'instanciation d'objets, etc, alors que l'utilisation de drawImage dessine simplement une texture/un contexte de dessin déjà existant à l'écran - ce qui avec le matériel moderne est incroyablement rapide.