在Symbian中,位图的管理由字体位图服务器负责,该服务器提供了专门处理位图的CFbsBitmap类。
应用程序中所有的位图信息都放在一个叫做多位图文件的包中(后缀为.mbm),在mbm文件中对每一个位图都有一个枚举类型的值来引用,这个枚举值在.mbg文件中定义。Symbian对位图的操作包括构建多位图文件、位图的创建、装载和位图处理等。下面介绍详细步骤。
1.生成多位图文件
如果应用程序要使用多位图文件,通常的做法是将所有的位图添加到多位图文件中,然后通过引用每一个位图的枚举来使用位图。
首先需要在应用程序的mmp文件中把要使用的位图列举出来。
START BITMAP samplecontrol.mbm // (1)
HEADER // (2)
SOURCEPATH ../bmp // (3)
TARGETPATH /system/apps/samplecontrol // (4)
SOURCE c12 girl.bmp // (5)
END
在mmp文件中(1)句定义多位图文件必须以START BITMAP开头。后面是多位图文件的文件名,注意多位图文件的文件名应该和应用程序的名称一致,只是扩展名为.mbm。接下来(2)句是一个HEADER字段,表示定义位图文件开始。(3)句SOURCEPATH字段指出位图文件的存放位置,这里应该使用相对路径。(4)句TARGETPATH是多位图文件,也就是samplecontrol.mbm存放的位置,通常放在"/system/apps/应用程序名"这个路径下面。(5)句的SOURCE字段列出每一个位图文件,一个位图文件使用一个SOURCE字段。c12用来指定该位图文件的色深。指定色深的语法格式为c[depth]。c表示彩色图片,depth用一个整数值表示深度,这里为12。最后以END表示结束。
定义好mmp文件后,应用程序会产生一个对应的.mbg文件。应用程序在需要使用位图的文件中必须加上对.mbg文件的包含。生成的mbg文件是一个文本文件,它包含了位图枚举的定义。定义如下所示。
enum TMbmSamplecontrol
{
EMbmSamplecontrolGirl
};
EMbmSamplecontrolGirl是程序要用到的位图的枚举值。枚举值的格式为EMbm+应用程序名+位图文件名。应用程序就是使用这些枚举值来使用位图文件的。
2.创建并加载位图
位图枚举值可以直接使用。但是如果要对位图进行处理,那么就应该创建位图对象。
void CSampleControlContainer::LoadBitMap()
{
iBitmap = new (ELeave) CFbsBitmap(); // (1)
_LIT(KMBMFILE, "//system//apps//samplecontrol//samplecontrol.mbm");
TFileName file(KMBMFILE);
User::LeaveIfError(CompleteWithAppPath(file));
User::LeaveIfError(iBitmap->Load(file, EMbmSamplecontrolGirl));
}
(1)句中iBitmap是CFbsBitmap类的指针,函数首先创建了CFbsBitmap类的对象,并将该对象赋给iBitmap。接下来就可以调用CFbsBitmap的Load()函数装载位图。Load()函数需要多位图文件的路径以及装载位图的枚举值,指定装载的是哪个位图;mbm文件的路径由_LIT文字给出,该文件用于初始化TFileName对象。ComplateWithAppPath()函数用于给路径添加上诸如驱动器等信息。最后将mbm路径和位图枚举值传递给Load()函数就实现了位图的装载。
3.显示视图
显示视图是在容器的Draw()函数中实现。CWindowGc提供了两个函数DrawBitMap()和Bitblt()来实现位图的绘制,这两个函数的原型为。
virtual void DrawBitmap(const TPoint& aTopLeft, const CFbsBitmap* aSource);
virtual void Bitblt(const TPoint& aPos, const CFbsBitmap* aDevice);
除了参数不一样外,它们的效率也不相同。DrawBitmap()的效率要低一些,因为它要执行位图的缩放,而Bitblt()只需要进行位图块的传输,效率较高。因此在显示位图时尽量使用Bitblt()。
void CSampleControlContainer::Draw(const TRect& aRect) const
{
CWindowGc& gc = SystemGc();
TPoint topLeft(30, 30);
gc.BitBlt(topLeft, iBitmap);
}
此程序运行的结果如下图所示。
4.位图处理
位图处理包括位图的旋转、缩放、各式转换、编码和解码等处理方式。这会涉及到字体位图服务器的许多类的使用以及活动对象的知识。处理位图的旋转有很多方法,可以使用API函数,但这需要使用活动对象,也可以在像素的基础上进行操作。
函数RotateBitmap()给出了位图旋转的代码。
void CSampleControlContainer::RotateBitMap()
{
iTargetBitmap = new (ELeave) CFbsBitmap();
TSize targetSize = iBitmap->SizeInPixels();
User::LeaveIfError(iTargetBitmap->Create(TSize(targetSize.iHeight,
targetSize.iWidth), iBitmap->DisplayMode()));
TBitmapUtil srcBitmapUtil(iBitmap);
TBitmapUtil targetBitmapUtil(iTargetBitmap);
srcBitmapUtil.Begin(TPoint(30, 30));
targetBitmapUtil.Begin(TPoint(30, 30), srcBitmapUtil);
TInt xPos;
for (TInt yPos = 0; yPos < targetSize.iHeight; yPos++)
{
srcBitmapUtil.SetPos(TPoint(0, yPos));
targetBitmapUtil.SetPos(TPoint(yPos, 0));
for (xPos = 0; xPos < targetSize.iWidth; xPos++)
{
targetBitmapUtil.SetPixel(srcBitmapUtil);
srcBitmapUtil.IncXPos();
targetBitmapUtil.IncYPos();
}
}
srcBitmapUtil.End();
targetBitmapUtil.End();
iBitmap->Duplicate(iTargetBitmap->Handle());
}
在这段代码中,位图的旋转采用了在像素级别上进行操作。首先需要定义两个位图对象,一个是源位图,另一个是目标位图,目标位图是源位图的旋转。
为了确定目标位图的尺寸,必须获得原位图的尺寸,将源位图旋转后的尺寸以及源位图的显示模式传递给Create()函数,就建了目标位图对象。获取源位图的显示模式是调用DisplayMode()函数。
为了能够在像素级别上操作位图,需要用到TBitmapUtil类,该类提供了在像素级别上操作的函数,源位图和目标位图都要用到TBitmapUtil类,因此用这两个位图初始化TBitmapUtil的对象。然后分别调用两个TBitmapUtil对象的Begin()函数。在位图操作完毕后要调用End()函数。这样做的目的是为了锁定位图使用的堆。
接下来的代码是位图旋转的操作。它的基本思想是从源位图中获取像素属性,再将旋转后该像素应该所在的位置上设置目标位图像素的值。这里用到TBitmapUtil的几个成员函数。
为了让其旋转之后能够复原,程序将目标位图拷贝给源位图,为的是再一次旋转时能够复原。复制位图的函数是Duplicate,它需要位图的句柄作为参数。CFbsBitmap的Handle()函数可以获取位图的句柄。
旋转后的效果如下图所示。