Récemment (toujours) j’ai été confronté a des transitions nécéssitant de découper et mettre a jour des bitmapdatas et où je me suis presque littéralement arraché les cheveux. J’ai d’ailleurs utilisé la technique “a la va vite” et, ayant un 30mn aujourd’hui, je reviens dessus, teste le pourquoi du comment.
Pour la petite démo, j’ai 4 images embarquées dans un swf, que je stocke dans 4 bitmapDatas différents, bmd1, 2, 3, et 4. J’ai également pris un “bmd0″, reflet de l’image affichée (un genre de référence au bmd courant). J’ai enfin un petit script permettant de faire des captures de ce “current”, et de dessiner la zone dans un nouveau Sprite.
Pour capturer un morceau d’image, un simple drag and drop suffit et pour changer d’image, c’est avec les touches 1, 2, 3, et 4 du clavier alphabétique que ca se passe.
Quand on teste une premiere fois de capturer une image, tout fonctionne bien, c’est impec. Vient le moment de changer d’image et la, stupeur et tremblements, le petit Sprite fraichement capturé, qui n’utilise que beginBitmapFill et ne stocke jamais de référence au bitmapData est pourtant lui aussi updaté.
Pourquoi ?
Je suppose qu’implicitement la méthode beginBitmapFill() garde une référence au bitmapData, et si le bitmapData change, elle s’auto-appelle pour mettre a jour le tout. Concretement je suis plutot décu de cette implémentation pseudo-intelligente. Je m’attendais a un comportement uniforme de la classe Graphics ; jusqu’a preuve du contraire “beginBitmapFill” devrait juste faire ce que son nom semble dire “begin bitmap fill” et pas “beginBitmapFillAndAutoupdateIfReferenceHasChanged”.
Workaround
J’avais testé plusieurs workarounds, et le dernier me semble le plus viable :
1/ D’abord j’avais pensé a garder une référence au bmd dans l’objet. Malheureusement, ca marche pas.
2/ Ensuite j’avais pensé a faire un clone du bmd en utilisant clone() mais c’est pas super optimisé, vu que dans le cas réel je traitais beaucoup de petites captures d’un très grand bitmapData.
3/ Solution du cas réel, j’ai créé des clones a la taille de la capture, et du coup ma matrice de transformation s’est transformée en rectangle au moment du copyPixels. Niveau optimisation, on y est un peu plus, mais franchement, c’pas encore ca.
Ce qui m’effraie le plus, c’est d’être passé a côté du plus simple. Comme pas mal de bugs graphiques, mettre des filtres “nuls” suffit. Oui oui, en effet, un simple “filters = [new BlurFilter(0, 0)]” et pouf le bug est parti.
Pour illustrer ca, retour a la démo, et appuyons sur Entrée pour switcher entre “auto update ON” et “auto update OFF”.
Sur ce, les sources.