flash swf 文件宽高修改VC实现
最近因为项目需求,学习了flash as3.0来做了一个特定功能的动画。
开发工具CS6,格式选了swf9,生成的swf放到web服务器上,用户通过浏览器加载运行。
该swf档内完全由as3.0脚本构成。
做过flash的人知道,IDE上有界面可以设置该swf的舞台宽高,这个生成swf文件时会编译进去。
加载该swf的htm文档内会设置该web将提供怎样的宽高来展示该swf,同时会设置对齐方式。
如果swf的宽高和htm设置的宽高不一致的话,那么你要展示的swf内容的原点就不是web页上展示swf的框的left-top。
因为项目最终将提供给各种用户,所以无法提前知道用户期望的舞台宽高。
这里就产生了一个需求:可不可以修改之前做好的swf文件内的舞台宽高?
这样就可以保证htm展示swf的框的宽高和swf档的宽高一样,两个原点就重合。
通过查找swf file format specification version 10文档发现,
SWF file structure
<Header><fileattributes tag><tag><tag>...<end tag>
而<Header>里边就放了舞台宽高。
swf file第9个字节开始是一个RECT结构,里边放舞台宽高。
swf file前4个字节是标示文件格式,包括是否压缩deflate
swf file第5到第8字节是整个swf文件的长度,实际试验发现是指未压缩前的长度。
RECT是一个奇怪的定义,头5个bit是说用多少bit来表示xMin\xMax\yMin\yMax4个参数,试验发现每个参数用15bit表示。
当然程序可以计算(5+bit_sum*4)/8,如果有余数就加1。
如果swf是经过deflate压缩的话,那么是从第9个字节开始压缩的,也就是RECT开始压缩,所以需要解压缩,重新计算后再用deflate压缩重组。
代码大致是这样:
1 二进制打开目标swf文件,将所有内容都读取到内存BYTE数组里头。
2 头四个字节可以判断是否经过deflate压缩,接下来4个字节是未压缩前的swf文件长度
3 利用zlib的uncompress函数解压缩第9个字节后的内容到新的BYTE数组里头。
4 根据RECT的格式定义,解析当前的xMin\xMax\yMin\yMax和RECT所占用的字节数。
5 根据RECT的格式定义,制作你想要设置的xMin\xMax\yMin\yMax和计算RECT所占用的字节数。
6 重新计算新的swf文件的长度,并修改头8个字节后4个字节表示文件长度,如果新旧RECT字节数一样就不需要重新计算修改。
7 将新的RECT和去掉旧的RECT后的数据合并,然后利用zlib的compress函数压缩文件。
8 将修改长度后的8个字节和压缩过后的字节组合,写到新的文件里,文件扩展名swf。
下面是测试代码:
//以下代码针对经deflate压缩的swf9文件
CxIOFile hFile;
bool ret = hFile.Open("D:\\FlaPrj\\flash.swf","r+b");
if(!ret)return;
long size = hFile.Size();
BYTE *prbyte = new BYTE[size];
hFile.Read(prbyte,size,1);
DWORD dwswflen = prbyte[4] | (prbyte[5]<<8) | (prbyte[6]<<16) | (prbyte[7]<<24);
unsigned long deflen = dwswflen-8;
BYTE *pwbyte = new BYTE[deflen];
//解压缩
uncompress(pwbyte,&deflen,&prbyte[8],size-8);
//改变宽高 max range:1000*1000
{
WORD flashwidth = 480;
WORD flashheight = 500;
WORD xMin=0*20;
WORD xMax=flashwidth*20;
WORD yMin=0*20;
WORD yMax=flashheight*20;
memset(pwbyte,0,9);
pwbyte[0] |= 0x78+((xMin>>12)&0x7);
pwbyte[1] |= ((xMin>>4)&0xff);
pwbyte[2] |= ((xMin<<4)&0xf0);
pwbyte[2] |= ((xMax>>11)&0xf);
pwbyte[3] |= ((xMax>>3)&0xff);
pwbyte[4] |= ((xMax<<5)&0xe0);
pwbyte[4] |= ((yMin>>10)&0x1f);
pwbyte[5] |= ((yMin>>2)&0xff);
pwbyte[6] |= ((yMin<<6)&0xc0);
pwbyte[6] |= ((yMax>>9)&0x3f);
pwbyte[7] |= ((yMax>>1)&0xff);
pwbyte[8] |= ((yMax<<7)&0x80);
}
//再压缩
BYTE *prcbyte = new BYTE[deflen];
compress(prcbyte,&deflen,pwbyte,deflen);
hFile.Close();
//保存新的文件
ret = hFile.Open("D:\\FlaPrj\\flash1.swf","wb");
if(!ret)goto Exit;
hFile.Write(prbyte,8,1);
hFile.Write(prcbyte,deflen,1);
hFile.Close();
Exit:
delete[] prcbyte;
delete[] prbyte;
delete[] pwbyte;