|
这是一个用程序实现如何高效率处理一般图形图象数据的小例子: 用Series 60 图像格式转换加载文件中(jpg/png/gif 三种格式为例) 的图像 从外部同步化进程,以便你得到一个图像加载的阻断方法 以12位元彩色的256色调色板执行简单色彩剪裁把图像转换成一个带有索引的位图。 注意: 此例子使用嵌套调度。 (嵌套 CActiveScheduler::Start(),CActiveScheduler::Stop()) 这种方法如果误用可能是危险的, 但谨慎地用,它是简单高效的。
以下是 CImageLoader 和 CTexture 这两个类的源文件; CTexture 是一个承载数据, 调色板和画面高度/宽度的图像类,但是因为我在3D texture mapper中直接使用了此代码,它叫做:texture。 程序中写了注释,读起来应该很好理解。当然希望大家从中真正地学到知识,而不是直接拷贝。 并且程序是受版权保护的。
Happy hacking!
--------------------------------------------------------------------------------
texture.h:
#ifndef __TEXTURE_H #define __TEXTURE_H
#include
/** * Represents a texture used by the texture mapping routines. */ class CTexture : public CBase { public: /*! @函数NewL @讨论建立CTexture的一个对象 @param aWidth texture宽度 (须在2的3次幂到2的10次幂之间,从而使宽度在8-1024的范围内) @param aHeight texture高度 @param aWidthShift==log2(aWidth) @param aPalette调色板信息,这个被复制到本地缓冲器中 @param aData 指向调色板指针的索引texture数据,它不被拷贝到本地缓冲器,所 以起始缓冲器在销毁这个对象之前不可以被释放 */ 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(); // texture
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 #include #include
#include "texture.h"
/** *色彩频率调度 */ struct FreqItem { TUint16 freq; TUint16 color; };
/** * 加载图象的有效方法. */ class CImageLoader : public CActive, public MMdaImageUtilObserver { public: /** * 加载texture的错误代码 */ enum TTextureLoadingError { KBadImageWidth = 1666001 };
/*! @函数LoadTextureL @加载一个图象文件并将其转化成的CTexture一个对象 @param 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
#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::Stop() // 在DoCancel()中被唤醒时停止 CActiveScheduler::Start();
// 如果出错,纠正错误代码 if( loader->iTexture == NULL ) { // 实例被cleanupstack销毁 User::Leave(loader->iErrorCode); }
// 得到实例的一个局部拷贝 // if error(s) in process, this will be NULL CTexture *texture = loader->iTexture;
// 解除配置例图 CleanupStack::PopAndDestroy();
// 返回创建的texture return texture; }
CImageLoader::CImageLoader(const TDesC *aFilename) : CActive(CActive::EPriorityStandard) { // 得到文件名的一个本地拷贝 iFilename = aFilename->Alloc(); }
CImageLoader::~CImageLoader() { RDebug::Print(_L("CImageLoader::~CImageLoader()"));
// 删除所有数据 delete iFilename; delete iTimer; delete iConverter; delete iBitmap; }
// 执行当前的读操作和格式转化 void CImageLoader::ReadImageL() { // 重置texture 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)); // 处理错误 if( error != KErrNone) { iErrorCode = error; Cancel(); return; } }
// 当ConvertL()结束时唤醒 void CImageLoader::MiuoConvertComplete(TInt aError) { if( aError != KErrNone ) { iErrorCode = aError; Cancel(); return; }
// 在位图数据外创建iTexture
CreateTexture();
// 解除定时器休眠从而使LoadTextureL()解除阻塞 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); } // 从最初的256入口用最小立方差找到象素 // 为12bit象素构成方法 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;
// 计算立方差异 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() { // 校验位图的大小; 宽度必须在8 to 1024之间 TSize imagesize = iBitmap->SizeInPixels(); TInt widthshift = 0;
// 通过log2(widht)得到正确的值, // 我们将使用log2(x) = log10(x) / log10(2) TReal res1, res2, val = (TReal)imagesize.iWidth, two = 2.0; Math::Log(res1, val); Math::Log(res2, two);
// 一定是一个整数; 检查结果的小数部份是否为0 res1 = res1 / res2; Math::Frac(res2, res1); if( (res2 == 0.0) && (res1 > 3.0) ) { widthshift = (TInt)res1; } else { iErrorCode = KBadImageWidth; return; }
// 为带索引的texture数据分配内存 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));
// 抽取点阵标题 SEpocBitmapHeader hdr = iBitmap->Header(); //计算位图数据的开始位址 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++; } }
//计算num.色彩 TInt num_colors = 0; for( i = 0; i < 4096; i++ ) { if( iFreqTable[i].freq > 0 ) { num_colors++; } }
// 彩色频率行列分类 SortFreqTable(0, 4095);
// 从最初调色板的256个项目中找到最近的匹配 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;
// 创建texture对象 TRAPD(error, (iTexture = CTexture::NewL(imagesize.iWidth, imagesize.iHeight, widthshift, palette, data))); if( error != KErrNone ) { User::Free(data); iErrorCode = error; return; } }
// 不使用 void CImageLoader::MiuoCreateComplete(TInt /*aError*/) { }
|