在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的几个成员函数。
- SetPos。确定要进行操作的像素点。
- SetPixel。该函数有多个版本。这里传递了源位图的指针,其含义是将源位图的像素值读取出来再将其设置为目标位图的像素值。
- IncYPos和IncXPos。以像素为单位在X或Y方向上增量。
为了让其旋转之后能够复原,程序将目标位图拷贝给源位图,为的是再一次旋转时能够复原。复制位图的函数是Duplicate,它需要位图的句柄作为参数。CFbsBitmap的Handle()函数可以获取位图的句柄。
旋转后的效果如下图所示。