这是一个用程序实现如何高效率处理一般图形图象数据的小例子:
用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 <e32base.h>
/**
* 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 <e32base.h>
#include <MdaImageConverter.h>
#include <fbs.h>
#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 <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::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*/)
{
}