45fan.com - 路饭网

搜索: 您的位置主页 > 手机频道 > 阅读资讯:如何在BREW中使用Gzip压缩减少应用程序包的大小?

如何在BREW中使用Gzip压缩减少应用程序包的大小?

2016-09-03 19:22:06 来源:www.45fan.com 【

如何在BREW中使用Gzip压缩减少应用程序包的大小?

目前在无线增值业务中,涉及图像、声音和数据处理的应用占很大比例,但由于掌上系统的存储能力和处理能力受到很大限制,因此目前BREW应用的大小一般都要求比较校如果图像在整个应用中占很大比例,那么减小图像的存储空间就成为非常迫切的要求。本文从一个开发者的角度阐述了一种解决存储空间限制的方法,使用Gzip压缩工具结合BREW IUnzipAStrem接口可以将资源的大小减小到原来的1/3左右。

大多数BREW开发者都回为手机的存储空间问题而苦恼吧,做个简单的小游戏,图片资源也要占个几十上百KB,有人试图用PNG图片来替代BMP图片,但在实际操作的时候会遇到不少的问题,一些底端的设备根本不支持PNG图片,即使支持在使用的时候也经常会遇到一些莫名其妙的问题。大家仔细看看BREW SDK的API文档,不难发现其中有一个IUnzipAStream接口,高通给出的描述如下:IUnzipAStream接口用于扩展IAStream接口,允许将压缩的IAStream解压并以流的方式读龋(此接口只能解压缩使用GZip算法压缩的数据)。

我的解决方案大致如下:

1. 使用Gzip压缩工具(Linux下使用GZip,Windows下使用7-Zip)压缩BMP图片、声音、数据等资源;

2. 把压缩后的文件作为资源加入到.bar文件中;

3. 在应用程序中使用IUnzipAStream接口来解压相应的数据。

注:PNG图片不能用GZip算法压缩,因为PNG图片本身已经进行了压缩处理,再用GZip算法压缩不会减少,在一些情况下甚至会变大。

了解了大体步骤之后我们来简单了解一下GZip算法。GZIP最早由Jean-loup Gailly和Mark Adler创建,用于UNIX系统的文件压缩。我们在Linux中经常会用到后缀为.gz的文件,它们就是GZIP格式的。现今已经成为Internet上使用非常普遍的一种数据压缩格式,或者说一种文件格式。HTTP协议上的GZIP编码是一种用来改进WEB应用程序性能的技术。大流量的WEB站点常常使用GZIP压缩技术来让用户感受更快的速度。

GZIP文件由1到多个“块”组成,实际上通常只有1块。每个块包含头、数据和尾三部分。块的概貌如下:

| ID1 | ID2 | CM | FLG | MTIME | XFL | OS | 额外的头字段 | 压缩数据 | CRC232 |ISIZE

这里强调一下和我们应用有关的块的最后一个字段ISIZE,共4个字节,存储了未压缩前数据的长度,这在解压程序中很重要。

应用程序中如何解压缩呢?我们看看下面一段解压的代码。

static uint32 UnZip(theApp *pi,int16 picId,byte **ppBuffer)

{

uint32size,len,ret;

void*pSource; //存放压缩图片的源数据

IMemAStream*memStream;

IUnzipAStream*unzipStream;

byte*pSourceBuff; //存放压缩图片的有效数据

byte*tempBuff; //存放解压图片的数据

AEEImageInfo info;

ISHELL_CreateInstance(pi->m_App.m_pIShell,AEECLSID_MEMASTREAM,(void **)&memStream);

ISHELL_CreateInstance(pi->m_App.m_pIShell,AEECLSID_UNZIPSTREAM,(void **)&unzipStream);

//载入压缩图片的源数据

pSource = ISHELL_LoadResDataEx(pi->m_App.m_pIShell,RES_FILE,picId,RESTYPE_IMAGE,NULL,&size);

size = size-*((byte*)pSource); //计算压缩图片有效数据的长度

pSourceBuff = (byte*)MALLOC(size);

MEMCPY(pSourceBuff,(byte*)pSource+*((byte *)pSource),size); //从源数据中拷贝出有效数据

ISHELL_FreeResData(pi->m_App.m_pIShell,pSource); //释放载入的源数据

//把内存流和压缩图片相关联

IMEMASTREAM_Set(memStream,pSourceBuff,size,0,FALSE);

//把IUNZIPASTREAM对象设置为从内存流中读取数据

IUNZIPASTREAM_SetStream(unzipStream,(IAStream *)memStream);

//计算解压后图片的大小

len = (*(pSourceBuff+size-4))

+(*(pSourceBuff+size-3)<<8)

+(*(pSourceBuff+size-2)<<16)

+(*(pSourceBuff+size-1)<<24);

tempBuff = (byte *)MALLOC(len);

//读取解压图片的数据流到tempBuff

ret = IUNZIPASTREAM_Read(unzipStream,tempBuff,len);

if (ret>0)

{

//如果没读完就继续读

while (ret<len)

{

ret += IUNZIPASTREAM_Read(unzipStream,(byte*)tempBuff+ret,len-ret);

}

IMEMASTREAM_Release(memStream); //释放内存流

memStream = NULL;

IUNZIPASTREAM_Release(unzipStream); //释放解压流

unzipStream = NULL;

//图片转换为位图放在内存中

*ppBuffer = CONVERTBMP(tempBuff,&info,FALSE);

FREE(tempBuff);

return len;

}

else if(ret == AEE_STREAM_WOULDBLOCK||ret == 0)

{

IMEMASTREAM_Release(memStream);

memStream = NULL;

IUNZIPASTREAM_Release(unzipStream);

unzipStream = NULL;

if (tempBuff)

{

FREE(tempBuff);

}

return 0;

}

IMEMASTREAM_Release(memStream);

memStream = NULL;

IUNZIPASTREAM_Release(unzipStream);

unzipStream = NULL;

return 0;

}

仔细分析这段代码,大概分为如下几步:

1. 用工厂方法产生内存流的指针memStream 和解压流的指针unzipStream;

2. 从资源文件中读取需要解压图片的数据,存放在pSource中;

3. 将有效的压缩图片数据拷贝到pSourceBuff中,并释放pSource;

4. 把内存流memStream和存放压缩图片数据的缓存相关联;

5. 把解压流和内存流相关联,从内存流memStream中读取压缩图片数据;

6. 根据压缩图片数据的最后4个字节计算出解压后图片的大小,并申请内存空间;

7. 从解压流unzipStream中读取解压后的数据存放到tempBuff中;

8. 释放内存流和解压流,用CONVERTBMP宏把解压后的图片数据转换为本地格式存放到ppBuff中;

9. 释放存放解压图片的内存;

细心一点可能会发现两个问题:

1. 为什么存放压缩图片数据的缓存pSourceBuff没有释放?

2. 存放本地格式位图的缓存ppBuffer事先并没有申请内存空间

其实当pSourceBuff和内存流memStream关联之后,当调用IMEMASTREAM_Release释放内存流时就会自动释放和流关联的数据缓冲区,不需要手动释放。而CONVERTBMP宏也会自动申请大小适合的内存空间。

同样声音和数据的解压函数和上面的函数大体相同,只是省去用CONVERTBMP宏进行转换的步骤。

这种方法对图片的压缩效果非常明显,可以达到PNG图片的压缩效果,对数据文件的压缩效果也比较明显,对声音文件的压缩效果可能要差一些。总体来说,这种方法可以大幅度减少应用程序的大小,而不影响质量,是为存储空间苦恼的开发者的一个不错的选择。

 

本文地址:http://www.45fan.com/a/luyou/71933.html
Tags: 压缩 BREW gzip
编辑:路饭网
  • 上一篇:流媒体定义
  • 下一篇:J2ME简明教程分析
  • 关于我们 | 联系我们 | 友情链接 | 网站地图 | Sitemap | App | 返回顶部