0 Replies Latest reply on Mar 20, 2010 2:57 PM by DHM 23

    Hiding whether images are embedded or run-time loaded

    DHM 23

      I'd like my coders to write the code without knowing whether the images any object requests are embedded or runtime loaded. This strategy will give us the ability to embed frequently used images and remote retrieve infrequent ones without having the code know which is which (thus allowing seasonal specials...).


      I have a class that mostly works, but some testers get some broken images. How can I debug these broken images and see why they did not render? Do I need to call an event--beyond setting the source and calling addChild(img)--to force the image to render? Is there a better way to populate an image other than set its source if my helper class has it's bitmap &/or class? [The worse thing is it's breaking on embedded pictures using the setPicture method below.]


      I'll include the code below. Here's the strategy. Given the picture name, first see if it's embedded. If not, see if it's already loaded. If not, request it from the server. Since writing this code, I noticed the remark in the documentation that Flex caches all loaded images and won't refetch; so, I can get rid of my caching? [Note, in my code, I'm not using .load() but am pulling over the bitmap from my DB. I'm going to switch to .load(), but left my bitmap stuff here.]


      If "foo.png" is embedded and a reference does not wrap "foo.png" with the embed tag, will the compiler/run-time vm do the right thing and find the embedded image? If so, that could be another strategy I could pursue.


      Another tack would be to catch the error if the Image does not find the source and point it to the server, but does Flex throw a catchable exception in this case (or any case?)


      I provide 2 interfaces:

      • getPicture(name, callback) uses a callback which takes an Obj assignable to Image.source and
      • setPicture(img, name) where the caller passes the Image obj and gets it immediately back with either the real image or a placeholder which gets replaced asynchronously.


      Usage patterns:


      var img:Image = new Image();

      PictureCatalog.getPicture(obj.pictureName, function(obj:Object):void { img.source = object });

      addChild(img); // note, source may not be set but will be eventually

      var img:Image = new Image();

      PictureCatalog.setPicture(img, obj.pictureName);

      addChild(img); // source will be set but may change later if fetching from server


      import mx.collections.ArrayCollection;

      import mx.controls.Image;

      import mx.core.Application;

      import mx.rpc.events.FaultEvent;

      import mx.rpc.events.ResultEvent;

      import mx.rpc.remoting.RemoteObject;


      public class PictureCatalog


           // sparse array indexed by pic name w/ class as value

           private static var embeddedPics:Object = initEmbedded();

           // sparse array w/ Picture instances as values

           private static var loadedPics:Object = new Object();

           private static var pictureRO:RemoteObject;

           // Hashmap of pictureID :-> list of fns to call w/ picture

           private static var callbacks:Object = new Object();



           * Will find a source for the picture and call callback with

           * a ResultEvent having result = Object suitable to bind to image.source


           public static function getPicture(name:String, callback:Function):void {

                if (embeddedPics.hasOwnProperty(name)) {

                     callback(new embeddedPics[name]());


                else if (loadedPics.hasOwnProperty(name)) {



                else {

                                   // create BlazeDS service

                     if (pictureRO == null) {

                          pictureRO = new RemoteObject()

                          pictureRO.destination = "pictureService";

                          pictureRO.addEventListener(FaultEvent.FAULT, Application.application.handleFault);

                          pictureRO.addEventListener(ResultEvent.RESULT, loadPic);


                     if (!callbacks.hasOwnProperty(name)) {

                          // first request

                          callbacks[name] = new ArrayCollection();



                                    // cache to do callbacks when picture bitmap is loaded from server







      * Assign the source to image getting the picture from the server if necessary.


      public static function setPicture(img:Image, name:String):void {

           if (embeddedPics.hasOwnProperty(name)) {

                img.source = new embeddedPics[name]();


           else if (loadedPics.hasOwnProperty(name)) {

                img.source = Picture(loadedPics[name]).getBitMap();


           else {

                img.source = new embeddedPics["placeholder.png"]();

                getPicture(name, setImage(img));




      private static function setImage(img:Image):Function {

           return function(pic:Object):void {

                img.source = pic;




      // Called from BlazeDS bitmap loader (see addEventListener above)


      private static function loadPic(event:ResultEvent):void {

           var serverPicture:Picture = event.result as Picture;

           loadedPics[serverPicture.pictureID] = serverPicture;


                function():void {

                     // finally ready to return

                     for each (var callback:Function in callbacks[serverPicture.pictureID]) {



                     callbacks[serverPicture.pictureID] = null;




      // Embed all pictures here!

      private static function initEmbedded():Object {

           var result:Object = new Object();


           var classVar:Class;

           result["SmallGrid3D.gif"] = classVar;


                return result;



      and from Picture

      public function getBitMap():Bitmap{

           // see http://livedocs.adobe.com/flex/3/html/help.html?content=Working_with_Bitmaps_07.html

           // may want to do as new Bitmap().draw(this.bitmap);

           return new Bitmap(this.bitMap.bitmapData.clone());