下面提供了一个小例子演示了如何一步步的在使用图像处理的程序里面高效率访问图像数据: 1 使用S60平台的图像变换框架来从文件(例如jpg/png/gif等)中载入图像。 2 与外界的进程同步,这样可以分块地进行图像载入。 3 进行简单退色,将图像转换为256色-12位色深的索引位图。
附注:这个例子用了嵌套调用(嵌套了 CActiveScheduler::Start(), CActiveScheduler:Stop())。如果滥用这种方法会有危险性。但如果小心地使用则是一条简单的途径,并且工作得非常好。
下面是类CImageLoader和CTexture的源代码, CTexture 基本上就是一个融合了数据、调色板以及高度和宽度的图像。但由于我将它直接用于3D纹理,所以我直接将其叫做Texture。源代码已经添加了注释,应该容易被理解。它主要是打算给那些希望从中间学到东西的人使用的,简单的拷贝-粘贴不受欢迎。
texture.h:
#ifndef __TEXTURE_H #define __TEXTURE_H
#include <e32base.h>
/** * 代表一个纹理(在纹理变换例程中使用) */ class CTexture : public CBase { public: /*!
NewL函数 描绘如何构造一个CTexture 对象 参数:aWidth 纹理宽度(必须是2的3~10次方乘幂),所以它的值的范围是8~1024 aHeight 纹理高度 aWidthShift 等于 log2(aWidth) aPalette 调色板信息 aData */ static CTexture * NewL(TInt aWidth, TInt aHeight, TInt aWidthShift, TUint16 *aPalette, TUint8 *aData); ~CTexture();
TInt GetWidth() { return iWidth; } TInt GetHeight() { return iHeight; } TInt GetWidthShift() { return iWidthShift; } TUint16 * GetPalette() { return iPalette; } TUint8 * GetData() { return iData; }
private: CTexture(); void ConstructL(TInt aWidth, TInt aHeight, TInt aWidthShift, TUint16 *aPalette, TUint8 *aData); TInt iWidth; TInt iHeight; TInt iWidthShift; TUint16 *iPalette; TUint8 *iData; };
#endif
--------------------------------------------------------------------------------
texture.cpp:
#include "texture.h"
CTexture * CTexture::NewL(TInt aWidth, TInt aHeight, TInt aWidthShift, TUint16 *aPalette, TUint8 *aData) { CTexture *texture = new (ELeave) CTexture(); CleanupStack::PushL(texture); texture->ConstructL(aWidth, aHeight, aWidthShift, aPalette, aData); CleanupStack::Pop(); // 调色
return texture; }
void CTexture::ConstructL(TInt aWidth, TInt aHeight, TInt aWidthShift, TUint16 *aPalette, TUint8 *aData) { iWidth = aWidth; iHeight = aHeight; iWidthShift = aWidthShift; iData = aData;
// 创建调色板并将其复制到本地指针 iPalette = (TUint16 *)User::AllocL(256 * sizeof(TUint16)); Mem::Copy(iPalette, aPalette, 256 * sizeof(TUint16)); }
CTexture::CTexture() { }
CTexture::~CTexture() { User::Free(iData); User::Free(iPalette); }
--------------------------------------------------------------------------------
imageloader.h:
#ifndef __IMAGELOADER_H #define __IMAGELOADER_H
#include <e32base.h> #include <MdaImageConverter.h> #include <fbs.h>
#include "texture.h"
/** * Color frequency array item. */ struct FreqItem { TUint16 freq; TUint16 color; };
/** * 装载图像的实用程序 */ class CImageLoader : public CActive, public MMdaImageUtilObserver { public: /** * 装载纹理的错误代码 */ enum TTextureLoadingError { KBadImageWidth = 1666001 };
/*! LoadTextureL函数 叙述如何载入一个图像文件,并将其转换为CTexture 对象 参数: aFilename 图像文件名 */ static CTexture * LoadTextureL(const TDesC &aFilename);
// 从 MMdaImageUtilObserver virtual void MiuoOpenComplete(TInt aError); virtual void MiuoConvertComplete(TInt aError); virtual void MiuoCreateComplete(TInt aError);
// 从 CActive void RunL(); void DoCancel(); private: CImageLoader(const TDesC *aFilename); ~CImageLoader(); void ReadImageL(); void CreateTexture(); void SortFreqTable(TInt aLeft, TInt aRight); TUint8 FindNearestColor(TUint16 aColor, TInt aPaletteSize);
TDesC *iFilename; CMdaImageFileToBitmapUtility *iConverter; RTimer *iTimer; CTexture *iTexture; CFbsBitmap *iBitmap; TInt iErrorCode; FreqItem *iFreqTable; };
#endif
--------------------------------------------------------------------------------
imageloader.cpp:
#include <e32math.h>
#include "imageloader.h"
#define IMAGEREAD_TIMEOUT 5 * 1000 * 1000
////////////////////////////////////// // CImageLoader //////////////////////////////////////
void CImageLoader::DoCancel() { // 退出计数器 iTimer->Cancel(); iTimer->Close();
// 停止阻塞 ReadTextureL() CActiveScheduler::Stop(); }
void CImageLoader::RunL() { // 超时错误,图像载入失败 Cancel(); iTimer->Close(); }
CTexture * CImageLoader::LoadTextureL(const TDesC &aFilename) { // 建立新的载入器实例 CImageLoader *loader = new (ELeave) CImageLoader(&aFilename); CleanupStack::PushL(loader);
// 将载入器添加至活动目录 CActiveScheduler::Add(loader);
// 图形读取和转换操作 loader->ReadImageL();
// 开始一个嵌套调用 CActiveScheduler::Start();
if( loader->iTexture == NULL ) { // cleanupstack销毁实例 User::Leave(loader->iErrorCode); }
// 得到一个实例产生的纹理的本地复制品 CTexture *texture = loader->iTexture;
// 释放实例 CleanupStack::PopAndDestroy();
// 返回生成的实例 return texture; }
CImageLoader::CImageLoader(const TDesC *aFilename) : CActive(CActive::EPriorityStandard) { // 产生一个本地的Filename复本 iFilename = aFilename->Alloc(); }
CImageLoader::~CImageLoader() { RDebug::Print(_L("CImageLoader::~CImageLoader()"));
// 释放所有数据 delete iFilename; delete iTimer; delete iConverter; delete iBitmap; }
// 进行实际的读写操作 void CImageLoader::ReadImageL() { // 清除纹理 iTexture = NULL;
iTimer = new RTimer(); iTimer->CreateLocal();
// 设定图像读取和转换过程的超时退出 iTimer->After(iStatus, IMAGEREAD_TIMEOUT); SetActive();
// 开始装载数据 iConverter = CMdaImageFileToBitmapUtility::NewL(*this); iConverter->OpenL(*iFilename); }
// 当OpenL()函数完成调用 void CImageLoader::MiuoOpenComplete(TInt aError) { if( aError != KErrNone ) { iErrorCode = aError; Cancel(); return; }
TFrameInfo info; iConverter->FrameInfo(0, info); // 产生一个待写入的位图 iBitmap = new (ELeave) CFbsBitmap(); TInt rc = iBitmap->Create(info.iOverallSizeInPixels, EColor4K); if( rc != KErrNone ) { iErrorCode = rc; Cancel(); return; }
// 将gif图转换为位图 TRAPD(error, iConverter->ConvertL(*iBitmap)); // handle the error if( error != KErrNone) { iErrorCode = error; Cancel(); return; } }
// 当ConvertL()完成时调用 void CImageLoader::MiuoConvertComplete(TInt aError) { if( aError != KErrNone ) { iErrorCode = aError; Cancel(); return; }
CreateTexture();
Cancel(); }
// 快速排序颜色频率表 void CImageLoader::SortFreqTable(TInt aLeft, TInt aRight) { TInt qleft = aLeft; TInt qright = aRight; TInt qpivot = iFreqTable[(qleft + qright) >> 1].freq;
do { while( (iFreqTable[qleft].freq > qpivot) && (qleft < aRight) ) { qleft++; }
while( (qpivot > iFreqTable[qright].freq) && (qright > aLeft) ) { qright--; }
if( qleft <= qright ) { // 交换元素 TUint16 tmp = iFreqTable[qleft].freq; iFreqTable[qleft].freq = iFreqTable[qright].freq; iFreqTable[qright].freq = tmp; tmp = iFreqTable[qleft].color; iFreqTable[qleft].color = iFreqTable[qright].color; iFreqTable[qright].color = tmp;
qleft++; qright--; } } while( qleft <= qright );
if( aLeft < qright ) SortFreqTable(aLeft, qright);
if( qleft < aRight ) SortFreqTable(qleft, aRight); }
inline TUint8 CImageLoader::FindNearestColor(TUint16 aColor, TInt aPaletteSize) { TInt index = -1; TUint difference = 0xffffffff;
// 提取原始颜色成分 TUint red0 = (aColor >> 8) & 0xf; TUint green0 = (aColor >> 4) & 0xf; TUint blue0 = aColor & 0xf;
for( TInt i = 0; i < aPaletteSize; i++ ) { TUint16 color = iFreqTable[i].color;
// 提取原始调色板颜色 TUint red = (color >> 8) & 0xf; TUint green = (color >> 4) & 0xf; TUint blue = color & 0xf;
// 计算cubic区别 TUint diff = ((red0 - red) * (red0 - red)) + ((green0 - green) * (green0 - green)) + ((blue0 - blue) * (blue0 - blue));
if( diff == 0 ) { return (TUint8)i; }
if( diff < difference ) { difference = diff; index = i; } }
return (TUint8)index; }
void CImageLoader::CreateTexture() { // 核对bitmap大小 TSize imagesize = iBitmap->SizeInPixels(); TInt widthshift = 0;
TReal res1, res2, val = (TReal)imagesize.iWidth, two = 2.0; Math::Log(res1, val); Math::Log(res2, two);
// 必须是整型数 res1 = res1 / res2; Math::Frac(res2, res1); if( (res2 == 0.0) && (res1 > 3.0) ) { widthshift = (TInt)res1; } else { iErrorCode = KBadImageWidth; return; }
// 为纹理数据分配内存 TInt texture_data_size = imagesize.iWidth * imagesize.iHeight; TUint8 *data = (TUint8 *)User::Alloc(texture_data_size); if( data == NULL ) { iErrorCode = KErrNoMemory; return; }
// 分配颜色频率矩阵 iFreqTable = (FreqItem *)User::Alloc(4096 * sizeof(FreqItem)); if( iFreqTable == NULL ) { iErrorCode = KErrNoMemory; User::Free(data); return; } Mem::FillZ(iFreqTable, 4096 * sizeof(FreqItem));
// 提取bitmap头 SEpocBitmapHeader hdr = iBitmap->Header();
// 计算实际bitmap数据的起始地址 TInt data_start = (TInt)iBitmap->DataAddress(); TInt datasize = hdr.iBitmapSize - hdr.iStructSize;
// 计算颜色频率 TUint16 *p = (TUint16 *)data_start; datasize >>= 1; for( TInt i = 0; i < datasize; i++ ) { TUint16 color = *p++; iFreqTable[color].color = color; if( iFreqTable[color].freq < 0xffff ) { iFreqTable[color].freq++; } }
TInt num_colors = 0; for( i = 0; i < 4096; i++ ) { if( iFreqTable[i].freq > 0 ) { num_colors++; } }
// 排序颜色频率矩阵 SortFreqTable(0, 4095);
p = (TUint16 *)data_start; for( i = 0; i < datasize; i++ ) { TUint16 color = *p++; data[i] = FindNearestColor(color, 256); }
// 拷贝调色板数据 TUint16 palette[256]; for( i = 0; i < 256; i++ ) { palette[i] = iFreqTable[i].color; }
// 释放颜色表 User::Free(iFreqTable); iFreqTable = NULL;
// 产生纹理对象 TRAPD(error, (iTexture = CTexture::NewL(imagesize.iWidth, imagesize.iHeight, widthshift, palette, data))); if( error != KErrNone ) { User::Free(data); iErrorCode = error; return; } }
// not used void CImageLoader::MiuoCreateComplete(TInt /*aError*/) { } |