Saturday, February 16, 2008

Display Images from remote server in flex2.

I had a tough time in finding the resources that give working examples on this topic. Let me set the context of the problem then this discussion will make more sense.
There are times when you want to display images from various sources on the internet on your flex page, or you have a image server and you want to display the images from the server on to your page.
There are two ways of doing this
1. The server has sent you the image in the form of a byte array and you just want to render that byte array on your flex page
2. To mention the URL of the image and ask flex to display the image from that URL

Note: Only jpg,png,gif and swf files can be displayed.


Method 1 (byte array)

This is quite simple. (courtesy http://www.kineticz.net/blahg/2007/07/26/rending-a-bitmap-from-a-bytearray-in-flash/ )

I am giving the pieces of the code. Basically Assuming that you have your byte array ready with you from the server. I will explain how to render


<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="init()">
<mx:Script>
<![CDATA[

private function renderImage():void
{
var byteLoader:Loader = new Loader();
byteLoader.loadBytes(Your_Byte_Array_Name);
imageCanvas.rawChildren.addChild(byteLoader);
}
</mx:Script>
<mx:Canvas id="imageCanvas" left="10" top="189" right="528" bottom="10"/>

</mx:Application>

We essentially have to do the following three steps:
step1 : declare an instance of Loader class.

var byteLoader:Loader = new Loader();

step2: Now load the bytes of the byte array in the loader. This is going to load the bytes in the security context of your application
byteLoader.loadBytes(your_byte_array);

step3: You need to have a canvas control where the image will be displayed so you must have something like
<mx:Canvas id="imageCanvas" left="10" top="189" right="528" bottom="10"/>

step4: Finally load the Byte Array in the canvas
imageCanvas.rawChildren.addChild(byteLoader);


Method 2: Directly accessing the images using Image URL
In this method I will give a sample code that will access the image using the image URL. First I will give the sample implementation and then explain whats need to be done. The code has been taken from http://onflex.org/flexapps/applications/ProgressiveImageLoading/srcview/index.html


<?xml version="1.0" encoding="utf-8"?>
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
initialize="appInit()"
layout="absolute"
viewSourceURL="srcview/index.html"
backgroundGradientAlphas="[1.0, 1.0]"
backgroundGradientColors="[#FFFFFF, #FFFFFF]">

<mx:Script>
<![CDATA[

// Progressive Image Loading

import flash.net.URLStream;
import flash.net.URLRequest;
import flash.utils.getTimer;

// loader to hold the loaded bytes
public var loader:Loader;

// URLStream to load the image bytes
public var imageStream:URLStream;

// ByteArray to hold aggregate image data
public var imageData:ByteArray;

// Set up initial conditions when the application initializes
public function appInit():void
{
//create a URLStream to load data in. The incoming data will be obtained using URLStream.
imageStream = new URLStream();
//add some event listeners for PROGRESS and COMPLETE. This will help in order to determine when the image download is complete
imageStream.addEventListener( ProgressEvent.PROGRESS , imageStreamProgress );
imageStream.addEventListener( Event.COMPLETE , imageStreamComplete );

//create a fresh loader instance
// this is similar to the Method 1 . Only thing is that the byte Array has not been obtained till now.
loader = new Loader();
imageCanvas.rawChildren.addChild( loader );
}

public function imageStreamProgress( event:Event ):void
{
// if there are no bytes do nothing
if( imageStream.bytesAvailable == 0 ) return

// ooo bytes process the image data
this.processImageData();
}

public function imageStreamComplete( event:Event ):void
{
// if connected, stop that.
if ( imageStream.connected ) imageStream.close();

// lets refresh the displayList after rendering cycle
imageCanvas.callLater( this.processImageData );
}

public function processImageData():void
{
// if connected, read all the bytes that have been loaded into the aggregate bytearray. The byte Array is filled with the incoming data
if ( imageStream.connected ) imageStream.readBytes( imageData , imageData.length );

// clean up the loader
loader.unload();

//push the aggregate bytearray of loaded image data in there.
loader.loadBytes( imageData );
}

public function loadImage( input:String ):void
{
//if connected we need to stop that
if ( imageStream.connected ) imageStream.close();

//lets load a new image url
imageStream.load( new URLRequest( input + '?' + getTimer() ) );

// clean out all the crud in that loader
loader.unload();

//create a fresh bytearray to store aggregate image data
imageData = new ByteArray();
}

]]>
</mx:Script>


<!-- this is the place that we are accessing the jpg image from our server-->
<mx:Button click="loadImage('http://sampleserver/scripts/sample.jpg')" y="10" label="Load sample" x="371" />

<mx:Canvas id="imageCanvas" left="10" top="40" right="10" bottom="10"/>

</mx:Application>


A rough algorithm

1. Create a URLStream to access the remote image URL
2. Create a loader object
3. Create a byte Array
4. Create a canvas or some container where to render the image. Associate the loader object as a child of this canvas
5. Listen to the events
ProgressEvent.PROGRESS,Event.COMPLETE. These will help in knowing if the download is over or still progressing
6. We load the URL to the URLStream
7. Clear the loader
8. initialize the ByteArray
9. Now listen to the events.
If the Progress event occurs then
10. Read the bytes into the byteArray and then load the bytes to the loader. So we will see the some portion of the image on the client
If the Complete Event occurs then
11 close the URLStream.







No comments: