Asynchronous loading of images - is it possible?

I’m using openfl target ( using html5 export ) and my main problem there is about image loading which a used in haxeui.

At the moment haxeui load images only synchronize and for that reason the user should wait on the loading screen .

For the other images , which I used, I create ImageManager who return immediately transparent pixel and after load successfully the image , the transparent pixel is replaced with the loaded image .

All images are load on demand ( after the first call and cache after that ).

I’m not sure how haxeui-html5 target works i.e. load all haxeui or load on the first call, but on openfl there a embeded in js ( which bring very big js file, slow loading times and etc. )

Hi, do you have a very simple example of what you are trying to do? With you “ImageManager” (or a simple verison of it).

It would help understanding what needs to change in haxeui to facilitate async image loading.

Ok, so here is example what I call from haxeui

		var rmImg = new Image();
		rmImg.mouseEnabled  = false;
		rmImg.verticalAlign = "center";
		rmImg.resource = "ui/red.png";
		hBox.addComponent(rmImg);

where <assets path="assets/ui" rename="ui" embed="true" /> i.e embed= true

If change embed=“false” it won’t load. The error is :
[lime.utils.Assets] ERROR: IMAGE asset "ui/red.png" exists, but only asynchronously

I’m using for all images openfl method Assets.loadBitmapData("…") , but HaxeUI use only Assets.getBitmapData

About ImageManager, I have:

_images = new Map<String,BitmapData>();  // store unique id  and bitmapdata 
// processing images with waiting to load Bitmap instances. 
// It's array, because it possible two or more bitmaps to wait loading
_loadImages = new Map<String,Array<GBitmap>>();

GBitmap extends Bitmap , but adding two new fields gWidth and gHeight for resize after load image

Here is the main method :

public function getBitmapDataByName(imgName : String, bitmap:GBitmap , ?imgPath:String = null) : BitmapData
		{
		var resultBD : BitmapData = null;
        try
        {
			// Is it a new image i.e. not in a cache ?
            if (_images[imgName]  == null) 
            {	
				resultBD = openfl.Assets.getBitmapData("embed/transparent_pixel .png");
				bitmap.bitmapData = resultBD;
                if (imgPath != null) 
                {
					//It's first time calling. Create array for waiting images
					if ( _loadImages[imgName] == null) {
					 _loadImages[imgName] = new Array<GBitmap>();
					} 
					_loadImages[imgName].push(bitmap);
					if ( _loadImages[imgName].length == 1) 
					{
						openfl.Assets.loadBitmapData(imgPath)
							// .onProgress(function (bytesLoaded, bytesTotal) { /* trace (bytesLoaded + "/" + bytesTotal); */ } )
							.onComplete(
							 function (bitmapData) 
							 {
								 _images[imgName] = bitmapData;
								 resultBD = bitmapData;
								 var i = _loadImages[imgName].length;
								 // set bitmapdata for each of waiting images
								 while (i > 0) {
									 var bmpd = _loadImages[imgName].shift();
									 bmpd.bitmapData = bitmapData;
									 if ( bmpd.gWidth > 0 && bmpd.gHeight > 0 ) {
										bmpd.width = bmpd.gWidth;
										bmpd.height = bmpd.gHeight;
									 }
									 
									 i--;
								 }
							 } ) 
							.onError(function (e) { trace (e); });
					}
                }
            } else {
				//we already have image in the cache
				// get bitmapdata and set width and height
				resultBD = _images[imgName];
				bitmap.bitmapData =  resultBD;
				if ( bitmap.gWidth <= 0 || bitmap.gHeight <= 0 ) {
					bitmap.width =  resultBD.width;
					bitmap.height = resultBD.height;
				} else {
					bitmap.width = bitmap.gWidth;
					bitmap.height = bitmap.gHeight;
				}
			}
        } catch (err : Error) {
			trace("Error: " + err + " -- "+imgName);
        }
        return resultBD;
    }

Maybe is too complicated, more simple version will looks like that:

public function getBitmapDataByName(imgName : String, bitmap:Bitmap , ?imgPath:String = null) : BitmapData
		{
		var resultBD : BitmapData = null;
        try
        {
            if (_images[imgName]  == null) 
            {	
				resultBD = openfl.Assets.getBitmapData("embed/transparent_pixel .png");
				bitmap.bitmapData = resultBD;
                if (imgPath != null) 
                {
					openfl.Assets.loadBitmapData(imgPath)
						.onComplete(
						 function (bitmapData) 
						 {
							_images[imgName] = bitmapData;
							resultBD = bitmapData;
							bitmap.bitmapData = bitmapData;
						 } ) 
						.onError(function (e) { trace (e); });
					
                }
            } else {
				resultBD = _images[imgName];
				bitmap.bitmapData =  resultBD;
				bitmap.width =  resultBD.width;
				bitmap.height = resultBD.height;
			}
        } catch (err : Error) {
			trace("Error: " + err + " -- "+imgName);
        }
        return resultBD;
    }

If you have any questions , I would be happy if can help

1 Like

Ok, great - that helps. So, from haxeui perspective would it only need to also be able to use loadBiimapData as well as getBitmapData?

Yes, that will be great.
I’m just wondering how haxeui-html target works ? Is it similar to openfl ( when target html5 ) i.e.preload all images before show anything on the screen or load images on demand ( first request )

Hey, so basically they all use this:

And if its an asset in (haxe.Resource) then html5 will essentially create an <img /> and use the resource data in the url, so essentially, yeah, its the same / similar. Might be scope for improvement there also.