Lorsqu’on a une application flex qui communique avec un serveur, il est fréquent qu’on reçoive des images sous forme de tableau de bytes.
Je souhaitais pouvoir utiliser les nouvelles fonctionnalités du BitmapImage(l'option fillmode notamment), malheureusement ce dernier n'accepte pas de ByteArray comme source pour le binding (alors qu'un mx:Image ou la version 4.5 du BitmapImage le supporte parfaitement). C’est pourquoi j’ai décidé de créer un BitmapImage customisé. Ce dernier permet aussi, si on le souhaite, de redimensionner l’image de manière à ce qu’elle soit adaptée à la taille du conteneur.
Je souhaitais pouvoir utiliser les nouvelles fonctionnalités du BitmapImage(l'option fillmode notamment), malheureusement ce dernier n'accepte pas de ByteArray comme source pour le binding (alors qu'un mx:Image ou la version 4.5 du BitmapImage le supporte parfaitement). C’est pourquoi j’ai décidé de créer un BitmapImage customisé. Ce dernier permet aussi, si on le souhaite, de redimensionner l’image de manière à ce qu’elle soit adaptée à la taille du conteneur.
import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.Loader; import flash.display.LoaderInfo; import flash.events.Event; import flash.utils.ByteArray; import spark.primitives.BitmapImage; public class ByteArrayBitmapImage extends BitmapImage { public function ByteArrayBitmapImage() { super(); } // The byteArray to load private var _currentByteArray:ByteArray; // The maximum width for the bitmap private var _maxContainerHeight:Number = -1; // The maximum height for the bitmap private var _maxContainerWidth:Number = -1; [Bindable] public function get maxContainerWidth():Number { return _maxContainerWidth; } public function set maxContainerWidth(value:Number):void { _maxContainerWidth = value; } [Bindable] public function get maxContainerHeight():Number { return _maxContainerHeight; } public function set maxContainerHeight(value:Number):void { _maxContainerHeight = value; } [Bindable] override public function set source(value:Object):void { var byteArray:ByteArray = null; if (value && value is ByteArray && (byteArray = ByteArray(value)).length > 0) { _currentByteArray = byteArray; // we set cursor at the beginning byteArray.position = 0; var img_loader:Loader = new Loader(); img_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, imageLoadComplete, false, 0, true); img_loader.loadBytes(byteArray); } else { // default behavior _currentByteArray = null; super.source = value; } } protected function imageLoadComplete(e:Event):void { e.stopImmediatePropagation(); var contentLoaderInfo:LoaderInfo = LoaderInfo(e.currentTarget) contentLoaderInfo.removeEventListener(Event.COMPLETE, imageLoadComplete); var bm:Bitmap = Bitmap(contentLoaderInfo.content); bm.smoothing = true; resizeImageIfNecessary(bm); super.source = bm; } protected function resizeImageIfNecessary(bmd:Bitmap):void { if ((_maxContainerWidth == -1) || (_maxContainerHeight == -1)) return; // no need to resize var imageRapport:Number; if (bmd.width >= bmd.height) { if (bmd.width > _maxContainerWidth) { imageRapport = Number(bmd.width) / Number(bmd.height); bmd.width = _maxContainerWidth; bmd.height = _maxContainerHeight / imageRapport; } } else { if (bmd.height > _maxContainerHeight) { imageRapport = Number(bmd.height) / Number(bmd.width); bmd.height = _maxContainerHeight; bmd.width = _maxContainerWidth / imageRapport; } } } }
Cependant je n’ai pas mis en place le redimensionnement automatique de l’image lorsque les limites du conteneur sont modifiées. Pour y remédier, il suffit d’appeler la méthode resizeImageIfNecessary(bmd:Bitmap) dans les 2 mutateurs.
Et voilà vous pouvez utiliser votre composant dans vos fichiers mxml :<common:bytearraybitmapimage height="@{model.test.imageHeight}" id="test" maxcontainerheight="{maxImageHeight}" maxcontainerwidth="{maxImageWidth}" source="{model.test.imageContent}" width="@{model.test.imageWidth}" />
4 commentaires:
Cool! Est-ce que je peux le reutiliser en Flex 3 avec quelques modificqtions mineurs?
Le soucis est que cette classe hérite d'un composant spark (BitmapImage) qui est présent qu'à partir de la version 4 du SDK Flex. En Flex 3, le composant mx:Image accepte un ByteArray comme source pour le binding. De plus si tu veux maintenir les proportions de ton image il te suffit d'utiliser la propriété maintainAspectRatio="true".
éhé à garder sous la main !
Par contre, question lisibilité, il y a une utilité à garder les getter et setter ? cf Article adobe : Why we don't have to use getters and setters
En fait je voulais rajouter du comportement lorsqu'on modifie la taille max du conteneur, mais je ne l'ai pas mis en place ni même testé :). Je le modifierai quand ce sera fait ;)
Enregistrer un commentaire