Asynchronous loading of images - is it possible?

#1

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. )

#2

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.

#3

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
#4

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

#5

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 )

#6

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.