开发视界翻译-图像载入和色彩剪裁

sbamdanb00 2006-03-07 07:59:34
出处:开发视界-http://www.sf.org.cn


这是一个用程序实现如何高效率处理一般图形图象数据的小例子:
用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);
}

贴子一次不能发太长剩余请到这里查看
http://www.sf.org.cn/Article/symbiandev/200603/17219.html
...全文
222 4 打赏 收藏 转发到动态 举报
写回复
用AI写文章
4 条回复
切换为时间正序
请发表友善的回复…
发表回复
sbamdanb00 2006-03-07
  • 打赏
  • 举报
回复
子腾兄所言甚是,下次一定注意
chenziteng 2006-03-07
  • 打赏
  • 举报
回复
二次不行可以发三次嘛,哈哈
--------------------------------------------------------------------------------

// 当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*/)
{
}
chenziteng 2006-03-07
  • 打赏
  • 举报
回复
一次不行发二次嘛,哈哈。
--------------------------------------------------------------------------------

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;
}
}
Brunhild 2006-03-07
  • 打赏
  • 举报
回复
mark

3,119

社区成员

发帖
与我相关
我的任务
社区描述
塞班系统(Symbian系统)是塞班公司为手机而设计的操作系统,它的前身是英国宝意昂公司的 EP ( Electronic Piece of cheese)操作系统。
社区管理员
  • Symbian社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧