zoukankan      html  css  js  c++  java
  • Serializing A Bundle Of Bitmaps As Data Objects

    http://www.ghostwire.com/blog/archives/as3-serializing-a-bundle-of-bitmaps-as-data-objects/

    [AS3] Serializing A Bundle Of Bitmaps As Data Objects

    Published by  at 2:31 pm under Flash,Flash AS3,Tips

    This post is a supplement to “Serializing Bitmaps (Storing BitmapData As Raw Binary/ByteArray)”. In that article, we looked at how to convert BitmapData to a ByteArray, save that ByteArray, and re-construct theBitmapData from the saved ByteArray.

    It is important to note that the technique saves the ByteArray “as is” in a flat binary file without any header or any block of metadata – this means that the file will in itself not be able to communicate its data structure and therefore, proper usage of the data requires prior knowledge of how the data has been packed (we used the first four bytes for storing the value of the width of the image). As a result, that method may be deemed as an “unorthodox” hack and unsuitable in team development.

    In this post, we look at how you can employ the same basic idea while making the saved data more “consumable” by other developers.


    Action Message Format (AMF)
    ByteArray objects store ActionScript objects using the AMF format. So instead of saving the binary bitmap data in raw form in the way we described previously, we will put the serialized data in an Object and write that object to a ByteArray:

    // assume you have Bitmap object "bitmapImage" you want to save
     
    // convert the BitmapData to ByteArray
    // this time, do not pack any other data in the same ByteArray object
    var data:ByteArray = new ByteArray();
    data.writeBytes(bitmapImage.bitmapData.getPixels(bitmapImage.bitmapData.rect));
     
    // create a new data object
    var bmObj:Object = new Object();
    bmObj.width = bitmapImage.bitmapData.width;
    bmObj.height = bitmapImage.bitmapData.height;
    bmObj.data = data;
     
    // create a new ByteArray object for saving
    var bytes:ByteArray = new ByteArray();
    bytes.writeObject(bmObj);
    bytes.compress();

    So that does it – you can now save the binary data normally (by posting it to a server script, via AIR local filesystem API, via SharedObject, via FP10 FileReference, etc.). Although we are still saving our data in a flat binary file, the difference here is that developers consuming the data only need to know that they must read in an Object – they do not need to have the low-level knowledge of how exactly the data is packed.


    ByteArray To BitmapData
    Let’s look at how the binary data can now be consumed in an application.

    First, load the file as normal:

    var ldr:URLLoader	= new URLLoader();
    ldr.dataFormat	= URLLoaderDataFormat.BINARY; // ** make sure you do this **
    ldr.addEventListener(Event.COMPLETE, on_fileLoad);
    ldr.addEventListener(IOErrorEvent.IO_ERROR, on_fileLoadError);
    ldr.load(new URLRequest(pathToBitmapDataFile));

    Process the loaded data:

    private function on_fileLoad(evt:Event):void
    {
    	if (evt.type == Event.COMPLETE)
    	{
    		var bytes:ByteArray = URLLoader(evt.target).data as ByteArray;
    		if (bytes)
    		{
    			try
    			{
    				bytes.uncompress();
    			}
    			catch(e:Error)
    			{
    			}
    			// bytes is now the uncompressed byte array
    			// ... process bytes ...
    			var obj:Object = bytes.readObject();
     
    			// obj now has the properties "width", "height" and "data" as saved previously
     
    			var bmd:BitmapData = new BitmapData(obj.width, obj.height, true, 0); // 32 bit transparent bitmap
    			bmd.setPixels(bmd.rect, obj.data);
     
    			var bm:Bitmap = new Bitmap(bmd);
    			addChild(bm);
    		}
    	}
    }


    Bundle of Bitmaps
    What if you have multiple images you want to save and use later? You can consider serializing the bitmaps and store them together in a single binary file. To do that, we will give each image a unique id (such as the path of the image file if you are attempting to load and serialize external image files), store the serialized data in a hash, write that hash to a ByteArray, and then write that ByteArray to file.

    // for storing the serialized images
    private var imgLibrary:Object = { };
     
    private function saveImage(id:String, image:Bitmap):void
    {
    	if (id == null || id == "")
    	{
    		return;
    	}
     
    	if (image == null)
    	{
    		imgLibrary[id] = null; // ** remove previously stored data **
    		return;
    	}
     
    	var data:ByteArray = new ByteArray();
    	data.writeBytes(image.bitmapData.getPixels(image.bitmapData.rect));
     
    	// create a new data object
    	var bmObj:Object = new Object();
    	bmObj.width = image.bitmapData.width;
    	bmObj.height = image.bitmapData.height;
    	bmObj.data = data;
     
    	imgLibrary[id] = bmObj; // ** will overwrite previously stored data **
    }
     
    saveImage("iconA", imageIconA);
    saveImage("iconB", imageIconB);
    saveImage("iconC", imageIconC);
    // imgLibrary now contains three data objects each representing an image

    Now, write imgLibrary to file:

    // ** must target Flash Player version 10+ **
    private function on_buttonClick(evt:MouseEvent):void
    {
    	var bytes:ByteArray = new ByteArray();
    	bytes.writeObject(imgLibrary); // store width of image
    	bytes.compress();
    	new FileReference().save(bytes, "image.bmd"); // default name "image.bmd"
    }

    In another application, we load the saved binary file as usual:

    var ldr:URLLoader	= new URLLoader();
    ldr.dataFormat	= URLLoaderDataFormat.BINARY; // ** make sure you do this **
    ldr.addEventListener(Event.COMPLETE, on_fileLoad);
    ldr.addEventListener(IOErrorEvent.IO_ERROR, on_fileLoadError);
    ldr.load(new URLRequest(pathToFile));

    And process and use the loaded binary data as follows:

    private var imgLibrary:Object;
     
    private function on_fileLoad(evt:Event):void
    {
    	if (evt.type == Event.COMPLETE)
    	{
    		var bytes:ByteArray = URLLoader(evt.target).data as ByteArray;
    		if (bytes)
    		{
    			try
    			{
    				bytes.uncompress();
    			}
    			catch(e:Error)
    			{
    			}
    			// bytes is now the uncompressed byte array
    			// ... process bytes ...
    			imgLibrary = bytes.readObject();
     
    			// imgLibrary is now initialized and contains data objects each representing a bitmap image
    		}
    	}
    }

    After populating the imgLibrary hash, you can use a method like the one below to query it:

    private function getImage(id:String):Bitmap
    {
    	if (id == "" || id == null || imgLibrary == null || imgLibrary[id] == null)
    	{
    		return null;
    	}
    	var obj:Object = imgLibrary[id];
    	try
    	{
    		// obj now has the properties "width", "height" and "data" as saved previously
     
    		var bmd:BitmapData = new BitmapData(obj.width, obj.height, true, 0); // 32 bit transparent bitmap
    		bmd.setPixels(bmd.rect, obj.data);
     
     		return new Bitmap(bmd);
    	}
    	catch(e:Error)
    	{
    	}
    	return null;
    }
     
    getImage("iconA"); // returns a Bitmap with BitmapData constructed from saved byte array

    The getImage() method can also be improved such that the ByteArray-to-BitmapData conversion is only done once per image:

    private function getImage(id:String):Bitmap
    {
    	if (id == "" || id == null || imgLibrary == null || imgLibrary[id] == null)
    	{
    		return null;
    	}
    	var obj:* = imgLibrary[id];
     
    	if (obj is BitmapData)
    	{
    		return new Bitmap(BitmapData(obj).clone());
    	}
     
    	try
    	{
    		// obj now has the properties "width", "height" and "data" as saved previously
     
    		var bmd:BitmapData = new BitmapData(obj.width, obj.height, true, 0); // 32 bit transparent bitmap
    		bmd.setPixels(bmd.rect, obj.data);
     
    		imgLibrary[id] = bmd;
     
     		return new Bitmap(bmd.clone());
    	}
    	catch(e:Error)
    	{
    	}
    	return null;
    }

    Note: If you are confident that the BitmapData is not going to be modified by instances, remove the clone()calls above – it will save memory since that means all Bitmap instances with the same id will be using the exact same BitmapData.


    Embedding Image Asset(s)
    After you have saved the binary file, remember that you are not limited to using it only as an external resource – you can also embed the file into your SWF:

    // ActionScript 3.0
    [Embed(source="assets/images/icons.bin", mimeType="application/octet-stream")]
    private static const iconsBundle:Class;
     
    private var imgLibrary:Object;
     
    private function initIcons():void
    {
    	var bytes:ByteArray = new iconsBundle() as ByteArray;
    	if (bytes)
    	{
    		try
    		{
    			bytes.uncompress();
    		}
    		catch(e:Error)
    		{
    			// data not compressed
    		}
    		imgLibrary = bytes.readObject();
    		// imgLibrary is now initialized and contains data objects each representing a bitmap image
    	}
    }
    Be Sociable, Share!
  • 相关阅读:
    JAVA基础知识|HTTP协议-两个特性
    JAVA基础知识|TCP/IP协议
    Spring Cloud|高可用的Eureka集群服务
    Hadoop环境搭建|第四篇:hive环境搭建
    C#中Func与Action的理解
    C# lambda表达式
    WPF ControlTemplate
    sublime text3插件安装及使用
    Dev Express之ImageComboBoxEdit,RepositoryItemImageComboBox使用方式
    SQL查询结果增加序列号
  • 原文地址:https://www.cnblogs.com/chenhongyu/p/3316032.html
Copyright © 2011-2022 走看看