在线用户    站点地图 技术论坛 文档中心 站点导航 资源下载 语言参考 教程专题 站点统计 业务项目 使用帮助
您的位置
MSDN参考新加了CSS2参考,全中文,制作精良。245k下载。           新加了sxf_sxf推荐的"动态网页专家指导" 下载!          新加了lsg2002lsg推荐的"ASP.NET高级编程(PDF)" 下载!          新加了DHTML代码预览!!,功能强大哦!欢迎试用          新加了网友lincong为大家提供的SQL Server 2000 程序员指南,有点大,但同时也就说明内容全咯!           新加了网友ibra为大家提供的北大的JAVA课件,很适合初学者入门           新加了一个java的连接缓冲池代码示例           新加了人月神话电子版下载!软件工程巨著哦~~           更新了评分标准,引入了“专家分”概念,相信可以更好的激励大家的学习!详情请看“使用帮助”           新加了由网友GGG提供的“IIS超级管理手册”,值得一看哦!(虽然我没看过 :P )           新加了“英雄榜”,欢迎测试!           “无组件上传·从原理剖析到实践”已经全部完成,源码全部开放,有兴趣的朋友请到文档中心一探究竟。  您的位置  首页>文档中心>C++>文档A0000966 在同一窗口中打开页面中的链接 在新窗口中打开页面中的链接 将ASPCHINA设为首页 将ASPCHINA加入书签    
 LOGIN HERE
用户:
密码: 忘记密码
记住密码 用户注册 游客进入
相关文章
没有相关文章
发表文章
TGA图像的处理

作者:happiness     提交人:happiness     发布时间:09-10-08     文章类型:原创     浏览量:3089
参考链结:http://    
关键字:TGA,解压,显示
[本文档没有附件]
字体:    视力保护色: 杏仁黄  秋叶褐  胭脂红  芥末绿  天蓝  雪青  灰  银河白(默认色) [A0000966]

游戏中的场景和角色有时是TGA图像,要想读取该格式的图像,应先了解该文件的结构:
typedef struct tagTGAINFOHEADER
{
  BYTE remarkSize;//图像描述长度,0表示无描述
  BYTE bHasPal;//有无颜色表,1表示有
  BYTE type;//1未压缩的颜色表图像,2,未压缩的RGB图像,9压缩的颜色表图像
  WORD palStartIndex;//颜色表开始索张,一般为0000
  WORD palEntries;//颜色表颜色个数,一般为0x100
  BYTE palBitCount;//颜色表的色深,=24,表示24位色,一个颜色3个字节
  WORD orgX;//图像水平开始点,一般为0000
  WORD orgY;//图像垂直开始点,一般为0000
  WORD width;//图像宽
  WORD height;//图像高
  BYTE bitCount;//一个像素用几个bit,8,8位256色,0x18,24位色
  BYTE remark;//描述开始位,一般为空格0x20,其后的长度由remarkSize决定
}TGAINFOHEADER,*PTGAINFOHEADER,*LPTGAINFOHEADER;

type还可以是:
0  -  文件中没有图像数据
1  -  未压缩的,颜色表图像
2  -  未压缩的,rgb 图像
3  -  未压缩的,黑白图像
9  -  runlength 编码的颜色表图像
10 -  runlength 编码的 rgb 图像
11 -  压缩的,黑白图像
32 -  使用 huffman,delta 和 runlength 编码的颜色表图像
33 -  使用 huffman,delta 和 runlength 编码的颜色映射图像,4 趟四叉树类型处理。

TGA图像数据流不遵循4字节对齐,且行是正序排列,颜色表一般是BB GG RR顺序,结合这些特点,我们可以将TGA转换为BMP图像保存和显示.在此我们主要分析1,2和9的情况:

type=1,2时简单,只需DWORD对齐就行了.
type=9时,解压缩bit流:

数据开始时,第1个即为bFlag(标志码),是一个BYTE,最高位如果是1,则后面是重复数,重复的次数:count = (bFlag & 0x7F) + 1
最高位是0,则后面是原数,数据个数也是count = (bFlag & 0x7F) + 1
根据规律我们很容易找出第2个,第3个...标志码.
00 C3 82 B9 01 90 49 84 4B 81 2E 00 47 82 4B 02 47 3F 47 84 4B 01 3F 47 86 4B 06 49 4B 4B 45 47 3F

红色的是标志码.00是标志码,表示其后是1个原数C3,82是标志码,表示其后是3个B9,01是标志码,表示其后是2个原数90 49,84是标志码,表示其后是5个4B...
所以还原过来就是:
C3 B9 B9 B9 90 49 4B 4B 4B 4B 4B ...
这种算法不是以行为单位的压缩.

新建一个基于CDocument类的CPicDoc类,用于处理TGA和保存数据,新建一个基于CScrollView的CPicView类,用于滚屏显示TGA图像.(不要忘了新建一个基于CMDIChildWnd的框架类)

不要用以上结构,用指针,因为结构里有不连续的BYTE值,不对齐,引用成员时和sizeof时会得到错误的值,所以直接用索引来访问.
因为是正序行,所以用-height来正常显示.

BYTE* m_pBmData是CPicDoc中的一个成员变量,用于保存BMP全部数据,方便显示和保存.
BOOL CPicDoc::LoadTgaFile(LPCTSTR lpszFileName)
{
  CFile file(lpszFileName, CFile::modeRead);
  BOOL bResult = FALSE;
  ////////////header
  BYTE tgaif[0x12];
  file.Read(tgaif, sizeof(tgaif));
  BYTE bHasPal = tgaif[1];//有无调色板
  BYTE type = tgaif[2];//图片类型
  WORD palEntries = *(WORD*)(tgaif + 0x05);//颜色表颜色个数
  WORD tgWidth = *(WORD*)(tgaif + 0x0c);//TGA宽
  WORD tgHeight = *(WORD*)(tgaif + 0x0e);//TGA高
  BYTE bitCount = *(BYTE*)(tgaif + 0x10);//TGA bit out
  int bmWidth = tgWidth % 4 == 0 ? tgWidth : tgWidth + 4 - (tgWidth % 4);//转换成4字节对齐的BMP宽
  DWORD bmBitsSize  = bmWidth * tgHeight * (bitCount / 8);//BMP图像流尺寸
  DWORD bmInfoSize  = sizeof(BITMAPINFOHEADER) + palEntries * sizeof(RGBQUAD);//BMP信息尺寸
  DWORD bmSize = sizeof(BITMAPFILEHEADER) + bmInfoSize + bmBitsSize;//BMP文件尺寸
  BITMAPFILEHEADER bmfh = {0x4d42, bmSize, 0, 0, sizeof(BITMAPFILEHEADER) + bmInfoSize};//BMP文件头
  BITMAPINFOHEADER bmih = {0x28, tgWidth, - tgHeight, 1, bitCount, 0, 0, 0, 0, palEntries, 0};//BMP信息头
  ///////////////////////////
  file.SeekToBegin();
  int tgSize = file.GetLength();
  BYTE* pTgBuf = new BYTE[tgSize];
  file.Read(pTgBuf, tgSize);
  m_pBmData = new BYTE[bmSize];
  memset(m_pBmData, 0, bmSize);
  memcpy(m_pBmData, &bmfh, sizeof(bmfh));//bitmap file header
  memcpy(m_pBmData + sizeof(bmfh), &bmih, sizeof(bmih));//bitmap info header
  BYTE* pTg = pTgBuf + 0x12 + *pTgBuf;
  BYTE* pBm = m_pBmData + sizeof(bmfh) + sizeof(bmih);
  if ((type == 1 || type == 9) && bHasPal == 1)
  {
    //////////palette
    for(int i = 0; i < palEntries; i ++)
    {
      BYTE* p  = pTg + i * 3;
      RGBQUAD rgb = {*p, *(p + 1), *(p + 2), 0};
      *(RGBQUAD*)(pBm + i * 4) = rgb;
    }
    /////////bits
    pTg += palEntries * 3;//TGA数据开始位置
    pBm += palEntries * sizeof(RGBQUAD);//BMP数据开始位置
    if (type == 1)
    {
      AlignDOWD(pBm, pTg, tgWidth, tgHeight, bitCount / 8);//对齐DWORD
    }
    else if (type == 9)
    {
      //decompress bits
      BYTE* pTempBits = new BYTE[bmBitsSize];
      BYTE* pTemp = pTempBits;
      while (pTg < pTgBuf + tgSize)
      {
        BYTE flags = *pTg;//标志
        int size = (flags & 0x7F) + 1;//长度
        pTg ++;
        if (flags > 0x7F)
        {
          memset(pTemp, *pTg, size);//重复size次
          pTg ++;
        }
        else
        {
          memcpy(pTemp, pTg, size);//拷贝size个原数
          pTg += size;
        }
        pTemp += size;//目的指针
      }
      AlignDOWD(pBm, pTempBits, tgWidth, tgHeight, bitCount / 8);//对齐DWORD
      delete pTempBits;
    }
    bResult = TRUE;
  }
  else if ((type == 2) && bHasPal == 0)
  {
    AlignDOWD(pBm, pTg, tgWidth, tgHeight, bitCount / 8);//对齐DWORD
    bResult = TRUE;
  }
  delete pTgBuf;

  return bResult;
}

void CPicDoc::AlignDOWD(BYTE *pDest, BYTE *pSrc, int nSrcWidth, int nSrcHeight, int nByte)
{
  if (nSrcWidth % 4 == 0)
  {
    memcpy(pDest, pSrc, nSrcWidth * nSrcHeight * nByte);
  }
  else
  {
    int nDestWidth = nSrcWidth + 4 - (nSrcWidth % 4);
    for (int rows = 0; rows < nSrcHeight; rows ++)
    {
      memcpy(pDest + rows * nDestWidth * nByte, pSrc + rows * nSrcWidth * nByte, nSrcWidth * nByte);
    }
  }
}

SIZE CPicDoc::GetPicSize()
{
  BITMAPINFOHEADER* p = (BITMAPINFOHEADER*)(m_pBmData + sizeof(BITMAPFILEHEADER));
  int cy = p->biHeight < 0 ? -p->biHeight : p->biHeight;
  SIZE sz = {p->biWidth, cy};
  return sz;
}

显示代码:
void CPicView::OnInitialUpdate()
{
  CScrollView::OnInitialUpdate();
  CPicDoc* pDoc = GetDocument();
  CSize sizeTotal = pDoc->GetPicSize();
  SetScrollSizes(MM_TEXT, sizeTotal);
}

void CPicView::OnDraw(CDC* pDC)
{
  CPicDoc* pDoc = GetDocument();
  HDC hDC = pDC->m_hDC;
  SIZE sizeTotal = pDoc->GetPicSize();
  BITMAPINFOHEADER* lpbmih = (BITMAPINFOHEADER*)(pDoc->m_pBmData + sizeof(BITMAPFILEHEADER));
  BYTE* lpbInit = pDoc->m_pBmData + ((BITMAPFILEHEADER*)pDoc->m_pBmData)->bfOffBits;

  ::StretchDIBits(hDC, 0, 0, sizeTotal.cx, sizeTotal.cy,
    0, 0, sizeTotal.cx, sizeTotal.cy, lpbInit, (BITMAPINFO*)lpbmih, DIB_RGB_COLORS, SRCCOPY);
}

保存成BITMAP图像,直接写入m_pBmData就行了,所以没有在此写出代码.以上代码在MFC下测试成功.
不要忘了在CPicDoc类构造函数中:
{
  m_pBmData = NULL;
}
在CPicDoc类在析构函数中:
{
  if (m_pBmData)
    delete m_pBmData;
}



关于这篇文章的评论 [注意:这里仅仅是给大家提供了一个发表对文章本身看法的地方,如果有疑问,请到论坛提出] 我要提问!
标题
内容
发言
*您尚未以注册用户身份登录,不能发表评论。这里登录
您的位置
  (c)2000-2018 Yup Studio, all rights reserved.  
66.40625