huffman编码是常见的压缩算法之一,
例如我们平常看到的jpeg图片就是用huffman进行熵编码压缩。
我实现了huffman的alchemy版和AS3版两个版本。
纯AS3实现是把C算法完整地移植过去的(使用uint的Array数组模拟char[])
因为huffman算法在网上比较容易找到,我就不详细介绍。
下面只着重记录如何用Alchemy技术把huffman的API暴露到AS3,
然后与纯AS3实现的结果进行比较。
(这里说的huffman算法压缩后头四个字节为解压长度,压缩使用位流)
一、安装Alchemy。
Alchemy的安装方法以前已经说过,不过我是按照官方的做法再做了一次
(稍有不同的是我的alchemy不需要alc-on):
以下以windows xp+cygwin为开发环境(假设已经安装flex sdk和jdk)
1. 在adobe官方网站下载alchemy的cygwin二进制包。
2. 本地或在线安装cygwin,Select packages时选中make,perl、zip(不需要安装gcc,也不需要安装源代码)。
本地安装是cygwin把在线安装的文件缓存在硬盘中,最开始一般都是在线安装。
选择zip时要小心,不要选其它名字带zip的压缩工具。zip程序用于后面生成swc文件。
3. 启动cygwin的批处理文件Cygwin.bat,完成cygwin的全部安装。
4. 把alchemy的二进制文件解压到cygwin安装目录下
5. 在/etc/profile最后加入
export PATH=/cygdrive/D/java/flex_sdk_4.1.0.16076/bin:$PATH
export PATH=/cygdrive/D/java/jdk1.6.0_20/bin:$PATH
export PATH=/alchemy-cygwin-v0.5a/achacks:/alchemy-cygwin-v0.5a/bin:$PATH
export ALCHEMY_HOME=/alchemy-cygwin-v0.5a
export FLEX_HOME=D:/java/flex_sdk_4.1.0.16076
export ASC=C:/cygwin3/alchemy-cygwin-v0.5a/bin/asc.jar
注意:这里jdk、flex sdk的位置和alchemy的目录位置可变;
cygdrive用于转换windows的绝对路径;
冒号用于分割;
另外FLEX_HOME和ASC最好不要用cygdrive转换,因为它用于flex的jar文件定位,
windows下的java可能无法识别路径名而报错;
因为cygwin没有装gcc,所以我直接把achacks目录加入PATH(与官网的安装方法不一样,所以后面不需要alc-on那么麻烦)
把/etc/profile保存为Unix换行(注意:需要用特殊的编辑器编辑,我是使用Notepad2 MOD菜单中的“行末符号->Unix换行”保存)
重新启动cygwin控制台以使环境变量生效。
6. 执行以下命令
$ cd /alchemy-cygwin-v0.5a/
$ ./config
Generating alchemy-setup...
Turning execution bit on for Alchemy binaries...
cygwin warning:
MS-DOS style path detected: C:/cygwin3/alchemy-cygwin-v0.5a/alchemy-setup
Preferred POSIX equivalent is: /alchemy-cygwin-v0.5a/alchemy-setup
CYGWIN environment variable option "nodosfilewarning" turns off this warning.
Consult the user's guide for more details about POSIX paths:
http://cygwin.com/cygwin-ug-net/using.html#using-pathnames
Add "source /alchemy-cygwin-v0.5a/alchemy-setup" to your login script.
"alc-home" takes you to the Alchemy install folder.
"alc-on" puts Alchemy gcc toolchain replacements at the front of your path.
"alc-off" restores original path.
"alc-util" shows you various Alchemy-related environment vars
You need Flash 10 or AIR 1.5 and the Flex 3.2 SDK installed for testing.
7. 测试一下以下命令:
$ explorer .
$ mxmlc -help (如果无法运行,请确保jar的路径是windows的绝对路径,设置FLEX_HOME环境变量)
$ java -help
$ perl --help
$ zip --help
8. 测试gcc是否正常:(不需要alc-on,是因为我已经把alchemy的gcc加入了PATH,而且cygwin中并没有装真正的gcc)
$ which gcc
/alchemy-cygwin-v0.5a/achacks/gcc
$ gcc -v
Using built-in specs.
Target: i686-pc-cygwin
Configured with: /home/anon/llvm-gcc4.0-2.1.source/configure : (reconfigured) /
home/anon/llvm-gcc4.0-2.1.source/configure : (reconfigured) /home/anon/llvm-gcc
4.0-2.1.source/configure --disable-libgcj --disable-libjava : (reconfigured) ../
../src/llvm-gcc4/configure --prefix=/home/anon/llvm-gcc4 --disable-threads --dis
able-nls --disable-shared --enable-languages=c,c++ --disable-c-mbchar --program-
prefix=llvm- --enable-llvm=/home/anon/src/llvm : (reconfigured) /home/anon/src/l
lvm-gcc4/configure --prefix=/home/anon/llvm-gcc4 --disable-threads --disable-nls
--disable-shared --enable-languages=c,c++ --disable-c-mbchar --program-prefix=l
lvm- --enable-llvm=/home/anon/src/llvm
Thread model: single
gcc version 4.0.1 (Apple Computer, Inc. build 5449)
可以看到alchemy官方版附带的gcc版本是4,用苹果机编译。
二、编写代码编译运行,比较Alchemy和AS3实现的结果。
为了简单起见忽略huffman压缩和解压算法的实现代码。
Alchemy的API导出文件(.gg文件)
---------------------------
{ /* 注意用大括号包含C代码, 一些通常用到的C函数定义,方便C和AS3的类型转换 */ #include <stdlib.h> #include <string.h> #include <malloc.h> /* 需要用到的头文件 */ #include "Huffman.h" /* AS3.h is included automatically by gluegen */ void sztrace(char*); AS3_Val no_params = NULL; AS3_Val zero_param = NULL; AS3_Val ByteArray_class = NULL; AS3_Val getTimer_method = NULL; // 保存压缩大小 static int compress_size = 0; /* This function will be called at the top of the generated main(). The GGINIT_DEFINED macro is required. */ /* 必须预定义GGINIT_DEFINED */ #define GGINIT_DEFINED true static void ggInit() { //sztrace("setting up as3_crypto_wrapper library"); /* setup some useful constants */ no_params = AS3_Array(""); zero_param = AS3_Int(0); AS3_Val flash_utils_namespace = AS3_String("flash.utils"); ByteArray_class = AS3_NSGetS(flash_utils_namespace, "ByteArray"); getTimer_method = AS3_NSGetS(flash_utils_namespace, "getTimer"); AS3_Release(flash_utils_namespace); /* initialize */ /* 这里插入全局初始化代码*/ } /* Copy the byteArray data into a malloc'd buffer */ /* ByteArray转void* */ static void* newMallocFromByteArray(AS3_Val byteArray, unsigned int* size) { AS3_Val byteArraySize = AS3_GetS(byteArray, "length"); *size = AS3_IntValue(byteArraySize); AS3_Release(byteArraySize); void* bytes = malloc(*size); AS3_SetS(byteArray, "position", zero_param); AS3_ByteArray_readBytes((char*)bytes, byteArray, (int)*size); return bytes; } /* Make a new ByteArray containing the data passed */ /* void*转ByteArray */ static AS3_Val newByteArrayFromMalloc(void *data, unsigned int size) { AS3_Val byteArray = AS3_New(ByteArray_class, no_params); AS3_ByteArray_writeBytes(byteArray, data, size); return byteArray; } #if 0 // use for profiling /* get a timestamp from Flash */ static int getTimestamp() { AS3_Val ts = AS3_Call(getTimer_method, NULL, no_params); int result = AS3_IntValue(ts); AS3_Release(ts); return result; } #endif /* C代码结束 */ /* 下面就可以加入要在swc中暴露的API声明 */ } public function huff_uncompress(indata:ByteArray, insize:uint, outsize:uint):ByteArray { unsigned int size = 0; unsigned char* inbuf = newMallocFromByteArray(indata, &size); unsigned char* outbuf = malloc(outsize); //测试用 //memset(outbuf, outsize, 10); Huffman_Uncompress(inbuf, outbuf, insize, outsize); AS3_Val ba = newByteArrayFromMalloc(outbuf, outsize); free(inbuf); free(outbuf); return ba; } public function huff_compress(indata:ByteArray, insize:uint):ByteArray { unsigned int size = 0; unsigned char* inbuf = newMallocFromByteArray(indata, &size); //足够容纳压缩内容的大小 unsigned int outsize = (insize*104+50)/100 + 384; unsigned char* outbuf = malloc(outsize); //测试用 //memset(outbuf, outsize, 10); //调试用 /* char strTrace[1000] = ""; sprintf(strTrace, "size: %d, outsize:%d, insize:%d", size, outsize, insize); sztrace(strTrace); sztrace(inbuf); */ compress_size = Huffman_Compress(inbuf, outbuf, insize); AS3_Val ba = newByteArrayFromMalloc(outbuf, compress_size); free(inbuf); free(outbuf); return ba; } public function huff_compress_size():uint { // 取出最近压缩的大小 return compress_size; }
----------------------------------------------
Alchemy实现的主入口代码如下:
package { import flash.display.Sprite; import flash.events.Event; import flash.utils.ByteArray; import flash.utils.Endian; /** * ... * @author */ public class Main extends Sprite { import cmodule.huff.CLibInit; private static const clibinit:CLibInit = new CLibInit(); private static const hufflib:Object = clibinit.init(); public function Main():void { if (stage) init(); else addEventListener(Event.ADDED_TO_STAGE, init); } private function init(e:Event = null):void { removeEventListener(Event.ADDED_TO_STAGE, init); // entry point //-------------------------------------------------- [Embed(source='../lib/output.dat', mimeType='application/octet-stream')] var output_dat:Class; //注意,是强制转换,不是new var data:ByteArray = ByteArray(new output_dat()); trace("ByteArray.length = ", data.length); data.position = 0; //不知为何,与网络传输时正好相反 //0xFF000000 --readUnsignedInt--> 0xFF data.endian = Endian.LITTLE_ENDIAN; if (data.bytesAvailable > 0) { // 第一个32位数是解压长度 var uncompress_length:uint = data.readUnsignedInt(); var inputdata:ByteArray = new ByteArray(); data.readBytes(inputdata); trace("inputdata.bytesAvailable", inputdata.bytesAvailable); trace("uncompress_length:", uncompress_length); inputdata.position = 0; //解码 var uncompress_bytes:ByteArray = huff_uncompress(inputdata, inputdata.bytesAvailable, uncompress_length); uncompress_bytes.position = 0; trace("uncompress:", uncompress_bytes.bytesAvailable, "bytes"); var str:String = uncompress_bytes.readMultiByte(uncompress_bytes.bytesAvailable, "gbk"); trace(str); } //-------------------------------------------------- //压缩测试 /* var compress_length:uint = huff_compress_size(); trace("compress_length", compress_length); */ /**/ uncompress_bytes.position = 0; trace("uncompress_bytes.bytesAvailable:", uncompress_bytes.bytesAvailable); var compress_bytes:ByteArray = huff_compress(uncompress_bytes, uncompress_bytes.bytesAvailable); var compress_length:uint = huff_compress_size(); compress_bytes.position = 0; trace("compress_length:", compress_length); trace("compress:", compress_bytes.bytesAvailable, "bytes"); compress_bytes.position = 0; while (compress_bytes.bytesAvailable > 0) { var byte:uint = compress_bytes.readByte() & 0xff; trace(byte.toString(16)); } /**/ } //对应huff.gg中的三个导出API //方便参数类型检查 public function huff_uncompress(bytes:ByteArray, insize:int, outsize:int):ByteArray { return hufflib.huff_uncompress(bytes, insize, outsize); } public function huff_compress(bytes:ByteArray, insize:int):ByteArray { //trace("insize:", insize); return hufflib.huff_compress(bytes, insize); } public function huff_compress_size():int { return hufflib.huff_compress_size(); } } }
-------------------------------------------------
纯AS3实现的主入口代码如下:
package huff { import flash.display.Sprite; import flash.utils.ByteArray; import flash.utils.Endian; public class CodecTest extends Sprite { public function CodecTest() { /* trace("hello, world"); var bytes:ByteArray = new ByteArray(); bytes.writeByte(0xF8); bytes.writeByte(0xF8); bytes.position = 0; var stream:Bitstream = new Bitstream(bytes); try { //testReadBit(stream); testReadBit(stream); testReadBit(stream); testReadBit(stream); testReadBit(stream); testReadBit(stream); testReadBit(stream); testReadBit(stream); testRead8Bits(stream); testRead8Bits(stream); testRead8Bits(stream); }catch (e:Error) { trace(e.getStackTrace()); } //---------------------------------------------------- stream = new Bitstream(); stream.writeBits(0xF8, 8); stream.writeBits(0xF8, 8); stream.rewind(); try { //testReadBit(stream); testReadBit(stream); testReadBit(stream); testReadBit(stream); testReadBit(stream); testReadBit(stream); testReadBit(stream); testReadBit(stream); testRead8Bits(stream); testRead8Bits(stream); testRead8Bits(stream); }catch (e:Error) { trace(e.getStackTrace()); } */ var stream:Bitstream = new Bitstream(); //-------------------------------------------------- [Embed(source='../../lib/output.dat', mimeType='application/octet-stream')] var output_dat:Class; //注意,是强制转换,不是new var data:ByteArray = ByteArray(new output_dat()); trace("ByteArray.length = ", data.length); data.position = 0; //不知为何,与网络传输时正好相反 //0xFF000000 --readUnsignedInt--> 0xFF data.endian = Endian.LITTLE_ENDIAN; if (data.bytesAvailable > 0) { // 第一个32位数是解压长度 var uncompress_length:uint = data.readUnsignedInt(); trace("uncompress_length:", uncompress_length); stream = new Bitstream(data); var uncompress_bytes:ByteArray = new ByteArray(); stream.uncompress(uncompress_bytes, uncompress_length); uncompress_bytes.position = 0; trace("uncompress:", uncompress_bytes.bytesAvailable, "bytes"); var str:String = uncompress_bytes.readMultiByte(uncompress_bytes.bytesAvailable, "gbk"); trace(str); } //-------------------------------------------------- //压缩测试 uncompress_bytes.position = 0; var compress_bytes:ByteArray = new ByteArray(); var stream2:Bitstream = new Bitstream(); var compress_length:uint = stream2.compress(uncompress_bytes, compress_bytes, uncompress_bytes.bytesAvailable); compress_bytes.position = 0; trace("compress_length:", compress_length); trace("compress:", compress_bytes.bytesAvailable, "bytes"); compress_bytes.position = 0; while (compress_bytes.bytesAvailable > 0) { var byte:uint = compress_bytes.readByte() & 0xff; trace(byte.toString(16)); } } public function testRead8Bits(stream:Bitstream):void { var i:uint = stream.read8Bits(); trace(i.toString(16)); } public function testReadBit(stream:Bitstream):void { var i:uint = stream.readBit(); trace(i); } } }
--------------------------
两种实现的输出如下所示,
* 解压出"Hello World!",
* 压缩除了alchemy没有加入开头4字节的长度外,其余和AS3版相同。
---------------------
alchemy实现的输出:
inputdata.bytesAvailable 16
uncompress_length: 12
uncompress: 12 bytes
Hello World!
uncompress_bytes.bytesAvailable: 12
compress_length: 16
compress: 16 bytes
cd
f1
4
90
21
9b
33
21
5e
72
32
b7
d0
b4
eb
1c
------------------------
纯AS3实现的输出
uncompress_length: 12
uncompress: 12 bytes
Hello World!
compress_length: 16
compress: 20 bytes
c
0
0
0
cd
f1
4
90
21
9b
33
21
5e
72
32
b7
d0
b4
eb
1c
------------------------
结论:
Alchemy和纯AS3都可以处理ByteArray数据,进行类似数据压缩和解压的复杂工作。
从上面的实践可以发现Alchemy开发的一些注意事项:
* 开发环境比较难搭建,需要耐心寻找原因。
* 难于调试。需要使用全局函数sztrace跟踪代码的去向。
* 如果遗漏了.o文件仍可以编译swc成功,但会导致运行期错误,所以写Makefile时必须十分小心。
* .gg文件必须把公共的C代码放在开头的大括号内。导出API放在大括号外。
代码在svn中:
svn://www.svnhost.cn/weimingtom_reversi/alchemy
相关推荐
[1/2]共包含2个部分,此为第1部分 ...包含使用Alchemy所需的: Perl zip gcc / g++ 版本 setup-version: 2.697 如需下载其他内容,下载镜像请选择: http://ftp.jaist.ac.jp 会自动生成目录,已下载的内容会跳过: ...
玩炼金技术人有福气了,一键安装就可以直接使用的 alchemy 环境。
[2/2]共包含2个部分,此为第2部分 ...包含使用Alchemy所需的: Perl zip gcc / g++ 版本 setup-version: 2.697 如需下载其他内容,下载镜像请选择: http://ftp.jaist.ac.jp 会自动生成目录,已下载的内容会跳过: ...
国际化Alchemy 的 i18n 插件
Alchemy是Adobe的一个实验项目,其目的是可以让C,C++的源代码编译成能够运行在开源的Adobe Actionscript VM2虚拟机上的技术。这项技术的目的是为了让大家可以利用数量众多的C,C++现成代码.
要安装 Yeoman,您只需要执行以下操作: $ npm install -g yo要从 npm 安装 generator-alchemy,请运行: $ npm install -g generator-alchemy-quickstart现在,您只需要创建要放置项目的文件夹并启动生成器: $ yo...
软件名称:小炼金术:Little Alchemy APK名称:com.sometimeswefly.littlealchemy 最新版本:1.1.1 支持ROM:4.0及更高版本 界面语言:英文软件 软件大小:3.99 M 开发者:Recloak 小炼金术 Little Alchemy是一款...
Flash页游未来新技术:Adobe Alchemy
这是旨在复兴Alchemy2项目的尝试。 Alchemy 2.0包含原始Alchemy系统中的以下算法: 判别权重学习(投票感知器,共轭梯度和牛顿法) 生殖体重学习 结构学习 命题MAP / MPE推断(包括内存有效) 命题和惰性概率...
Alchemy Eye是一个专门设计用来监控从您电脑连线的网络上其它主机状况的软件,网管人员可以藉由这个简单实用的工具随时监控远端的主机是否仍然正常的运作,而不用亲自坐在主机面前操作,这项功能不仅可以有效的取代...
Alchemy3D——Flash3D引擎
编辑-》首选参数-》actionscript-》actionscript 3.0设置-》库路径-》浏览到swc文件,然后选择那个shineMP3_alchemy.swc 另外,在“发布设置”的flash选项里,也要勾选“发布swc” 不需要通过后台或者fms,直接在...
马尔可夫逻辑网络工具包alchemy,感兴趣的可以相互交流一下
Laravel开发-alchemy-api 用于炼金术的Laravel包装。
手机游戏 alchemy380全攻略 在原有的360基础上,将新增添的20中已经重点标注粗来了喔~ 相信会有帮助滴~
安装节点: : 安装Gulp: npm install -g gulp 安装Yeoman: npm install -g yeoman 安装Symfony Alchemy: npm install -g generator-symfony-alchemy 现在,所有依赖项都已就位,您可以安装Symfony Alchemy。...
alchemy-mock:SQLAlchemy模拟助手
alchemy-annotations.zip,炼金术收藏的一部分。
安装 npm i --save es-alchemy 设置 概述如何使用 : 定义数据模型 根据数据模型定义索引 为索引生成(版本化)模式,在Elasticsearch中创建它们,并对它们进行别名以进行查询 获取索引的源映射中定义的输入数据并...
RMI Alchemy™ Processors AutoBoot Boot Loader User’s Guide