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
相关推荐
《全图Alchemy安装详解》 Alchemy,源自Adobe的实验项目,旨在将C和C++的源代码编译成可在Adobe Actionscript VM2虚拟机上运行的程序,为开发者提供了利用大量现有C、C++代码资源的可能性。本文将详细介绍在Windows...
《Alchemy-i18n:实现Alchemy的多语言支持》 在现代Web开发中,为用户提供多语言支持已经成为了一项重要的需求。Alchemy-i18n是专门为Alchemy框架设计的一个国际化插件,旨在帮助开发者轻松地将他们的网站或应用...
[1/2]共包含2个部分,此为第1部分 ...包含使用Alchemy所需的: Perl zip gcc / g++ 版本 setup-version: 2.697 如需下载其他内容,下载镜像请选择: http://ftp.jaist.ac.jp 会自动生成目录,已下载的内容会跳过: ...
玩炼金技术人有福气了,一键安装就可以直接使用的 alchemy 环境。
6. **使用Alchemy API**:现在,你可以通过依赖注入或服务容器在任何需要的地方使用Alchemy API。例如,在控制器中: ```php use App\Facades\AlchemyApi; public function analyzeText($text) { $result = ...
Alchemy 的安装 在开始使用 Alchemy 之前,需要先安装以下软件: * Alchemy * Cygwin * FlexSDK * Java(JRE) Alchemy 的安装步骤如下: 1. 下载 Alchemy,并将其解压缩到 C:/alchemy 路径下。 2. 安装 Java,...
- **全面支持**:Alchemy 支持包括模板、异常、运行时类型信息 (RTTI) 和标准模板库 (STL) 在内的各种高级 C/C++ 功能,确保了代码的完整性和健壮性。 - **跨平台兼容**:Alchemy 编译后的代码可以在移动设备和 PC ...
Alchemy3D是一款强大的Flash3D引擎,它为开发者提供了在Adobe Flash平台上构建高度交互性和视觉效果丰富的3D应用的能力。这款引擎的出现,极大地扩展了Flash的潜力,使其不仅仅局限于2D动画和游戏,而是能够涉足更为...
[2/2]共包含2个部分,此为第2部分 ...包含使用Alchemy所需的: Perl zip gcc / g++ 版本 setup-version: 2.697 如需下载其他内容,下载镜像请选择: http://ftp.jaist.ac.jp 会自动生成目录,已下载的内容会跳过: ...
6. **扩展与定制**:Alchemy是开源的,允许研究人员和开发者对其进行修改和扩展,以适应特定的应用场景或研究需求。 在实际应用中,马尔科夫逻辑网和Alchemy工具包常被用于知识图谱的构建、推荐系统、自然语言处理...
2. **学习算法**:Alchemy包含了多种权重学习算法,如Maximum-Marginal Likelihood(MML)、Annealed Importance Sampling(AIS)等,这些算法用于从数据中学习逻辑规则的权重,以最大化模型与观测数据的拟合度。...
2. **注解定义**:Alchemy-annotations定义了一系列自定义注解,如@Inject、@Singleton等,这些都是为了在应用程序中实现依赖注入、状态管理和其他高级功能而设计的。通过这些注解,开发者可以声明式地指定代码的...
Alchemy 是 Adobe 推出的一个工具,它允许开发者将 C 或 C++ 代码转换为 ActionScript 3 可以调用的格式,以提高 Flash 平台的性能。在本教程中,我们将学习如何使用 Alchemy 将 C 代码转换为 SWC 文件,以便在 ...
《SQLAlchemy模拟助手:alchemy-mock深度解析》 在Python的数据库操作中,SQLAlchemy以其强大的ORM(对象关系映射)功能,深受开发者喜爱。然而,在进行单元测试时,直接与真实数据库交互可能会带来一系列问题,如...
要安装 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是一款...
这是旨在复兴Alchemy2项目的尝试。 Alchemy 2.0包含原始Alchemy系统中的以下算法: 判别权重学习(投票感知器,共轭梯度和牛顿法) 生殖体重学习 结构学习 命题MAP / MPE推断(包括内存有效) 命题和惰性概率...
名称:Alchemy 化合物数据集 来源:[29] 参考文献 时间范围:覆盖多个时间点,累计收集202579个样本 特征概览: - 数据规模:包含202579份样本 - 结构特性:每份数据包含平均10.10个节点和10.44个边 - 属性种类:...
《RMI Alchemy Processors AutoBoot Boot Loader User's Guide》是关于如何安装、使用及定制适用于RMI Alchemy系列处理器的AutoBoot多平台引导加载程序的手册。该文档主要针对的处理器包括:Au1000™、Au1100®、Au...
Alchemy Eye是一个专门设计用来监控从您电脑连线的网络上其它主机状况的软件,网管人员可以藉由这个简单实用的工具随时监控远端的主机是否仍然正常的运作,而不用亲自坐在主机面前操作,这项功能不仅可以有效的取代...