zoukankan      html  css  js  c++  java
  • Bitmap序列化(将BitmapData保存为原生Binary/ByteArray)

    当应用程序需要将位图图像保存到本地或发送到服务端时, 通常的方法是在发送数据前将图像通过PNG或JPEG编码。如果只是想保存位图图像,只要序列化BitmapData即可,将图像转换为JPEG/PNG是完全没有必要的。

    BitmapData 转换为 ByteArray

    获得BitmapData对应的字节数组, 所要做的只是调用getPixels()方法。getPixels()方法需要指定捕捉区域;最便捷的方法就是使用即将序列化的BitmapData的rect属性。
    1. // ActionScript 3.0
    2. // 假定“bitmapImage”是需要序列化的位图对象
    3. var bytes:ByteArray = bitmapImage.bitmapData.getPixels(bitmapImage.bitmapData.rect);
    复制代码
    这个方法会返回一个ByteArray对象,BitmapData的每个像素对应ByteArray对象中的一个4字节的无符号整型。这意味着如果是20x20的位图图像, 对应的ByteArray对象在压缩前有1600个字节(20x20x4=1600)
    得到ByteArray对象后, 压缩:
    1. var bytes:ByteArray = bitmapImage.bitmapData.getPixels(bitmapImage.bitmapData.rect);
    2. bytes.compress();
    复制代码
    得到了位图图像无损压缩的二进制数据了.

    位图尺寸(宽与高)

    这样看来, 得到位图图像对应的ByteArray数据很容易 - 只要调用getPixel()方法即可.当然, 将ByteArray再构造为位图图像才能证明数据是有用的. 除像素数据外, 字节数组不能为位图图像指定尺寸.就是说你得把尺寸信息也要保存在字节数组里.其实只要保存高度或宽度即可, 因为已经知道了像素总数, 通过计算便能算出另一个.

    下面的代码中,字节数组前4个字节保存BitmapData的宽度, 接下来再保存图像字节数组.
    1. var bytes:ByteArray = new ByteArray();
    2. bytes.writeUnsignedInt(bitmapImage.bitmapData.width);
    3. bytes.writeBytes(bitmapImage.bitmapData.getPixels(bitmapImage.bitmapData.rect));
    4. bytes.compress();
    复制代码
    保存文件

    前面的工作完成后就可以使用常用的方法保存二进制数据了(发送给服务端脚本,AIR本地文件API,SharedObject以及FP10 FileReference等等).这个例子中, 我们通过使用FileReference类的save()方法(需要Flash Player 10)将二进制数据保存到本地存储器中.由于Flash Player的安全措施,save()方法只有在用户交互事件中才能够调用(例如鼠标点击事件).因此需要新建一个按钮并附加一个监听器, 在事件处理方法中调用save()方法.
    1. // ** 需要Flash Player 10以上版本 **
    2. function on_buttonClick(evt:MouseEvent):void
    3. {
    4.         var bytes:ByteArray = new ByteArray();
    5.         bytes.writeUnsignedInt(bitmapImage.bitmapData.width); // 保存图像宽度
    6.         bytes.writeBytes(bitmapImage.bitmapData.getPixels(bitmapImage.bitmapData.rect)); //保存图像字节数组
    7.         bytes.compress();
    8.         new FileReference().save(bytes, "image.bmd"); // 默认文件名: "image.bmd"
    9. }
    复制代码
    文件可任意命名.上面的例子中, 我使用了".bmd"(BitmapData)做为文件扩展名,不过这只是一个自己想出的文件类型.最终保存的文件无有效MIME的, 不会当作已知的文件类型运行 - 这是我们自定义的二进制数据格式文件, 仅仅是用来保存图像数据, 方便以后我们的程序重用.

    ByteArray 转换为 BitmapData

    上面提到过, 我们要将保存的数据重构, 这样才能还原出原始位图图像.
    首先, 通过URLLoader加载文件:
    1. var ldr:URLLoader        = new URLLoader();
    2. ldr.dataFormat        = URLLoaderDataFormat.BINARY; // ** 这里一定要指定dataFormat为URLLoaderDataFormat.BINARY **
    3. ldr.addEventListener(Event.COMPLETE, on_fileLoad);
    4. ldr.addEventListener(IOErrorEvent.IO_ERROR, on_fileLoadError);
    5. ldr.load(new URLRequest(pathToBitmapDataFile));
    复制代码
    事件处理方法on_fileLoad:
    1. function on_fileLoad(evt:Event):void
    2. {
    3.         if (evt.type == Event.COMPLETE)
    4.         {
    5.                 var data:ByteArray = URLLoader(evt.target).data as ByteArray;
    6.                 if (data)
    7.                 {
    8.                         try
    9.                         {
    10.                                 data.uncompress();
    11.                         }
    12.                         catch(e:Error)
    13.                         {
    14.                         }
    15.                         // 此时的数据已经是解压后的字节数组了
    16.                         // ... 处理数据 ...
    17.                 }
    18.         }
    19. }
    复制代码
    现在我们来取出位图图像的尺寸. 还记得之前我们在二进制数据的头4个字节保存了宽度值吧.
    1. // 数据解压后
    2. var int = data.readUnsignedInteger(); // 起始的4个字节
    复制代码
    得到高度:
    1. // after data.uncompress()
    2. var height:int = ((data.length - 4) / 4) / width;
    3. // (data.length - 4) ** 去掉开始的4个字节,其余的便是位图的字节数组了 **
    4. // ((data.length - 4) / 4) ** 每个像素4个字节长, 所以要除以4得到总像素数 **
    5. // ((data.length - 4) / 4) / 宽度 ** 记住,因为是矩形才能这样计算出高度 **
    复制代码
    注意:如果要忽略尺寸计算, 可以把高宽同时保存在二进制数据中.两种方法都是可行的, 可自行选择.

    得到尺寸后, 就可以使用setPixels()方法重构Bitmap对象了.
    1. var bmd:BitmapData = new BitmapData(width, height, true, 0); // 32位支持alpha通道的位图
    2. bmd.setPixels(bmd.rect, data); // 数据的position指向第5个字节了
    3. var bm:Bitmap = new Bitmap(bmd);
    4. addChild(bm);
    复制代码
    结论

    以上方法展现了将BitmapData数据转换为ByteArray, 保存ByteArray, 然后再将已保存的ByteArray重新构造为BitmapData的整个过程.虽然基本目标是能够把位图图像保存到服务器/本地存储器, 但上述技巧放在其他情况中也是十分有用的.例如, 得到图像的ByteArray数据后, 可以将其发送(post)到服务器做进一步处理. 也可用来裁减外部的JPEG/PNG图像文件,去掉所有的JPEG/PNG编码中含有的元数据信息(meta information), 只留下原始(raw)图像数据(文件可能更小了).当然了, 最终的二进制文件不能做为JPEG/PNG打开了, 但应用程序能够在运行时很容易的重构出相应的图像来.实际上,也可认为这是一种保护外部图片不被盗链的好方法.

    原文链接:http://www.ghostwire.com/blog/archives/as3-serializing-bitmaps-storing-bitmapdata-as-raw-binarybytearray/

  • 相关阅读:
    归并排序(Merge Sort)
    AtCoder AGC035D Add and Remove (状压DP)
    AtCoder AGC034D Manhattan Max Matching (费用流)
    AtCoder AGC033F Adding Edges (图论)
    AtCoder AGC031F Walk on Graph (图论、数论)
    AtCoder AGC031E Snuke the Phantom Thief (费用流)
    AtCoder AGC029F Construction of a Tree (二分图匹配)
    AtCoder AGC029E Wandering TKHS
    AtCoder AGC039F Min Product Sum (容斥原理、组合计数、DP)
    AtCoder AGC035E Develop (DP、图论、计数)
  • 原文地址:https://www.cnblogs.com/chenhongyu/p/3316031.html
Copyright © 2011-2022 走看看