Search Box

Google
 

Sunday, February 11, 2007

BitmapData.........

Hai all,

i am back after a very long long time. But happy i am back atleast now. Today we shall discuss about caching image using BitmapData class. Actually "bitmapdata" is a new class that has been introduced for flash player 8. What this class can do is enormous, but we are here to discuss today what it can do for caching dynamically loaded images.

I was always wondering how can i stop those reloading of images again and again, until i was introduced to the BitmapData class by a colleague of mine who recently discovered this. After playing around with the class for sometime an idea struck to me for solving the problem of reloading the loaded images with BitmapData class being the key. This solution ultimately gave birth to a class "ImageCache" which looks after the images loaded using it and ultimately returns a BitmapData which can be attached to the image holding movieClip using attachBitmap() method.

The content of the class goes like this :

import flash.display.BitmapData

class ImageCache
{
/**
@ varible __paths
@ description: The array that holds the path of the images loaded.
*/
private var __paths:Array;

/**
@ varible loader
@ description: MovieClip that holds the images to be loaded and cached.This is a temporary movieClip.
*/
private var loader:MovieClip;


/**
@ method ImageCache
@ description: Constructor Function.
*/
public function ImageCache()
{
__paths = new Array();
}

/**
@ method registerTempLoader
@ arguments : None;
@ access : Public
@ returns : Nothing.
@ description: Method that registers a valid MovieClip to be used for caching Images.
*/
public function registerTempLoader(mc:MovieClip):Void
{
loader = mc;
}


/**
@ method : cacheImage
@ arguments : String path , float Width, float Height;
@ access : Public
@ returns : BitmapData.
@ description : When a path is passed into the argument along with the width and height
loads the image and returns the cached image as a BitmapData.
*/
public function cacheImage(path:String,w:Number,h:Number):BitmapData
{
var index:Number = isCached(path);
if( index < 0)
{
var obj:Object = new Object();
var mc:MovieClip = loader.createEmptyMovieClip('loader'+__paths.length,__paths.length);
obj.path = path;
obj.bdata = new BitmapData((w==undefined)?100:w,(h==undefined)?100:h,false,0xcc33ff);
mc.loader = new MovieClipLoader();
mc.loader.addListener(this);
mc.loader.loadClip(path,mc.createEmptyMovieClip('loader',0));
mc.index = __paths.length;
__paths.push(obj);
return obj.bdata;
}
else
{
return __paths[index].bdata;
}

}


/**
@ method : isCached
@ arguments : String path;
@ returns : Number.
@ access : Private
@ description : When a path is passed into the argument checks from the
__paths array if the path is already loaded returns the
index of the path in the array else returns -1.
*/
private function isCached(path:String):Number
{
for(var i:Number=0;i<__paths.length;i++)
{
if(__paths[i].path == path)
{
return i;
}
}
return -1;
}


/**
@ method : onLoadInit
@ arguments : target MovieClip;
@ returns : Nothing.
@ access : Private
@ description : When an image loads successfully its parent get drawn using BitmapData.
*/
private function onLoadInit(target:MovieClip):Void
{
__paths[target._parent.index].bdata.draw(target._parent);
}
}



Okay, the class is written but how do we use it ??? Nice Question !

i had developed a image gallery using this class believe me. i will paste the actionscript that exists in the timeline of the stage as given below. But before that have two things ready in the library. one is a macromedia scrollpane and the next is create two empty movieclips with one having a linkage name "thumbHolder" and the other empty movieclip does not require any linkage ids.

Now drag the ScrollPane to the stage and name it "$spane" with the content path in the parameters field as "thumbHolder". Now drag the empty movieClip without any linkage id to the stage and name it "$main".

Then paste the below actions on the first frame of the Stage.


//Instance of the ImageCache Class.
var iCache:ImageCache = new ImageCache();

//Temporary images holder.
var imageHolder:MovieClip = this.createEmptyMovieClip('tempImageHolder',0);


//The thumbnal images holder
var galleryHolder:MovieClip = $spane.spContentHolder.createEmptyMovieClip('thumbNailholder',1);


//The main picture holder.
var mainPicture:MovieClip = $main.createEmptyMovieClip('mainLoader',0);

var width:Number = 360;//Width value - change at your will.

var height:Number = 480;//Height value - change at your will.

//The below function is the one that starts to cache images.
function cacheImages():Void
{
var ratio:Number = 360/480;
var thumbHeight:Number = 480/4;
var thumbHolder:MovieClip = galleryHolder.createEmptyMovieClip('holder',0);
for(var i:Number=0;i<19;i++)
{
var index:Number = 787 + i;
var path:String = 'images/SP_A0'+index+'.jpg';//Change this value to your custom image path
var thumb:MovieClip = thumbHolder.createEmptyMovieClip('gal'+i,i);
thumb.createEmptyMovieClip('loader',0).attachBitmap(iCache.cacheImage(path,360,480),0);
thumb.loader._width = ratio * thumbHeight;
thumb.loader._height = thumbHeight;
thumb._y = (thumbHeight+5) * i;
thumb.path = path;
thumb.onPress = function()
{
mainPicture.attachBitmap(iCache.cacheImage(this.path,360,480),0);
//mainPicture.createEmptyMovieClip('loader',0).loadMovie(this.path);
}
}
$spane.redraw(1);
}
imageHolder._visible = false;//setting the visiblity of the tempimages holder to false.

imageHolder._x = 100000;//setting the distance of the tempimages holder to a large one so we cannot see it.


iCache.registerTempLoader(imageHolder);//REgsitering the tempImage Holder as the loader for caching images.


cacheImages();//Start Caching Images.


So having restarted my blogging with the BitmapData class makes me feel a bit enthus !!!!

Thanks for reading.

Regards,

Ashok Srinivasan.

4 comments:

Brian C said...

Your file worked pretty well. The problem is that it over-draws the image area. Isn't there a simple way to pass it the original image height & width or to call it once it loaded so that the viewed image is exactly the size of the original?

It was really difficult to get images and thumbnails sized and positioned correctly.... There has to be a better logic.

Let me know...

Ashok Srinivasan said...

As you said the bitmap actually overdraws the image area and it can be solved by making the changes as mentioned below :

//The class Defintion starts here.

import flash.display.BitmapData

class ImageCache
{
/**
@ varible __paths
@ description: The array that holds the path of the images loaded.
*/
private var __paths:Array;

/**
@ varible loader
@ description: MovieClip that holds the images to be loaded and cached.This is a temporary movieClip.
*/
private var loader:MovieClip;


/**
@ method ImageCache
@ description: Constructor Function.
*/
public function ImageCache()
{
__paths = new Array();
}

/**
@ method registerTempLoader
@ arguments : None;
@ access : Public
@ returns : Nothing.
@ description: Method that registers a valid MovieClip to be used for caching Images.
*/
public function registerTempLoader(mc:MovieClip):Void
{
loader = mc;
}


/**
@ method : cacheImage
@ arguments : String path , float Width, float Height;
@ access : Public
@ returns : BitmapData.
@ description : When a path is passed into the argument along with the width and height
loads the image and returns the cached image as a BitmapData.
*/
public function cacheImage(path:String,w:Number,h:Number):BitmapData
{
var index:Number = isCached(path);
if( index < 0)
{
var obj:Object = new Object();
var mc:MovieClip = loader.createEmptyMovieClip('loader'+__paths.length,__paths.length);
obj.path = path;
obj.bdata = new BitmapData((w==undefined)?100:w,(h==undefined)?100:h,false,0xcc33ff);
mc.loader = new MovieClipLoader();
mc.loader.addListener(this);
mc.loader.loadClip(path,mc.createEmptyMovieClip('loader',0));
mc.index = __paths.length;
__paths.push(obj);
return obj.bdata;
}
else
{
__paths[index].bdata = new BitmapData(__paths[index].width,__paths[index].height,true,0);
__paths[index].bdata.draw(__paths[index].movie);
return __paths[index].bdata;
}

}


/**
@ method : isCached
@ arguments : String path;
@ returns : Number.
@ access : Private
@ description : When a path is passed into the argument checks from the
__paths array if the path is already loaded returns the
index of the path in the array else returns -1.
*/
private function isCached(path:String):Number
{
for(var i:Number=0;i<__paths.length;i++)
{
if(__paths[i].path == path)
{
return i;
}
}
return -1;
}


/**
@ method : onLoadInit
@ arguments : target MovieClip;
@ returns : Nothing.
@ access : Private
@ description : When an image loads successfully its parent get drawn using BitmapData.
*/
private function onLoadInit(target:MovieClip):Void
{
__paths[target._parent.index].width = target._width;
__paths[target._parent.index].height = target._height;
__paths[target._parent.index].movie = target._parent;
__paths[target._parent.index].bdata.draw(target._parent);
}
}

//The class Definition ends here


Hope this solves your problem.

Regarding the Thumbnail arrangements i am sorry but the fact was that i felt a bit lazy to add thumbnail images and instead used the actual pictures itself.

The logic behind arranging bitmaps was just to show the thumnails and am sure it could have been done in a better way.

Thank you for dropping in and dropping in a comment. I am happy with your visit to my blog.

Regards,

Ashok Srinivasan.

Morty said...

Thank you very much for sharing your code.
Can you please post a link to a sample of your gallery using this class, so everybody can see how it really works?
Am I right that this solution enables smooth resizing of images (after adding this feature)?
Thanks...

Anonymous said...

sexy code does look different..