Media Art, User Experience Design, and Interface Development

Loading assets dynamically (part 3: images)

Posted on 2009-10-10

In many projects, you will be faced with the necessity to load images dynamically. Oftentimes I have been requested to use a loaded image as a background for a website that took the full viewport area. What you need in such a case is to know that you have to resize your image proportionnally, and even though that seems obvious and simple, people often ask me how to deal with that. I provide the sources for this tutorial at the end of the post. Read more after the jump.

The first part is obviously loading your image. Create our loader and add listeners to it.

private var _loader:Loader;

public function loadImage():void
{
	var urlRequest:URLRequest = new URLRequest();
	urlRequest.url = "image.jpg";

	_loader = new Loader();
	_loader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, loaderProgressHandler, false, 0, true);
	_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loaderCompleteHandler, false, 0, true);
	_loader.load(urlRequest);
}

The loaderProgressHandler will serve to display the percentage of the load of your image. Here I will simply show how to trace the percentage. This is where you can get creative with what you do with said percentage.

private function loaderProgressHandler(event:ProgressEvent):void
{
	var ratio:Number = event.bytesLoaded / event.bytesTotal; // this division will give us a ratio out of one
	var loaded:String = "Loaded: " + int(ratio * 100) + "%"; // we cast the number to an int (integer) so its floating points get truncated
	trace(loaded);
}

Next up is handling the loaded image. Prior to everything, in the variables declarations, create a placeholder for the image to be added onto. It has to be done outside of the function so that said holder may be available throughout the class.

private var _imageHolder:Sprite;

private function loaderCompleteHandler(event:Event):void
{
	// always remember to remove your listeners when you are done with them
	_loader.contentLoaderInfo.removeEventListener(ProgressEvent.PROGRESS, loaderProgressHandler);
	_loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, loaderCompleteHandler);

	// handle the content of the loader
	// pass the data to a bitmap object
	var bitmap:Bitmap = Bitmap(_loader.content);

	// make sure you add smoothing to the bitmap, so the resizing is not pixelated
	bitmap.smoothing = true;

	// add the bitmap to the display list
	_imageHolder = new Sprite();
	_imageHolder.addChild(bitmap);
	addChild(_imageHolder);
}

To handle the resizing of the image, listen to the resize event from the stage. However, that is not sufficient, you need to make sure that your stage is aligned in the top left to make sure that it is locked in place.

private function initStage():void
{
	stage.align = StageAlign.TOP_LEFT;
	stage.scaleMode = StageScaleMode.NO_SCALE;
	stage.addEventListener(Event.RESIZE, stageResizeHandler, false, 0, true);
}

private function stageResizeHandler(event:Event):void
{
	// calls this function everytime the stage is resized
	// in this case, the browser window
	resize(stage.stageWidth, stage.stageHeight);
}

In the following example, the image is resized to always view the whole image. I also usually create _width and _height variables, if i ever need those values called at other moments than when the stage is resized.

private var _width:int;
private var _height:int;

public function resize(newWidth:int, newHeight:int):void
{
	_width = newWidth;
	_height = newHeight;

	if(_imageLoaded)
	{
		// assign a new width to the image
		_imageHolder.width = _width;

		// give the height the same scale as the width, so the image is proportionnal
		_imageHolder.scaleY = _imageHolder.scaleX;

		// if the image is too high, rely on the height
		if(_imageHolder.height > _height)
		{
			// assign a new height to the image
			_imageHolder.height = _height;

			// dont forget to give the width the same scale as the new height, so the image stays proportionnal
			_imageHolder.scaleX = _imageHolder.scaleY;
		}

		// center the image
		_imageHolder.x = int(stage.stageWidth * 0.5 - _imageHolder.width * 0.5);
		_imageHolder.y = int(stage.stageHeight * 0.5 - _imageHolder.height * 0.5);
	}
}

You may need to cover the whole background rather than see the whole image. In that case, let’s take the resize functionality and put it into different functions, so we may test their different uses.

public function resize(newWidth:int, newHeight:int):void
{
	_width = newWidth;
	_height = newHeight;

	if(_imageLoaded)
	{
	//resizeImageToViewAllOfIt();
	resizeImageToFillBackground();

	// center the image
	_imageHolder.x = int(stage.stageWidth * 0.5 - _imageHolder.width * 0.5);
	_imageHolder.y = int(stage.stageHeight * 0.5 - _imageHolder.height * 0.5);
	}
}

	private function resizeImageToViewAllOfIt():void
	{
	// assign a new width to the image
	_imageHolder.width = _width;

	// give the height the same scale as the width, so the image is proportionnal
	_imageHolder.scaleY = _imageHolder.scaleX;

	// if the image is too high, rely on the height
	if(_imageHolder.height > _height)
	{
		// assign a new height to the image
		_imageHolder.height = _height;

		// dont forget to give the width the same scale as the new height, so the image stays proportionnal
		_imageHolder.scaleX = _imageHolder.scaleY;
	}
}

private function resizeImageToFillBackground():void
{
	// assign a new width to the image
	_imageHolder.width = _width;

	// give the height the same scale as the width, so the image is proportionnal
	_imageHolder.scaleY = _imageHolder.scaleX;

	// if the image does not cover the whole height, change the scale
	if(_imageHolder.height < _height)
	{
		// assign a new height to the image
		_imageHolder.height = _height;

		// dont forget to give the width the same scale as the new height, so the image stays proportionnal
		_imageHolder.scaleX = _imageHolder.scaleY;
	}
}

Notice the subtlety: when you need to see the whole image, you check if the image height is higher than the available height to make sure it does not exceed it, while when you want to cover the whole background with your image, you check if the height is lower than the available height so that there is no moment when one side of the image is too small.

I hope this helps, here are the sources for this tutorial. Simply comment either resizeImageToViewAllOfIt() or resizeImageToFillBackground() to test the different behaviors.


2 responses to “Loading assets dynamically (part 3: images)”

  1. Walter Zeller says:

    Hello,
    Thank aou for the very helpfull script.

    Question: Is it also possible to download the .fla files which are not included at the “Tutorial_LoadingAssetsDynamicallyPart3.zip” package?

    Thank you again,
    Walter Zeller

  2. admin says:

    Hello Walter, I do not actually ever publish from FLA files to get my SWFs, I publish directly with Flash Builder. The Main.as class would be set as the default application.

    However, in this case it was simple enough to use the same class as the Document class in the Flash IDE.

    I updated the sources, you may want to look into assets/fla/resizeImage_CS4.fla or (assets/fla/resizeImage_CS3.fla, if that’s the version you have).

    Thanks for reading.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.