操作系统  办公  实用知识  设计  开发  WEB开发  移动开发  数据库  软件工程  网管  安全  管理  信息化  答疑  渠道 

图像载入和色彩剪裁

2006-10-9 网友评论 0 条 点击进入论坛

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

已有 0 位对此文章感兴趣的网友发布了看法    
我来评两句 登录邮箱: 密码:
  匿名发表
今日推荐
技术文库(共有 46468 篇文章)
操作系统
办公软件
实用知识
网络管理
软件开发
WEB开发
软件工程
数据库
设计在线
信息安全
行业信息化
管理信息化
重点推荐
电子杂志订阅
点击电子杂志名称查看样刊
输入E-mail地址即可订阅
E-mail